From 935c934277bf3453804534dee194f2fedbee60c7 Mon Sep 17 00:00:00 2001
From: LHCb Analysis Productions Bot <lhcb-dpa-wp2-admins@cern.ch>
Date: Thu, 11 Apr 2024 08:37:51 +0000
Subject: [PATCH 01/70] Add dynamic options

---
 ap_merger.py                                  | 112 ++++++++++++++++++
 ...darkScalar2hh_2018_MagDown_job_autoconf.py |  13 ++
 ...r_darkScalar2hh_2018_MagUp_job_autoconf.py |  13 ++
 3 files changed, 138 insertions(+)
 create mode 100644 ap_merger.py
 create mode 100644 dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagDown_job_autoconf.py
 create mode 100644 dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagUp_job_autoconf.py

diff --git a/ap_merger.py b/ap_merger.py
new file mode 100644
index 0000000000..cf7dc2fac6
--- /dev/null
+++ b/ap_merger.py
@@ -0,0 +1,112 @@
+###############################################################################
+# (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.                                       #
+###############################################################################
+import subprocess
+import sys
+import tempfile
+import xml.etree.ElementTree as ET
+from pathlib import Path
+
+# pylint: disable=import-error
+from GaudiConf.LbExec.options import FileFormats
+from GaudiConf.LbExec.options import Options as OptionsBase
+
+SUMMARY_XML_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
+<summary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:noNamespaceSchemaLocation="$XMLSUMMARYBASEROOT/xml/XMLSummary.xsd">
+    <success>True</success>
+    <step>finalize</step>
+    <usage><stat unit="KB" useOf="MemoryMaximum">0</stat></usage>
+    <input>
+{input_files}
+    </input>
+    <output>
+{output_files}
+    </output>
+</summary>
+"""
+XML_FILE_TEMPLATE = '     <file GUID="" name="{name}" status="full">{n}</file>'
+ALG_TO_CODE = {
+    "ZLIB": 1,
+    "LZMA": 2,
+    "LZ4": 4,
+    "ZSTD": 5,
+}
+
+
+class Options(OptionsBase):
+    """Conditions"""
+
+    input_type: FileFormats = FileFormats.ROOT
+    simulation: None = False
+    data_type: None = None
+
+
+def read_xml_file_catalog(xml_file_catalog):
+    if xml_file_catalog is None:
+        return {}
+
+    tree = ET.parse(xml_file_catalog)
+    pfn_lookup: dict[str, list[str]] = {}
+    for file in tree.findall("./File"):
+        lfns = [x.attrib.get("name") for x in file.findall("./logical/lfn")]
+        if len(lfns) == 0:
+            continue
+        if len(lfns) > 1:
+            raise NotImplementedError(lfns)
+        lfn = lfns[0]
+        pfn_lookup[f"LFN:{lfn}"] = [
+            x.attrib.get("name") for x in file.findall("./physical/pfn")
+        ]
+    return pfn_lookup
+
+
+def resolve_input_files(input_files, file_catalog):
+    resolved = []
+    for input_file in input_files:
+        if input_file.startswith("LFN:"):
+            print("Resolved", input_file, "to", file_catalog[input_file][0])
+            input_file = file_catalog[input_file][0]
+        resolved.append(input_file)
+    return resolved
+
+
+def hadd(options: Options, compression: str = "ZSTD:4"):
+    file_catalog = read_xml_file_catalog(options.xml_file_catalog)
+    input_files = resolve_input_files(options.input_files, file_catalog)
+
+    alg, level = compression.split(":")
+    flags = [f"-f{ALG_TO_CODE[alg]}{int(level):02d}"]
+    flags += ["-j", f"{options.n_threads}"]
+    flags += ["-n", f"{max(10, options.n_threads*2)}"]
+
+    with tempfile.NamedTemporaryFile(mode="wt") as tmpfile:
+        tmpfile.write("\n".join(input_files))
+        tmpfile.flush()
+        cmd = ["hadd"] + flags + [options.ntuple_file, f"@{tmpfile.name}"]
+        print("Running", cmd)
+        subprocess.run(cmd, check=True)
+
+    summary_xml = SUMMARY_XML_TEMPLATE.format(
+        input_files="\n".join(
+            XML_FILE_TEMPLATE.format(
+                name=name if name.startswith("LFN:") else f"PFN:{name}", n=1
+            )
+            for name in options.input_files
+        ),
+        output_files=XML_FILE_TEMPLATE.format(
+            name=f"PFN:{options.ntuple_file}", n=len(input_files)
+        ),
+    )
+    if options.xml_summary_file:
+        print("Writing XML summary to", options.xml_summary_file)
+        Path(options.xml_summary_file).write_text(summary_xml)
+
+    print("All done")
+    sys.exit(0)
diff --git a/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagDown_job_autoconf.py b/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagDown_job_autoconf.py
new file mode 100644
index 0000000000..f079315413
--- /dev/null
+++ b/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagDown_job_autoconf.py
@@ -0,0 +1,13 @@
+from Configurables import DaVinci
+try:
+    DaVinci().Turbo = False
+except AttributeError:
+    # Older DaVinci versions don't support Turbo at all
+    pass
+
+DaVinci().InputType = 'MDST'
+DaVinci().DataType = '2018'
+DaVinci().Simulation = False
+DaVinci().Lumi = True
+from Configurables import CondDB
+CondDB(LatestGlobalTagByDataType=DaVinci().DataType)
\ No newline at end of file
diff --git a/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagUp_job_autoconf.py b/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagUp_job_autoconf.py
new file mode 100644
index 0000000000..f079315413
--- /dev/null
+++ b/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagUp_job_autoconf.py
@@ -0,0 +1,13 @@
+from Configurables import DaVinci
+try:
+    DaVinci().Turbo = False
+except AttributeError:
+    # Older DaVinci versions don't support Turbo at all
+    pass
+
+DaVinci().InputType = 'MDST'
+DaVinci().DataType = '2018'
+DaVinci().Simulation = False
+DaVinci().Lumi = True
+from Configurables import CondDB
+CondDB(LatestGlobalTagByDataType=DaVinci().DataType)
\ No newline at end of file
-- 
GitLab


From 80c7235ace67a97c61a258b2bb29f5af33aa6412 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 18 Jun 2024 11:31:26 +0100
Subject: [PATCH 02/70] test

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 bu2kdarkscalar_darkscalar2hh/info.yaml

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
new file mode 100644
index 0000000000..a5a3712843
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -0,0 +1,25 @@
+{%- set polarities = ["Down", "Up"]%}
+
+{%- for polarity in polarities %}
+
+Bu2KdarkScalar_darkScalar2hh_2018_Mag{{polarity}}_job:
+  application: DaVinci/v46r8
+  wg: QEE
+  automatically_configure: yes
+  turbo: no
+  inform:
+    - eleanor.whiter@cern.ch
+  options:
+    command:
+      - python
+    files:
+      - job.py
+      - photonSource_default.py
+
+  input:
+    bk_query: /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
+    
+  output: bu2kdarkscalar_darkscalar2hh.ROOT
+
+
+{%- endfor %}
\ No newline at end of file
-- 
GitLab


From dbf2d927f01a2900477e029b43a4aca037dd8c8b Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 18 Jun 2024 11:40:25 +0100
Subject: [PATCH 03/70] monte carlo test

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index a5a3712843..7637fb7664 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -2,7 +2,7 @@
 
 {%- for polarity in polarities %}
 
-Bu2KdarkScalar_darkScalar2hh_2018_Mag{{polarity}}_job:
+Bu2KKK_2018_Mag{{polarity}}_job:
   application: DaVinci/v46r8
   wg: QEE
   automatically_configure: yes
@@ -17,9 +17,12 @@ Bu2KdarkScalar_darkScalar2hh_2018_Mag{{polarity}}_job:
       - photonSource_default.py
 
   input:
-    bk_query: /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
+    bk_query: /MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
+
+    #/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
     
-  output: bu2kdarkscalar_darkscalar2hh.ROOT
+  output: B2KKK.ROOT
+  #bu2kdarkscalar_darkscalar2hh.ROOT
 
 
 {%- endfor %}
\ No newline at end of file
-- 
GitLab


From a86251ffa5a26a6d55e69c3d091c2b99b71a5bb8 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 26 Jun 2024 11:16:48 +0100
Subject: [PATCH 04/70] comments

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 7637fb7664..9c5aaa8adf 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -2,7 +2,7 @@
 
 {%- for polarity in polarities %}
 
-Bu2KKK_2018_Mag{{polarity}}_job:
+Bu2KdarkScalar_darkScalar2hh_2018_Mag{{polarity}}_job:
   application: DaVinci/v46r8
   wg: QEE
   automatically_configure: yes
@@ -17,11 +17,12 @@ Bu2KKK_2018_Mag{{polarity}}_job:
       - photonSource_default.py
 
   input:
-    bk_query: /MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
-
+    bk_query: /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
+    #/MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
     #/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
     
-  output: B2KKK.ROOT
+  output: bu2kdarkscalar_darkscalar2hh.ROOT
+  #B2KKK.ROOT
   #bu2kdarkscalar_darkscalar2hh.ROOT
 
 
-- 
GitLab


From 1fc25d04a67b65e2994fb39829693c8bc68b2feb Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 15 Jul 2024 13:23:18 +0100
Subject: [PATCH 05/70] adapted AP to work to process MC

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 587 ++++++++++++
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 939 +++++++++++++++++++
 bu2kdarkscalar_darkscalar2hh/inputData.py    |  14 +
 bu2kdarkscalar_darkscalar2hh/job.py          | 135 +++
 4 files changed, 1675 insertions(+)
 create mode 100644 bu2kdarkscalar_darkscalar2hh/MCEventTools.py
 create mode 100644 bu2kdarkscalar_darkscalar2hh/Ntuple.py
 create mode 100644 bu2kdarkscalar_darkscalar2hh/inputData.py
 create mode 100644 bu2kdarkscalar_darkscalar2hh/job.py

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
new file mode 100644
index 0000000000..e985d51e09
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -0,0 +1,587 @@
+import ROOT as r
+import GaudiPython as GP
+from GaudiConf import IOHelper
+from Configurables import DaVinci, TriggerTisTos, ToolSvc
+from ROOT import TLorentzVector as tlv
+from LoKiMC.decorators import MCPX, MCPY, MCPZ, MCE, MCID, MCABSID, MCPT, MCM, MCETA, MCP, MCPHI
+from LoKiPhys.decorators import M, PX, PY, PZ, E, ID, ABSID, PROBNNk, PROBNNghost, IPCHI2, P, PT, CL, ETA, TRGHOSTPROB, PHI
+from array import array
+from math import sqrt
+
+class MCPart:
+    """
+    Simple class for storing rec and gen mc particles.
+
+    INPUTS
+    ------
+    par (mandatory): particle or mc particle from TES [LHCb.Particle/LHCb.MCParticle]
+    dl             : list of daughter particles [list]
+    tos            : list of L0 and HLT1 TOS [list(bool)]
+    ipc2           : IPCHI2 parameter [float]
+    lpar           : linked particle [MCPart]
+    orvrt          : MCParticle origin vertex type
+    mother         : MCParticle mother [MCPart]
+
+    INTERNAL MEMBERS
+    ----------------
+    par        : particle or mc particle
+    pid        : particle's PID
+    isrec      : flag for if particle is rec or gen [bool]
+    p          : particle's 4-vector [TLorentzVector]
+    dl         : daughter list
+    tos        : tos list 
+    ipc2       : IPCHI2 parameter
+    lpar       : linked particle
+    corlinked  : flag (intended for Bs) for whether all daughter particles have been
+                 linked to like particles (i.e. pi+ linked to pi+) [bool]
+    alllinked  : flag (intended for Bs) for whether all daughter particles have
+                 been linked to anything [bool]
+    orvrt      : origin vertex type for LHCb.MCParticle type particles
+    mother     : mother particles for LHCb.MCParticle type particles
+    clink      : flag (intended for daughter particles) for whether particle has
+                 been linked to a matching particle type [bool]
+    pnnk       : particle's PROBNNk
+    pnng       : particle's PROBNNghost
+    trgp       : particle's TRGHOSTPROB
+    dectype    : category of decay type (assigned via MCEvent.categorize()) [int]
+    lineage    : stores shared ancestor particles (back to grandmother particle) [list(int)]
+                    -first digit is ancestor relation to h-
+                    -second digit is ancestor relation to h+
+                    -third digit is ancestor relation to K
+                    -1: particle; 2: mother; 3: grandmother; 0: no shared relation (if only two particles share ancestor)
+    sl         : sister list (other particles from same origin vertex)
+    cl         : particle's confidence level
+    isdrmatched: flag for if a B candidate has been linked using delta r matching
+    pv         : coordinates of associated PV [list(float)]
+    sv         : coordinates of associated SV [list(float)]
+    odectype   : category of other decay type [int]
+    bgtype     : background category [int]
+    """
+    def __init__(self, par, dl=[], tos=[0,0,0], ipc2=None, lpar=None, orvrt=None,
+                 mother=None, clink=None, pnnk=None, pnng=None, trgp=None, dectype=None,
+                 lineage=None, sl=[], cl=None, isdrmatched=False, pv=[], sv=[],
+                 odectype=None, bgtype=None):
+        self.par = par
+        self.pid = int(self.par.particleID().pid())
+        self.p = tlv(par.momentum().Px(),par.momentum().Py(),par.momentum().Pz(),par.momentum().E())
+        self.dl = dl
+        self.tos = tos
+        self.ipc2 = ipc2
+        self.lpar = lpar
+        self.corlinked = False
+        self.alllinked = False
+        self.orvrt = orvrt
+        self.mother = mother
+        self.clink = clink
+        self.pnnk = pnnk
+        self.pnng = pnng
+        self.trgp = trgp
+        self.dectype = dectype
+        self.lineage = lineage
+        self.sl = sl
+        self.cl = cl
+        self.isdrmatched = isdrmatched
+        self.pv = pv
+        self.sv = sv
+        self.odectype = odectype
+        self.bgtype = bgtype
+
+    def update(self, newdp=None, newdl=None, newl0tos=0, newhlt1etos=0, newhlt1mvatos=0,
+               newtos=[], newipc2=None, newlpar=None, newcorlinked=0, neworvrt=None,
+               newmother=None, newclink=None, newpnnk=None, newpnng=None, newtrgp=None,
+               newdectype=None, newlineage=None, newsp=None, newsl=None, newalllinked=0,
+               newcl=None, newisdrmatched=None, newpv=None, newsv=None,
+               newodectype=None, newbgtype=None):
+        """
+        Method for updating MCPart information.
+
+        INPUTS
+        ------
+        newdp        : adds single daughter particle to existing daughter list [MCPart]
+        newdl        : overwrites existing daughter list with newdl [list(MCPart)]
+        newl0tos     : updates L0 TOS [bool]
+        newhlt1etos  : updates HLT1Electron TOS [bool]
+        newhlt1mvatos: updates HLT1TrackMVA TOS [bool]
+        newtos       : overwrites existing tos list with newtos [list(bool)]
+        newipc2      : updates ipc2 (float)
+        newlpar      : updates linked particle (MCPart)
+        newcorlinked : updates the corlinked flag [bool]
+        neworvrt     : updates origin vertex type
+        newmother    : updates associated mother particle
+        newclink     : updates clink flag [bool]
+        newpnnk      : updates PROBNNk
+        newpnng      : updates PROBNNghost
+        newtrgp      : updates TRGHOSTPROB
+        newdectype   : updates the B decay type
+        newlineage   : updates the shared ancestor list
+        newsp        : adds single sister particle to existing list [MCPart]
+        newsl        : overwrites existing sister list with newsl [list(MCPart)]
+        newalllinked : updates the alllinked flag [bool]
+        newcl        : updates particle's confidence level
+        """
+        if newdp != None:
+            if type(newdp) == type(self): self.dl += [newdp]
+            else: self.dl += [MCPart(newdp)]
+        if newdl != None: self.dl = newdl
+        if newl0tos != 0: self.tos[0] = newl0tos
+        if newhlt1etos != 0: self.tos[1] = newhlt1etos
+        if newhlt1mvatos != 0: self.tos[2] = newhlt1mvatos
+        #if len(newtos) == 2: self.tos = newtos
+        if len(newtos) == 3: self.tos = newtos
+        if newipc2 != None: self.ipc2 = newipc2
+        if newlpar != None:
+            if type(newlpar) == type(self): self.lpar = newlpar
+            else: self.lpar = MCPart(newlpar)
+        if newcorlinked != 0: self.corlinked = newcorlinked
+        if newalllinked != 0: self.alllinked = newalllinked
+        if neworvrt != None: self.orvrt = neworvrt
+        if newmother != None:
+            if type(newmother) == type(self): self.mother = newmother
+            else: self.mother = MCPart(newmother)
+        if newclink != None: self.clink = newclink
+        if newpnnk != None: self.pnnk = newpnnk
+        if newpnng != None: self.pnng = newpnng
+        if newtrgp != None: self.trgp = newtrgp
+        if newdectype != None: self.dectype = newdectype
+        if newlineage != None:
+            if type(newlineage) == list: self.lineage = newlineage
+            elif type(newlineage) == int: self.lineage += [newlineage]
+        if newsp != None:
+            if type(newsp) == type(self): self.dl += [newsp]
+            else: self.dl += [MCPart(newsp)]
+        if newsl != None: self.sl = newsl
+        if newcl != None: self.cl = newcl
+        if newisdrmatched != None: self.isdrmatched = newisdrmatched
+        if newpv != None: self.pv = newpv
+        if newsv != None: self.sv = newsv
+        if newodectype != None: self.odectype = newodectype
+        if newbgtype != None: self.bgtype = newbgtype
+
+class MCEvent:
+    """
+    Class for processing MC events.
+    """
+    def __init__(self, all_Bparticles, mctool):
+        """
+        Initializes MCEvent class. Creates list of rec level Bparticles, adds associated
+        daughter particles to Bparticles daughter list.
+
+        INPUTS
+        ------
+        all_Bparticles   : B+/B-s from the TES
+        mctool : IParticle2MCWeightedAssociator instance to be used
+
+        INTERNAL MEMBERS
+        ----------------
+        hcuts: flag for whether the applyhcuts method has been run on this instance
+               of MCEvent [bool]
+        links: flag for whether the linkpars method has been run on this instance
+               of MCEvent [bool]
+        Bparticles  : list of combined Bparticles with daughter particles in daughter list [list(MCPart)]
+        """
+        self.hcuts = False
+        self.links = False
+        self.iscategorized = False
+        self.Bstore = all_Bparticles
+        self.mctool = mctool
+        self.Bparticles = []
+        self.dihquery = []
+        for Bparticle in all_Bparticles: # loop over all the B+/B-s stored in the TES
+            dps = [0,0]
+            dpsv = None
+            svcoor = None
+            for dp in B.daughters(): # loop over the daughters of the B+/B- particle
+                if abs(ID(dp)) == 321:
+                    dps[1] = MCPart(dp,pnnk=PROBNNk(dp),pnng=PROBNNghost(dp),cl=CL(dp))
+                else:
+                    hadrons = [0,0]
+                    dpsv = dp.endVertex()
+                    for ddp in dp.endVertex().outgoingParticlesVector():
+                        hadron = MCPart(ddp)
+                        hadron.update(newpnnk=PROBNNk(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
+                        if hadron.pid == 321: hadrons[0] = hadron
+                        elif hadron.pid == -321: hadrons[1] = hadron
+                    svcoor = [dpsv.position().X(),dpsv.position().Y(),dpsv.position().Z()]
+                    dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
+            B = MCPart(Bparticle,dl=dps)
+            self.Bparticles += [B]
+
+    def linkpars(self):
+        """
+        Links the rec level daughter particles (K, h-, h+) to gen level particles.
+        rels refers to related particles
+        rel_K: related K particle
+        rel_hadron_minus: related h- particle
+        rel_hadron_plus: related h+ particle
+        """
+        self.allreglinked = True
+        for Bparticle in self.Bparticles:
+            rels = self.mctool.relatedMCPs(Bparticle.dl[1].par)
+            w = 0
+            rel_K = None
+            for rel in rels:
+                if rel.weight() > w: w = rel.weight(); rel_K = rel.to()
+            if rel_K:
+                Bparticle.dl[1].update(newlpar=MCPart(rel_K,orvrt=rel_K.originVertex().type()))
+                if rel_K.originVertex().type() != 1:
+                    try:
+                        rel_K.mother().originVertex().type()
+                        Bparticle.dl[1].lpar.update(newmother=MCPart(rel_K.mother(),orvrt=rel_K.mother().originVertex().type()))
+                        if rel_K.mother().originVertex().type() != 1:
+                            try:
+                                rel_K.mother().mother().originVertex().type()
+                                Bparticle.dl[1].lpar.mother.update(newmother=MCPart(rel_K.mother().mother(),orvrt=rel_K.mother().mother().originVertex().type()))
+                            except:
+                                Bparticle.dl[1].lpar.mother.update(newmother=None)
+                    except:
+                        Bparticle.dl[1].lpar.update(newmother=None)
+
+                if MCID(rel_K) == Bparticle.dl[1].pid: Bparticle.dl[1].update(newclink=True)
+                else: Bparticle.dl[1].update(newclink=False)
+
+            rels = self.mctool.relatedMCPs(Bparticle.dl[0].dl[0].par)
+            w = 0
+            rel_hadron_minus = None
+            for rel in rels:
+                if rel.weight() > w: w = rel.weight(); rel_hadron_minus = rel.to()
+            if rel_hadron_minus:
+                Bparticle.dl[0].dl[0].update(newlpar=MCPart(rel_hadron_minus,orvrt=rel_hadron_minus.originVertex().type()))
+                if rel_hadron_minus.originVertex().type() != 1:
+                    try:
+                        rel_hadron_minus.mother().originVertex().type()
+                        Bparticle.dl[0].dl[0].lpar.update(newmother=MCPart(rel_hadron_minus.mother(),orvrt=rel_hadron_minus.mother().originVertex().type()))
+                        if rel_hadron_minus.mother().originVertex().type() != 1:
+                            try:
+                                rel_hadron_minus.mother().mother().originVertex().type()
+                                Bparticle.dl[0].dl[0].lpar.mother.update(newmother=MCPart(rel_hadron_minus.mother().mother(),orvrt=rel_hadron_minus.mother().mother().originVertex().type()))
+                            except:
+                                Bparticle.dl[0].dl[0].lpar.mother.update(newmother=None)
+                    except:
+                        Bparticle.dl[0].dl[0].lpar.update(newmother=None)
+                if MCID(rel_hadron_minus) == Bparticle.dl[0].dl[0].pid: Bparticle.dl[0].dl[0].update(newclink=True)
+                else: Bparticle.dl[0].dl[0].update(newclink=False)
+
+            rels = self.mctool.relatedMCPs(Bparticle.dl[0].dl[1].par)
+            w = 0
+            rel_hadron_plus = None
+            for rel in rels:
+                if rel.weight() > w: w = rel.weight(); rel_hadron_plus = rel.to()
+            if rel_hadron_plus:
+                Bparticle.dl[0].dl[1].update(newlpar=MCPart(rel_hadron_plus,orvrt=rel_hadron_plus.originVertex().type()))
+                if rel_hadron_plus.originVertex().type() != 1:
+                    try:
+                        rel_hadron_plus.mother().originVertex().type()
+                        particle.dl[0].dl[1].lpar.update(newmother=MCPart(rel_hadron_plus.mother(),orvrt=rel_hadron_plus.mother().originVertex().type()))
+                        if rel_hadron_plus.mother().originVertex().type() != 1:
+                            try:
+                                rel_hadron_plus.mother().mother().originVertex().type()
+                                Bparticle.dl[0].dl[1].lpar.mother.update(newmother=MCPart(rel_hadron_plus.mother().mother(),orvrt=rel_hadron_plus.mother().mother().originVertex().type()))
+                            except:
+                                Bparticle.dl[0].dl[1].lpar.mother.update(newmother=None)
+                    except:
+                        Bparticle.dl[0].dl[1].lpar.update(newmother=None)
+                if MCID(rel_hadron_plus) == Bparticle.dl[0].dl[1].pid: Bparticle.dl[0].dl[1].update(newclink=True)
+                else: Bparticle.dl[0].dl[1].update(newclink=False)
+
+            if rel_K and rel_hadron_minus and rel_hadron_plus:
+                Bparticle.update(newalllinked=True)
+                if MCID(rel_K) == Bparticle.dl[1].pid and MCID(rel_hadron_minus) == Bparticle.dl[0].dl[0].pid and MCID(rel_hadron_plus) == Bparticle.dl[0].dl[1].pid: Bparticle.update(newcorlinked=True)
+
+                if Bparticle.dl[1].lpar.mother:
+                    if Bparticle.dl[1].lpar.mother.mother:
+                        Klin = [Bparticle.dl[1].lpar.par,Bparticle.dl[1].lpar.mother.par, Bparticle.dl[1].lpar.mother.mother.par]
+                    else:
+                        Klin = [Bparticle.dl[1].lpar.par,Bparticle.dl[1].lpar.mother.par]
+                else: Klin = [Bparticle.dl[1].lpar.par]
+
+                if Bparticle.dl[0].dl[0].lpar.mother:
+                    if Bparticle.dl[0].dl[0].lpar.mother.mother:
+                        hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par,Bparticle.dl[0].dl[0].lpar.mother.par, Bparticle.dl[0].dl[0].lpar.mother.mother.par]
+                    else:
+                        hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par,Bparticle.dl[0].dl[0].lpar.mother.par]
+                else: hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par]
+
+                if Bparticle.dl[0].dl[1].lpar.mother:
+                    if Bparticle.dl[0].dl[1].lpar.mother.mother:
+                        hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par, B.dl[0].dl[1].lpar.mother.mother.par]
+                    else:
+                        hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par]
+                else: hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par]
+
+                sharelin = []
+                for i in range(len(hadron_minus_lin)):
+                    for j in range(len(hadron_plus_lin)):
+                        for k in range(len(Klin)):
+                            lin = 0
+                            if hadron_minus_lin[i] == hadron_plus_lin[j]:
+                                lin += (i+1)*100 + (j+1)*10
+                                if hadron_minus_lin[i] == Klin[k]: lin += k+1; sharelin += [lin]
+                                else: sharelin += [lin]
+                            else:
+                                if hadron_minus_lin[i] == Klin[k]: lin += (i+1)*100 + (k+1); sharelin += [lin]
+                                if hadron_plus_lin[j] == Klin[k]: lin = 0; lin += (j+1)*10 + (k+1); sharelin += [lin]
+                B.update(newlineage=sharelin)
+
+                for prt in B.dl[1].lpar.par.originVertex().products():
+                    B.dl[1].lpar.update(newsp=prt)
+                if B.dl[1].lpar.mother:
+                    for prt in B.dl[1].lpar.mother.par.originVertex().products():
+                        B.dl[1].lpar.mother.update(newsp=prt)
+
+                for prt in B.dl[0].dl[0].lpar.par.originVertex().products():
+                    Bparticle.dl[0].dl[0].lpar.update(newsp=prt)
+                if Bparticle.dl[0].dl[0].lpar.mother:
+                    for prt in B.dl[0].dl[0].lpar.mother.par.originVertex().products():
+                        Bparticle.dl[0].dl[0].lpar.mother.update(newsp=prt)
+
+                for prt in Bparticle.dl[0].dl[1].lpar.par.originVertex().products():
+                    Bparticle.dl[0].dl[1].lpar.update(newsp=prt)
+                if Bparticle.dl[0].dl[1].lpar.mother:
+                    for prt in B.dl[0].dl[1].lpar.mother.par.originVertex().products():
+                        Bparticle.dl[0].dl[1].lpar.mother.update(newsp=prt)
+            elif self.allreglinked: self.allreglinked = False
+        self.links = True
+
+    def deltarlink(self, mcpstore):
+        if not self.links: self.linkpars()
+
+        for Bparticle in self.Bparticles:
+            if not Bparticle.alllinked:
+                for recp in [Bparticle.dl[1],Bparticle.dl[0].dl[0],Bparticle.dl[0].dl[1]]:
+                    if not recp.lpar:
+                        mindr = 99999999999
+                        parlink = None
+                        for mcp in mcpstore:
+                            if MCID(mcp) == recp.pid:
+                                dphi = MCPHI(mcp) - PHI(recp.par)
+                                deta = MCETA(mcp) - ETA(recp.par)
+                                deltar = sqrt(dphi**2 + deta**2)
+                                if deltar < mindr: mindr = deltar; parlink = mcp
+                        recp.update(newlpar=MCPart(parlink,orvrt=parlink.originVertex().type()))
+                        if MCID(parlink) == recp.pid: recp.update(newclink=True)
+                        else: recp.update(newclink=False)
+                        if parlink.originVertex().type() != 1:
+                            try:
+                                parlink.mother().originVertex().type()
+                                recp.lpar.update(newmother=MCPart(parlink.mother(),orvrt=parlink.mother().originVertex().type()))
+                                if parlink.mother().originVertex().type() != 1:
+                                    try:
+                                        parlink.mother().mother().originVertex().type()
+                                        recp.lpar.mother.update(newmother=MCPart(parlink.mother().mother(),orvrt=parlink.mother().mother().originVertex().type()))
+                                    except:
+                                        recp.lpar.mother.update(newmother=None)
+                            except:
+                                recp.lpar.update(newmother=None)
+
+                if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar:
+                    B.update(newisdrmatched=True)
+                    if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
+
+                    if B.dl[1].lpar.mother:
+                        if B.dl[1].lpar.mother.mother:
+                            Klin = [B.dl[1].lpar.par,B.dl[1].lpar.mother.par, B.dl[1].lpar.mother.mother.par]
+                        else:
+                            Klin = [B.dl[1].lpar.par,B.dl[1].lpar.mother.par]
+                    else: Klin = [B.dl[1].lpar.par]
+
+                    if B.dl[0].dl[0].lpar.mother:
+                        if B.dl[0].dl[0].lpar.mother.mother:
+                            hadron_minus_lin = [B.dl[0].dl[0].lpar.par,B.dl[0].dl[0].lpar.mother.par, B.dl[0].dl[0].lpar.mother.mother.par]
+                        else:
+                            hadron_minus_lin = [B.dl[0].dl[0].lpar.par,B.dl[0].dl[0].lpar.mother.par]
+                    else: hadron_minus_lin = [B.dl[0].dl[0].lpar.par]
+
+                    if B.dl[0].dl[1].lpar.mother:
+                        if B.dl[0].dl[1].lpar.mother.mother:
+                            hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par, B.dl[0].dl[1].lpar.mother.mother.par]
+                        else:
+                            hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par]
+                    else: hadron_plus_lin = [B.dl[0].dl[1].lpar.par]
+
+                    sharelin = []
+                    for i in range(len(hadron_minus_lin)):
+                        for j in range(len(hadron_plus_lin)):
+                            for k in range(len(Klin)):
+                                lin = 0
+                                if hadron_minus_lin[i] == hadron_plus_lin[j]:
+                                    lin += (i+1)*100 + (j+1)*10
+                                    if hadron_minus_lin[i] == Klin[k]: lin += k+1; sharelin += [lin]
+                                    else: sharelin += [lin]
+                                else:
+                                    if hadron_minus_lin[i] == Klin[k]: lin += (i+1)*100 + (k+1); sharelin += [lin]
+                                    if hadron_plus_lin[j] == Klin[k]: lin = 0; lin += (j+1)*10 + (k+1); sharelin += [lin]
+                    B.update(newlineage=sharelin)
+
+                    for prt in B.dl[1].lpar.par.originVertex().products():
+                        B.dl[1].lpar.update(newsp=prt)
+                    if B.dl[1].lpar.mother:
+                        for prt in B.dl[1].lpar.mother.par.originVertex().products():
+                            B.dl[1].lpar.mother.update(newsp=prt)
+
+                    for prt in B.dl[0].dl[0].lpar.par.originVertex().products():
+                        B.dl[0].dl[0].lpar.update(newsp=prt)
+                    if B.dl[0].dl[0].lpar.mother:
+                        for prt in B.dl[0].dl[0].lpar.mother.par.originVertex().products():
+                            B.dl[0].dl[0].lpar.mother.update(newsp=prt)
+
+                    for prt in B.dl[0].dl[1].lpar.par.originVertex().products():
+                        B.dl[0].dl[1].lpar.update(newsp=prt)
+                    if B.dl[0].dl[1].lpar.mother:
+                        for prt in B.dl[0].dl[1].lpar.mother.par.originVertex().products():
+                            B.dl[0].dl[1].lpar.mother.update(newsp=prt)
+
+    def corlin(self, B):
+        """
+        Internal method to be used in cattest method for determining if an MC
+        candidate has been linked properly and its source type can be categorized.
+        """
+        if B.corlinked: pass
+        else: return False
+
+        K = B.dl[1]
+        hadron_minus = B.dl[0].dl[0]
+        hadron_plus = B.dl[0].dl[1]
+
+        try: hadron_plus.lpar.mother.orvrt
+        except: return False
+
+        try: hadron_minus.lpar.mother.orvrt
+        except: return False
+
+        return True
+
+    def categorize(self):
+        """
+        Categorizes the type of decay (i.e. type of background, signal).
+
+        SOURCE TYPES
+        ------------
+
+        0: MC signal (B+/- -> K+/- darkScalar (darkScalar -> h- h+) )
+        1: MC normalisation (B+/- -> K+/- h- h+)
+        9: there was an error in MC truth matching
+        """
+        if not self.links: self.linkpars()
+
+        for Bparticle in self.Bparticles:
+            if self.corlin(B):
+                K = Bparticle.dl[1]
+                hadron_minus = Bparticle.dl[0].dl[0]
+                hadron_plus = Bparticle.dl[0].dl[1]
+                try: fillKpid = K.lpar.mother.pid
+                except: fillKpid = 0
+
+                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(B.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle
+                    #if K is K+ this must be a B+, if K is K- this must be a B-
+                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=0)
+                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=0)
+
+
+            for dp in Bparticle.dl:
+                dp.update(newbgtype=Bparticle.bgtype)
+                for ddp in dp.dl:
+                    ddp.update(newbgtype=Bparticle.bgtype)
+
+    def bgtypequery(self, part):
+        """
+        Method to match an input particle to a TES particle and return the
+        input particle's decay type.
+
+        INPUTS
+        ------
+        part: particle to be matched [LHCb Particle object]
+
+        OUTPUTS
+        -------
+        dectype: decay type of the input particle [int]
+        """
+        dectype = -99
+        B = None
+        if ID(part) == 310:
+            dectype = ID(part)
+        elif part in self.Bstore:
+            for Bparticle in self.Bparticles:
+                if part == B.par:
+                    B = B
+                    break
+            if B != None:
+                K = B.dl[1]
+                hadron_minus = B.dl[0].dl[0]
+                hadron_plus = B.dl[0].dl[1]
+
+                fill_B_dectype = B.dectype # fill B decay type
+                fill_B_odectype = B.odectype # fill B decay type
+                try: hadron_minus_morvrt = em.lpar.mother.orvrt
+                except: hadron_minus_morvrt = 99
+                try: hadron_plus_morvrt = _hadron_plus.lpar.mother.orvrt
+                except: hadron_plus_morvrt = 99
+                K_orvrt = K.orvrt
+
+                try:
+                    fill_K_mother_dectype = K.lpar.mother.pid
+                except:
+                    fill_K_mother_dectype.pid = 0
+                if not B.corlinked or hadron_minus_morvrt == 99 or hadron_plus_morvrt == 99:
+                    dectype = 8
+                elif fill_B_dectype == 0:
+                    dectype = 0
+            else:
+                dectype = -33
+        else:
+            dectype = -66
+
+        return dectype
+
+    def drquery(self, part):
+        """
+        Method to match an input particle to a TES particle and return if the
+        input particle's MC truth matching was done by delta R matching.
+
+        INPUTS
+        ------
+        part: particle to be matched [LHCb Particle object]
+
+        OUTPUTS
+        -------
+        drmatch: whether particle was delta R matched [int (0: no; 1: yes; 99: error)]
+        """
+        drmatch = 99
+        B = None
+        if ID(part) == 310:
+            drmatch = ID(part)
+        elif part in self.Bstore:
+            for Bparticle in self.Bparticles:
+                if part == Bparticle.par:
+                    B = Bparticle
+                    break
+            if B != None:
+                if B.isdrmatched: drmatch = 1
+                else: drmatch = 0
+            else:
+                drmatch = 9
+
+        return drmatch
+
+    def mcpquery(self, part):
+        """
+        Method to match an input particle to a TES particle and return the
+        input particle's MCPart object.
+
+        INPUTS
+        ------
+        part: particle to be matched [LHCb Particle object]
+
+        OUTPUTS
+        -------
+        B: MCPart object of the corresponding B/eta [MCPart]
+        """
+        B = None
+        if ID(part) == 310:
+            B = self.Bparticles[0]
+        elif part in self.Bstore:
+            for Bparticle in self.Bparticles:
+                if part == Bparticle.par:
+                    B = Bparticle
+                    break
+
+        return B
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
new file mode 100644
index 0000000000..cbebf68a4e
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -0,0 +1,939 @@
+"""Defines the Ntuple class for storing an ntuple."""
+import array
+from collections import OrderedDict
+import ctypes
+from math import sqrt
+import time
+from typing import Any, Union
+
+from Configurables import DaVinci
+import GaudiPython
+from LoKiArrayFunctors.decorators import AMAXDOCA
+import ROOT
+
+from dtf import dtf
+import MCEventTools
+from ReconstructionTools import BremOverlapChecker, SelectRhos
+
+
+class Ntuple:
+    """Class for storing an ntuple."""
+
+    ###########################################################################
+    def __init__(
+        self, gaudi, output_filename: "str"
+    ):
+        """Initialize the ntuple."""
+        # Internal tools.
+        #self.combinatorial_fakePhotons = combinatorial_fakePhotons
+        self._detTool = gaudi.detSvc()["/dd/Structure/LHCb/BeforeMagnetRegion/Velo"]
+        self._pvrTool = gaudi.toolsvc().create(
+            "GenericParticle2PVRelator<_p2PVWithIPChi2, "
+            "OfflineDistanceCalculatorName>/P2PVWithIPChi2",
+            interface="IRelatedPVFinder",
+        )
+        self._dstTool = gaudi.toolsvc().create(
+            "LoKi::TrgDistanceCalculator", interface="IDistanceCalculator"
+        )
+        self._trkTool = gaudi.toolsvc().create(
+            "TrackMasterExtrapolator", interface="ITrackExtrapolator"
+        )
+        self._trgTool = [
+            gaudi.toolsvc().create("L0TriggerTisTos", interface="ITriggerTisTos"),
+            gaudi.toolsvc().create(
+                "TriggerTisTos/Hlt1TriggerTisTos", interface="ITriggerTisTos"
+            ),
+            gaudi.toolsvc().create(
+                "TriggerTisTos/Hlt2TriggerTisTos", interface="ITriggerTisTos"
+            ),
+            gaudi.toolsvc().create(
+                "TriggerTisTos/Strip/PhysTriggerTisTos", interface="ITriggerTisTos"
+            ),
+        ]
+        self._docaTool = GaudiPython.gbl.LoKi.Particles.DOCA(0, 0, self._dstTool)
+        self._veloTool = ROOT.VeloMaterial()
+
+        # Triggers.
+        self.tos: "list[list[str]]" = [
+            ["L0Electron.*"],
+            ["Hlt1.*Electron.*", "Hlt1.*TrackMVA.*"],
+            ["Hlt2ExoticaPi0ToDiEGamma", "Hlt2ExoticaEtaToDiEGamma"],
+            [],
+        ]
+        self.tis: "list[list[str]]" = [[], [], ["Hlt2Topo.*"], []]
+
+        # Stored variables.
+        self.saved: "dict[str, int]" = {}
+        self.keys: "dict[str, str]" = {}
+        self.pres = {"tag": 0, "trk": 1, "cal": 2}
+        self.nhit = 2
+        self.ntuple: "OrderedDict[str, array.array | Any]" = OrderedDict()
+        self.tfile = ROOT.TFile(output_filename, "RECREATE", "", 207)
+        self.ttree = ROOT.TTree("DecayData", "DecayData")
+        self.pvrs = "Rec/Vertex/Primary"
+        if DaVinci().InputType == "MDST":
+            self.pvrs = "Leptonic/" + self.pvrs
+        vrsVrt = ["x", "y", "z", "dx", "dy", "dz"]
+        vrsMom = ["px", "py", "pz", "e"]
+        vrsTrk = [
+            "pnn_e",
+            "pnn_mu",
+            "pnn_pi",
+            "pnn_k",
+            "pnn_p",
+            "pnn_ghost",
+            "ip",
+            "ip_chi2",
+            "vt_miss",
+            "mm",
+            "dmm",
+            "m",
+            "dm",
+            "idx_pvr",
+            "ecalx",
+            "ecaly",
+            "ecalz",
+            "veloCharge",
+        ]
+        for h in range(0, self.nhit):
+            vrsTrk += [f"x{h}", f"y{h}", f"z{h}", f"t{h}", f"p{h}"]
+        vrsTag = (
+            [
+                "mm",
+                "dmm",
+                "m",
+                "dm",
+                "doca",
+                "chi2",
+                "ip",
+                "ip_chi2",
+                "fd",
+                "fd_chi2",
+                "vt_tip",
+                "vt_d",
+                "withBrem",
+                "BremMatched",
+                "photonBremOverlap",
+                "nBremAdded_em",
+                "nBremAdded_ep",
+                "etrackOL",
+            ]
+            + [
+                f"{dtf}dtf_{x}"
+                for dtf in ["p", "d"]
+                for x in ["m", "dm", "chi2"]
+                + vrsMom
+                + vrsVrt
+                + [f"die_{y}" for y in ["m"] + vrsMom]
+            ]
+            + [f"die_{x}" for x in ["m"] + vrsMom]
+        )
+
+        vrsMC = []
+        if DaVinci().Simulation:
+            dps = ["em", "ep", "g"]
+            params = ["mpid", "orvrt", "morvrt", "mmpid", "mmorvrt"]
+            for dp in dps:
+                vrsMC += [dp + "_lpid"]
+                vrsMC += [dp + "_l" + param for param in vrsMom]
+                vrsMC += [dp + "_" + param for param in params]
+            vrsMC += ["bgtype", "drmatch"]
+
+        vrsTrg = [
+            f"tos{idx}" for idx in range(0, sum(len(lvl) for lvl in self.tos))
+        ] + [f"tis{idx}" for idx in range(0, sum(len(lvl) for lvl in self.tis))]
+        vrsIdx = ["idx_pvr", "idx_prt0", "idx_prt1", "pre_prt0", "pre_prt1"]
+        self._vrs("tag", vrsIdx + vrsMom + ["pid"] + vrsVrt + vrsTag + vrsTrg + vrsMC)
+        self._vrs("trk", vrsMom + ["pid"] + vrsTrk)
+        self._vrs("cal", ["mm", "dmm", "m", "dm", "idx_pvr", "pid"] + vrsMom)
+        self._vrs("pvr", vrsVrt)
+        self.ntuple["pvr_n"] = array.array("i", [-1])
+        self.ntuple["spd_n"] = array.array("i", [-1])
+        self.ntuple["run_n"] = array.array("l", [-1])
+        self.ntuple["evt_n"] = array.array("l", [-1])
+        self.ntuple["evt_tck"] = array.array("l", [-1])
+        # tmap = {int: "/I", long: "/L", float: "/F"}
+        tmap = {"i": "/I", "l": "/L", "f": "/F"}
+        for key, val in self.ntuple.items():
+            if isinstance(val, array.array):
+                self.ttree.Branch(key, val, key + tmap[val.typecode])
+            else:
+                self.ttree.Branch(key, val)
+
+        # Cache time and size.
+        self.tfile.Write(self.ttree.GetName(), ROOT.TObject.kOverwrite)
+        self.size = self.tfile.GetBytesWritten()
+        self.time = time.time()
+
+    ###########################################################################
+    def _vrs(self, pre: "str", vrs):
+        """Initialize variables with a given prefix."""
+        self.keys[pre] = f"{pre}_{vrs[0]}"
+        tmap = {"int": ["pid", "idx", "pre", "tip", "Brem"], "bool": ["tis", "tos"]}
+        for var in vrs:
+            t = "float"
+            for key, k_list in tmap.items():
+                if any(sub in var for sub in k_list):
+                    t = key
+                    break
+            self.ntuple[f"{pre}_{var}"] = ROOT.vector(t)()
+
+    ###########################################################################
+    def _key(self, obj):
+        """Return the key for an object."""
+        try:
+            trk = obj.proto().track().momentum()
+        except:
+            trk = None
+        try:
+            cal = obj.proto().calo()[0].position()
+        except:
+            cal = None
+        try:
+            vrt = obj.position()
+        except:
+            vrt = None
+        if trk:
+            return (trk.X(), trk.Y(), trk.Z())
+        if cal:
+            return (cal.x(), cal.y(), cal.z(), cal.e())
+        if vrt:
+            return (vrt.X(), vrt.Y(), vrt.Z())
+        return (obj.momentum().Px(), obj.momentum().Py(), obj.momentum().Pz())
+
+    ###########################################################################
+    def _save(self, pre: "str", key):
+        """Save an object and return the index."""
+        val: "Any" = self.ntuple[self.keys[pre]]
+        idx = val.size() - 1
+        self.saved[key] = idx
+        return idx
+
+    ###########################################################################
+    def _index(self, key):
+        """Return the saved index, if it exists."""
+        return self.saved.get(key)
+
+    ###########################################################################
+    def close(self, events):
+        """Close the ntuple."""
+        pTime = ROOT.TParameter(float)("time", time.time() - self.time)
+        self.tfile.WriteTObject(self.ttree, self.ttree.GetName(), "Overwrite")
+        pSize = ROOT.TParameter(float)("size", self.tfile.GetBytesWritten() - self.size)
+        pEvts = ROOT.TParameter(int)("evts", events)
+        self.tfile.WriteTObject(pTime, "time", "Overwrite")
+        self.tfile.WriteTObject(pSize, "size", "Overwrite")
+        self.tfile.WriteTObject(pEvts, "evts", "Overwrite")
+        self.tfile.Close()
+
+    ###########################################################################
+    def clear(self):
+        """Clear the ntuple."""
+        self.saved.clear()
+        for val in self.ntuple.values():
+            try:
+                val.clear()
+            except:
+                val[0] = -1
+
+    ###########################################################################
+    def fill(
+        self,
+        key: "str | None" = None,
+        val: "float | int | None" = None,
+        idx: "int | None" = None,
+    ):
+        """Fill a variable into the ntuple."""
+        if key is None and val is None:
+            self.tfile.Cd("")
+            self.ttree.Fill()
+        elif key is not None and val is not None:
+            if key not in self.ntuple:
+                raise ValueError(f"key '{key}' not recognized")
+            if idx is None:
+                _nval: "Any" = self.ntuple[key]
+                _nval.push_back(val)
+            elif idx < len(self.ntuple[key]):
+                self.ntuple[key][idx] = val
+            else:
+                raise ValueError(
+                    f"idx must be less than {len(self.ntuple[key])} for '{key}'"
+                    f", not {idx}"
+                )
+        else:
+            raise ValueError("must specify both key and val or neither")
+
+    ###########################################################################
+    def _fillVrt(self, pre: "str", pos, cov: "list[list[float]] | None"):
+        """Fill a vertex."""
+        if pos is None or cov is None:
+            self.fill(f"{pre}_x", -1)
+            self.fill(f"{pre}_y", -1)
+            self.fill(f"{pre}_z", -1)
+            self.fill(f"{pre}_dx", -1)
+            self.fill(f"{pre}_dy", -1)
+            self.fill(f"{pre}_dz", -1)
+        else:
+            self.fill(f"{pre}_x", pos.X())
+            self.fill(f"{pre}_y", pos.Y())
+            self.fill(f"{pre}_z", pos.Z())
+            self.fill(f"{pre}_dx", sqrt(abs(cov[0][0])))
+            self.fill(f"{pre}_dy", sqrt(abs(cov[1][1])))
+            self.fill(f"{pre}_dz", sqrt(abs(cov[2][2])))
+
+    ###########################################################################
+    def _fillMom(self, pre: "str", mom):
+        """Fill momentum for a particle."""
+        if mom is None:
+            self.fill(f"{pre}_px", -1)
+            self.fill(f"{pre}_py", -1)
+            self.fill(f"{pre}_pz", -1)
+            self.fill(f"{pre}_e", -1)
+        else:
+            self.fill(f"{pre}_px", mom.Px())
+            self.fill(f"{pre}_py", mom.Py())
+            self.fill(f"{pre}_pz", mom.Pz())
+            self.fill(f"{pre}_e", mom.E())
+
+    ###########################################################################
+    def _fillMM(self, pre: "str", prt):
+        """Fill measured mass for a particle."""
+        self.fill(f"{pre}_mm", prt.measuredMass())
+        self.fill(f"{pre}_dmm", prt.measuredMassErr())
+
+    ###########################################################################
+    def _fillM(self, pre: "str", mom):
+        """Fill mass from a particle's momentum."""
+        try:
+            m_class = mom.m()
+            m = m_class.value()
+            dm = m_class.error()
+        except:
+            m = -1
+            dm = -1
+        self.fill(f"{pre}_m", m)
+        self.fill(f"{pre}_dm", dm)
+
+    ###########################################################################
+    def _filldieMomMass(self, pre: "str", mom):
+        """Fill momentum and mass for a particle."""
+        if mom is None:
+            self.fill(f"{pre}_die_px", -1)
+            self.fill(f"{pre}_die_py", -1)
+            self.fill(f"{pre}_die_pz", -1)
+            self.fill(f"{pre}_die_e", -1)
+            self.fill(f"{pre}_die_m", -1)
+        else:
+            self.fill(f"{pre}_die_px", mom.Px())
+            self.fill(f"{pre}_die_py", mom.Py())
+            self.fill(f"{pre}_die_pz", mom.Pz())
+            self.fill(f"{pre}_die_e", mom.E())
+            self.fill(f"{pre}_die_m", mom.M())
+
+    ###########################################################################
+    def _fillgenMomPID(self, pre: "str", mcp):
+        """Fill generator level MC momentum and pid for a particle."""
+        if mcp:
+            if mcp.pid == 11:
+                dptype = "em"
+            elif mcp.pid == -11:
+                dptype = "ep"
+            elif mcp.pid == 22:
+                dptype = "g"
+            else:
+                raise ValueError(f"mcp.pid {mcp.pid} not recognized")
+            mom = mcp.lpar.p
+            lpid = mcp.lpar.pid
+            try:
+                lpid = int(mcp.lpar.pid)
+            except:
+                lpid = 99
+            self.fill(f"{pre}_{dptype}_lpx", mom.Px())
+            self.fill(f"{pre}_{dptype}_lpy", mom.Py())
+            self.fill(f"{pre}_{dptype}_lpz", mom.Pz())
+            self.fill(f"{pre}_{dptype}_le", mom.E())
+            self.fill(f"{pre}_{dptype}_lpid", lpid)
+        else:
+            for dptype in ["em", "ep", "g"]:
+                self.fill(f"{pre}_{dptype}_lpx", -1)
+                self.fill(f"{pre}_{dptype}_lpy", -1)
+                self.fill(f"{pre}_{dptype}_lpz", -1)
+                self.fill(f"{pre}_{dptype}_le", -1)
+                self.fill(f"{pre}_{dptype}_lpid", -1)
+
+    ###########################################################################
+    def _filltrkOL(self, pre: "str", prt):
+        """Find number of shared track lhcbIDs between e- and e+.
+
+        Accessed through dielectron candidate.
+        """
+        if prt.particleID().pid() == 310:
+            nol = 0
+            em = ep = None
+            for i_dp in range(len(prt.daughtersVector())):
+                dp = prt.daughtersVector()[i_dp]
+                #if dp.particleID().pid() == -321:
+                if dp.particleID().pid() == -321 or dp.particleID().pid() == -211:
+                    assert em is None
+                    em = dp
+                #elif dp.particleID().pid() == 321:
+                elif dp.particleID().pid() == 321 or dp.particleID().pid() == 211:
+                    assert ep is None
+                    ep = dp
+            assert em is not None and ep is not None, prt
+            for i_emid in range(len(em.proto().track().lhcbIDs())):
+                emid = em.proto().track().lhcbIDs()[i_emid]
+                for i_epid in range(len(ep.proto().track().lhcbIDs())):
+                    epid = ep.proto().track().lhcbIDs()[i_epid]
+                    if emid == epid:
+                        nol += 1
+            if (nol * 1.0) / len(em.proto().track().lhcbIDs()) > (nol * 1.0) / len(
+                ep.proto().track().lhcbIDs()
+            ):
+                olperc = (nol * 1.0) / len(em.proto().track().lhcbIDs())
+            else:
+                olperc = (nol * 1.0) / len(ep.proto().track().lhcbIDs())
+        else:
+            olperc = -1
+        self.fill(f"{pre}_etrackOL", olperc)
+
+    ###########################################################################
+    def _fillMat(
+        self,
+        pre: "str",
+        pvr,
+        pos,
+        dtrs: "list",
+        cov: "list[list[float]] | None",
+        year: "int",
+        run: "int",
+    ):
+        """Fill the material information for a particle.
+
+        Relies on self.veloTool.
+        """
+        if pvr and len(dtrs) == 2 and not any(x is None for x in (pos, cov)):
+            if year not in (2016, 2017, 2018):
+                raise ValueError(f"year {year} not recognized")
+            pvp = pvr.position()
+            vfv = (pos.X() - pvp.X(), pos.Y() - pvp.Y(), pos.Z() - pvp.Z())
+            assert cov is not None
+            self.fill(
+                f"{pre}_vt_d",
+                self._veloTool.distance(
+                    pos.X(),
+                    pos.Y(),
+                    pos.Z(),
+                    vfv[0],
+                    vfv[1],
+                    vfv[2],
+                    dtrs[0].Px(),
+                    dtrs[0].Py(),
+                    dtrs[0].Pz(),
+                    dtrs[1].Px(),
+                    dtrs[1].Py(),
+                    dtrs[1].Pz(),
+                    sqrt(abs(cov[0][0])),
+                    sqrt(abs(cov[1][1])),
+                    sqrt(abs(cov[2][2])),
+                    year,
+                    run,
+                ),
+            )
+            self.fill(
+                f"{pre}_vt_tip",
+                self._veloTool.tip(
+                    pvp.X(), pvp.Y(), pvp.Z(), vfv[0], vfv[1], vfv[2], year, run
+                ),
+            )
+        else:
+            self.fill(f"{pre}_vt_d", -1)
+            self.fill(f"{pre}_vt_tip", -1)
+
+    ###########################################################################
+    def _fillBrem(self, pre: "str", prt: "Any"):
+        """Fill the Brem information for a particle."""
+        if prt.particleID().pid() == 113:
+            # pion/eta
+            assert prt.hasInfo(1) and prt.hasInfo(2)
+            extraInfo = prt.extraInfo()
+            self.fill(f"{pre}_withBrem", int(extraInfo[1]))
+            self.fill(f"{pre}_BremMatched", int(extraInfo[2]))
+        else:
+            # not pion/eta
+            assert not (prt.hasInfo(1) or prt.hasInfo(2))
+            self.fill(f"{pre}_withBrem", -1)
+            self.fill(f"{pre}_BremMatched", -1)
+        BOC = BremOverlapChecker(prt)
+        self.fill(f"{pre}_photonBremOverlap", BOC.overlapFound())
+        self.fill(f"{pre}_nBremAdded_em", BOC.nBremAdded("em"))
+        self.fill(f"{pre}_nBremAdded_ep", BOC.nBremAdded("ep"))
+
+    ###########################################################################
+    def _fillTrg(self, pre: "str", prt):
+        """Fill the trigger lines for a particle."""
+        # Trigger on signal decisions.
+        idx = 0
+        for trg, decs in zip(self._trgTool, self.tos):
+            trg.setOfflineInput(prt)
+            for dec in decs:
+                trg.setTriggerInput(dec + "Decision")
+                dec = trg.tisTosTobTrigger()
+                self.fill(f"{pre}_tos{idx}", dec.tos())
+                idx = idx + 1
+
+        # Trigger independent signal decisions.
+        idx = 0
+        for trg, decs in zip(self._trgTool, self.tis):
+            trg.setOfflineInput(prt)
+            for dec in decs:
+                trg.setTriggerInput(dec + "Decision")
+                dec = trg.tisTosTobTrigger()
+                self.fill(f"{pre}_tis{idx}", dec.tis())
+                idx = idx + 1
+
+    ###########################################################################
+    def _fillTag(
+        self,
+        pre: "str",
+        prt,
+        year: "int",
+        run: "int",
+        check=False,
+        mctool=None,
+    ):
+        """Fill the information for a tag."""
+        # Vertex.
+        pvr = self._pvrTool.relatedPV(prt, self.pvrs)
+        mom = prt.momentum()
+        vrt = prt.endVertex()
+        cov = vrt.covMatrix()
+        pos = vrt.position()
+        if check:
+            if prt.particleID().pid() not in (521, -521, 310):
+                return False
+            for i_dtr in range(len(prt.daughtersVector())):
+                dtr = prt.daughtersVector()[i_dtr]
+                if not self.fillPrt(dtr, pos, year, run, mctool=mctool, check=True):
+                    return False
+            if pvr == -1:
+                return False
+            return True
+
+        pdtf = dtf(prt, pvr, True)
+        ddtf = dtf(prt, pvr, False)
+        if prt.particleID().pid() in (-521, 521):
+            # pion/eta
+            pdtf.fit()
+            ddtf.fit()
+            assert pdtf.dielectron == ddtf.dielectron
+            assert pdtf.dielectron is not None
+            dtrp = pdtf.dielectron.momentum()
+        elif prt.particleID().pid() == 310:
+            # dielectron
+            dtrp = prt.momentum()
+        else:
+            raise ValueError(
+                f"prt.particleID().pid() {prt.particleID().pid()} not recognized"
+            )
+
+        # Daughters.
+        daughter_momenta = []
+        for idx in range(len(prt.daughtersVector())):
+            dtr = prt.daughtersVector()[idx]
+            daughter_momenta += [dtr.momentum()]
+            dtrPre, dtrIdx = self.fillPrt(  # type: ignore
+                dtr, pos, year, run, mctool=mctool
+            )
+            self.fill(f"{pre}_idx_prt{idx}", dtrIdx)
+            self.fill(f"{pre}_pre_prt{idx}", self.pres[dtrPre])
+            # dtf (dtf_pos) not implemented for these daughters
+            # because fillPrt is designed to automatically determine the branch names
+
+        self._filldieMomMass(pre, dtrp)
+        self._filldieMomMass(f"{pre}_pdtf", pdtf.get_die_momentum())
+        self._filldieMomMass(f"{pre}_ddtf", ddtf.get_die_momentum())
+        self._filltrkOL(pre, prt)
+
+        # MC BG type
+        if mctool is not None:
+            mcprt = mctool.mcpquery(prt)
+
+            if mcprt:
+                self._fillgenMomPID(pre, mcprt.dl[1])
+                self._fillgenMomPID(pre, mcprt.dl[0].dl[0])
+                self._fillgenMomPID(pre, mcprt.dl[0].dl[1])
+            else:
+                self._fillgenMomPID(pre, mcprt)
+
+            try:
+                emmpid = int(mcprt.dl[0].dl[0].lpar.mother.pid)
+            except:
+                emmpid = 99
+            try:
+                epmpid = int(mcprt.dl[0].dl[1].lpar.mother.pid)
+            except:
+                epmpid = 99
+            try:
+                gmpid = int(mcprt.dl[1].lpar.mother.pid)
+            except:
+                gmpid = 99
+
+            try:
+                emorvrt = int(mcprt.dl[0].dl[0].lpar.orvrt)
+            except:
+                emorvrt = 99
+            try:
+                eporvrt = int(mcprt.dl[0].dl[1].lpar.orvrt)
+            except:
+                eporvrt = 99
+            try:
+                gorvrt = int(mcprt.dl[1].lpar.orvrt)
+            except:
+                gorvrt = 99
+
+            try:
+                emmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.orvrt)
+            except:
+                emmorvrt = 99
+            try:
+                epmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.orvrt)
+            except:
+                epmorvrt = 99
+            try:
+                gmorvrt = int(mcprt.dl[1].lpar.mother.orvrt)
+            except:
+                gmorvrt = 99
+
+            try:
+                emmmpid = int(mcprt.dl[0].dl[0].lpar.mother.mother.pid)
+            except:
+                emmmpid = 99
+            try:
+                epmmpid = int(mcprt.dl[0].dl[1].lpar.mother.mother.pid)
+            except:
+                epmmpid = 99
+            try:
+                gmmpid = int(mcprt.dl[1].lpar.mother.mother.pid)
+            except:
+                gmmpid = 99
+
+            try:
+                emmmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.mother.orvrt)
+            except:
+                emmmorvrt = 99
+            try:
+                epmmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.mother.orvrt)
+            except:
+                epmmorvrt = 99
+            try:
+                gmmorvrt = int(mcprt.dl[1].lpar.mother.mother.orvrt)
+            except:
+                gmmorvrt = 99
+
+            try:
+                bgt = int(mcprt.bgtype)
+            except:
+                bgt = 99
+
+            self.fill(f"{pre}_bgtype", bgt)
+            try:
+                drm = 1 if mcprt.isdrmatched else 0
+            except:
+                drm = -1
+            self.fill(f"{pre}_drmatch", drm)
+
+            self.fill(f"{pre}_em_mpid", emmpid)
+            self.fill(f"{pre}_ep_mpid", epmpid)
+            self.fill(f"{pre}_g_mpid", gmpid)
+
+            self.fill(f"{pre}_em_mmpid", emmmpid)
+            self.fill(f"{pre}_ep_mmpid", epmmpid)
+            self.fill(f"{pre}_g_mmpid", gmmpid)
+
+            self.fill(f"{pre}_em_orvrt", emorvrt)
+            self.fill(f"{pre}_ep_orvrt", eporvrt)
+            self.fill(f"{pre}_g_orvrt", gorvrt)
+
+            self.fill(f"{pre}_em_morvrt", emmorvrt)
+            self.fill(f"{pre}_ep_morvrt", epmorvrt)
+            self.fill(f"{pre}_g_morvrt", gmorvrt)
+
+            self.fill(f"{pre}_em_mmorvrt", emmmorvrt)
+            self.fill(f"{pre}_ep_mmorvrt", epmmorvrt)
+            self.fill(f"{pre}_g_mmorvrt", gmmorvrt)
+
+        # Trigger.
+        self._fillTrg(pre, prt)
+
+        # Vertex.
+        self.fill(f"{pre}_doca", AMAXDOCA("")(prt.daughters()))
+        self.fill(f"{pre}_chi2", vrt.chi2())
+        self.fill(
+            f"{pre}_pdtf_chi2", -1 if pdtf.get_chi2() is None else pdtf.get_chi2()
+        )
+        self.fill(
+            f"{pre}_ddtf_chi2", -1 if ddtf.get_chi2() is None else ddtf.get_chi2()
+        )
+        self._fillVrt(pre, pos, cov)
+        self._fillVrt(
+            f"{pre}_pdtf", pdtf.get_position(), pdtf.get_position_covariance()
+        )
+        self._fillVrt(
+            f"{pre}_ddtf", ddtf.get_position(), ddtf.get_position_covariance()
+        )
+
+        # Material tool.
+        self._fillMat(pre, pvr, pos, daughter_momenta, cov, year, run)
+        # fillMat not implemented for dtf b/c it's a pain to code up daughter momenta
+
+        # Brem.
+        self._fillBrem(pre, prt)
+
+        # Flight distance.
+        fd, fdChi2 = ctypes.c_double(-1), ctypes.c_double(-1)
+        if pvr and vrt:
+            self._dstTool.distance(vrt, pvr, fd, fdChi2)
+        self.fill(f"{pre}_fd", fd.value)
+        self.fill(f"{pre}_fd_chi2", fdChi2.value)
+
+        # IP and momentum.
+        self._fillMom(pre, mom)
+        self._fillMom(f"{pre}_pdtf", pdtf.get_momentum())
+        self._fillMom(f"{pre}_ddtf", ddtf.get_momentum())
+        self._fillMM(pre, prt)
+        self._fillM(pre, mom)
+        self._fillM(f"{pre}_pdtf", pdtf.get_momentum())
+        self._fillM(f"{pre}_ddtf", ddtf.get_momentum())
+        ip, ipChi2 = ctypes.c_double(-1), ctypes.c_double(-1)
+        if pvr:
+            self._dstTool.distance(prt, pvr, ip, ipChi2)
+        self.fill(f"{pre}_ip", ip.value)
+        self.fill(f"{pre}_ip_chi2", ipChi2.value)
+
+        return pvr
+
+    ###########################################################################
+    def _fillTrk(self, pre: str, prt, org, year: "int", run: "int"):
+        """Fill the information for a track."""
+        # Particle ID variables.
+        pid, pro, mom = prt.particleID().pid(), prt.proto(), prt.momentum()
+        for idx, pid in enumerate(("e", "mu", "pi", "k", "p", "ghost"), 700):
+            self.fill(f"{pre}_pnn_{pid}", pro.info(idx, -100))
+
+        # Hits.
+        trk, ids = pro.track(), []
+        # VELO
+        for i_id in range(len(trk.lhcbIDs())):
+            idx = trk.lhcbIDs()[i_id]
+            if idx.isVelo():
+                det = self._detTool.sensor(idx.veloID())
+                ids += [(det.z(), det, idx)]
+        ids.sort(key=lambda x: (x[0], x[1], x[2].lhcbID()))
+        for hit in range(0, self.nhit):
+            assert hit < len(ids)
+            z, det, idx = ids[hit]
+            sns, vec = idx.veloID(), GaudiPython.gbl.LHCb.StateVector()
+            self._trkTool.propagate(trk, z, vec, prt.particleID())
+            self.fill(f"{pre}_x{hit}", vec.x())
+            self.fill(f"{pre}_y{hit}", vec.y())
+            self.fill(f"{pre}_z{hit}", vec.z())
+            if sns.isPhiType():
+                self.fill(f"{pre}_t{hit}", det.globalPhi(sns.strip(), 0))
+                self.fill(f"{pre}_p{hit}", -det.phiPitch(sns.strip()))
+            if sns.isRType():
+                self.fill(f"{pre}_t{hit}", det.globalR(sns.strip(), 0))
+                self.fill(f"{pre}_p{hit}", det.rPitch(sns.strip()))
+        # veloCharge
+        self.fill(
+            f"{pre}_veloCharge",
+            pro.info(GaudiPython.gbl.LHCb.ProtoParticle.VeloCharge, -10000.0),
+        )
+        # ECal
+        em_hypo = None  # calorimeter hypothesis using EmCharged
+        ecal_vec = GaudiPython.gbl.LHCb.StateVector()  # position of interaction
+        for i_hypo in range(len(pro.calo())):
+            if (
+                pro.calo()[i_hypo].hypothesis()
+                == GaudiPython.gbl.LHCb.CaloHypo.EmCharged
+            ):
+                assert em_hypo is None
+                em_hypo = pro.calo()[i_hypo]
+        if em_hypo:
+            assert em_hypo.hypothesis() == GaudiPython.gbl.LHCb.CaloHypo.EmCharged
+            ecal_z = (
+                em_hypo.position().z()
+            )  # mm, Z-position where cluster parameters are estimated
+            self._trkTool.propagate(trk, ecal_z, ecal_vec, prt.particleID())
+        else:
+            ecal_vec.setX(-1e9)
+            ecal_vec.setY(-1e9)
+            ecal_vec.setZ(-1e9)
+        self.fill(f"{pre}_ecalx", ecal_vec.x())
+        self.fill(f"{pre}_ecaly", ecal_vec.y())
+        self.fill(f"{pre}_ecalz", ecal_vec.z())
+
+        # Material tool.
+        self.fill(
+            f"{pre}_vt_miss",
+            self._veloTool.miss(
+                org.x(),
+                org.y(),
+                org.z(),
+                mom.Px(),
+                mom.Py(),
+                mom.Pz(),
+                ids[0][0],
+                year,
+                run,
+            ),
+        )
+
+        # IP and momentum.
+        pvr = self._pvrTool.relatedPV(prt, self.pvrs)
+        self._fillMom(pre, mom)
+        self._fillM(pre, mom)
+        self._fillMM(pre, prt)
+        ip, ipChi2 = ctypes.c_double(-1), ctypes.c_double(-1)
+        if pvr:
+            self._dstTool.distance(prt, pvr, ip, ipChi2)
+        self.fill(f"{pre}_ip", ip.value)
+        self.fill(f"{pre}_ip_chi2", ipChi2.value)
+        return pvr
+
+    ###########################################################################
+    def _fillCal(self, pre: "str", prt):
+        """Fill the information for a calorimetry object."""
+        mom = prt.momentum()
+        self._fillMom(pre, mom)
+        self._fillM(pre, mom)
+        self._fillMM(pre, prt)
+
+    ###########################################################################
+    def fillPrt(
+        self,
+        prt,
+        org=None,
+        year=None,
+        run=None,
+        check=False,
+        mctool=None,
+    ):
+        """Fill the information for a particle."""
+        vrt = prt.endVertex()
+        key = self._key(prt)
+        idx = self._index(key)
+        pre = "tag" if vrt else ("trk" if prt.charge() else "cal")
+        if idx is not None:
+            return (pre, idx)
+
+        # Check if the particle is valid without filling.
+        tagargs, tagkwargs = [pre, prt, year, run], {"mctool": mctool}
+        if check:
+            assert year is not None and run is not None, (year, run)
+            return (
+                pre == "tag" and self._fillTag(*tagargs, **tagkwargs, check=True)
+            ) or pre != "tag"
+        # Fill the particle.
+        if pre == "tag":
+            assert year is not None and run is not None, (year, run)
+            assert prt.particleID().pid() in (-521, 521, 310), prt.particleID().pid()
+            pvr = self._fillTag(*tagargs, **tagkwargs)
+            assert not isinstance(pvr, bool), pvr
+        elif pre == "trk":
+            assert year is not None and run is not None, (year, run)
+            #assert prt.particleID().pid() in (-321, 321), prt.particleID().pid()
+            assert prt.particleID().pid() in (-321, 321, -211, 211), prt.particleID().pid()
+            pvr = self._fillTrk(pre, prt, org, year, run)
+        elif pre == "cal":
+            assert prt.particleID().pid() == 22, prt.particleID().pid()
+            assert self._fillCal(pre, prt) is None
+            pvr = None
+        else:
+            raise ValueError(f"pre '{pre}' not recognized")
+        self.fill(f"{pre}_pid", prt.particleID().pid())
+
+        # Primary vertex.
+        if pvr:
+            pvrKey = self._key(pvr)
+            pvrIdx = self._index(pvrKey)
+            if pvrIdx is None:
+                self._fillVrt("pvr", pvr.position(), pvr.covMatrix())
+                pvrIdx = self._save("pvr", pvrKey)
+            self.fill(f"{pre}_idx_pvr", pvrIdx)
+        else:
+            self.fill(f"{pre}_idx_pvr", -1)
+        return (pre, self._save(pre, key))
+
+
+def fill_ntuple(
+    ntuple: "Ntuple",
+    tes,
+    candloc_Brem: "str",
+    candloc_noBrem: "str",
+    #head: "Union[str, None]",
+    genTool,
+):
+    """Assign values to the ntuple."""
+    year = int(DaVinci().DataType)
+
+    def get_particles(candloc):
+        try:
+            particles = tes[candloc]
+            len(particles)
+            size = len(particles)
+            #print("found {0} particles".format(size))
+        except:
+            particles = []
+        return particles
+
+    # Fill the event.
+    daq = tes["DAQ/ODIN"]
+    rnum = daq.runNumber()
+    ntuple.ntuple["run_n"][0] = rnum
+    ntuple.ntuple["evt_n"][0] = daq.eventNumber()
+    ntuple.ntuple["evt_tck"][0] = daq.triggerConfigurationKey()
+    ntuple.ntuple["pvr_n"][0] = len(tes[ntuple.pvrs])
+    ntuple.ntuple["spd_n"][0] = int(
+        GaudiPython.gbl.LoKi.L0.DataValue("Spd(Mult)")(tes["Trig/L0/L0DUReport"])
+    )
+
+    # Fill the particles.
+    all_rhos = get_particles(candloc_Brem) 
+
+
+    
+    #SelectRhos(
+    #     get_particles(candloc_Brem),
+    #     get_particles(candloc_noBrem),
+    #     ntuple.combinatorial_fakePhotons,
+    # )
+    if DaVinci().Simulation:
+        mct = MCEventTools.MCEvent(all_rhos, genTool)
+        mct.linkpars()
+        mcpstore = get_particles(
+            "AllStreams/MC/Particles"
+            if DaVinci().InputType == "MDST"
+            else "MC/Particles"
+        )
+        mct.deltarlink(mcpstore)
+        mct.categorize()
+    else:
+        mct = None
+    isfilled = False
+
+    for rho in all_rhos:
+        print("its working")
+        args, kwargs = [rho], {"year": year, "run": rnum, "mctool": mct}
+
+        boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
+        print("I find bool is {0}".format(boolVal))
+        if ntuple.fillPrt(*args, **kwargs, check=True):
+            ntuple.fillPrt(*args, **kwargs)
+            isfilled = True
+            print("isfilled has been set to {0}".format(isfilled))
+
+    if len(all_rhos) > 0 and isfilled:
+        print("conditions for filling tuple met")
+        ntuple.fill()
+        ntuple.clear()
diff --git a/bu2kdarkscalar_darkscalar2hh/inputData.py b/bu2kdarkscalar_darkscalar2hh/inputData.py
new file mode 100644
index 0000000000..dcf6ea0974
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/inputData.py
@@ -0,0 +1,14 @@
+from GaudiConf import IOHelper
+
+'''
+IOHelper("ROOT").inputFiles(["/home/exw330/data/00092412_00000138_1.leptonic.mdst"])
+from Configurables import DaVinci
+DaVinci().DataType = "2018"
+DaVinci().InputType = "MDST"
+
+'''
+# Monte Carlo
+IOHelper("ROOT").inputFiles(["/home/exw330/MC/00217278_00000014_1.AllStreams.dst"])
+from Configurables import DaVinci
+DaVinci().InputType = 'DST'
+DaVinci().DataType = '2018'
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
new file mode 100644
index 0000000000..6def5a0301
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -0,0 +1,135 @@
+"""Create Ntuple."""
+import argparse
+import importlib.machinery
+import importlib.util
+from pathlib import Path
+import shutil
+from typing import Union
+
+from Configurables import DaVinci, ToolSvc, TriggerTisTos
+import GaudiPython
+import ROOT
+
+#when running locally you need to uncomment the following lines
+#but if you are running on the grid, you need to comment them
+import sys
+sys.path.append("../")
+
+
+from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
+
+
+# =================================================================================
+# The next lines allow configuration to be done in separate files in a gaudirun-like way
+# This is needed for AnalysisProductions, but also helps us.
+# You run with 'python job.py MyConfig.py'
+
+def parse_args() -> "tuple[Union[str, None], bool]":
+    """Parse command line arguments."""
+    parser = argparse.ArgumentParser(
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+        description=__file__.__doc__,
+    )
+    parser.add_argument(
+        "options_paths",
+        nargs="+",
+        type=Path,
+        help="Additional options files to load before starting Gaudi Python",
+    )
+    args = parser.parse_args()
+
+    for options_path in args.options_paths:
+        print("Adding options file:", options_path)
+        # execute module
+        # https://stackoverflow.com/a/19011259/4655426
+        loader = importlib.machinery.SourceFileLoader(
+            "head_particle", str(options_path.resolve())
+        )
+        spec = importlib.util.spec_from_loader(loader.name, loader)
+        assert spec is not None
+        mod = importlib.util.module_from_spec(spec)
+        loader.exec_module(mod)
+
+
+
+
+    return 
+
+
+# In order to use Run 1+2 GaudiPython with analysis productions the arguments
+# passed to the script need to be executed to set up input data and other state
+
+parse_args()
+# =================================================================================
+# Set up material tool
+print("About to compile velo material tool")
+ROOT.gErrorIgnoreLevel = ROOT.kError
+this_dir = Path(__file__).parent
+if ROOT.gROOT.LoadMacro(str(this_dir / "velo.C+")) < 0:
+    raise RuntimeError("Failed to load velo material tool.")
+print("Compiled tool")
+
+# =================================================================================
+try:
+    # use ProdConf if available, as with an AnalysisProduction
+    from ProdConf import ProdConf
+
+    NOfEvents = ProdConf().NOfEvents
+    # The script also needs to inspect ProdConf to determine the output filename
+    output_filename = f"{ProdConf().OutputFilePrefix}.{ProdConf().OutputFileTypes[0]}"
+    # FIXME: This shouldn't be needed but is, for AnalysisProductions to run
+    shutil.copy(this_dir / "pars.root", Path.cwd())
+except ModuleNotFoundError:
+    NOfEvents = DaVinci().EvtMax
+    output_filename = DaVinci().TupleFile
+
+# FIXME: Turn off lumi tuple or it overwrites ntuple. Cleverer solution possible
+DaVinci().Lumi = False
+
+# =================================================================================
+# Configuring DiEMaker-based particle reconstruction
+#candloc_Brem, candloc_noBrem = diemaker(combinatorial_fakePhotons)
+#print("candloc_Brem is {0} and candloc_noBrem is {1}".format(candloc_Brem, candloc_noBrem))
+
+candloc_KK_Brem = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
+candloc_KK_noBrem = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
+
+candloc_PiPi_Brem = "/Event/Leptonic/Phys/B2KX2PiPiDarkBosonLine/Particles"
+candloc_PiPi_noBrem = "/Event/Leptonic/Phys/B2KX2PiPiDarkBosonLine/Particles"
+
+# =================================================================================
+# TisTos configuration.
+for stage in ("Hlt1", "Hlt2", "Strip/Phys"):
+    ToolSvc().addTool(TriggerTisTos, stage + "TriggerTisTos")
+    tool = getattr(ToolSvc(), stage + "TriggerTisTos")
+    tool.HltDecReportsLocation = f"/Event/{stage}/DecReports"
+    tool.HltSelReportsLocation = f"/Event/{stage}/SelReports"
+
+# =================================================================================
+# Run.
+gaudi = GaudiPython.AppMgr()
+tes = gaudi.evtsvc()
+ntuple = Ntuple(gaudi, output_filename)
+# Setting up tools for MC BG categorizing
+genTool = (
+    gaudi.toolsvc().create(
+        "DaVinciSmartAssociator", interface="IParticle2MCWeightedAssociator"
+    )
+    if DaVinci().Simulation
+    else None
+)
+
+event = 0
+while (NOfEvents == -1) or (event < NOfEvents):
+    gaudi.run(1)
+    if not bool(tes["/Event"]):
+        break
+    event += 1
+    #print("found evt")
+
+    fill_ntuple(ntuple, tes, candloc_KK_Brem, candloc_KK_noBrem, genTool)
+    fill_ntuple(ntuple, tes, candloc_PiPi_Brem, candloc_PiPi_noBrem, genTool)
+
+
+# Close.
+ntuple.close(event)
-- 
GitLab


From 45d4103ef7d9f8f0e5341b584afbfc86567edb8f Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 15 Jul 2024 15:21:43 +0100
Subject: [PATCH 06/70] editing to work for mc

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py    | 146 +++++++++-------------
 bu2kdarkscalar_darkscalar2hh/dtf.py       | 108 ++++++++++++++++
 bu2kdarkscalar_darkscalar2hh/info.yaml    |  15 ++-
 bu2kdarkscalar_darkscalar2hh/inputData.py |   1 +
 bu2kdarkscalar_darkscalar2hh/job.py       |  16 +--
 5 files changed, 181 insertions(+), 105 deletions(-)
 create mode 100644 bu2kdarkscalar_darkscalar2hh/dtf.py

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index cbebf68a4e..77d38e36f8 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -11,9 +11,9 @@ import GaudiPython
 from LoKiArrayFunctors.decorators import AMAXDOCA
 import ROOT
 
-from dtf import dtf
+from dtf import dtf #dtf: decay tree fitter
 import MCEventTools
-from ReconstructionTools import BremOverlapChecker, SelectRhos
+#from ReconstructionTools import BremOverlapChecker, SelectRhos
 
 
 class Ntuple:
@@ -55,8 +55,8 @@ class Ntuple:
 
         # Triggers.
         self.tos: "list[list[str]]" = [
-            ["L0Electron.*"],
-            ["Hlt1.*Electron.*", "Hlt1.*TrackMVA.*"],
+            ["L0Hadron.*"],
+            ["Hlt1.*Hadron.*", "Hlt1.*TrackMVA.*"],
             ["Hlt2ExoticaPi0ToDiEGamma", "Hlt2ExoticaEtaToDiEGamma"],
             [],
         ]
@@ -111,11 +111,6 @@ class Ntuple:
                 "fd_chi2",
                 "vt_tip",
                 "vt_d",
-                "withBrem",
-                "BremMatched",
-                "photonBremOverlap",
-                "nBremAdded_em",
-                "nBremAdded_ep",
                 "etrackOL",
             ]
             + [
@@ -124,15 +119,15 @@ class Ntuple:
                 for x in ["m", "dm", "chi2"]
                 + vrsMom
                 + vrsVrt
-                + [f"die_{y}" for y in ["m"] + vrsMom]
+                + [f"dih_{y}" for y in ["m"] + vrsMom]
             ]
-            + [f"die_{x}" for x in ["m"] + vrsMom]
+            + [f"dih_{x}" for x in ["m"] + vrsMom]
         )
 
         vrsMC = []
         if DaVinci().Simulation:
-            dps = ["em", "ep", "g"]
-            params = ["mpid", "orvrt", "morvrt", "mmpid", "mmorvrt"]
+            dps = ["hm", "hp", "K"]
+            params = ["mpid", "orvrt", "morvrt", "mmpid", "mmorvrt"] # mpid: mother pid, orvrt: origin vertex, morvrt: mother origin vertex, mmpid: mother mother pid, mmorvrt: mother mother origin vertex
             for dp in dps:
                 vrsMC += [dp + "_lpid"]
                 vrsMC += [dp + "_l" + param for param in vrsMom]
@@ -315,29 +310,29 @@ class Ntuple:
         self.fill(f"{pre}_dm", dm)
 
     ###########################################################################
-    def _filldieMomMass(self, pre: "str", mom):
+    def _filldihMomMass(self, pre: "str", mom):
         """Fill momentum and mass for a particle."""
         if mom is None:
-            self.fill(f"{pre}_die_px", -1)
-            self.fill(f"{pre}_die_py", -1)
-            self.fill(f"{pre}_die_pz", -1)
-            self.fill(f"{pre}_die_e", -1)
-            self.fill(f"{pre}_die_m", -1)
+            self.fill(f"{pre}_dih_px", -1)
+            self.fill(f"{pre}_dih_py", -1)
+            self.fill(f"{pre}_dih_pz", -1)
+            self.fill(f"{pre}_dih_e", -1)
+            self.fill(f"{pre}_dih_m", -1)
         else:
-            self.fill(f"{pre}_die_px", mom.Px())
-            self.fill(f"{pre}_die_py", mom.Py())
-            self.fill(f"{pre}_die_pz", mom.Pz())
-            self.fill(f"{pre}_die_e", mom.E())
-            self.fill(f"{pre}_die_m", mom.M())
+            self.fill(f"{pre}_dih_px", mom.Px())
+            self.fill(f"{pre}_dih_py", mom.Py())
+            self.fill(f"{pre}_dih_pz", mom.Pz())
+            self.fill(f"{pre}_dih_e", mom.E())
+            self.fill(f"{pre}_dih_m", mom.M())
 
     ###########################################################################
     def _fillgenMomPID(self, pre: "str", mcp):
         """Fill generator level MC momentum and pid for a particle."""
-        if mcp:
-            if mcp.pid == 11:
-                dptype = "em"
-            elif mcp.pid == -11:
-                dptype = "ep"
+        if mcp: # mcp: monte carlo particle
+            if mcp.pid == -321 or mcp.pid == -211:
+                dptype = "hm" # dptype: daughter particle type
+            elif mcp.pid == +321 or mcp.pid == +211:
+                dptype = "hp"
             elif mcp.pid == 22:
                 dptype = "g"
             else:
@@ -354,7 +349,7 @@ class Ntuple:
             self.fill(f"{pre}_{dptype}_le", mom.E())
             self.fill(f"{pre}_{dptype}_lpid", lpid)
         else:
-            for dptype in ["em", "ep", "g"]:
+            for dptype in ["hm", "hp", "g"]:
                 self.fill(f"{pre}_{dptype}_lpx", -1)
                 self.fill(f"{pre}_{dptype}_lpy", -1)
                 self.fill(f"{pre}_{dptype}_lpz", -1)
@@ -365,37 +360,37 @@ class Ntuple:
     def _filltrkOL(self, pre: "str", prt):
         """Find number of shared track lhcbIDs between e- and e+.
 
-        Accessed through dielectron candidate.
+        Accessed through dihadron candidate.
         """
-        if prt.particleID().pid() == 310:
+        if prt.particleID().pid() == 310: #310 is K short
             nol = 0
-            em = ep = None
+            hm = hp = None
             for i_dp in range(len(prt.daughtersVector())):
                 dp = prt.daughtersVector()[i_dp]
                 #if dp.particleID().pid() == -321:
                 if dp.particleID().pid() == -321 or dp.particleID().pid() == -211:
-                    assert em is None
-                    em = dp
+                    assert hm is None
+                    hm = dp
                 #elif dp.particleID().pid() == 321:
                 elif dp.particleID().pid() == 321 or dp.particleID().pid() == 211:
-                    assert ep is None
-                    ep = dp
-            assert em is not None and ep is not None, prt
-            for i_emid in range(len(em.proto().track().lhcbIDs())):
-                emid = em.proto().track().lhcbIDs()[i_emid]
-                for i_epid in range(len(ep.proto().track().lhcbIDs())):
-                    epid = ep.proto().track().lhcbIDs()[i_epid]
-                    if emid == epid:
+                    assert hp is None
+                    hp = dp
+            assert hm is not None and hp is not None, prt
+            for i_hmid in range(len(hm.proto().track().lhcbIDs())):
+                hmid = hm.proto().track().lhcbIDs()[i_hmid]
+                for i_hpid in range(len(hp.proto().track().lhcbIDs())):
+                    hpid = hp.proto().track().lhcbIDs()[i_hpid]
+                    if hmid == hpid:
                         nol += 1
-            if (nol * 1.0) / len(em.proto().track().lhcbIDs()) > (nol * 1.0) / len(
-                ep.proto().track().lhcbIDs()
+            if (nol * 1.0) / len(hm.proto().track().lhcbIDs()) > (nol * 1.0) / len(
+                hp.proto().track().lhcbIDs()
             ):
-                olperc = (nol * 1.0) / len(em.proto().track().lhcbIDs())
+                olperc = (nol * 1.0) / len(hm.proto().track().lhcbIDs())
             else:
-                olperc = (nol * 1.0) / len(ep.proto().track().lhcbIDs())
+                olperc = (nol * 1.0) / len(hp.proto().track().lhcbIDs())
         else:
             olperc = -1
-        self.fill(f"{pre}_etrackOL", olperc)
+        self.fill(f"{pre}_htrackOL", olperc)
 
     ###########################################################################
     def _fillMat(
@@ -450,25 +445,6 @@ class Ntuple:
             self.fill(f"{pre}_vt_d", -1)
             self.fill(f"{pre}_vt_tip", -1)
 
-    ###########################################################################
-    def _fillBrem(self, pre: "str", prt: "Any"):
-        """Fill the Brem information for a particle."""
-        if prt.particleID().pid() == 113:
-            # pion/eta
-            assert prt.hasInfo(1) and prt.hasInfo(2)
-            extraInfo = prt.extraInfo()
-            self.fill(f"{pre}_withBrem", int(extraInfo[1]))
-            self.fill(f"{pre}_BremMatched", int(extraInfo[2]))
-        else:
-            # not pion/eta
-            assert not (prt.hasInfo(1) or prt.hasInfo(2))
-            self.fill(f"{pre}_withBrem", -1)
-            self.fill(f"{pre}_BremMatched", -1)
-        BOC = BremOverlapChecker(prt)
-        self.fill(f"{pre}_photonBremOverlap", BOC.overlapFound())
-        self.fill(f"{pre}_nBremAdded_em", BOC.nBremAdded("em"))
-        self.fill(f"{pre}_nBremAdded_ep", BOC.nBremAdded("ep"))
-
     ###########################################################################
     def _fillTrg(self, pre: "str", prt):
         """Fill the trigger lines for a particle."""
@@ -523,14 +499,13 @@ class Ntuple:
         pdtf = dtf(prt, pvr, True)
         ddtf = dtf(prt, pvr, False)
         if prt.particleID().pid() in (-521, 521):
-            # pion/eta
             pdtf.fit()
             ddtf.fit()
-            assert pdtf.dielectron == ddtf.dielectron
-            assert pdtf.dielectron is not None
-            dtrp = pdtf.dielectron.momentum()
+            assert pdtf.dihadron == ddtf.dihadron
+            assert pdtf.dihadron is not None
+            dtrp = pdtf.dihadron.momentum()
         elif prt.particleID().pid() == 310:
-            # dielectron
+            # dihadron candidate
             dtrp = prt.momentum()
         else:
             raise ValueError(
@@ -551,8 +526,8 @@ class Ntuple:
             # because fillPrt is designed to automatically determine the branch names
 
         self._filldieMomMass(pre, dtrp)
-        self._filldieMomMass(f"{pre}_pdtf", pdtf.get_die_momentum())
-        self._filldieMomMass(f"{pre}_ddtf", ddtf.get_die_momentum())
+        self._filldieMomMass(f"{pre}_pdtf", pdtf.get_dih_momentum())
+        self._filldieMomMass(f"{pre}_ddtf", ddtf.get_dih_momentum())
         self._filltrkOL(pre, prt)
 
         # MC BG type
@@ -869,8 +844,8 @@ class Ntuple:
 def fill_ntuple(
     ntuple: "Ntuple",
     tes,
-    candloc_Brem: "str",
-    candloc_noBrem: "str",
+    candloc: "str",
+    #candloc_noBrem: "str",
     #head: "Union[str, None]",
     genTool,
 ):
@@ -882,7 +857,7 @@ def fill_ntuple(
             particles = tes[candloc]
             len(particles)
             size = len(particles)
-            #print("found {0} particles".format(size))
+            print("found {0} particles".format(size))
         except:
             particles = []
         return particles
@@ -899,17 +874,10 @@ def fill_ntuple(
     )
 
     # Fill the particles.
-    all_rhos = get_particles(candloc_Brem) 
-
+    all_Bs = get_particles(candloc) 
 
-    
-    #SelectRhos(
-    #     get_particles(candloc_Brem),
-    #     get_particles(candloc_noBrem),
-    #     ntuple.combinatorial_fakePhotons,
-    # )
     if DaVinci().Simulation:
-        mct = MCEventTools.MCEvent(all_rhos, genTool)
+        mct = MCEventTools.MCEvent(all_Bs, genTool) # mct: monte carlo tool
         mct.linkpars()
         mcpstore = get_particles(
             "AllStreams/MC/Particles"
@@ -922,9 +890,9 @@ def fill_ntuple(
         mct = None
     isfilled = False
 
-    for rho in all_rhos:
+    for B in all_Bs:
         print("its working")
-        args, kwargs = [rho], {"year": year, "run": rnum, "mctool": mct}
+        args, kwargs = [B], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
         print("I find bool is {0}".format(boolVal))
@@ -933,7 +901,7 @@ def fill_ntuple(
             isfilled = True
             print("isfilled has been set to {0}".format(isfilled))
 
-    if len(all_rhos) > 0 and isfilled:
+    if len(all_Bs) > 0 and isfilled:
         print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
diff --git a/bu2kdarkscalar_darkscalar2hh/dtf.py b/bu2kdarkscalar_darkscalar2hh/dtf.py
new file mode 100644
index 0000000000..826477d4e8
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/dtf.py
@@ -0,0 +1,108 @@
+"""Defines dtf class for B -> K h+ h- ( h is K or pi) decays."""
+from typing import Any
+
+import GaudiPython
+
+
+class dtf:
+    """Create a DecayTreeFitter and extract some information."""
+
+    def __init__(self, particle: "Any", relatedPV: "Any", prompt: "bool"):
+        self.particle = particle
+        self.relatedPV = relatedPV
+        self.prompt = prompt
+
+        self._dtf = None  # the DecayTreeFitter (must be stored for persistency)
+        self._dtf_mom = None  # the fitted B momentum
+        self._dtf_cov = None  # the covariance matrix of the fitted position
+        self._dtf_pos = None  # the fitted vertex position
+        self._dtf_chi2 = None  # the chi2 of the fit
+        self._dtf_dtrp = None  # the fitted dihadron momentum
+
+        self.dihadron = None  # the dihadron
+
+    def fit(self):
+        """Fit the B and extract some information."""
+        self._get_daughter()
+        self._set_prompt()
+        self._get_dtf()
+        self._reset_prompt()
+        params = [
+            self._dtf_mom,
+            self._dtf_cov,
+            self._dtf_pos,
+            self._dtf_chi2,
+            self._dtf_dtrp,
+        ]
+        truth = [x is None for x in params]
+        assert all(truth) or not any(truth), truth
+
+    def _get_daughter(self):
+        """Find the daughter whose PID == 310.
+
+        Sets `self.dihadron`.
+        """
+        for i_fdtr in range(len(self.particle.daughtersVector())):
+            _fdtr = self.particle.daughtersVector()[i_fdtr]
+            if _fdtr.particleID().pid() == 310:
+                assert self.dihadron is None
+                self.dihadron = _fdtr
+        assert self.dihadron is not None, self.particle
+
+    def _set_prompt(self):
+        """Change the dihadron PID to 10111 if `self.prompt` is True."""
+        if self.prompt:
+            assert self.dihadron is not None
+            assert self.dihadron.particleID().pid() == 310
+            self.dihadron.setParticleID(GaudiPython.gbl.LHCb.ParticleID(10111))
+            assert self.dihadron.particleID().pid() == 10111
+
+    def _get_dtf(self):
+        """Create the DecayTreeFitter and extract some information.
+
+        Only fills information if `bool(self.relatedPV)`
+        and the fit is successful
+        and the dihadron mass error from the fit is not 0.
+        """
+        if self.relatedPV:
+            self._dtf = GaudiPython.gbl.DecayTreeFitter.Fitter(
+                self.particle, self.relatedPV
+            )
+            self._dtf.fit()
+            if self._dtf.status() == self._dtf.Success:
+                dtf_params = self._dtf.fitParams(self.particle)
+                dtf_momentum = dtf_params.momentum()
+                if dtf_momentum.m().error() != 0:
+                    self._dtf_mom = dtf_momentum
+                    self._dtf_chi2 = self._dtf.chiSquare()
+                    self._dtf_cov = dtf_params.posCovMatrix()
+                    self._dtf_pos = dtf_params.position()
+                    self._dtf_dtrp = self._dtf.getFitted(self.dihadron).momentum()
+
+    def _reset_prompt(self):
+        """Ensure the dihadron's PID is 310."""
+        assert self.dihadron is not None
+        if self.prompt:
+            assert self.dihadron.particleID().pid() == 10111
+            self.dihadron.setParticleID(GaudiPython.gbl.LHCb.ParticleID(310))
+        assert self.dihadron.particleID().pid() == 310
+
+    def get_momentum(self):
+        """Return the fitted B momentum."""
+        return self._dtf_mom
+
+    def get_position_covariance(self):
+        """Return the covariance matrix of the fitted position."""
+        return self._dtf_cov
+
+    def get_position(self):
+        """Return the fitted vertex position."""
+        return self._dtf_pos
+
+    def get_chi2(self):
+        """Return the chi2 of the fit."""
+        return self._dtf_chi2
+
+    def get_dih_momentum(self):
+        """Return the fitted dihadron momentum."""
+        return self._dtf_dtrp
diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 9c5aaa8adf..cee77310d1 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -14,16 +14,19 @@ Bu2KdarkScalar_darkScalar2hh_2018_Mag{{polarity}}_job:
       - python
     files:
       - job.py
-      - photonSource_default.py
 
   input:
-    bk_query: /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
-    #/MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
-    #/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
+    bk_query: /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p3/90000000/LEPTONIC.MDST
+    # For MC
+    # /MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
+    # For data
+    # /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
     
   output: bu2kdarkscalar_darkscalar2hh.ROOT
-  #B2KKK.ROOT
-  #bu2kdarkscalar_darkscalar2hh.ROOT
+  # For MC
+  # B2KKK.ROOT
+  # For data
+  # bu2kdarkscalar_darkscalar2hh.ROOT
 
 
 {%- endfor %}
\ No newline at end of file
diff --git a/bu2kdarkscalar_darkscalar2hh/inputData.py b/bu2kdarkscalar_darkscalar2hh/inputData.py
index dcf6ea0974..22ef3691c8 100644
--- a/bu2kdarkscalar_darkscalar2hh/inputData.py
+++ b/bu2kdarkscalar_darkscalar2hh/inputData.py
@@ -1,6 +1,7 @@
 from GaudiConf import IOHelper
 
 '''
+# Real Data
 IOHelper("ROOT").inputFiles(["/home/exw330/data/00092412_00000138_1.leptonic.mdst"])
 from Configurables import DaVinci
 DaVinci().DataType = "2018"
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 6def5a0301..891ccc6b81 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -87,15 +87,11 @@ except ModuleNotFoundError:
 DaVinci().Lumi = False
 
 # =================================================================================
-# Configuring DiEMaker-based particle reconstruction
-#candloc_Brem, candloc_noBrem = diemaker(combinatorial_fakePhotons)
-#print("candloc_Brem is {0} and candloc_noBrem is {1}".format(candloc_Brem, candloc_noBrem))
 
-candloc_KK_Brem = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
-candloc_KK_noBrem = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
+#candidate locations
+candloc_KK = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
+candloc_PiPi = "/Event/Leptonic/Phys/B2KX2PiPiDarkBosonLine/Particles"
 
-candloc_PiPi_Brem = "/Event/Leptonic/Phys/B2KX2PiPiDarkBosonLine/Particles"
-candloc_PiPi_noBrem = "/Event/Leptonic/Phys/B2KX2PiPiDarkBosonLine/Particles"
 
 # =================================================================================
 # TisTos configuration.
@@ -125,10 +121,10 @@ while (NOfEvents == -1) or (event < NOfEvents):
     if not bool(tes["/Event"]):
         break
     event += 1
-    #print("found evt")
+    print("found evt")
 
-    fill_ntuple(ntuple, tes, candloc_KK_Brem, candloc_KK_noBrem, genTool)
-    fill_ntuple(ntuple, tes, candloc_PiPi_Brem, candloc_PiPi_noBrem, genTool)
+    fill_ntuple(ntuple, tes, candloc_KK, genTool)
+    fill_ntuple(ntuple, tes, candloc_PiPi, genTool)
 
 
 # Close.
-- 
GitLab


From c52c9ac531aaf8e5254e993f57788fe44b678937 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 16 Jul 2024 12:42:31 +0100
Subject: [PATCH 07/70] adapting for mc

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 168 +++++++++----------
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       |  24 ++-
 bu2kdarkscalar_darkscalar2hh/job.py          |   3 +-
 3 files changed, 104 insertions(+), 91 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index e985d51e09..7cf5bd0cdd 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -163,8 +163,8 @@ class MCEvent:
     """
     def __init__(self, all_Bparticles, mctool):
         """
-        Initializes MCEvent class. Creates list of rec level Bparticles, adds associated
-        daughter particles to Bparticles daughter list.
+        Initializes MCEvent class. Creates list of rec level B particles, adds associated
+        daughter particles to all_Bparticles daughter list.
 
         INPUTS
         ------
@@ -177,7 +177,7 @@ class MCEvent:
                of MCEvent [bool]
         links: flag for whether the linkpars method has been run on this instance
                of MCEvent [bool]
-        Bparticles  : list of combined Bparticles with daughter particles in daughter list [list(MCPart)]
+        Bparticles  : list of combined all_Bparticles with daughter particles in daughter list [list(MCPart)]
         """
         self.hcuts = False
         self.links = False
@@ -186,7 +186,7 @@ class MCEvent:
         self.mctool = mctool
         self.Bparticles = []
         self.dihquery = []
-        for Bparticle in all_Bparticles: # loop over all the B+/B-s stored in the TES
+        for B in all_Bparticles: # loop over all the B+/B-s stored in the TES
             dps = [0,0]
             dpsv = None
             svcoor = None
@@ -203,7 +203,7 @@ class MCEvent:
                         elif hadron.pid == -321: hadrons[1] = hadron
                     svcoor = [dpsv.position().X(),dpsv.position().Y(),dpsv.position().Z()]
                     dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
-            B = MCPart(Bparticle,dl=dps)
+            B = MCPart(B,dl=dps)
             self.Bparticles += [B]
 
     def linkpars(self):
@@ -271,7 +271,7 @@ class MCEvent:
                 if rel_hadron_plus.originVertex().type() != 1:
                     try:
                         rel_hadron_plus.mother().originVertex().type()
-                        particle.dl[0].dl[1].lpar.update(newmother=MCPart(rel_hadron_plus.mother(),orvrt=rel_hadron_plus.mother().originVertex().type()))
+                        Bparticle.dl[0].dl[1].lpar.update(newmother=MCPart(rel_hadron_plus.mother(),orvrt=rel_hadron_plus.mother().originVertex().type()))
                         if rel_hadron_plus.mother().originVertex().type() != 1:
                             try:
                                 rel_hadron_plus.mother().mother().originVertex().type()
@@ -303,9 +303,9 @@ class MCEvent:
 
                 if Bparticle.dl[0].dl[1].lpar.mother:
                     if Bparticle.dl[0].dl[1].lpar.mother.mother:
-                        hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par, B.dl[0].dl[1].lpar.mother.mother.par]
+                        hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,Bparticle.dl[0].dl[1].lpar.mother.par, Bparticle.dl[0].dl[1].lpar.mother.mother.par]
                     else:
-                        hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par]
+                        hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,Bparticle.dl[0].dl[1].lpar.mother.par]
                 else: hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par]
 
                 sharelin = []
@@ -320,24 +320,24 @@ class MCEvent:
                             else:
                                 if hadron_minus_lin[i] == Klin[k]: lin += (i+1)*100 + (k+1); sharelin += [lin]
                                 if hadron_plus_lin[j] == Klin[k]: lin = 0; lin += (j+1)*10 + (k+1); sharelin += [lin]
-                B.update(newlineage=sharelin)
+                Bparticle.update(newlineage=sharelin)
 
-                for prt in B.dl[1].lpar.par.originVertex().products():
-                    B.dl[1].lpar.update(newsp=prt)
-                if B.dl[1].lpar.mother:
-                    for prt in B.dl[1].lpar.mother.par.originVertex().products():
-                        B.dl[1].lpar.mother.update(newsp=prt)
+                for prt in Bparticle.dl[1].lpar.par.originVertex().products():
+                    Bparticle.dl[1].lpar.update(newsp=prt)
+                if Bparticle.dl[1].lpar.mother:
+                    for prt in Bparticle.dl[1].lpar.mother.par.originVertex().products():
+                        Bparticle.dl[1].lpar.mother.update(newsp=prt)
 
-                for prt in B.dl[0].dl[0].lpar.par.originVertex().products():
+                for prt in Bparticle.dl[0].dl[0].lpar.par.originVertex().products():
                     Bparticle.dl[0].dl[0].lpar.update(newsp=prt)
                 if Bparticle.dl[0].dl[0].lpar.mother:
-                    for prt in B.dl[0].dl[0].lpar.mother.par.originVertex().products():
+                    for prt in Bparticle.dl[0].dl[0].lpar.mother.par.originVertex().products():
                         Bparticle.dl[0].dl[0].lpar.mother.update(newsp=prt)
 
                 for prt in Bparticle.dl[0].dl[1].lpar.par.originVertex().products():
                     Bparticle.dl[0].dl[1].lpar.update(newsp=prt)
                 if Bparticle.dl[0].dl[1].lpar.mother:
-                    for prt in B.dl[0].dl[1].lpar.mother.par.originVertex().products():
+                    for prt in Bparticle.dl[0].dl[1].lpar.mother.par.originVertex().products():
                         Bparticle.dl[0].dl[1].lpar.mother.update(newsp=prt)
             elif self.allreglinked: self.allreglinked = False
         self.links = True
@@ -373,30 +373,30 @@ class MCEvent:
                             except:
                                 recp.lpar.update(newmother=None)
 
-                if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar:
-                    B.update(newisdrmatched=True)
-                    if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
+                if Bparticle.dl[1].lpar and Bparticle.dl[0].dl[0].lpar and Bparticle.dl[0].dl[1].lpar:
+                    Bparticle.update(newisdrmatched=True)
+                    if Bparticle.dl[1].lpar.pid == Bparticle.dl[1].pid and Bparticle.dl[0].dl[0].lpar.pid == Bparticle.dl[0].dl[0].pid and Bparticle.dl[0].dl[1].lpar.pid == Bparticle.dl[0].dl[1].pid: Bparticle.update(newcorlinked=True)
 
-                    if B.dl[1].lpar.mother:
-                        if B.dl[1].lpar.mother.mother:
-                            Klin = [B.dl[1].lpar.par,B.dl[1].lpar.mother.par, B.dl[1].lpar.mother.mother.par]
+                    if Bparticle.dl[1].lpar.mother:
+                        if Bparticle.dl[1].lpar.mother.mother:
+                            Klin = [Bparticle.dl[1].lpar.par,Bparticle.dl[1].lpar.mother.par, Bparticle.dl[1].lpar.mother.mother.par]
                         else:
-                            Klin = [B.dl[1].lpar.par,B.dl[1].lpar.mother.par]
-                    else: Klin = [B.dl[1].lpar.par]
+                            Klin = [Bparticle.dl[1].lpar.par,Bparticle.dl[1].lpar.mother.par]
+                    else: Klin = [Bparticle.dl[1].lpar.par]
 
-                    if B.dl[0].dl[0].lpar.mother:
-                        if B.dl[0].dl[0].lpar.mother.mother:
-                            hadron_minus_lin = [B.dl[0].dl[0].lpar.par,B.dl[0].dl[0].lpar.mother.par, B.dl[0].dl[0].lpar.mother.mother.par]
+                    if Bparticle.dl[0].dl[0].lpar.mother:
+                        if Bparticle.dl[0].dl[0].lpar.mother.mother:
+                            hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par,Bparticle.dl[0].dl[0].lpar.mother.par, Bparticle.dl[0].dl[0].lpar.mother.mother.par]
                         else:
-                            hadron_minus_lin = [B.dl[0].dl[0].lpar.par,B.dl[0].dl[0].lpar.mother.par]
-                    else: hadron_minus_lin = [B.dl[0].dl[0].lpar.par]
+                            hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par,Bparticle.dl[0].dl[0].lpar.mother.par]
+                    else: hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par]
 
-                    if B.dl[0].dl[1].lpar.mother:
-                        if B.dl[0].dl[1].lpar.mother.mother:
-                            hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par, B.dl[0].dl[1].lpar.mother.mother.par]
+                    if Bparticle.dl[0].dl[1].lpar.mother:
+                        if Bparticle.dl[0].dl[1].lpar.mother.mother:
+                            hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,Bparticle.dl[0].dl[1].lpar.mother.par, Bparticle.dl[0].dl[1].lpar.mother.mother.par]
                         else:
-                            hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par]
-                    else: hadron_plus_lin = [B.dl[0].dl[1].lpar.par]
+                            hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,Bparticle.dl[0].dl[1].lpar.mother.par]
+                    else: hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par]
 
                     sharelin = []
                     for i in range(len(hadron_minus_lin)):
@@ -410,25 +410,25 @@ class MCEvent:
                                 else:
                                     if hadron_minus_lin[i] == Klin[k]: lin += (i+1)*100 + (k+1); sharelin += [lin]
                                     if hadron_plus_lin[j] == Klin[k]: lin = 0; lin += (j+1)*10 + (k+1); sharelin += [lin]
-                    B.update(newlineage=sharelin)
-
-                    for prt in B.dl[1].lpar.par.originVertex().products():
-                        B.dl[1].lpar.update(newsp=prt)
-                    if B.dl[1].lpar.mother:
-                        for prt in B.dl[1].lpar.mother.par.originVertex().products():
-                            B.dl[1].lpar.mother.update(newsp=prt)
-
-                    for prt in B.dl[0].dl[0].lpar.par.originVertex().products():
-                        B.dl[0].dl[0].lpar.update(newsp=prt)
-                    if B.dl[0].dl[0].lpar.mother:
-                        for prt in B.dl[0].dl[0].lpar.mother.par.originVertex().products():
-                            B.dl[0].dl[0].lpar.mother.update(newsp=prt)
-
-                    for prt in B.dl[0].dl[1].lpar.par.originVertex().products():
-                        B.dl[0].dl[1].lpar.update(newsp=prt)
-                    if B.dl[0].dl[1].lpar.mother:
-                        for prt in B.dl[0].dl[1].lpar.mother.par.originVertex().products():
-                            B.dl[0].dl[1].lpar.mother.update(newsp=prt)
+                    Bparticle.update(newlineage=sharelin)
+
+                    for prt in Bparticle.dl[1].lpar.par.originVertex().products():
+                        Bparticle.dl[1].lpar.update(newsp=prt)
+                    if Bparticle.dl[1].lpar.mother:
+                        for prt in Bparticle.dl[1].lpar.mother.par.originVertex().products():
+                            Bparticle.dl[1].lpar.mother.update(newsp=prt)
+
+                    for prt in Bparticle.dl[0].dl[0].lpar.par.originVertex().products():
+                        Bparticle.dl[0].dl[0].lpar.update(newsp=prt)
+                    if Bparticle.dl[0].dl[0].lpar.mother:
+                        for prt in Bparticle.dl[0].dl[0].lpar.mother.par.originVertex().products():
+                            Bparticle.dl[0].dl[0].lpar.mother.update(newsp=prt)
+
+                    for prt in Bparticle.dl[0].dl[1].lpar.par.originVertex().products():
+                        Bparticle.dl[0].dl[1].lpar.update(newsp=prt)
+                    if Bparticle.dl[0].dl[1].lpar.mother:
+                        for prt in Bparticle.dl[0].dl[1].lpar.mother.par.originVertex().products():
+                            Bparticle.dl[0].dl[1].lpar.mother.update(newsp=prt)
 
     def corlin(self, B):
         """
@@ -464,17 +464,17 @@ class MCEvent:
         if not self.links: self.linkpars()
 
         for Bparticle in self.Bparticles:
-            if self.corlin(B):
+            if self.corlin(Bparticle):
                 K = Bparticle.dl[1]
                 hadron_minus = Bparticle.dl[0].dl[0]
                 hadron_plus = Bparticle.dl[0].dl[1]
                 try: fillKpid = K.lpar.mother.pid
                 except: fillKpid = 0
 
-                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(B.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle
+                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(Bparticle.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle
                     #if K is K+ this must be a B+, if K is K- this must be a B-
-                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=0)
-                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=0)
+                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: Bparticle.update(newbgtype=0)
+                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: Bparticle.update(newbgtype=0)
 
 
             for dp in Bparticle.dl:
@@ -496,24 +496,24 @@ class MCEvent:
         dectype: decay type of the input particle [int]
         """
         dectype = -99
-        B = None
+        Bparticle = None
         if ID(part) == 310:
             dectype = ID(part)
         elif part in self.Bstore:
-            for Bparticle in self.Bparticles:
+            for B in self.Bparticles:
                 if part == B.par:
-                    B = B
+                    Bparticle = B
                     break
-            if B != None:
-                K = B.dl[1]
-                hadron_minus = B.dl[0].dl[0]
-                hadron_plus = B.dl[0].dl[1]
-
-                fill_B_dectype = B.dectype # fill B decay type
-                fill_B_odectype = B.odectype # fill B decay type
-                try: hadron_minus_morvrt = em.lpar.mother.orvrt
+            if Bparticle != None:
+                K = Bparticle.dl[1]
+                hadron_minus = Bparticle.dl[0].dl[0]
+                hadron_plus = Bparticle.dl[0].dl[1]
+
+                fill_B_dectype = Bparticle.dectype # fill B decay type
+                fill_B_odectype = Bparticle.odectype # fill B decay type
+                try: hadron_minus_morvrt = hadron_minus.lpar.mother.orvrt
                 except: hadron_minus_morvrt = 99
-                try: hadron_plus_morvrt = _hadron_plus.lpar.mother.orvrt
+                try: hadron_plus_morvrt = hadron_plus.lpar.mother.orvrt
                 except: hadron_plus_morvrt = 99
                 K_orvrt = K.orvrt
 
@@ -521,7 +521,7 @@ class MCEvent:
                     fill_K_mother_dectype = K.lpar.mother.pid
                 except:
                     fill_K_mother_dectype.pid = 0
-                if not B.corlinked or hadron_minus_morvrt == 99 or hadron_plus_morvrt == 99:
+                if not Bparticle.corlinked or hadron_minus_morvrt == 99 or hadron_plus_morvrt == 99:
                     dectype = 8
                 elif fill_B_dectype == 0:
                     dectype = 0
@@ -546,16 +546,16 @@ class MCEvent:
         drmatch: whether particle was delta R matched [int (0: no; 1: yes; 99: error)]
         """
         drmatch = 99
-        B = None
+        Bparticle = None
         if ID(part) == 310:
             drmatch = ID(part)
         elif part in self.Bstore:
-            for Bparticle in self.Bparticles:
-                if part == Bparticle.par:
-                    B = Bparticle
+            for B in self.Bparticles:
+                if part == B.par:
+                    Bparticle = B
                     break
-            if B != None:
-                if B.isdrmatched: drmatch = 1
+            if Bparticle != None:
+                if Bparticle.isdrmatched: drmatch = 1
                 else: drmatch = 0
             else:
                 drmatch = 9
@@ -573,15 +573,15 @@ class MCEvent:
 
         OUTPUTS
         -------
-        B: MCPart object of the corresponding B/eta [MCPart]
+        Bparticle: MCPart object of the corresponding B/eta [MCPart]
         """
-        B = None
+        Bparticle = None
         if ID(part) == 310:
-            B = self.Bparticles[0]
+            Bparticle = self.Bparticles[0]
         elif part in self.Bstore:
-            for Bparticle in self.Bparticles:
-                if part == Bparticle.par:
-                    B = Bparticle
+            for B in self.Bparticles:
+                if part == B.par:
+                    Bparticle = B
                     break
 
-        return B
+        return Bparticle
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 77d38e36f8..6073387e3e 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -525,9 +525,9 @@ class Ntuple:
             # dtf (dtf_pos) not implemented for these daughters
             # because fillPrt is designed to automatically determine the branch names
 
-        self._filldieMomMass(pre, dtrp)
-        self._filldieMomMass(f"{pre}_pdtf", pdtf.get_dih_momentum())
-        self._filldieMomMass(f"{pre}_ddtf", ddtf.get_dih_momentum())
+        self._filldihMomMass(pre, dtrp)
+        self._filldihMomMass(f"{pre}_pdtf", pdtf.get_dih_momentum())
+        self._filldihMomMass(f"{pre}_ddtf", ddtf.get_dih_momentum())
         self._filltrkOL(pre, prt)
 
         # MC BG type
@@ -812,13 +812,12 @@ class Ntuple:
         # Fill the particle.
         if pre == "tag":
             assert year is not None and run is not None, (year, run)
-            assert prt.particleID().pid() in (-521, 521, 310), prt.particleID().pid()
+            assert prt.particleID().pid() in (-521, 521, 310), prt.particleID().pid() # B-, B+, dark scalar
             pvr = self._fillTag(*tagargs, **tagkwargs)
             assert not isinstance(pvr, bool), pvr
         elif pre == "trk":
             assert year is not None and run is not None, (year, run)
-            #assert prt.particleID().pid() in (-321, 321), prt.particleID().pid()
-            assert prt.particleID().pid() in (-321, 321, -211, 211), prt.particleID().pid()
+            assert prt.particleID().pid() in (-321, 321, -211, 211), prt.particleID().pid() # K-, K+, pi-, pi+
             pvr = self._fillTrk(pre, prt, org, year, run)
         elif pre == "cal":
             assert prt.particleID().pid() == 22, prt.particleID().pid()
@@ -855,10 +854,12 @@ def fill_ntuple(
     def get_particles(candloc):
         try:
             particles = tes[candloc]
+            #print(particles)
             len(particles)
             size = len(particles)
             print("found {0} particles".format(size))
         except:
+            print("no particles found")
             particles = []
         return particles
 
@@ -873,11 +874,18 @@ def fill_ntuple(
         GaudiPython.gbl.LoKi.L0.DataValue("Spd(Mult)")(tes["Trig/L0/L0DUReport"])
     )
 
+    print(candloc)
+
     # Fill the particles.
     all_Bs = get_particles(candloc) 
+    print(f"length of all bs is {len(all_Bs)}")
+
+
 
     if DaVinci().Simulation:
+        print("yay its working for mc")
         mct = MCEventTools.MCEvent(all_Bs, genTool) # mct: monte carlo tool
+        print(mct)
         mct.linkpars()
         mcpstore = get_particles(
             "AllStreams/MC/Particles"
@@ -888,8 +896,12 @@ def fill_ntuple(
         mct.categorize()
     else:
         mct = None
+
+
     isfilled = False
 
+    print('moving onto for loop')
+  
     for B in all_Bs:
         print("its working")
         args, kwargs = [B], {"year": year, "run": rnum, "mctool": mct}
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 891ccc6b81..b24f45abd0 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -124,7 +124,8 @@ while (NOfEvents == -1) or (event < NOfEvents):
     print("found evt")
 
     fill_ntuple(ntuple, tes, candloc_KK, genTool)
-    fill_ntuple(ntuple, tes, candloc_PiPi, genTool)
+    print("filled ntuple KK")
+    #fill_ntuple(ntuple, tes, candloc_PiPi, genTool)
 
 
 # Close.
-- 
GitLab


From 5273acff6a5504da6b04637ee390c5ec6f6f8315 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 24 Jul 2024 16:22:44 +0100
Subject: [PATCH 08/70] edited to work for mc

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 342 ++++++++++---------
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 187 ++++------
 bu2kdarkscalar_darkscalar2hh/README.md       |  47 +++
 bu2kdarkscalar_darkscalar2hh/hh_KK.py        |   5 +
 bu2kdarkscalar_darkscalar2hh/hh_PiPi.py      |   5 +
 bu2kdarkscalar_darkscalar2hh/info.yaml       |   6 +-
 bu2kdarkscalar_darkscalar2hh/job.py          |  42 ++-
 7 files changed, 337 insertions(+), 297 deletions(-)
 create mode 100644 bu2kdarkscalar_darkscalar2hh/README.md
 create mode 100644 bu2kdarkscalar_darkscalar2hh/hh_KK.py
 create mode 100644 bu2kdarkscalar_darkscalar2hh/hh_PiPi.py

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 7cf5bd0cdd..f42bd97f38 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -4,7 +4,7 @@ from GaudiConf import IOHelper
 from Configurables import DaVinci, TriggerTisTos, ToolSvc
 from ROOT import TLorentzVector as tlv
 from LoKiMC.decorators import MCPX, MCPY, MCPZ, MCE, MCID, MCABSID, MCPT, MCM, MCETA, MCP, MCPHI
-from LoKiPhys.decorators import M, PX, PY, PZ, E, ID, ABSID, PROBNNk, PROBNNghost, IPCHI2, P, PT, CL, ETA, TRGHOSTPROB, PHI
+from LoKiPhys.decorators import M, PX, PY, PZ, E, ID, ABSID, PROBNNk, PROBNNpi, PROBNNghost, IPCHI2, P, PT, CL, ETA, TRGHOSTPROB, PHI
 from array import array
 from math import sqrt
 
@@ -32,15 +32,16 @@ class MCPart:
     tos        : tos list 
     ipc2       : IPCHI2 parameter
     lpar       : linked particle
-    corlinked  : flag (intended for Bs) for whether all daughter particles have been
+    corlinked  : flag (intended for all_Bs) for whether all daughter particles have been
                  linked to like particles (i.e. pi+ linked to pi+) [bool]
-    alllinked  : flag (intended for Bs) for whether all daughter particles have
+    alllinked  : flag (intended for all_Bs) for whether all daughter particles have
                  been linked to anything [bool]
     orvrt      : origin vertex type for LHCb.MCParticle type particles
     mother     : mother particles for LHCb.MCParticle type particles
     clink      : flag (intended for daughter particles) for whether particle has
                  been linked to a matching particle type [bool]
     pnnk       : particle's PROBNNk
+    ppnpi      : particle's PROBNNpi
     pnng       : particle's PROBNNghost
     trgp       : particle's TRGHOSTPROB
     dectype    : category of decay type (assigned via MCEvent.categorize()) [int]
@@ -51,14 +52,14 @@ class MCPart:
                     -1: particle; 2: mother; 3: grandmother; 0: no shared relation (if only two particles share ancestor)
     sl         : sister list (other particles from same origin vertex)
     cl         : particle's confidence level
-    isdrmatched: flag for if a B candidate has been linked using delta r matching
+    isdrmatched: flag for if a all_B candidate has been linked using delta r matching
     pv         : coordinates of associated PV [list(float)]
     sv         : coordinates of associated SV [list(float)]
     odectype   : category of other decay type [int]
     bgtype     : background category [int]
     """
     def __init__(self, par, dl=[], tos=[0,0,0], ipc2=None, lpar=None, orvrt=None,
-                 mother=None, clink=None, pnnk=None, pnng=None, trgp=None, dectype=None,
+                 mother=None, clink=None, pnnk=None, pnnpi=None, pnng=None, trgp=None, dectype=None,
                  lineage=None, sl=[], cl=None, isdrmatched=False, pv=[], sv=[],
                  odectype=None, bgtype=None):
         self.par = par
@@ -74,6 +75,7 @@ class MCPart:
         self.mother = mother
         self.clink = clink
         self.pnnk = pnnk
+        self.pnnpi = pnnpi
         self.pnng = pnng
         self.trgp = trgp
         self.dectype = dectype
@@ -86,9 +88,9 @@ class MCPart:
         self.odectype = odectype
         self.bgtype = bgtype
 
-    def update(self, newdp=None, newdl=None, newl0tos=0, newhlt1etos=0, newhlt1mvatos=0,
+    def update(self, newdp=None, newdl=None, newl0tos=0, newhlt1htos=0, newhlt1mvatos=0,
                newtos=[], newipc2=None, newlpar=None, newcorlinked=0, neworvrt=None,
-               newmother=None, newclink=None, newpnnk=None, newpnng=None, newtrgp=None,
+               newmother=None, newclink=None, newpnnk=None, newpnnpi=None, newpnng=None, newtrgp=None,
                newdectype=None, newlineage=None, newsp=None, newsl=None, newalllinked=0,
                newcl=None, newisdrmatched=None, newpv=None, newsv=None,
                newodectype=None, newbgtype=None):
@@ -100,7 +102,7 @@ class MCPart:
         newdp        : adds single daughter particle to existing daughter list [MCPart]
         newdl        : overwrites existing daughter list with newdl [list(MCPart)]
         newl0tos     : updates L0 TOS [bool]
-        newhlt1etos  : updates HLT1Electron TOS [bool]
+        newhlt1htos  : updates HLT1Hlectron TOS [bool]
         newhlt1mvatos: updates HLT1TrackMVA TOS [bool]
         newtos       : overwrites existing tos list with newtos [list(bool)]
         newipc2      : updates ipc2 (float)
@@ -110,9 +112,10 @@ class MCPart:
         newmother    : updates associated mother particle
         newclink     : updates clink flag [bool]
         newpnnk      : updates PROBNNk
+        newpnnpi     : updates PROBNNpi
         newpnng      : updates PROBNNghost
         newtrgp      : updates TRGHOSTPROB
-        newdectype   : updates the B decay type
+        newdectype   : updates the all_B decay type
         newlineage   : updates the shared ancestor list
         newsp        : adds single sister particle to existing list [MCPart]
         newsl        : overwrites existing sister list with newsl [list(MCPart)]
@@ -124,7 +127,7 @@ class MCPart:
             else: self.dl += [MCPart(newdp)]
         if newdl != None: self.dl = newdl
         if newl0tos != 0: self.tos[0] = newl0tos
-        if newhlt1etos != 0: self.tos[1] = newhlt1etos
+        if newhlt1htos != 0: self.tos[1] = newhlt1htos
         if newhlt1mvatos != 0: self.tos[2] = newhlt1mvatos
         #if len(newtos) == 2: self.tos = newtos
         if len(newtos) == 3: self.tos = newtos
@@ -140,6 +143,7 @@ class MCPart:
             else: self.mother = MCPart(newmother)
         if newclink != None: self.clink = newclink
         if newpnnk != None: self.pnnk = newpnnk
+        if newpnnpi != None: self.pnnpi = newpnnpi
         if newpnng != None: self.pnng = newpnng
         if newtrgp != None: self.trgp = newtrgp
         if newdectype != None: self.dectype = newdectype
@@ -161,14 +165,14 @@ class MCEvent:
     """
     Class for processing MC events.
     """
-    def __init__(self, all_Bparticles, mctool):
+    def __init__(self, all_Bs, mctool):
         """
-        Initializes MCEvent class. Creates list of rec level B particles, adds associated
-        daughter particles to all_Bparticles daughter list.
+        Initializes MCEvent class. Creates list of rec level all_Bs, adds associated
+        daughter particles to all_Bs daughter list.
 
         INPUTS
         ------
-        all_Bparticles   : B+/B-s from the TES
+        all_Bs   : B+/B-s from the TES
         mctool : IParticle2MCWeightedAssociator instance to be used
 
         INTERNAL MEMBERS
@@ -177,136 +181,145 @@ class MCEvent:
                of MCEvent [bool]
         links: flag for whether the linkpars method has been run on this instance
                of MCEvent [bool]
-        Bparticles  : list of combined all_Bparticles with daughter particles in daughter list [list(MCPart)]
+        Bs  : list of combined all_Bs with daughter particles in daughter list [list(MCPart)]
         """
         self.hcuts = False
         self.links = False
         self.iscategorized = False
-        self.Bstore = all_Bparticles
+        self.Bstore = all_Bs
         self.mctool = mctool
-        self.Bparticles = []
+        self.Bs = []
         self.dihquery = []
-        for B in all_Bparticles: # loop over all the B+/B-s stored in the TES
+        for all_B in all_Bs: # loop over all the B+/B-s stored in the TES
             dps = [0,0]
             dpsv = None
             svcoor = None
-            for dp in B.daughters(): # loop over the daughters of the B+/B- particle
+            for dp in all_B.daughters(): # loop over the daughters of the B+/B- particle
                 if abs(ID(dp)) == 321:
-                    dps[1] = MCPart(dp,pnnk=PROBNNk(dp),pnng=PROBNNghost(dp),cl=CL(dp))
+                    dps[1] = MCPart(dp,pnnk=PROBNNk(dp),pnnpi=PROBNNpi(dp),pnng=PROBNNghost(dp),cl=CL(dp))
                 else:
                     hadrons = [0,0]
                     dpsv = dp.endVertex()
                     for ddp in dp.endVertex().outgoingParticlesVector():
                         hadron = MCPart(ddp)
-                        hadron.update(newpnnk=PROBNNk(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
+                        hadron.update(newpnnk=PROBNNk(ddp),newpnnpi=PROBNNpi(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
+                        print(hadron.pid)
                         if hadron.pid == 321: hadrons[0] = hadron
                         elif hadron.pid == -321: hadrons[1] = hadron
                     svcoor = [dpsv.position().X(),dpsv.position().Y(),dpsv.position().Z()]
                     dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
-            B = MCPart(B,dl=dps)
-            self.Bparticles += [B]
+            B = MCPart(all_B,dl=dps)
+            self.Bs += [B]
+            print(f"self.Bs is {self.Bs}")
 
     def linkpars(self):
         """
-        Links the rec level daughter particles (K, h-, h+) to gen level particles.
+        Links the reconstruction level daughter particles (K, h-, h+) to gen level particles.
         rels refers to related particles
         rel_K: related K particle
         rel_hadron_minus: related h- particle
         rel_hadron_plus: related h+ particle
+        dl: daughter list
         """
         self.allreglinked = True
-        for Bparticle in self.Bparticles:
-            rels = self.mctool.relatedMCPs(Bparticle.dl[1].par)
+        for B in self.Bs:
+            rels = self.mctool.relatedMCPs(B.dl[1].par)
             w = 0
             rel_K = None
             for rel in rels:
                 if rel.weight() > w: w = rel.weight(); rel_K = rel.to()
             if rel_K:
-                Bparticle.dl[1].update(newlpar=MCPart(rel_K,orvrt=rel_K.originVertex().type()))
+                B.dl[1].update(newlpar=MCPart(rel_K,orvrt=rel_K.originVertex().type()))
                 if rel_K.originVertex().type() != 1:
                     try:
                         rel_K.mother().originVertex().type()
-                        Bparticle.dl[1].lpar.update(newmother=MCPart(rel_K.mother(),orvrt=rel_K.mother().originVertex().type()))
+                        B.dl[1].lpar.update(newmother=MCPart(rel_K.mother(),orvrt=rel_K.mother().originVertex().type()))
                         if rel_K.mother().originVertex().type() != 1:
                             try:
                                 rel_K.mother().mother().originVertex().type()
-                                Bparticle.dl[1].lpar.mother.update(newmother=MCPart(rel_K.mother().mother(),orvrt=rel_K.mother().mother().originVertex().type()))
+                                B.dl[1].lpar.mother.update(newmother=MCPart(rel_K.mother().mother(),orvrt=rel_K.mother().mother().originVertex().type()))
                             except:
-                                Bparticle.dl[1].lpar.mother.update(newmother=None)
+                                B.dl[1].lpar.mother.update(newmother=None)
                     except:
-                        Bparticle.dl[1].lpar.update(newmother=None)
-
-                if MCID(rel_K) == Bparticle.dl[1].pid: Bparticle.dl[1].update(newclink=True)
-                else: Bparticle.dl[1].update(newclink=False)
-
-            rels = self.mctool.relatedMCPs(Bparticle.dl[0].dl[0].par)
+                        B.dl[1].lpar.update(newmother=None)
+
+                if MCID(rel_K) == B.dl[1].pid: B.dl[1].update(newclink=True)
+                else: B.dl[1].update(newclink=False)
+
+            print(f"type of B dl dl is {type(B.dl[0].dl[0])}")
+            print(f"type of B is {type(B)}")
+            print(f"type is {type(B.dl[0])}")
+            print(f"B dl is {B.dl}")
+            print(f"B dl dl is {B.dl[0].dl}")
+            print(f"B is {B}")
+            rels = self.mctool.relatedMCPs(B.dl[0].dl[0].par)
             w = 0
             rel_hadron_minus = None
             for rel in rels:
                 if rel.weight() > w: w = rel.weight(); rel_hadron_minus = rel.to()
             if rel_hadron_minus:
-                Bparticle.dl[0].dl[0].update(newlpar=MCPart(rel_hadron_minus,orvrt=rel_hadron_minus.originVertex().type()))
+                B.dl[0].dl[0].update(newlpar=MCPart(rel_hadron_minus,orvrt=rel_hadron_minus.originVertex().type()))
                 if rel_hadron_minus.originVertex().type() != 1:
                     try:
                         rel_hadron_minus.mother().originVertex().type()
-                        Bparticle.dl[0].dl[0].lpar.update(newmother=MCPart(rel_hadron_minus.mother(),orvrt=rel_hadron_minus.mother().originVertex().type()))
+                        B.dl[0].dl[0].lpar.update(newmother=MCPart(rel_hadron_minus.mother(),orvrt=rel_hadron_minus.mother().originVertex().type()))
                         if rel_hadron_minus.mother().originVertex().type() != 1:
                             try:
                                 rel_hadron_minus.mother().mother().originVertex().type()
-                                Bparticle.dl[0].dl[0].lpar.mother.update(newmother=MCPart(rel_hadron_minus.mother().mother(),orvrt=rel_hadron_minus.mother().mother().originVertex().type()))
+                                B.dl[0].dl[0].lpar.mother.update(newmother=MCPart(rel_hadron_minus.mother().mother(),orvrt=rel_hadron_minus.mother().mother().originVertex().type()))
                             except:
-                                Bparticle.dl[0].dl[0].lpar.mother.update(newmother=None)
+                                B.dl[0].dl[0].lpar.mother.update(newmother=None)
                     except:
-                        Bparticle.dl[0].dl[0].lpar.update(newmother=None)
-                if MCID(rel_hadron_minus) == Bparticle.dl[0].dl[0].pid: Bparticle.dl[0].dl[0].update(newclink=True)
-                else: Bparticle.dl[0].dl[0].update(newclink=False)
+                        B.dl[0].dl[0].lpar.update(newmother=None)
+                if MCID(rel_hadron_minus) == B.dl[0].dl[0].pid: B.dl[0].dl[0].update(newclink=True)
+                else: B.dl[0].dl[0].update(newclink=False)
 
-            rels = self.mctool.relatedMCPs(Bparticle.dl[0].dl[1].par)
+            rels = self.mctool.relatedMCPs(B.dl[0].dl[1].par)
             w = 0
             rel_hadron_plus = None
             for rel in rels:
                 if rel.weight() > w: w = rel.weight(); rel_hadron_plus = rel.to()
             if rel_hadron_plus:
-                Bparticle.dl[0].dl[1].update(newlpar=MCPart(rel_hadron_plus,orvrt=rel_hadron_plus.originVertex().type()))
+                B.dl[0].dl[1].update(newlpar=MCPart(rel_hadron_plus,orvrt=rel_hadron_plus.originVertex().type()))
                 if rel_hadron_plus.originVertex().type() != 1:
                     try:
                         rel_hadron_plus.mother().originVertex().type()
-                        Bparticle.dl[0].dl[1].lpar.update(newmother=MCPart(rel_hadron_plus.mother(),orvrt=rel_hadron_plus.mother().originVertex().type()))
+                        B.dl[0].dl[1].lpar.update(newmother=MCPart(rel_hadron_plus.mother(),orvrt=rel_hadron_plus.mother().originVertex().type()))
                         if rel_hadron_plus.mother().originVertex().type() != 1:
                             try:
                                 rel_hadron_plus.mother().mother().originVertex().type()
-                                Bparticle.dl[0].dl[1].lpar.mother.update(newmother=MCPart(rel_hadron_plus.mother().mother(),orvrt=rel_hadron_plus.mother().mother().originVertex().type()))
+                                B.dl[0].dl[1].lpar.mother.update(newmother=MCPart(rel_hadron_plus.mother().mother(),orvrt=rel_hadron_plus.mother().mother().originVertex().type()))
                             except:
-                                Bparticle.dl[0].dl[1].lpar.mother.update(newmother=None)
+                                B.dl[0].dl[1].lpar.mother.update(newmother=None)
                     except:
-                        Bparticle.dl[0].dl[1].lpar.update(newmother=None)
-                if MCID(rel_hadron_plus) == Bparticle.dl[0].dl[1].pid: Bparticle.dl[0].dl[1].update(newclink=True)
-                else: Bparticle.dl[0].dl[1].update(newclink=False)
+                        B.dl[0].dl[1].lpar.update(newmother=None)
+                if MCID(rel_hadron_plus) == B.dl[0].dl[1].pid: B.dl[0].dl[1].update(newclink=True)
+                else: B.dl[0].dl[1].update(newclink=False)
 
             if rel_K and rel_hadron_minus and rel_hadron_plus:
-                Bparticle.update(newalllinked=True)
-                if MCID(rel_K) == Bparticle.dl[1].pid and MCID(rel_hadron_minus) == Bparticle.dl[0].dl[0].pid and MCID(rel_hadron_plus) == Bparticle.dl[0].dl[1].pid: Bparticle.update(newcorlinked=True)
+                B.update(newalllinked=True)
+                if MCID(rel_K) == B.dl[1].pid and MCID(rel_hadron_minus) == B.dl[0].dl[0].pid and MCID(rel_hadron_plus) == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
 
-                if Bparticle.dl[1].lpar.mother:
-                    if Bparticle.dl[1].lpar.mother.mother:
-                        Klin = [Bparticle.dl[1].lpar.par,Bparticle.dl[1].lpar.mother.par, Bparticle.dl[1].lpar.mother.mother.par]
+                if B.dl[1].lpar.mother:
+                    if B.dl[1].lpar.mother.mother:
+                        Klin = [B.dl[1].lpar.par,B.dl[1].lpar.mother.par, B.dl[1].lpar.mother.mother.par]
                     else:
-                        Klin = [Bparticle.dl[1].lpar.par,Bparticle.dl[1].lpar.mother.par]
-                else: Klin = [Bparticle.dl[1].lpar.par]
+                        Klin = [B.dl[1].lpar.par,B.dl[1].lpar.mother.par]
+                else: Klin = [B.dl[1].lpar.par]
 
-                if Bparticle.dl[0].dl[0].lpar.mother:
-                    if Bparticle.dl[0].dl[0].lpar.mother.mother:
-                        hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par,Bparticle.dl[0].dl[0].lpar.mother.par, Bparticle.dl[0].dl[0].lpar.mother.mother.par]
+                if B.dl[0].dl[0].lpar.mother:
+                    if B.dl[0].dl[0].lpar.mother.mother:
+                        hadron_minus_lin = [B.dl[0].dl[0].lpar.par,B.dl[0].dl[0].lpar.mother.par, B.dl[0].dl[0].lpar.mother.mother.par]
                     else:
-                        hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par,Bparticle.dl[0].dl[0].lpar.mother.par]
-                else: hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par]
+                        hadron_minus_lin = [B.dl[0].dl[0].lpar.par,B.dl[0].dl[0].lpar.mother.par]
+                else: hadron_minus_lin = [B.dl[0].dl[0].lpar.par]
 
-                if Bparticle.dl[0].dl[1].lpar.mother:
-                    if Bparticle.dl[0].dl[1].lpar.mother.mother:
-                        hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,Bparticle.dl[0].dl[1].lpar.mother.par, Bparticle.dl[0].dl[1].lpar.mother.mother.par]
+                if B.dl[0].dl[1].lpar.mother:
+                    if B.dl[0].dl[1].lpar.mother.mother:
+                        hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par, B.dl[0].dl[1].lpar.mother.mother.par]
                     else:
-                        hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,Bparticle.dl[0].dl[1].lpar.mother.par]
-                else: hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par]
+                        hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par]
+                else: hadron_plus_lin = [B.dl[0].dl[1].lpar.par]
 
                 sharelin = []
                 for i in range(len(hadron_minus_lin)):
@@ -320,43 +333,48 @@ class MCEvent:
                             else:
                                 if hadron_minus_lin[i] == Klin[k]: lin += (i+1)*100 + (k+1); sharelin += [lin]
                                 if hadron_plus_lin[j] == Klin[k]: lin = 0; lin += (j+1)*10 + (k+1); sharelin += [lin]
-                Bparticle.update(newlineage=sharelin)
-
-                for prt in Bparticle.dl[1].lpar.par.originVertex().products():
-                    Bparticle.dl[1].lpar.update(newsp=prt)
-                if Bparticle.dl[1].lpar.mother:
-                    for prt in Bparticle.dl[1].lpar.mother.par.originVertex().products():
-                        Bparticle.dl[1].lpar.mother.update(newsp=prt)
-
-                for prt in Bparticle.dl[0].dl[0].lpar.par.originVertex().products():
-                    Bparticle.dl[0].dl[0].lpar.update(newsp=prt)
-                if Bparticle.dl[0].dl[0].lpar.mother:
-                    for prt in Bparticle.dl[0].dl[0].lpar.mother.par.originVertex().products():
-                        Bparticle.dl[0].dl[0].lpar.mother.update(newsp=prt)
-
-                for prt in Bparticle.dl[0].dl[1].lpar.par.originVertex().products():
-                    Bparticle.dl[0].dl[1].lpar.update(newsp=prt)
-                if Bparticle.dl[0].dl[1].lpar.mother:
-                    for prt in Bparticle.dl[0].dl[1].lpar.mother.par.originVertex().products():
-                        Bparticle.dl[0].dl[1].lpar.mother.update(newsp=prt)
+                B.update(newlineage=sharelin)
+
+                for prt in B.dl[1].lpar.par.originVertex().products():
+                    B.dl[1].lpar.update(newsp=prt)
+                if B.dl[1].lpar.mother:
+                    for prt in B.dl[1].lpar.mother.par.originVertex().products():
+                        B.dl[1].lpar.mother.update(newsp=prt)
+
+                for prt in B.dl[0].dl[0].lpar.par.originVertex().products():
+                    B.dl[0].dl[0].lpar.update(newsp=prt)
+                if B.dl[0].dl[0].lpar.mother:
+                    for prt in B.dl[0].dl[0].lpar.mother.par.originVertex().products():
+                        B.dl[0].dl[0].lpar.mother.update(newsp=prt)
+
+                for prt in B.dl[0].dl[1].lpar.par.originVertex().products():
+                    B.dl[0].dl[1].lpar.update(newsp=prt)
+                if B.dl[0].dl[1].lpar.mother:
+                    for prt in B.dl[0].dl[1].lpar.mother.par.originVertex().products():
+                        B.dl[0].dl[1].lpar.mother.update(newsp=prt)
             elif self.allreglinked: self.allreglinked = False
         self.links = True
 
     def deltarlink(self, mcpstore):
         if not self.links: self.linkpars()
 
-        for Bparticle in self.Bparticles:
-            if not Bparticle.alllinked:
-                for recp in [Bparticle.dl[1],Bparticle.dl[0].dl[0],Bparticle.dl[0].dl[1]]:
+        for B in self.Bs:
+            if not B.alllinked:
+                #print("not all Bs are linked")
+                for recp in [B.dl[1],B.dl[0].dl[0],B.dl[0].dl[1]]:
                     if not recp.lpar:
                         mindr = 99999999999
                         parlink = None
                         for mcp in mcpstore:
+                            #print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
                             if MCID(mcp) == recp.pid:
                                 dphi = MCPHI(mcp) - PHI(recp.par)
                                 deta = MCETA(mcp) - ETA(recp.par)
                                 deltar = sqrt(dphi**2 + deta**2)
                                 if deltar < mindr: mindr = deltar; parlink = mcp
+                        """ print(f"deltar is {deltar}")
+                        print(f"mindr is {mindr}")
+                        print(f"parlink is {parlink}") """
                         recp.update(newlpar=MCPart(parlink,orvrt=parlink.originVertex().type()))
                         if MCID(parlink) == recp.pid: recp.update(newclink=True)
                         else: recp.update(newclink=False)
@@ -373,30 +391,30 @@ class MCEvent:
                             except:
                                 recp.lpar.update(newmother=None)
 
-                if Bparticle.dl[1].lpar and Bparticle.dl[0].dl[0].lpar and Bparticle.dl[0].dl[1].lpar:
-                    Bparticle.update(newisdrmatched=True)
-                    if Bparticle.dl[1].lpar.pid == Bparticle.dl[1].pid and Bparticle.dl[0].dl[0].lpar.pid == Bparticle.dl[0].dl[0].pid and Bparticle.dl[0].dl[1].lpar.pid == Bparticle.dl[0].dl[1].pid: Bparticle.update(newcorlinked=True)
+                if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar:
+                    B.update(newisdrmatched=True)
+                    if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
 
-                    if Bparticle.dl[1].lpar.mother:
-                        if Bparticle.dl[1].lpar.mother.mother:
-                            Klin = [Bparticle.dl[1].lpar.par,Bparticle.dl[1].lpar.mother.par, Bparticle.dl[1].lpar.mother.mother.par]
+                    if B.dl[1].lpar.mother:
+                        if B.dl[1].lpar.mother.mother:
+                            Klin = [B.dl[1].lpar.par,B.dl[1].lpar.mother.par, B.dl[1].lpar.mother.mother.par]
                         else:
-                            Klin = [Bparticle.dl[1].lpar.par,Bparticle.dl[1].lpar.mother.par]
-                    else: Klin = [Bparticle.dl[1].lpar.par]
+                            Klin = [B.dl[1].lpar.par,B.dl[1].lpar.mother.par]
+                    else: Klin = [B.dl[1].lpar.par]
 
-                    if Bparticle.dl[0].dl[0].lpar.mother:
-                        if Bparticle.dl[0].dl[0].lpar.mother.mother:
-                            hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par,Bparticle.dl[0].dl[0].lpar.mother.par, Bparticle.dl[0].dl[0].lpar.mother.mother.par]
+                    if B.dl[0].dl[0].lpar.mother:
+                        if B.dl[0].dl[0].lpar.mother.mother:
+                            hadron_minus_lin = [B.dl[0].dl[0].lpar.par,B.dl[0].dl[0].lpar.mother.par, B.dl[0].dl[0].lpar.mother.mother.par]
                         else:
-                            hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par,Bparticle.dl[0].dl[0].lpar.mother.par]
-                    else: hadron_minus_lin = [Bparticle.dl[0].dl[0].lpar.par]
+                            hadron_minus_lin = [B.dl[0].dl[0].lpar.par,B.dl[0].dl[0].lpar.mother.par]
+                    else: hadron_minus_lin = [B.dl[0].dl[0].lpar.par]
 
-                    if Bparticle.dl[0].dl[1].lpar.mother:
-                        if Bparticle.dl[0].dl[1].lpar.mother.mother:
-                            hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,Bparticle.dl[0].dl[1].lpar.mother.par, Bparticle.dl[0].dl[1].lpar.mother.mother.par]
+                    if B.dl[0].dl[1].lpar.mother:
+                        if B.dl[0].dl[1].lpar.mother.mother:
+                            hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par, B.dl[0].dl[1].lpar.mother.mother.par]
                         else:
-                            hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par,Bparticle.dl[0].dl[1].lpar.mother.par]
-                    else: hadron_plus_lin = [Bparticle.dl[0].dl[1].lpar.par]
+                            hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par]
+                    else: hadron_plus_lin = [B.dl[0].dl[1].lpar.par]
 
                     sharelin = []
                     for i in range(len(hadron_minus_lin)):
@@ -410,25 +428,25 @@ class MCEvent:
                                 else:
                                     if hadron_minus_lin[i] == Klin[k]: lin += (i+1)*100 + (k+1); sharelin += [lin]
                                     if hadron_plus_lin[j] == Klin[k]: lin = 0; lin += (j+1)*10 + (k+1); sharelin += [lin]
-                    Bparticle.update(newlineage=sharelin)
-
-                    for prt in Bparticle.dl[1].lpar.par.originVertex().products():
-                        Bparticle.dl[1].lpar.update(newsp=prt)
-                    if Bparticle.dl[1].lpar.mother:
-                        for prt in Bparticle.dl[1].lpar.mother.par.originVertex().products():
-                            Bparticle.dl[1].lpar.mother.update(newsp=prt)
-
-                    for prt in Bparticle.dl[0].dl[0].lpar.par.originVertex().products():
-                        Bparticle.dl[0].dl[0].lpar.update(newsp=prt)
-                    if Bparticle.dl[0].dl[0].lpar.mother:
-                        for prt in Bparticle.dl[0].dl[0].lpar.mother.par.originVertex().products():
-                            Bparticle.dl[0].dl[0].lpar.mother.update(newsp=prt)
-
-                    for prt in Bparticle.dl[0].dl[1].lpar.par.originVertex().products():
-                        Bparticle.dl[0].dl[1].lpar.update(newsp=prt)
-                    if Bparticle.dl[0].dl[1].lpar.mother:
-                        for prt in Bparticle.dl[0].dl[1].lpar.mother.par.originVertex().products():
-                            Bparticle.dl[0].dl[1].lpar.mother.update(newsp=prt)
+                    B.update(newlineage=sharelin)
+
+                    for prt in B.dl[1].lpar.par.originVertex().products():
+                        B.dl[1].lpar.update(newsp=prt)
+                    if B.dl[1].lpar.mother:
+                        for prt in B.dl[1].lpar.mother.par.originVertex().products():
+                            B.dl[1].lpar.mother.update(newsp=prt)
+
+                    for prt in B.dl[0].dl[0].lpar.par.originVertex().products():
+                        B.dl[0].dl[0].lpar.update(newsp=prt)
+                    if B.dl[0].dl[0].lpar.mother:
+                        for prt in B.dl[0].dl[0].lpar.mother.par.originVertex().products():
+                            B.dl[0].dl[0].lpar.mother.update(newsp=prt)
+
+                    for prt in B.dl[0].dl[1].lpar.par.originVertex().products():
+                        B.dl[0].dl[1].lpar.update(newsp=prt)
+                    if B.dl[0].dl[1].lpar.mother:
+                        for prt in B.dl[0].dl[1].lpar.mother.par.originVertex().products():
+                            B.dl[0].dl[1].lpar.mother.update(newsp=prt)
 
     def corlin(self, B):
         """
@@ -463,24 +481,24 @@ class MCEvent:
         """
         if not self.links: self.linkpars()
 
-        for Bparticle in self.Bparticles:
-            if self.corlin(Bparticle):
-                K = Bparticle.dl[1]
-                hadron_minus = Bparticle.dl[0].dl[0]
-                hadron_plus = Bparticle.dl[0].dl[1]
+        for B in self.Bs:
+            if self.corlin(B):
+                K = B.dl[1]
+                hadron_minus = B.dl[0].dl[0]
+                hadron_plus = B.dl[0].dl[1]
                 try: fillKpid = K.lpar.mother.pid
                 except: fillKpid = 0
 
-                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(Bparticle.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle
+                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(B.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle
                     #if K is K+ this must be a B+, if K is K- this must be a B-
-                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: Bparticle.update(newbgtype=0)
-                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: Bparticle.update(newbgtype=0)
+                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=0)
+                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=0)
 
 
-            for dp in Bparticle.dl:
-                dp.update(newbgtype=Bparticle.bgtype)
+            for dp in B.dl:
+                dp.update(newbgtype=B.bgtype)
                 for ddp in dp.dl:
-                    ddp.update(newbgtype=Bparticle.bgtype)
+                    ddp.update(newbgtype=B.bgtype)
 
     def bgtypequery(self, part):
         """
@@ -496,21 +514,21 @@ class MCEvent:
         dectype: decay type of the input particle [int]
         """
         dectype = -99
-        Bparticle = None
+        B = None
         if ID(part) == 310:
             dectype = ID(part)
         elif part in self.Bstore:
-            for B in self.Bparticles:
-                if part == B.par:
-                    Bparticle = B
+            for all_B in self.Bs:
+                if part == all_B.par:
+                    B = all_B
                     break
-            if Bparticle != None:
-                K = Bparticle.dl[1]
-                hadron_minus = Bparticle.dl[0].dl[0]
-                hadron_plus = Bparticle.dl[0].dl[1]
+            if B != None:
+                K = B.dl[1]
+                hadron_minus = B.dl[0].dl[0]
+                hadron_plus = B.dl[0].dl[1]
 
-                fill_B_dectype = Bparticle.dectype # fill B decay type
-                fill_B_odectype = Bparticle.odectype # fill B decay type
+                fill_B_dectype = B.dectype # fill B decay type
+                fill_B_odectype = B.odectype # fill B decay type
                 try: hadron_minus_morvrt = hadron_minus.lpar.mother.orvrt
                 except: hadron_minus_morvrt = 99
                 try: hadron_plus_morvrt = hadron_plus.lpar.mother.orvrt
@@ -521,7 +539,7 @@ class MCEvent:
                     fill_K_mother_dectype = K.lpar.mother.pid
                 except:
                     fill_K_mother_dectype.pid = 0
-                if not Bparticle.corlinked or hadron_minus_morvrt == 99 or hadron_plus_morvrt == 99:
+                if not B.corlinked or hadron_minus_morvrt == 99 or hadron_plus_morvrt == 99:
                     dectype = 8
                 elif fill_B_dectype == 0:
                     dectype = 0
@@ -546,16 +564,16 @@ class MCEvent:
         drmatch: whether particle was delta R matched [int (0: no; 1: yes; 99: error)]
         """
         drmatch = 99
-        Bparticle = None
+        B = None
         if ID(part) == 310:
             drmatch = ID(part)
         elif part in self.Bstore:
-            for B in self.Bparticles:
-                if part == B.par:
-                    Bparticle = B
+            for all_B in self.Bs:
+                if part == all_B.par:
+                    B = all_B
                     break
-            if Bparticle != None:
-                if Bparticle.isdrmatched: drmatch = 1
+            if B != None:
+                if B.isdrmatched: drmatch = 1
                 else: drmatch = 0
             else:
                 drmatch = 9
@@ -573,15 +591,15 @@ class MCEvent:
 
         OUTPUTS
         -------
-        Bparticle: MCPart object of the corresponding B/eta [MCPart]
+        B: MCPart object of the corresponding B/eta [MCPart]
         """
-        Bparticle = None
+        B = None
         if ID(part) == 310:
-            Bparticle = self.Bparticles[0]
+            B = self.Bs[0]
         elif part in self.Bstore:
-            for B in self.Bparticles:
-                if part == B.par:
-                    Bparticle = B
+            for all_B in self.Bs:
+                if part == all_B.par:
+                    B = all_B
                     break
 
-        return Bparticle
+        return B
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 6073387e3e..da3e3e1ea7 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -13,8 +13,6 @@ import ROOT
 
 from dtf import dtf #dtf: decay tree fitter
 import MCEventTools
-#from ReconstructionTools import BremOverlapChecker, SelectRhos
-
 
 class Ntuple:
     """Class for storing an ntuple."""
@@ -25,18 +23,17 @@ class Ntuple:
     ):
         """Initialize the ntuple."""
         # Internal tools.
-        #self.combinatorial_fakePhotons = combinatorial_fakePhotons
-        self._detTool = gaudi.detSvc()["/dd/Structure/LHCb/BeforeMagnetRegion/Velo"]
+        self._detTool = gaudi.detSvc()["/dd/Structure/LHCb/BeforeMagnetRegion/Velo"] # detector tool
         self._pvrTool = gaudi.toolsvc().create(
             "GenericParticle2PVRelator<_p2PVWithIPChi2, "
             "OfflineDistanceCalculatorName>/P2PVWithIPChi2",
-            interface="IRelatedPVFinder",
+            interface="IRelatedPVFinder", #primary vertex relator tool
         )
         self._dstTool = gaudi.toolsvc().create(
-            "LoKi::TrgDistanceCalculator", interface="IDistanceCalculator"
+            "LoKi::TrgDistanceCalculator", interface="IDistanceCalculator" # distance tool
         )
         self._trkTool = gaudi.toolsvc().create(
-            "TrackMasterExtrapolator", interface="ITrackExtrapolator"
+            "TrackMasterExtrapolator", interface="ITrackExtrapolator" #track tool
         )
         self._trgTool = [
             gaudi.toolsvc().create("L0TriggerTisTos", interface="ITriggerTisTos"),
@@ -49,7 +46,7 @@ class Ntuple:
             gaudi.toolsvc().create(
                 "TriggerTisTos/Strip/PhysTriggerTisTos", interface="ITriggerTisTos"
             ),
-        ]
+        ] # trigger tools
         self._docaTool = GaudiPython.gbl.LoKi.Particles.DOCA(0, 0, self._dstTool)
         self._veloTool = ROOT.VeloMaterial()
 
@@ -65,7 +62,7 @@ class Ntuple:
         # Stored variables.
         self.saved: "dict[str, int]" = {}
         self.keys: "dict[str, str]" = {}
-        self.pres = {"tag": 0, "trk": 1, "cal": 2}
+        self.pres = {"tag": 0, "trk": 1}
         self.nhit = 2
         self.ntuple: "OrderedDict[str, array.array | Any]" = OrderedDict()
         self.tfile = ROOT.TFile(output_filename, "RECREATE", "", 207)
@@ -90,9 +87,6 @@ class Ntuple:
             "m",
             "dm",
             "idx_pvr",
-            "ecalx",
-            "ecaly",
-            "ecalz",
             "veloCharge",
         ]
         for h in range(0, self.nhit):
@@ -111,7 +105,7 @@ class Ntuple:
                 "fd_chi2",
                 "vt_tip",
                 "vt_d",
-                "etrackOL",
+                "htrackOL",
             ]
             + [
                 f"{dtf}dtf_{x}"
@@ -140,7 +134,6 @@ class Ntuple:
         vrsIdx = ["idx_pvr", "idx_prt0", "idx_prt1", "pre_prt0", "pre_prt1"]
         self._vrs("tag", vrsIdx + vrsMom + ["pid"] + vrsVrt + vrsTag + vrsTrg + vrsMC)
         self._vrs("trk", vrsMom + ["pid"] + vrsTrk)
-        self._vrs("cal", ["mm", "dmm", "m", "dm", "idx_pvr", "pid"] + vrsMom)
         self._vrs("pvr", vrsVrt)
         self.ntuple["pvr_n"] = array.array("i", [-1])
         self.ntuple["spd_n"] = array.array("i", [-1])
@@ -164,7 +157,7 @@ class Ntuple:
     def _vrs(self, pre: "str", vrs):
         """Initialize variables with a given prefix."""
         self.keys[pre] = f"{pre}_{vrs[0]}"
-        tmap = {"int": ["pid", "idx", "pre", "tip", "Brem"], "bool": ["tis", "tos"]}
+        tmap = {"int": ["pid", "idx", "pre", "tip"], "bool": ["tis", "tos"]}
         for var in vrs:
             t = "float"
             for key, k_list in tmap.items():
@@ -180,18 +173,12 @@ class Ntuple:
             trk = obj.proto().track().momentum()
         except:
             trk = None
-        try:
-            cal = obj.proto().calo()[0].position()
-        except:
-            cal = None
         try:
             vrt = obj.position()
         except:
             vrt = None
         if trk:
             return (trk.X(), trk.Y(), trk.Z())
-        if cal:
-            return (cal.x(), cal.y(), cal.z(), cal.e())
         if vrt:
             return (vrt.X(), vrt.Y(), vrt.Z())
         return (obj.momentum().Px(), obj.momentum().Py(), obj.momentum().Pz())
@@ -333,8 +320,9 @@ class Ntuple:
                 dptype = "hm" # dptype: daughter particle type
             elif mcp.pid == +321 or mcp.pid == +211:
                 dptype = "hp"
-            elif mcp.pid == 22:
+            elif mcp.pid == 22: #photon - this is topologically mapped to a bachelor akaon for our analysis but how should I deal with this?
                 dptype = "g"
+                # check that the mother is a K short
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
             mom = mcp.lpar.p
@@ -343,7 +331,7 @@ class Ntuple:
                 lpid = int(mcp.lpar.pid)
             except:
                 lpid = 99
-            self.fill(f"{pre}_{dptype}_lpx", mom.Px())
+            self.fill(f"{pre}_{dptype}_lpx", mom.Px()) # l denotes that it is variable associated to a linked particle
             self.fill(f"{pre}_{dptype}_lpy", mom.Py())
             self.fill(f"{pre}_{dptype}_lpz", mom.Pz())
             self.fill(f"{pre}_{dptype}_le", mom.E())
@@ -358,20 +346,18 @@ class Ntuple:
 
     ###########################################################################
     def _filltrkOL(self, pre: "str", prt):
-        """Find number of shared track lhcbIDs between e- and e+.
+        """Find number of shared track lhcbIDs between h- and h+.
 
         Accessed through dihadron candidate.
         """
         if prt.particleID().pid() == 310: #310 is K short
             nol = 0
-            hm = hp = None
+            hm = hp = None # hm: hadron (pi or K) minus, hp: hadron plus
             for i_dp in range(len(prt.daughtersVector())):
                 dp = prt.daughtersVector()[i_dp]
-                #if dp.particleID().pid() == -321:
                 if dp.particleID().pid() == -321 or dp.particleID().pid() == -211:
                     assert hm is None
                     hm = dp
-                #elif dp.particleID().pid() == 321:
                 elif dp.particleID().pid() == 321 or dp.particleID().pid() == 211:
                     assert hp is None
                     hp = dp
@@ -410,7 +396,7 @@ class Ntuple:
         if pvr and len(dtrs) == 2 and not any(x is None for x in (pos, cov)):
             if year not in (2016, 2017, 2018):
                 raise ValueError(f"year {year} not recognized")
-            pvp = pvr.position()
+            pvp = pvr.position() # pvp: primary vertex position
             vfv = (pos.X() - pvp.X(), pos.Y() - pvp.Y(), pos.Z() - pvp.Z())
             assert cov is not None
             self.fill(
@@ -515,7 +501,7 @@ class Ntuple:
         # Daughters.
         daughter_momenta = []
         for idx in range(len(prt.daughtersVector())):
-            dtr = prt.daughtersVector()[idx]
+            dtr = prt.daughtersVector()[idx] #daughter
             daughter_momenta += [dtr.momentum()]
             dtrPre, dtrIdx = self.fillPrt(  # type: ignore
                 dtr, pos, year, run, mctool=mctool
@@ -542,65 +528,65 @@ class Ntuple:
                 self._fillgenMomPID(pre, mcprt)
 
             try:
-                emmpid = int(mcprt.dl[0].dl[0].lpar.mother.pid)
+                hmmpid = int(mcprt.dl[0].dl[0].lpar.mother.pid) #hmmpid: hadron minus mother pid
             except:
-                emmpid = 99
+                hmmpid = 99
             try:
-                epmpid = int(mcprt.dl[0].dl[1].lpar.mother.pid)
+                hpmpid = int(mcprt.dl[0].dl[1].lpar.mother.pid)
             except:
-                epmpid = 99
+                hpmpid = 99
             try:
                 gmpid = int(mcprt.dl[1].lpar.mother.pid)
             except:
                 gmpid = 99
 
             try:
-                emorvrt = int(mcprt.dl[0].dl[0].lpar.orvrt)
+                hmorvrt = int(mcprt.dl[0].dl[0].lpar.orvrt)
             except:
-                emorvrt = 99
+                hmorvrt = 99
             try:
-                eporvrt = int(mcprt.dl[0].dl[1].lpar.orvrt)
+                hporvrt = int(mcprt.dl[0].dl[1].lpar.orvrt)
             except:
-                eporvrt = 99
+                hporvrt = 99
             try:
                 gorvrt = int(mcprt.dl[1].lpar.orvrt)
             except:
                 gorvrt = 99
 
             try:
-                emmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.orvrt)
+                hmmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.orvrt)
             except:
-                emmorvrt = 99
+                hmmorvrt = 99
             try:
-                epmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.orvrt)
+                hpmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.orvrt)
             except:
-                epmorvrt = 99
+                hpmorvrt = 99
             try:
                 gmorvrt = int(mcprt.dl[1].lpar.mother.orvrt)
             except:
                 gmorvrt = 99
 
             try:
-                emmmpid = int(mcprt.dl[0].dl[0].lpar.mother.mother.pid)
+                hmmmpid = int(mcprt.dl[0].dl[0].lpar.mother.mother.pid)
             except:
-                emmmpid = 99
+                hmmmpid = 99
             try:
-                epmmpid = int(mcprt.dl[0].dl[1].lpar.mother.mother.pid)
+                hpmmpid = int(mcprt.dl[0].dl[1].lpar.mother.mother.pid)
             except:
-                epmmpid = 99
+                hpmmpid = 99
             try:
                 gmmpid = int(mcprt.dl[1].lpar.mother.mother.pid)
             except:
                 gmmpid = 99
 
             try:
-                emmmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.mother.orvrt)
+                hmmmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.mother.orvrt)
             except:
-                emmmorvrt = 99
+                hmmmorvrt = 99
             try:
-                epmmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.mother.orvrt)
+                hpmmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.mother.orvrt)
             except:
-                epmmorvrt = 99
+                hpmmorvrt = 99
             try:
                 gmmorvrt = int(mcprt.dl[1].lpar.mother.mother.orvrt)
             except:
@@ -618,25 +604,25 @@ class Ntuple:
                 drm = -1
             self.fill(f"{pre}_drmatch", drm)
 
-            self.fill(f"{pre}_em_mpid", emmpid)
-            self.fill(f"{pre}_ep_mpid", epmpid)
-            self.fill(f"{pre}_g_mpid", gmpid)
+            self.fill(f"{pre}_hm_mpid", hmmpid)
+            self.fill(f"{pre}_hp_mpid", hpmpid)
+            self.fill(f"{pre}_K_mpid", gmpid)
 
-            self.fill(f"{pre}_em_mmpid", emmmpid)
-            self.fill(f"{pre}_ep_mmpid", epmmpid)
-            self.fill(f"{pre}_g_mmpid", gmmpid)
+            self.fill(f"{pre}_hm_mmpid", hmmmpid)
+            self.fill(f"{pre}_hp_mmpid", hpmmpid)
+            self.fill(f"{pre}_K_mmpid", gmmpid)
 
-            self.fill(f"{pre}_em_orvrt", emorvrt)
-            self.fill(f"{pre}_ep_orvrt", eporvrt)
-            self.fill(f"{pre}_g_orvrt", gorvrt)
+            self.fill(f"{pre}_hm_orvrt", hmorvrt)
+            self.fill(f"{pre}_hp_orvrt", hporvrt)
+            self.fill(f"{pre}_K_orvrt", gorvrt)
 
-            self.fill(f"{pre}_em_morvrt", emmorvrt)
-            self.fill(f"{pre}_ep_morvrt", epmorvrt)
-            self.fill(f"{pre}_g_morvrt", gmorvrt)
+            self.fill(f"{pre}_hm_morvrt", hmmorvrt)
+            self.fill(f"{pre}_hp_morvrt", hpmorvrt)
+            self.fill(f"{pre}_K_morvrt", gmorvrt)
 
-            self.fill(f"{pre}_em_mmorvrt", emmmorvrt)
-            self.fill(f"{pre}_ep_mmorvrt", epmmorvrt)
-            self.fill(f"{pre}_g_mmorvrt", gmmorvrt)
+            self.fill(f"{pre}_hm_mmorvrt", hmmmorvrt)
+            self.fill(f"{pre}_hp_mmorvrt", hpmmorvrt)
+            self.fill(f"{pre}_K_mmorvrt", gmmorvrt)
 
         # Trigger.
         self._fillTrg(pre, prt)
@@ -662,9 +648,6 @@ class Ntuple:
         self._fillMat(pre, pvr, pos, daughter_momenta, cov, year, run)
         # fillMat not implemented for dtf b/c it's a pain to code up daughter momenta
 
-        # Brem.
-        self._fillBrem(pre, prt)
-
         # Flight distance.
         fd, fdChi2 = ctypes.c_double(-1), ctypes.c_double(-1)
         if pvr and vrt:
@@ -724,29 +707,6 @@ class Ntuple:
             f"{pre}_veloCharge",
             pro.info(GaudiPython.gbl.LHCb.ProtoParticle.VeloCharge, -10000.0),
         )
-        # ECal
-        em_hypo = None  # calorimeter hypothesis using EmCharged
-        ecal_vec = GaudiPython.gbl.LHCb.StateVector()  # position of interaction
-        for i_hypo in range(len(pro.calo())):
-            if (
-                pro.calo()[i_hypo].hypothesis()
-                == GaudiPython.gbl.LHCb.CaloHypo.EmCharged
-            ):
-                assert em_hypo is None
-                em_hypo = pro.calo()[i_hypo]
-        if em_hypo:
-            assert em_hypo.hypothesis() == GaudiPython.gbl.LHCb.CaloHypo.EmCharged
-            ecal_z = (
-                em_hypo.position().z()
-            )  # mm, Z-position where cluster parameters are estimated
-            self._trkTool.propagate(trk, ecal_z, ecal_vec, prt.particleID())
-        else:
-            ecal_vec.setX(-1e9)
-            ecal_vec.setY(-1e9)
-            ecal_vec.setZ(-1e9)
-        self.fill(f"{pre}_ecalx", ecal_vec.x())
-        self.fill(f"{pre}_ecaly", ecal_vec.y())
-        self.fill(f"{pre}_ecalz", ecal_vec.z())
 
         # Material tool.
         self.fill(
@@ -776,14 +736,6 @@ class Ntuple:
         self.fill(f"{pre}_ip_chi2", ipChi2.value)
         return pvr
 
-    ###########################################################################
-    def _fillCal(self, pre: "str", prt):
-        """Fill the information for a calorimetry object."""
-        mom = prt.momentum()
-        self._fillMom(pre, mom)
-        self._fillM(pre, mom)
-        self._fillMM(pre, prt)
-
     ###########################################################################
     def fillPrt(
         self,
@@ -798,7 +750,7 @@ class Ntuple:
         vrt = prt.endVertex()
         key = self._key(prt)
         idx = self._index(key)
-        pre = "tag" if vrt else ("trk" if prt.charge() else "cal")
+        pre = "tag" if vrt else "trk"
         if idx is not None:
             return (pre, idx)
 
@@ -819,10 +771,6 @@ class Ntuple:
             assert year is not None and run is not None, (year, run)
             assert prt.particleID().pid() in (-321, 321, -211, 211), prt.particleID().pid() # K-, K+, pi-, pi+
             pvr = self._fillTrk(pre, prt, org, year, run)
-        elif pre == "cal":
-            assert prt.particleID().pid() == 22, prt.particleID().pid()
-            assert self._fillCal(pre, prt) is None
-            pvr = None
         else:
             raise ValueError(f"pre '{pre}' not recognized")
         self.fill(f"{pre}_pid", prt.particleID().pid())
@@ -839,19 +787,21 @@ class Ntuple:
             self.fill(f"{pre}_idx_pvr", -1)
         return (pre, self._save(pre, key))
 
+# End of class Ntuple
 
 def fill_ntuple(
     ntuple: "Ntuple",
     tes,
-    candloc: "str",
-    #candloc_noBrem: "str",
-    #head: "Union[str, None]",
+    candidate_loc: "str",
+    hh: "str",
     genTool,
 ):
+    print(f"hh is {hh}")
     """Assign values to the ntuple."""
     year = int(DaVinci().DataType)
 
     def get_particles(candloc):
+        print(f"candidate_loc is {candloc}")
         try:
             particles = tes[candloc]
             #print(particles)
@@ -874,24 +824,20 @@ def fill_ntuple(
         GaudiPython.gbl.LoKi.L0.DataValue("Spd(Mult)")(tes["Trig/L0/L0DUReport"])
     )
 
-    print(candloc)
-
     # Fill the particles.
-    all_Bs = get_particles(candloc) 
-    print(f"length of all bs is {len(all_Bs)}")
-
-
+    all_Bparticles = get_particles(candidate_loc) 
+    print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
-        print("yay its working for mc")
-        mct = MCEventTools.MCEvent(all_Bs, genTool) # mct: monte carlo tool
-        print(mct)
+        mct = MCEventTools.MCEvent(all_Bparticles, genTool) # mct: monte carlo tool
+        #print(mct)
         mct.linkpars()
         mcpstore = get_particles(
             "AllStreams/MC/Particles"
             if DaVinci().InputType == "MDST"
             else "MC/Particles"
         )
+        print(f"got {len(mcpstore)} B mesons from MC/Particles")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
@@ -899,12 +845,10 @@ def fill_ntuple(
 
 
     isfilled = False
-
-    print('moving onto for loop')
   
-    for B in all_Bs:
+    for all_Bparticle in all_Bparticles:
         print("its working")
-        args, kwargs = [B], {"year": year, "run": rnum, "mctool": mct}
+        args, kwargs = [all_Bparticle], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
         print("I find bool is {0}".format(boolVal))
@@ -913,7 +857,10 @@ def fill_ntuple(
             isfilled = True
             print("isfilled has been set to {0}".format(isfilled))
 
-    if len(all_Bs) > 0 and isfilled:
+    if len(all_Bparticles) > 0 and isfilled:
         print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
+
+# End of fill_ntuple function
+
diff --git a/bu2kdarkscalar_darkscalar2hh/README.md b/bu2kdarkscalar_darkscalar2hh/README.md
new file mode 100644
index 0000000000..fd0c9bc37d
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/README.md
@@ -0,0 +1,47 @@
+# `bu2kdarkscalar_darkscalar2hh`
+
+Analysis production for dark scalar ($\chi$) search in
+$B \rightarrow K (\chi \rightarrow h^+ h^-)$ decays.
+
+This production is based off the production for the dark photon ($`A^\prime`$)/true muonium search in
+$`\pi^0 / \eta \rightarrow \gamma (A^\prime \rightarrow e^+ e^-)`$ decays.
+
+## Working with the n-tuples from `job.py`
+
+In the following: `TFile` will be shorthand for `ROOT.TFile("<treefile.root>")`,
+where `treefile.root` is the ROOT file containing the n-tuple.
+Likewise, `tree` will be shorthand for `TFile.DecayData`.
+
+### Prefixes and Accessing variables
+
+In the output `TFile`,
+there are 3 prefixes used to label data:
+
+| Prefix Name | Prefix Number | Associated Data |
+|:-----------:|:-------------:|:---------------:|
+| `tag` | 0 | reconstructed particles (i.e. $B^{\pm}$, dihadron) [object has an `endVertex`] |
+| `trk` | 1 | tracks (hadrons: $K^{\pm}$, $\pi^{\pm}$) [object does not have an `endVertex` (long-lived) and is charged] |
+
+The data for a particular prefix is accessed
+(after getting event with `tree.GetEntry(i)`) from `tree.<Prefix Name>_<variable>[j]`,
+where `i` denotes the i<sup>th</sup> event and `j` denotes the j<sup>th</sup> particle in the event with prefix `Prefix Name`;
+`variable` is the specific variable being accessed.
+For example, `tree.tag_pid[0]` would be the PID of the first tag object in the event.
+
+**_Note:_** Whether a tag is a $B^{\pm}$ or a dihadron can be determined by checking its PID;
+if PID is +/-521: tag is a $B^{\pm}$, if PID is 310: tag is a dihadron
+
+### Establishing Lineage of Particles
+
+For a tag object, the variables `tag_pre_prt0`, `tag_idx_prt0`, `tag_pre_prt1`, and `tag_idx_prt1` are used to find its associated daughter particles.
+`tag_pre_prt0` and `tag_pre_prt1` are the prefix numbers of the first and second daughter particles respectively (pre refers to prefix);
+`tag_idx_prt0` and `tag_idx_prt1` are the indices of the first and second daughter particles respectively in their prefix's particle entries for the event (idx refers to index).
+For example, if tree had `tree.tag_pre_prt0[i] == 1`, `tree.tag_idx_prt0[i] == 2`, `tree.tag_pre_prt1[i] == 0`, `tree.tag_idx_prt1[i] == 3`,
+the data for the first daughter particle (prt0) would be stored at `tree.trk_<var>[2]` and the data for the second daughter particle (prt1) would be stored at `tree.tag_<var>[3]`.
+
+`keys`: a 3- tuple.
+
+- for a `trk` particle this is the three-vector of momentum
+- for a `vrt` this is the position vector
+- otherwise this is the object momentum three-vector
+
diff --git a/bu2kdarkscalar_darkscalar2hh/hh_KK.py b/bu2kdarkscalar_darkscalar2hh/hh_KK.py
new file mode 100644
index 0000000000..c2e23771fd
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/hh_KK.py
@@ -0,0 +1,5 @@
+"""Set hh for job.py.
+
+This file should be passed as a command-line option to job.py.
+"""
+head = "KK"
diff --git a/bu2kdarkscalar_darkscalar2hh/hh_PiPi.py b/bu2kdarkscalar_darkscalar2hh/hh_PiPi.py
new file mode 100644
index 0000000000..21570c9612
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/hh_PiPi.py
@@ -0,0 +1,5 @@
+"""Set head for job.py.
+
+This file should be passed as a command-line option to job.py.
+"""
+head = "PiPi"
diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index cee77310d1..d4354840b4 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -2,7 +2,7 @@
 
 {%- for polarity in polarities %}
 
-Bu2KdarkScalar_darkScalar2hh_2018_Mag{{polarity}}_job:
+B2KKK_2018_Mag{{polarity}}_job:
   application: DaVinci/v46r8
   wg: QEE
   automatically_configure: yes
@@ -16,13 +16,13 @@ Bu2KdarkScalar_darkScalar2hh_2018_Mag{{polarity}}_job:
       - job.py
 
   input:
-    bk_query: /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p3/90000000/LEPTONIC.MDST
+    bk_query: /MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
     # For MC
     # /MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
     # For data
     # /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
     
-  output: bu2kdarkscalar_darkscalar2hh.ROOT
+  output: B2KKK.ROOT
   # For MC
   # B2KKK.ROOT
   # For data
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index b24f45abd0..e785c149b8 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -38,28 +38,41 @@ def parse_args() -> "tuple[Union[str, None], bool]":
     )
     args = parser.parse_args()
 
+    allowed_hh = ("PiPi", "KK")
+    hh = None
+
+
     for options_path in args.options_paths:
         print("Adding options file:", options_path)
         # execute module
         # https://stackoverflow.com/a/19011259/4655426
         loader = importlib.machinery.SourceFileLoader(
-            "head_particle", str(options_path.resolve())
+            "hh_particle", str(options_path.resolve())
         )
         spec = importlib.util.spec_from_loader(loader.name, loader)
         assert spec is not None
         mod = importlib.util.module_from_spec(spec)
         loader.exec_module(mod)
-
-
-
-
-    return 
+        # try to get head
+        try:
+            hh = mod.head
+        except AttributeError:
+            # did not set head
+            pass
+    if DaVinci().Simulation:
+        if hh is None:
+            raise parser.error("One options file must set hh for MC.")
+        elif hh not in allowed_hh:
+            raise ValueError(f"hh must be one of {allowed_hh}")
+        else:
+            print(f"Running with hh == '{hh}'.")
+    return hh
 
 
 # In order to use Run 1+2 GaudiPython with analysis productions the arguments
 # passed to the script need to be executed to set up input data and other state
 
-parse_args()
+hh = parse_args()
 # =================================================================================
 # Set up material tool
 print("About to compile velo material tool")
@@ -89,8 +102,14 @@ DaVinci().Lumi = False
 # =================================================================================
 
 #candidate locations
-candloc_KK = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
-candloc_PiPi = "/Event/Leptonic/Phys/B2KX2PiPiDarkBosonLine/Particles"
+if hh == "KK":
+    candloc = "/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles"
+elif hh == "PiPi":
+    candloc = "/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles"
+
+
+#candloc_KK = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
+#candloc_PiPi = "/Event/Leptonic/Phys/B2KX2PiPiDarkBosonLine/Particles"
 
 
 # =================================================================================
@@ -123,9 +142,8 @@ while (NOfEvents == -1) or (event < NOfEvents):
     event += 1
     print("found evt")
 
-    fill_ntuple(ntuple, tes, candloc_KK, genTool)
-    print("filled ntuple KK")
-    #fill_ntuple(ntuple, tes, candloc_PiPi, genTool)
+    fill_ntuple(ntuple, tes, candloc, hh, genTool)
+    print("filled")
 
 
 # Close.
-- 
GitLab


From 6f63b008f4930afc6ab1285b7391d08cb04a8f56 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Thu, 25 Jul 2024 17:00:44 +0100
Subject: [PATCH 09/70] logic for B2KKK must be differnt than dark photon

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py |   2 +-
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 142 ++++++++++---------
 bu2kdarkscalar_darkscalar2hh/README.md       |  83 ++++++++++-
 bu2kdarkscalar_darkscalar2hh/info.yaml       |  21 ++-
 bu2kdarkscalar_darkscalar2hh/job.py          |   2 +-
 5 files changed, 177 insertions(+), 73 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index f42bd97f38..32740602ef 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -3,7 +3,7 @@ import GaudiPython as GP
 from GaudiConf import IOHelper
 from Configurables import DaVinci, TriggerTisTos, ToolSvc
 from ROOT import TLorentzVector as tlv
-from LoKiMC.decorators import MCPX, MCPY, MCPZ, MCE, MCID, MCABSID, MCPT, MCM, MCETA, MCP, MCPHI
+from LoKiMC.decorators import MCPX, MCPY, MCPZ, MCE, MCID, MCABSID, MCPT, MCM, MCETA, MCP, MCPHI, MCINANCESTORS
 from LoKiPhys.decorators import M, PX, PY, PZ, E, ID, ABSID, PROBNNk, PROBNNpi, PROBNNghost, IPCHI2, P, PT, CL, ETA, TRGHOSTPROB, PHI
 from array import array
 from math import sqrt
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index da3e3e1ea7..e0d1fb4f43 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -9,6 +9,7 @@ from typing import Any, Union
 from Configurables import DaVinci
 import GaudiPython
 from LoKiArrayFunctors.decorators import AMAXDOCA
+from LoKiMC.decorators import MCINANCESTORS, MCID
 import ROOT
 
 from dtf import dtf #dtf: decay tree fitter
@@ -46,7 +47,7 @@ class Ntuple:
             gaudi.toolsvc().create(
                 "TriggerTisTos/Strip/PhysTriggerTisTos", interface="ITriggerTisTos"
             ),
-        ] # trigger tools
+        ] # trigger tools: L0, Hlt1, Hlt2, Stripping
         self._docaTool = GaudiPython.gbl.LoKi.Particles.DOCA(0, 0, self._dstTool)
         self._veloTool = ROOT.VeloMaterial()
 
@@ -54,10 +55,12 @@ class Ntuple:
         self.tos: "list[list[str]]" = [
             ["L0Hadron.*"],
             ["Hlt1.*Hadron.*", "Hlt1.*TrackMVA.*"],
-            ["Hlt2ExoticaPi0ToDiEGamma", "Hlt2ExoticaEtaToDiEGamma"],
+            ["Hlt2.*"],
             [],
         ]
-        self.tis: "list[list[str]]" = [[], [], ["Hlt2Topo.*"], []]
+
+        #["Hlt2ExoticaPi0ToDiEGamma", "Hlt2ExoticaEtaToDiEGamma"],
+        self.tis: "list[list[str]]" = [[], [], ["Hlt2.*"], []]
 
         # Stored variables.
         self.saved: "dict[str, int]" = {}
@@ -109,7 +112,7 @@ class Ntuple:
             ]
             + [
                 f"{dtf}dtf_{x}"
-                for dtf in ["p", "d"]
+                for dtf in ["p", "d"] # p: parent, d: daughter
                 for x in ["m", "dm", "chi2"]
                 + vrsMom
                 + vrsVrt
@@ -279,7 +282,11 @@ class Ntuple:
 
     ###########################################################################
     def _fillMM(self, pre: "str", prt):
-        """Fill measured mass for a particle."""
+        """Fill measured mass for a particle.
+        mm: measured mass
+        dmm: delta measured mass (the error on the measured mass)
+        
+        """
         self.fill(f"{pre}_mm", prt.measuredMass())
         self.fill(f"{pre}_dmm", prt.measuredMassErr())
 
@@ -313,16 +320,20 @@ class Ntuple:
             self.fill(f"{pre}_dih_m", mom.M())
 
     ###########################################################################
-    def _fillgenMomPID(self, pre: "str", mcp):
+    def _fillgenMomPID(self, pre: "str", mcp, dptype):
         """Fill generator level MC momentum and pid for a particle."""
         if mcp: # mcp: monte carlo particle
-            if mcp.pid == -321 or mcp.pid == -211:
-                dptype = "hm" # dptype: daughter particle type
-            elif mcp.pid == +321 or mcp.pid == +211:
-                dptype = "hp"
-            elif mcp.pid == 22: #photon - this is topologically mapped to a bachelor akaon for our analysis but how should I deal with this?
-                dptype = "g"
-                # check that the mother is a K short
+            if mcp.pid in (310, 211, -211, 321, -321, 521, -521):
+                print(f"mcp.pid is set to {mcp.pid}")
+
+                if dptype in ("hadron0", "hadron1"):
+                    if mcp.pid in (-211, -321):
+                        dptype = "hm"
+                        print(f"found mcp particle which is hm with pid {mcp.pid}")
+                    elif mcp.pid in (211, 321):
+                        dptype = "hp" 
+                        print(f"found mcp particle which is hp with pid {mcp.pid}")
+                pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
             mom = mcp.lpar.p
@@ -337,7 +348,7 @@ class Ntuple:
             self.fill(f"{pre}_{dptype}_le", mom.E())
             self.fill(f"{pre}_{dptype}_lpid", lpid)
         else:
-            for dptype in ["hm", "hp", "g"]:
+            for dptype in ["hm", "hp", "K"]:
                 self.fill(f"{pre}_{dptype}_lpx", -1)
                 self.fill(f"{pre}_{dptype}_lpy", -1)
                 self.fill(f"{pre}_{dptype}_lpz", -1)
@@ -485,6 +496,7 @@ class Ntuple:
         pdtf = dtf(prt, pvr, True)
         ddtf = dtf(prt, pvr, False)
         if prt.particleID().pid() in (-521, 521):
+            # B- or B+
             pdtf.fit()
             ddtf.fit()
             assert pdtf.dihadron == ddtf.dihadron
@@ -520,77 +532,79 @@ class Ntuple:
         if mctool is not None:
             mcprt = mctool.mcpquery(prt)
 
+            hh = "KK"
+
             if mcprt:
-                self._fillgenMomPID(pre, mcprt.dl[1])
-                self._fillgenMomPID(pre, mcprt.dl[0].dl[0])
-                self._fillgenMomPID(pre, mcprt.dl[0].dl[1])
+                self._fillgenMomPID(pre, mcprt.dl[1], "K") # B's daughter: bachelor kaon
+                self._fillgenMomPID(pre, mcprt.dl[0].dl[0], "hadron0") # B's daughter, dark scalar,has two daughters itself
+                self._fillgenMomPID(pre, mcprt.dl[0].dl[1], "hadron1") # B's daughter: hadron 
             else:
-                self._fillgenMomPID(pre, mcprt)
+                self._fillgenMomPID(pre, mcprt, hh, "B")
 
             try:
-                hmmpid = int(mcprt.dl[0].dl[0].lpar.mother.pid) #hmmpid: hadron minus mother pid
+                hm_mpid = int(mcprt.dl[0].dl[0].lpar.mother.pid) #hm_mpid: hadron minus mother pid
             except:
-                hmmpid = 99
+                hm_mpid = 99
             try:
-                hpmpid = int(mcprt.dl[0].dl[1].lpar.mother.pid)
+                hp_mpid = int(mcprt.dl[0].dl[1].lpar.mother.pid)
             except:
-                hpmpid = 99
+                hp_mpid = 99
             try:
-                gmpid = int(mcprt.dl[1].lpar.mother.pid)
+                K_mpid = int(mcprt.dl[1].lpar.mother.pid)
             except:
-                gmpid = 99
+                K_mpid = 99
 
             try:
-                hmorvrt = int(mcprt.dl[0].dl[0].lpar.orvrt)
+                hm_orvrt = int(mcprt.dl[0].dl[0].lpar.orvrt)
             except:
-                hmorvrt = 99
+                hm_orvrt = 99
             try:
-                hporvrt = int(mcprt.dl[0].dl[1].lpar.orvrt)
+                hp_orvrt = int(mcprt.dl[0].dl[1].lpar.orvrt)
             except:
-                hporvrt = 99
+                hp_orvrt = 99
             try:
-                gorvrt = int(mcprt.dl[1].lpar.orvrt)
+                K_orvrt = int(mcprt.dl[1].lpar.orvrt)
             except:
-                gorvrt = 99
+                K_orvrt = 99
 
             try:
-                hmmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.orvrt)
+                hm_morvrt = int(mcprt.dl[0].dl[0].lpar.mother.orvrt)
             except:
-                hmmorvrt = 99
+                hm_morvrt = 99
             try:
-                hpmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.orvrt)
+                hp_morvrt = int(mcprt.dl[0].dl[1].lpar.mother.orvrt)
             except:
-                hpmorvrt = 99
+                hp_morvrt = 99
             try:
-                gmorvrt = int(mcprt.dl[1].lpar.mother.orvrt)
+                K_morvrt = int(mcprt.dl[1].lpar.mother.orvrt)
             except:
-                gmorvrt = 99
+                K_morvrt = 99
 
             try:
-                hmmmpid = int(mcprt.dl[0].dl[0].lpar.mother.mother.pid)
+                hm_mmpid = int(mcprt.dl[0].dl[0].lpar.mother.mother.pid)
             except:
-                hmmmpid = 99
+                hm_mmpid = 99
             try:
-                hpmmpid = int(mcprt.dl[0].dl[1].lpar.mother.mother.pid)
+                hp_mmpid = int(mcprt.dl[0].dl[1].lpar.mother.mother.pid)
             except:
-                hpmmpid = 99
+                hp_mmpid = 99
             try:
-                gmmpid = int(mcprt.dl[1].lpar.mother.mother.pid)
+                K_mmpid = int(mcprt.dl[1].lpar.mother.mother.pid)
             except:
-                gmmpid = 99
+                K_mmpid = 99
 
             try:
-                hmmmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.mother.orvrt)
+                hm_mmorvrt = int(mcprt.dl[0].dl[0].lpar.mother.mother.orvrt)
             except:
-                hmmmorvrt = 99
+                hm_mmorvrt = 99
             try:
-                hpmmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.mother.orvrt)
+                hp_mmorvrt = int(mcprt.dl[0].dl[1].lpar.mother.mother.orvrt)
             except:
-                hpmmorvrt = 99
+                hp_mmorvrt = 99
             try:
-                gmmorvrt = int(mcprt.dl[1].lpar.mother.mother.orvrt)
+                K_mmorvrt = int(mcprt.dl[1].lpar.mother.mother.orvrt)
             except:
-                gmmorvrt = 99
+                K_mmorvrt = 99
 
             try:
                 bgt = int(mcprt.bgtype)
@@ -604,25 +618,25 @@ class Ntuple:
                 drm = -1
             self.fill(f"{pre}_drmatch", drm)
 
-            self.fill(f"{pre}_hm_mpid", hmmpid)
-            self.fill(f"{pre}_hp_mpid", hpmpid)
-            self.fill(f"{pre}_K_mpid", gmpid)
+            self.fill(f"{pre}_hm_mpid", hm_mpid)
+            self.fill(f"{pre}_hp_mpid", hp_mpid)
+            self.fill(f"{pre}_K_mpid", K_mpid)
 
-            self.fill(f"{pre}_hm_mmpid", hmmmpid)
-            self.fill(f"{pre}_hp_mmpid", hpmmpid)
-            self.fill(f"{pre}_K_mmpid", gmmpid)
+            self.fill(f"{pre}_hm_mmpid", hm_mmpid)
+            self.fill(f"{pre}_hp_mmpid", hp_mmpid)
+            self.fill(f"{pre}_K_mmpid", K_mmpid)
 
-            self.fill(f"{pre}_hm_orvrt", hmorvrt)
-            self.fill(f"{pre}_hp_orvrt", hporvrt)
-            self.fill(f"{pre}_K_orvrt", gorvrt)
+            self.fill(f"{pre}_hm_orvrt", hm_orvrt)
+            self.fill(f"{pre}_hp_orvrt", hp_orvrt)
+            self.fill(f"{pre}_K_orvrt", K_orvrt)
 
-            self.fill(f"{pre}_hm_morvrt", hmmorvrt)
-            self.fill(f"{pre}_hp_morvrt", hpmorvrt)
-            self.fill(f"{pre}_K_morvrt", gmorvrt)
+            self.fill(f"{pre}_hm_morvrt", hm_morvrt)
+            self.fill(f"{pre}_hp_morvrt", hp_morvrt)
+            self.fill(f"{pre}_K_morvrt", K_morvrt)
 
-            self.fill(f"{pre}_hm_mmorvrt", hmmmorvrt)
-            self.fill(f"{pre}_hp_mmorvrt", hpmmorvrt)
-            self.fill(f"{pre}_K_mmorvrt", gmmorvrt)
+            self.fill(f"{pre}_hm_mmorvrt", hm_mmorvrt)
+            self.fill(f"{pre}_hp_mmorvrt", hp_mmorvrt)
+            self.fill(f"{pre}_K_mmorvrt", K_mmorvrt)
 
         # Trigger.
         self._fillTrg(pre, prt)
@@ -787,7 +801,7 @@ class Ntuple:
             self.fill(f"{pre}_idx_pvr", -1)
         return (pre, self._save(pre, key))
 
-# End of class Ntuple
+################################ End of class Ntuple ################################################
 
 def fill_ntuple(
     ntuple: "Ntuple",
diff --git a/bu2kdarkscalar_darkscalar2hh/README.md b/bu2kdarkscalar_darkscalar2hh/README.md
index fd0c9bc37d..1907f83c8f 100644
--- a/bu2kdarkscalar_darkscalar2hh/README.md
+++ b/bu2kdarkscalar_darkscalar2hh/README.md
@@ -19,7 +19,7 @@ there are 3 prefixes used to label data:
 
 | Prefix Name | Prefix Number | Associated Data |
 |:-----------:|:-------------:|:---------------:|
-| `tag` | 0 | reconstructed particles (i.e. $B^{\pm}$, dihadron) [object has an `endVertex`] |
+| `tag` | 0 | reconstructed particles (i.e. $B^{\pm}$, dihadron (the dark scalar)) [object has an `endVertex`] |
 | `trk` | 1 | tracks (hadrons: $K^{\pm}$, $\pi^{\pm}$) [object does not have an `endVertex` (long-lived) and is charged] |
 
 The data for a particular prefix is accessed
@@ -45,3 +45,84 @@ the data for the first daughter particle (prt0) would be stored at `tree.trk_<va
 - for a `vrt` this is the position vector
 - otherwise this is the object momentum three-vector
 
+
+### List of branches added to the ntuple
+
+*Br    0 :tag_idx_pvr : vector       Vector for tags in the event giving the index of the associated pv in the array of associated ‘pvr’ objects found in this event. There should be one entry per tag.
+
+*Br    1 :tag_idx_prt0 : vector      Vector for tags in the event giving the index of the first daughter particle
+*Br    2 :tag_idx_prt1 : vector      …second daughter…
+
+*Br    3 :tag_pre_prt0 : vector      Vector for tags in the event giving the prefix of the first daughter (0=tag, 1=trk)
+*Br    4 :tag_pre_prt1 : vector      …second daughter…
+
+*Br    5 :tag_pid   : vector         Vector for tags in the event giving the particle ID number.
+
+*Br    6 :tag_px    : vector          x momentum of the tag
+*Br    7 :tag_py    : vector          y
+*Br    8 :tag_pz    : vector          z
+*Br    9 :tag_e     : vector          computed energy using particle ID and four-momentum
+
+*Br   10 :tag_x     : vector          x position of the endvertex associated to the tag
+*Br   11 :tag_y     : vector          y
+*Br   12 :tag_z     : vector          z
+
+*Br   13 :tag_dx    : vector          uncertainty on x position, determined from its covariance matrix
+*Br   14 :tag_dy    : vector
+*Br   15 :tag_dz    : vector
+
+*Br   16 :tag_m     : vector         mass after vertex-fit
+*Br   17 :tag_dm    : vector        ‘error’ on the vertex fit mass
+
+
+*Br   18 :tag_mm    : vector        ‘measured-mass’ (i.e. before vertex fit)
+*Br   19 :tag_dm    : vector        ‘error’ on the measured mass
+
+*Br   20 :tag_doca  : vector        maximum doca between the momenta of the daughters of this vertex
+*Br   21 :tag_chi2  : vector        chi2 of the vertex fit
+
+*Br   20 :tag_dtf_chi2 : vector   chi2 of the DTF refit which requires that the particle should originate from its PV. -1 if fails
+
+*Br   21 :tag_ip    : vector           use loki distance calculator to find IP wrt associated PV
+*Br   22 :tag_ip_chi2 : vector    chi2 of that IP
+
+*Br   23 :tag_fd    : vector          uses same calculator to find distance between this vertex and pv
+*Br   24 :tag_fd_chi2 : vector     chi2 of that FD
+
+*Br   25 :tag_vt_tip : vector        returns true if flight distance of a vertex intercepts a foil tip
+*Br   26 :tag_vt_d  : vector         (offset, uncertainty weighted, scaled) material distance
+*Br   27 :tag_tos0  : vector         the index corresponds to the L0, Hlt1, or Hlt2 triggers
+*Br   31 :tag_tis0  : vector          ???
+
+*Br   32 :trk_idx_pvr : vector         index of the associated pvr in the list of pvr’s found for this event
+*Br   33 :trk_pid   : vector              pid of the charged particles: always 11 (electron)
+*Br   34 :trk_px    : vector           momentum component before any refitting
+*Br   35 :trk_py    : vector
+*Br   36 :trk_pz    : vector
+*Br   37 :trk_e     : vector
+*Br   38 :trk_pnn_e : vector        probnne
+*Br   39 :trk_pnn_pi : vector       probnnpi
+*Br   40 :trk_pnn_ghost : vector probnnghost
+*Br   41 :trk_ip    : vector            ip with respect to associated PV, calculated using the LoKi distance calculator
+*Br   42 :trk_ip_chi2 : vector      ipchi2 as above
+*Br   43 :trk_vt_miss : vector     returns true if the expected first hit of a track is missed, given a flight direction and vertex
+
+*Br   44 :trk_x0    : vector           ??? position for first hit in the VELO
+*Br   45 :trk_y0    : vector            y…
+*Br   46 :trk_z0    : vector            z…
+*Br   47 :trk_t0    : vector
+*Br   48 :trk_p0    : vector
+
+*Br   49 :trk_x1    : vector           ??? position for second hit in the VELO
+*Br   50 :trk_y1    : vector
+*Br   51 :trk_z1    : vector
+*Br   52 :trk_t1    : vector
+*Br   53 :trk_p1    : vector
+
+*Br   59 :pvr_x     : vector            position and uncertainty on any associated primary vertex related to a filled particle
+*Br   60 :pvr_y     : vector
+*Br   61 :pvr_z     : vector
+*Br   62 :pvr_dx    : vector
+*Br   63 :pvr_dy    : vector
+*Br   64 :pvr_dz    : vector
+
diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index d4354840b4..ba431d2f95 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,8 +1,14 @@
 {%- set polarities = ["Down", "Up"]%}
+{%- set datasets = [
+  ('KK', 18, 6500, '18', '34NoPrescalingFlagged'),
+  ('PiPi', 18, 6500, '18', '34NoPrescalingFlagged'),
+]%}
 
-{%- for polarity in polarities %}
 
-B2KKK_2018_Mag{{polarity}}_job:
+{%- for hh, year, energy, reco, strip in datasets %}
+   {%- for polarity in polarities %}
+
+my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_job:
   application: DaVinci/v46r8
   wg: QEE
   automatically_configure: yes
@@ -16,17 +22,20 @@ B2KKK_2018_Mag{{polarity}}_job:
       - job.py
 
   input:
-    bk_query: /MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
-    # For MC
-    # /MC/2018/Beam6500GeV-2018-MagDown-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
+    bk_query: /MC/2018/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco{{reco}}/Turbo05-WithTurcal/Stripping{{strip}}/23103008/ALLSTREAMS.DST
+    # For KK MC
+    # /MC/2018/Beam6500GeV-2018-Mag{{polarity}}-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
+    # For PiPi MC
+    #
     # For data
     # /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
     
-  output: B2KKK.ROOT
+  output: B2K{{hh}}.ROOT
   # For MC
   # B2KKK.ROOT
   # For data
   # bu2kdarkscalar_darkscalar2hh.ROOT
 
 
+   {%- endfor %}
 {%- endfor %}
\ No newline at end of file
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index e785c149b8..d29b6b2d38 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -105,7 +105,7 @@ DaVinci().Lumi = False
 if hh == "KK":
     candloc = "/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles"
 elif hh == "PiPi":
-    candloc = "/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles"
+    candloc = "/Event/AllStreams/Phys/B2KX2PiPiDarkBosonLine/Particles"
 
 
 #candloc_KK = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
-- 
GitLab


From b791988679b2253207ff5df944b5b4971d67b63c Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 26 Jul 2024 16:57:03 +0100
Subject: [PATCH 10/70] updated readme

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

diff --git a/bu2kdarkscalar_darkscalar2hh/README.md b/bu2kdarkscalar_darkscalar2hh/README.md
index 1907f83c8f..053db7f67e 100644
--- a/bu2kdarkscalar_darkscalar2hh/README.md
+++ b/bu2kdarkscalar_darkscalar2hh/README.md
@@ -46,7 +46,7 @@ the data for the first daughter particle (prt0) would be stored at `tree.trk_<va
 - otherwise this is the object momentum three-vector
 
 
-### List of branches added to the ntuple
+### List of branches added to the ntuple (INCOMPLETE)
 
 *Br    0 :tag_idx_pvr : vector       Vector for tags in the event giving the index of the associated pv in the array of associated ‘pvr’ objects found in this event. There should be one entry per tag.
 
-- 
GitLab


From 62884aefc8d0404a30015a76e67c68ad080266f3 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 2 Aug 2024 16:13:33 +0100
Subject: [PATCH 11/70] fixed issue with it not finding mcp

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 50 +++++++++++++++-----
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 48 +++++++++++--------
 bu2kdarkscalar_darkscalar2hh/hh_PiPi.py      |  2 +-
 bu2kdarkscalar_darkscalar2hh/info.yaml       | 45 +++++++++---------
 bu2kdarkscalar_darkscalar2hh/job.py          | 24 +++++++---
 5 files changed, 108 insertions(+), 61 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 32740602ef..52e413446a 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -165,7 +165,7 @@ class MCEvent:
     """
     Class for processing MC events.
     """
-    def __init__(self, all_Bs, mctool):
+    def __init__(self, all_Bs, mctool, hh):
         """
         Initializes MCEvent class. Creates list of rec level all_Bs, adds associated
         daughter particles to all_Bs daughter list.
@@ -183,6 +183,7 @@ class MCEvent:
                of MCEvent [bool]
         Bs  : list of combined all_Bs with daughter particles in daughter list [list(MCPart)]
         """
+        print(f"hh is {hh}")
         self.hcuts = False
         self.links = False
         self.iscategorized = False
@@ -204,8 +205,14 @@ class MCEvent:
                         hadron = MCPart(ddp)
                         hadron.update(newpnnk=PROBNNk(ddp),newpnnpi=PROBNNpi(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
                         print(hadron.pid)
-                        if hadron.pid == 321: hadrons[0] = hadron
-                        elif hadron.pid == -321: hadrons[1] = hadron
+
+                        if hh == "KK":
+                            hhPID = 321
+                        elif hh == "PiPi":
+                            hhPID = 211
+
+                        if hadron.pid == hhPID: hadrons[0] = hadron
+                        elif hadron.pid == -hhPID: hadrons[1] = hadron
                     svcoor = [dpsv.position().X(),dpsv.position().Y(),dpsv.position().Z()]
                     dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
             B = MCPart(all_B,dl=dps)
@@ -359,22 +366,37 @@ class MCEvent:
         if not self.links: self.linkpars()
 
         for B in self.Bs:
+            print("looping over Bs")
             if not B.alllinked:
-                #print("not all Bs are linked")
+                print("not all Bs are linked")
                 for recp in [B.dl[1],B.dl[0].dl[0],B.dl[0].dl[1]]:
+                    print("looping over recps")
                     if not recp.lpar:
+                        print("if recp has no linked particle")
                         mindr = 99999999999
                         parlink = None
+                        print(f"mcp store is {mcpstore}")
+                        #print(f"mcp store contains {len(mcpstore)} mc particles")
+                        thereExistsMCPIDequalRECPID = False
                         for mcp in mcpstore:
-                            #print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
+                            print(f"mc particle is {mcp}")
+                            print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
                             if MCID(mcp) == recp.pid:
+                                thereExistsMCPIDequalRECPID = True
+                                print("mc pid is same as rec particle pid")
                                 dphi = MCPHI(mcp) - PHI(recp.par)
                                 deta = MCETA(mcp) - ETA(recp.par)
                                 deltar = sqrt(dphi**2 + deta**2)
-                                if deltar < mindr: mindr = deltar; parlink = mcp
-                        """ print(f"deltar is {deltar}")
-                        print(f"mindr is {mindr}")
-                        print(f"parlink is {parlink}") """
+                                print(f"deltar is {deltar}")
+                                print(f"mindr is {mindr}")
+                                if deltar < mindr: 
+                                    mindr = deltar
+                                    print(f"mindr is {mindr}")
+                                    parlink = mcp
+                                    print(f"parlink is {parlink}")
+                        if thereExistsMCPIDequalRECPID == False:
+                            print("no mc particle with same pid as rec particle")
+                            break
                         recp.update(newlpar=MCPart(parlink,orvrt=parlink.originVertex().type()))
                         if MCID(parlink) == recp.pid: recp.update(newclink=True)
                         else: recp.update(newclink=False)
@@ -391,7 +413,13 @@ class MCEvent:
                             except:
                                 recp.lpar.update(newmother=None)
 
-                if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar:
+                # i guess L418 shouldn't be being called - is this checking if all particles have been linked?
+                # in which case we should be checking if all particles have been linked to the same particle type
+                if thereExistsMCPIDequalRECPID == False:
+                    print("no mc particle with same pid as rec particle")
+                    break
+
+                if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar: 
                     B.update(newisdrmatched=True)
                     if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
 
@@ -489,7 +517,7 @@ class MCEvent:
                 try: fillKpid = K.lpar.mother.pid
                 except: fillKpid = 0
 
-                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(B.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle
+                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(B.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle and B has 3 deacy products
                     #if K is K+ this must be a B+, if K is K- this must be a B-
                     if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=0)
                     if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=0)
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index e0d1fb4f43..e5c6a2b514 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -72,7 +72,7 @@ class Ntuple:
         self.ttree = ROOT.TTree("DecayData", "DecayData")
         self.pvrs = "Rec/Vertex/Primary"
         if DaVinci().InputType == "MDST":
-            self.pvrs = "Leptonic/" + self.pvrs
+            self.pvrs = "AllStreams/" + self.pvrs
         vrsVrt = ["x", "y", "z", "dx", "dy", "dz"]
         vrsMom = ["px", "py", "pz", "e"]
         vrsTrk = [
@@ -322,8 +322,8 @@ class Ntuple:
     ###########################################################################
     def _fillgenMomPID(self, pre: "str", mcp, dptype):
         """Fill generator level MC momentum and pid for a particle."""
-        if mcp: # mcp: monte carlo particle
-            if mcp.pid in (310, 211, -211, 321, -321, 521, -521):
+        if mcp: # mcp: monte carlo particle, this is a boolean
+            if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
                 print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
@@ -333,19 +333,31 @@ class Ntuple:
                     elif mcp.pid in (211, 321):
                         dptype = "hp" 
                         print(f"found mcp particle which is hp with pid {mcp.pid}")
+                elif dptype == "K":
+                    if mcp.pid in (321, -321):
+                        dptype = "K"
+                        print(f"found mcp particle which is K with pid {mcp.pid}")
                 pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
-            mom = mcp.lpar.p
-            lpid = mcp.lpar.pid
             try:
-                lpid = int(mcp.lpar.pid)
+               mom = mcp.lpar.p
+               momPx = mom.Px()
+               momPy = mom.Py()
+               momPz = mom.Pz()
+               momE = mom.E()
             except:
-                lpid = 99
-            self.fill(f"{pre}_{dptype}_lpx", mom.Px()) # l denotes that it is variable associated to a linked particle
-            self.fill(f"{pre}_{dptype}_lpy", mom.Py())
-            self.fill(f"{pre}_{dptype}_lpz", mom.Pz())
-            self.fill(f"{pre}_{dptype}_le", mom.E())
+               momPx = momPy = momPz = momE = 0.0
+
+            try:
+                lpid = int(mcp.lpar.pid) # try get the linked pid
+            except:
+                lpid = 99 # if not found, i.e. couldn't link this particle, set to 99
+
+            self.fill(f"{pre}_{dptype}_lpx", momPx) # l denotes that it is variable associated to a linked particle
+            self.fill(f"{pre}_{dptype}_lpy", momPy)
+            self.fill(f"{pre}_{dptype}_lpz", momPz)
+            self.fill(f"{pre}_{dptype}_le", momE)
             self.fill(f"{pre}_{dptype}_lpid", lpid)
         else:
             for dptype in ["hm", "hp", "K"]:
@@ -536,7 +548,7 @@ class Ntuple:
 
             if mcprt:
                 self._fillgenMomPID(pre, mcprt.dl[1], "K") # B's daughter: bachelor kaon
-                self._fillgenMomPID(pre, mcprt.dl[0].dl[0], "hadron0") # B's daughter, dark scalar,has two daughters itself
+                self._fillgenMomPID(pre, mcprt.dl[0].dl[0], "hadron0") # B's daughter, dark scalar,has two daughters itself, the first we will call hadron0
                 self._fillgenMomPID(pre, mcprt.dl[0].dl[1], "hadron1") # B's daughter: hadron 
             else:
                 self._fillgenMomPID(pre, mcprt, hh, "B")
@@ -843,15 +855,11 @@ def fill_ntuple(
     print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
-        mct = MCEventTools.MCEvent(all_Bparticles, genTool) # mct: monte carlo tool
+        mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
         #print(mct)
         mct.linkpars()
-        mcpstore = get_particles(
-            "AllStreams/MC/Particles"
-            if DaVinci().InputType == "MDST"
-            else "MC/Particles"
-        )
-        print(f"got {len(mcpstore)} B mesons from MC/Particles")
+        mcpstore = get_particles('/Event/AllStreams/MC/Particles')
+        print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
@@ -866,6 +874,8 @@ def fill_ntuple(
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
         print("I find bool is {0}".format(boolVal))
+
+        # if not all parricles are linked 
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
             isfilled = True
diff --git a/bu2kdarkscalar_darkscalar2hh/hh_PiPi.py b/bu2kdarkscalar_darkscalar2hh/hh_PiPi.py
index 21570c9612..0504f41322 100644
--- a/bu2kdarkscalar_darkscalar2hh/hh_PiPi.py
+++ b/bu2kdarkscalar_darkscalar2hh/hh_PiPi.py
@@ -1,4 +1,4 @@
-"""Set head for job.py.
+"""Set hh for job.py.
 
 This file should be passed as a command-line option to job.py.
 """
diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index ba431d2f95..0b1b2bc94f 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,14 +1,24 @@
 {%- set polarities = ["Down", "Up"]%}
-{%- set datasets = [
-  ('KK', 18, 6500, '18', '34NoPrescalingFlagged'),
-  ('PiPi', 18, 6500, '18', '34NoPrescalingFlagged'),
-]%}
+{%- set MCdatasets = [('PiPi', 18, 12103024, 6500, '18', '34NoPrescalingFlagged')]%}
+{%- set datasets = ["PiPi", "KK"]%}
 
+{%- for polarity in polarities %}
 
-{%- for hh, year, energy, reco, strip in datasets %}
-   {%- for polarity in polarities %}
+{%- for hh in datasets %}
 
-my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_job:
+my_B2KDarkScalar_DarkScalar2{{hh}}_2018_Mag{{polarity}}_Data_job:
+  input:
+    bk_query: "/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST"
+  options:
+    command:
+      - python
+    files:
+      - job.py
+      - head_{{hh}}.py
+
+{%- for hh, year, eventnumber, energy, reco, strip in MCdatasets %}
+
+my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   application: DaVinci/v46r8
   wg: QEE
   automatically_configure: yes
@@ -20,22 +30,11 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_job:
       - python
     files:
       - job.py
+      - head_{{hh}}.py
 
   input:
-    bk_query: /MC/2018/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco{{reco}}/Turbo05-WithTurcal/Stripping{{strip}}/23103008/ALLSTREAMS.DST
-    # For KK MC
-    # /MC/2018/Beam6500GeV-2018-Mag{{polarity}}-Fix1-Pythia8/Sim10c/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/23103008/ALLSTREAMS.DST
-    # For PiPi MC
-    #
-    # For data
-    # /LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST
-    
-  output: B2K{{hh}}.ROOT
-  # For MC
-  # B2KKK.ROOT
-  # For data
-  # bu2kdarkscalar_darkscalar2hh.ROOT
-
-
-   {%- endfor %}
+    bk_query: /MC/20{{year}}/{{eventnumber}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim09h/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/ALLSTREAMS.MDST
+
+
+{%- endfor %}
 {%- endfor %}
\ No newline at end of file
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index d29b6b2d38..96745fd31e 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -102,15 +102,25 @@ DaVinci().Lumi = False
 # =================================================================================
 
 #candidate locations
+# IMPORTANT WARNING!!!
+# is the data is saved in microDST format we must use '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles'
+#
+if DaVinci.Simulation:
+    stream = 'AllStreams'
+else:
+    stream = 'Leptonic'
+
+""" if DaVinci().InputType == "MDST":
+   stream = 'Leptonic'
+elif DaVinci().InputType == "DST":
+   stream = 'AllStreams' """
+
 if hh == "KK":
-    candloc = "/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles"
+    candloc = '/Event/' + stream + '/Phys/B2KX2KKDarkBosonLine/Particles'
 elif hh == "PiPi":
-    candloc = "/Event/AllStreams/Phys/B2KX2PiPiDarkBosonLine/Particles"
-
-
-#candloc_KK = "/Event/Leptonic/Phys/B2KX2KKDarkBosonLine/Particles"
-#candloc_PiPi = "/Event/Leptonic/Phys/B2KX2PiPiDarkBosonLine/Particles"
+    candloc = '/Event/' + stream + '/Phys/B2KX2PiPiDarkBosonLine/Particles'
 
+print(f"Using candidate location: {candloc}")
 
 # =================================================================================
 # TisTos configuration.
@@ -140,7 +150,7 @@ while (NOfEvents == -1) or (event < NOfEvents):
     if not bool(tes["/Event"]):
         break
     event += 1
-    print("found evt")
+    print(f"found event {event}")
 
     fill_ntuple(ntuple, tes, candloc, hh, genTool)
     print("filled")
-- 
GitLab


From 82cfc59b28c627756b6d766519a760d709ea6735 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 5 Aug 2024 14:39:55 +0100
Subject: [PATCH 12/70] change root in tes for mc productions

---
 bu2kdarkscalar_darkscalar2hh/job.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 96745fd31e..8057fb822b 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -12,8 +12,8 @@ import ROOT
 
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
-import sys
-sys.path.append("../")
+#import sys
+#sys.path.append("../")
 
 
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
@@ -107,6 +107,8 @@ DaVinci().Lumi = False
 #
 if DaVinci.Simulation:
     stream = 'AllStreams'
+    DaVinci().RootInTES = "/Event/AllStreams"
+
 else:
     stream = 'Leptonic'
 
-- 
GitLab


From 9c55c8ce8414c53a3e47c0ac4cffd72b7b98e70b Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 5 Aug 2024 14:49:42 +0100
Subject: [PATCH 13/70] remove dynamic

---
 ...calar_darkScalar2hh_2018_MagDown_job_autoconf.py | 13 -------------
 ...kScalar_darkScalar2hh_2018_MagUp_job_autoconf.py | 13 -------------
 2 files changed, 26 deletions(-)
 delete mode 100644 dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagDown_job_autoconf.py
 delete mode 100644 dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagUp_job_autoconf.py

diff --git a/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagDown_job_autoconf.py b/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagDown_job_autoconf.py
deleted file mode 100644
index f079315413..0000000000
--- a/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagDown_job_autoconf.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from Configurables import DaVinci
-try:
-    DaVinci().Turbo = False
-except AttributeError:
-    # Older DaVinci versions don't support Turbo at all
-    pass
-
-DaVinci().InputType = 'MDST'
-DaVinci().DataType = '2018'
-DaVinci().Simulation = False
-DaVinci().Lumi = True
-from Configurables import CondDB
-CondDB(LatestGlobalTagByDataType=DaVinci().DataType)
\ No newline at end of file
diff --git a/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagUp_job_autoconf.py b/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagUp_job_autoconf.py
deleted file mode 100644
index f079315413..0000000000
--- a/dynamic/bu2kdarkscalar_darkscalar2hh/Bu2KdarkScalar_darkScalar2hh_2018_MagUp_job_autoconf.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from Configurables import DaVinci
-try:
-    DaVinci().Turbo = False
-except AttributeError:
-    # Older DaVinci versions don't support Turbo at all
-    pass
-
-DaVinci().InputType = 'MDST'
-DaVinci().DataType = '2018'
-DaVinci().Simulation = False
-DaVinci().Lumi = True
-from Configurables import CondDB
-CondDB(LatestGlobalTagByDataType=DaVinci().DataType)
\ No newline at end of file
-- 
GitLab


From 4ea3fdae1a494936d11b98f9f236b5caf61aecea Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 5 Aug 2024 15:06:08 +0100
Subject: [PATCH 14/70] tidy

---
 bu2kdarkscalar_darkscalar2hh/job.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 8057fb822b..9f183a6d64 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -18,7 +18,6 @@ import ROOT
 
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
 
-
 # =================================================================================
 # The next lines allow configuration to be done in separate files in a gaudirun-like way
 # This is needed for AnalysisProductions, but also helps us.
-- 
GitLab


From f33c994a0aa747a30a6f8a1eb4fd0703ccd871eb Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 5 Aug 2024 15:56:45 +0100
Subject: [PATCH 15/70] fixed info.yaml formatting

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 27 ++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 0b1b2bc94f..5cee402ca8 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -7,6 +7,12 @@
 {%- for hh in datasets %}
 
 my_B2KDarkScalar_DarkScalar2{{hh}}_2018_Mag{{polarity}}_Data_job:
+  application: DaVinci/v46r8
+  wg: QEE
+  automatically_configure: yes
+  turbo: no
+  inform:
+    - eleanor.whiter@cern.ch
   input:
     bk_query: "/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST"
   options:
@@ -14,7 +20,12 @@ my_B2KDarkScalar_DarkScalar2{{hh}}_2018_Mag{{polarity}}_Data_job:
       - python
     files:
       - job.py
-      - head_{{hh}}.py
+      - hh_{{hh}}.py
+  output: b2kdarkscalar.root
+
+{%- endfor %}
+
+
 
 {%- for hh, year, eventnumber, energy, reco, strip in MCdatasets %}
 
@@ -25,16 +36,16 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   turbo: no
   inform:
     - eleanor.whiter@cern.ch
+  input:
+     bk_query: /MC/20{{year}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim09h/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/{{eventnumber}}/ALLSTREAMS.MDST
   options:
-    command:
+     command:
       - python
-    files:
+     files:
       - job.py
-      - head_{{hh}}.py
-
-  input:
-    bk_query: /MC/20{{year}}/{{eventnumber}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim09h/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/ALLSTREAMS.MDST
-
+      - hh_{{hh}}.py
+  output: b2khh.root
 
 {%- endfor %}
+
 {%- endfor %}
\ No newline at end of file
-- 
GitLab


From 9e416b48ee302ed81afe9881b8445f8509da96bd Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 5 Aug 2024 16:17:09 +0100
Subject: [PATCH 16/70] test for only data

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 5cee402ca8..0e92b2d7ab 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,5 +1,4 @@
 {%- set polarities = ["Down", "Up"]%}
-{%- set MCdatasets = [('PiPi', 18, 12103024, 6500, '18', '34NoPrescalingFlagged')]%}
 {%- set datasets = ["PiPi", "KK"]%}
 
 {%- for polarity in polarities %}
@@ -25,27 +24,4 @@ my_B2KDarkScalar_DarkScalar2{{hh}}_2018_Mag{{polarity}}_Data_job:
 
 {%- endfor %}
 
-
-
-{%- for hh, year, eventnumber, energy, reco, strip in MCdatasets %}
-
-my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
-  application: DaVinci/v46r8
-  wg: QEE
-  automatically_configure: yes
-  turbo: no
-  inform:
-    - eleanor.whiter@cern.ch
-  input:
-     bk_query: /MC/20{{year}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim09h/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/{{eventnumber}}/ALLSTREAMS.MDST
-  options:
-     command:
-      - python
-     files:
-      - job.py
-      - hh_{{hh}}.py
-  output: b2khh.root
-
-{%- endfor %}
-
 {%- endfor %}
\ No newline at end of file
-- 
GitLab


From aae02d01753df47fb7db58e7ffa9b19e1b04d2ff Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 6 Aug 2024 12:02:31 +0100
Subject: [PATCH 17/70] removed unecessary file

---
 ap_merger.py | 112 ---------------------------------------------------
 1 file changed, 112 deletions(-)
 delete mode 100644 ap_merger.py

diff --git a/ap_merger.py b/ap_merger.py
deleted file mode 100644
index cf7dc2fac6..0000000000
--- a/ap_merger.py
+++ /dev/null
@@ -1,112 +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.                                       #
-###############################################################################
-import subprocess
-import sys
-import tempfile
-import xml.etree.ElementTree as ET
-from pathlib import Path
-
-# pylint: disable=import-error
-from GaudiConf.LbExec.options import FileFormats
-from GaudiConf.LbExec.options import Options as OptionsBase
-
-SUMMARY_XML_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
-<summary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:noNamespaceSchemaLocation="$XMLSUMMARYBASEROOT/xml/XMLSummary.xsd">
-    <success>True</success>
-    <step>finalize</step>
-    <usage><stat unit="KB" useOf="MemoryMaximum">0</stat></usage>
-    <input>
-{input_files}
-    </input>
-    <output>
-{output_files}
-    </output>
-</summary>
-"""
-XML_FILE_TEMPLATE = '     <file GUID="" name="{name}" status="full">{n}</file>'
-ALG_TO_CODE = {
-    "ZLIB": 1,
-    "LZMA": 2,
-    "LZ4": 4,
-    "ZSTD": 5,
-}
-
-
-class Options(OptionsBase):
-    """Conditions"""
-
-    input_type: FileFormats = FileFormats.ROOT
-    simulation: None = False
-    data_type: None = None
-
-
-def read_xml_file_catalog(xml_file_catalog):
-    if xml_file_catalog is None:
-        return {}
-
-    tree = ET.parse(xml_file_catalog)
-    pfn_lookup: dict[str, list[str]] = {}
-    for file in tree.findall("./File"):
-        lfns = [x.attrib.get("name") for x in file.findall("./logical/lfn")]
-        if len(lfns) == 0:
-            continue
-        if len(lfns) > 1:
-            raise NotImplementedError(lfns)
-        lfn = lfns[0]
-        pfn_lookup[f"LFN:{lfn}"] = [
-            x.attrib.get("name") for x in file.findall("./physical/pfn")
-        ]
-    return pfn_lookup
-
-
-def resolve_input_files(input_files, file_catalog):
-    resolved = []
-    for input_file in input_files:
-        if input_file.startswith("LFN:"):
-            print("Resolved", input_file, "to", file_catalog[input_file][0])
-            input_file = file_catalog[input_file][0]
-        resolved.append(input_file)
-    return resolved
-
-
-def hadd(options: Options, compression: str = "ZSTD:4"):
-    file_catalog = read_xml_file_catalog(options.xml_file_catalog)
-    input_files = resolve_input_files(options.input_files, file_catalog)
-
-    alg, level = compression.split(":")
-    flags = [f"-f{ALG_TO_CODE[alg]}{int(level):02d}"]
-    flags += ["-j", f"{options.n_threads}"]
-    flags += ["-n", f"{max(10, options.n_threads*2)}"]
-
-    with tempfile.NamedTemporaryFile(mode="wt") as tmpfile:
-        tmpfile.write("\n".join(input_files))
-        tmpfile.flush()
-        cmd = ["hadd"] + flags + [options.ntuple_file, f"@{tmpfile.name}"]
-        print("Running", cmd)
-        subprocess.run(cmd, check=True)
-
-    summary_xml = SUMMARY_XML_TEMPLATE.format(
-        input_files="\n".join(
-            XML_FILE_TEMPLATE.format(
-                name=name if name.startswith("LFN:") else f"PFN:{name}", n=1
-            )
-            for name in options.input_files
-        ),
-        output_files=XML_FILE_TEMPLATE.format(
-            name=f"PFN:{options.ntuple_file}", n=len(input_files)
-        ),
-    )
-    if options.xml_summary_file:
-        print("Writing XML summary to", options.xml_summary_file)
-        Path(options.xml_summary_file).write_text(summary_xml)
-
-    print("All done")
-    sys.exit(0)
-- 
GitLab


From 10d68d0b48cf10f5019415f13ba3382dcb3a63d4 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 6 Aug 2024 13:40:45 +0100
Subject: [PATCH 18/70] removed inputdata - only meant for local test

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 12 ++++++------
 bu2kdarkscalar_darkscalar2hh/inputData.py    | 15 ---------------
 bu2kdarkscalar_darkscalar2hh/job.py          |  1 +
 3 files changed, 7 insertions(+), 21 deletions(-)
 delete mode 100644 bu2kdarkscalar_darkscalar2hh/inputData.py

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 52e413446a..5a503f5955 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -498,7 +498,7 @@ class MCEvent:
 
     def categorize(self):
         """
-        Categorizes the type of decay (i.e. type of background, signal).
+        Categorizes the type of decay (i.e. type of background, signal) and sets dectype as one of the follwoing numbers.
 
         SOURCE TYPES
         ------------
@@ -517,10 +517,10 @@ class MCEvent:
                 try: fillKpid = K.lpar.mother.pid
                 except: fillKpid = 0
 
-                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(B.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle and B has 3 deacy products
+                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(B.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle and B has 3 decay products
                     #if K is K+ this must be a B+, if K is K- this must be a B-
-                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=0)
-                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=0)
+                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=1)
+                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=1)
 
 
             for dp in B.dl:
@@ -604,7 +604,7 @@ class MCEvent:
                 if B.isdrmatched: drmatch = 1
                 else: drmatch = 0
             else:
-                drmatch = 9
+                drmatch = 99
 
         return drmatch
 
@@ -619,7 +619,7 @@ class MCEvent:
 
         OUTPUTS
         -------
-        B: MCPart object of the corresponding B/eta [MCPart]
+        B: MCPart object of the corresponding B [MCPart]
         """
         B = None
         if ID(part) == 310:
diff --git a/bu2kdarkscalar_darkscalar2hh/inputData.py b/bu2kdarkscalar_darkscalar2hh/inputData.py
deleted file mode 100644
index 22ef3691c8..0000000000
--- a/bu2kdarkscalar_darkscalar2hh/inputData.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from GaudiConf import IOHelper
-
-'''
-# Real Data
-IOHelper("ROOT").inputFiles(["/home/exw330/data/00092412_00000138_1.leptonic.mdst"])
-from Configurables import DaVinci
-DaVinci().DataType = "2018"
-DaVinci().InputType = "MDST"
-
-'''
-# Monte Carlo
-IOHelper("ROOT").inputFiles(["/home/exw330/MC/00217278_00000014_1.AllStreams.dst"])
-from Configurables import DaVinci
-DaVinci().InputType = 'DST'
-DaVinci().DataType = '2018'
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 9f183a6d64..e003a2aa57 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -93,6 +93,7 @@ try:
     shutil.copy(this_dir / "pars.root", Path.cwd())
 except ModuleNotFoundError:
     NOfEvents = DaVinci().EvtMax
+    print(f"number of events is {NOfEvents}")
     output_filename = DaVinci().TupleFile
 
 # FIXME: Turn off lumi tuple or it overwrites ntuple. Cleverer solution possible
-- 
GitLab


From 05223efa866d7f723502e5893a2fc66801f7715f Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 6 Aug 2024 14:35:54 +0100
Subject: [PATCH 19/70] test for mc

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 0e92b2d7ab..96629dca92 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,11 +1,14 @@
 {%- set polarities = ["Down", "Up"]%}
-{%- set datasets = ["PiPi", "KK"]%}
 
 {%- for polarity in polarities %}
 
-{%- for hh in datasets %}
 
-my_B2KDarkScalar_DarkScalar2{{hh}}_2018_Mag{{polarity}}_Data_job:
+{%- set MCdatasets = [('PiPi', 18, 12103024, 6500, '18', '34NoPrescalingFlagged')]%}
+
+{%- for polarity in polarities %}
+{%- for hh, year, eventnumber, energy, reco, strip in MCdatasets %}
+
+my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   application: DaVinci/v46r8
   wg: QEE
   automatically_configure: yes
@@ -13,15 +16,16 @@ my_B2KDarkScalar_DarkScalar2{{hh}}_2018_Mag{{polarity}}_Data_job:
   inform:
     - eleanor.whiter@cern.ch
   input:
-    bk_query: "/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST"
+     bk_query: /MC/20{{year}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim09h/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/{{eventnumber}}/ALLSTREAMS.MDST
   options:
-    command:
+     command:
       - python
-    files:
+     files:
       - job.py
       - hh_{{hh}}.py
-  output: b2kdarkscalar.root
+  output: b2khh.root
 
 {%- endfor %}
 
+
 {%- endfor %}
\ No newline at end of file
-- 
GitLab


From 0f4591e57998a1afc330b40bfb4df90b7b8a8f90 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 6 Aug 2024 14:40:09 +0100
Subject: [PATCH 20/70] typo

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 96629dca92..59338bf5db 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,8 +1,4 @@
 {%- set polarities = ["Down", "Up"]%}
-
-{%- for polarity in polarities %}
-
-
 {%- set MCdatasets = [('PiPi', 18, 12103024, 6500, '18', '34NoPrescalingFlagged')]%}
 
 {%- for polarity in polarities %}
@@ -26,6 +22,4 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   output: b2khh.root
 
 {%- endfor %}
-
-
 {%- endfor %}
\ No newline at end of file
-- 
GitLab


From 092fdff99df7efd6b4b0673c9d98d00e168817e5 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 6 Aug 2024 16:15:09 +0100
Subject: [PATCH 21/70] fixed to work siimulatenously for data

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py |  6 +++++-
 bu2kdarkscalar_darkscalar2hh/info.yaml | 24 ++++++++++++++++++++++++
 bu2kdarkscalar_darkscalar2hh/job.py    |  5 ++++-
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index e5c6a2b514..f0e4c96282 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -71,8 +71,12 @@ class Ntuple:
         self.tfile = ROOT.TFile(output_filename, "RECREATE", "", 207)
         self.ttree = ROOT.TTree("DecayData", "DecayData")
         self.pvrs = "Rec/Vertex/Primary"
-        if DaVinci().InputType == "MDST":
+        #if DaVinci().InputType == "MDST":
+        #    self.pvrs = "AllStreams/" + self.pvrs
+        if DaVinci().Simulation:
             self.pvrs = "AllStreams/" + self.pvrs
+        else:
+            self.pvrs = "/Event/Leptonic/" + self.pvrs
         vrsVrt = ["x", "y", "z", "dx", "dy", "dz"]
         vrsMom = ["px", "py", "pz", "e"]
         vrsTrk = [
diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 59338bf5db..acd6d538d9 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,4 +1,5 @@
 {%- set polarities = ["Down", "Up"]%}
+{%- set datasets = ["PiPi", "KK"]%}
 {%- set MCdatasets = [('PiPi', 18, 12103024, 6500, '18', '34NoPrescalingFlagged')]%}
 
 {%- for polarity in polarities %}
@@ -22,4 +23,27 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   output: b2khh.root
 
 {%- endfor %}
+
+
+{%- for hh in datasets %}
+
+my_B2KDarkScalar_DarkScalar2{{hh}}_2018_Mag{{polarity}}_Data_job:
+  application: DaVinci/v46r8
+  wg: QEE
+  automatically_configure: yes
+  turbo: no
+  inform:
+    - eleanor.whiter@cern.ch
+  input:
+    bk_query: "/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST"
+  options:
+    command:
+      - python
+    files:
+      - job.py
+      - hh_{{hh}}.py
+  output: b2kdarkscalar.root
+
+{%- endfor %}
+
 {%- endfor %}
\ No newline at end of file
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index e003a2aa57..4f83d69785 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -105,12 +105,15 @@ DaVinci().Lumi = False
 # IMPORTANT WARNING!!!
 # is the data is saved in microDST format we must use '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles'
 #
-if DaVinci.Simulation:
+if DaVinci().Simulation:
     stream = 'AllStreams'
     DaVinci().RootInTES = "/Event/AllStreams"
+    print(f"stream set as {stream}")
 
 else:
     stream = 'Leptonic'
+    #DaVinci().RootInTES = "/Event/AllStreams"
+    print(f"stream set as {stream}")
 
 """ if DaVinci().InputType == "MDST":
    stream = 'Leptonic'
-- 
GitLab


From ac27941f4bcd61597ad68974362fe6b5753d72d4 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 7 Aug 2024 13:44:30 +0100
Subject: [PATCH 22/70] chnaged categorisation

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 21 +++++++++++++---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 26 ++++++++++++++++----
 2 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 5a503f5955..83e95f7dd7 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -174,6 +174,7 @@ class MCEvent:
         ------
         all_Bs   : B+/B-s from the TES
         mctool : IParticle2MCWeightedAssociator instance to be used
+        hh     : decay mode (KK or PiPi)
 
         INTERNAL MEMBERS
         ----------------
@@ -363,6 +364,14 @@ class MCEvent:
         self.links = True
 
     def deltarlink(self, mcpstore):
+        """
+        MC truth matching using delta r matching.
+
+        INPUTS
+        ------
+        self: MCEvent instance
+        mcpstore: list of MC particles from the TES
+        """
         if not self.links: self.linkpars()
 
         for B in self.Bs:
@@ -444,7 +453,7 @@ class MCEvent:
                             hadron_plus_lin = [B.dl[0].dl[1].lpar.par,B.dl[0].dl[1].lpar.mother.par]
                     else: hadron_plus_lin = [B.dl[0].dl[1].lpar.par]
 
-                    sharelin = []
+                    sharelin = [] # shared lineage
                     for i in range(len(hadron_minus_lin)):
                         for j in range(len(hadron_plus_lin)):
                             for k in range(len(Klin)):
@@ -517,10 +526,16 @@ class MCEvent:
                 try: fillKpid = K.lpar.mother.pid
                 except: fillKpid = 0
 
-                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(B.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle and B has 3 decay products
+                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(K.lpar.par.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle and B (accessed by K origin vertex) has 3 decay products
                     #if K is K+ this must be a B+, if K is K- this must be a B-
                     if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=1)
-                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=1)
+                    elif K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=1)
+
+                elif hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par and hadron_minus.lpar.mother.pid == 310: # Check h+ and h- came from the same particle and that particle was a Ks
+                    if K.lpar.mother == hadron_minus.lpar.mother.mother.par == hadron_plus.lpar.mother.mother.par: # Check K, hm and hp all came from the same particle
+                       if abs(K.lpar.mother.pid) == 521: # check this was a B
+                          self.dec: B.update(newbgtype=0)
+                    
 
 
             for dp in B.dl:
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index f0e4c96282..fb752aba32 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -286,7 +286,10 @@ class Ntuple:
 
     ###########################################################################
     def _fillMM(self, pre: "str", prt):
-        """Fill measured mass for a particle.
+        """
+        Fill measured mass.
+
+
         mm: measured mass
         dmm: delta measured mass (the error on the measured mass)
         
@@ -296,7 +299,9 @@ class Ntuple:
 
     ###########################################################################
     def _fillM(self, pre: "str", mom):
-        """Fill mass from a particle's momentum."""
+        """
+        Fill mass.
+        """
         try:
             m_class = mom.m()
             m = m_class.value()
@@ -325,12 +330,22 @@ class Ntuple:
 
     ###########################################################################
     def _fillgenMomPID(self, pre: "str", mcp, dptype):
-        """Fill generator level MC momentum and pid for a particle."""
+        """
+        Fill generator level MC momentum and pid for a particle.
+
+        INPUTS
+        ------
+
+        pre: prefix for the variable name, either "tag" or "trk"
+        mcp: monte carlo particle
+        dptype: daughter particle type, can be: "K", "hadron0", "hadron1"
+        """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
                 print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
+                    #only when we inspect pid do we know the charges associated to hadron0 and hadron1
                     if mcp.pid in (-211, -321):
                         dptype = "hm"
                         print(f"found mcp particle which is hm with pid {mcp.pid}")
@@ -351,7 +366,7 @@ class Ntuple:
                momPz = mom.Pz()
                momE = mom.E()
             except:
-               momPx = momPy = momPz = momE = 0.0
+               momPx = momPy = momPz = momE = 0.0 # if mcp has no linked particle set these to 0
 
             try:
                 lpid = int(mcp.lpar.pid) # try get the linked pid
@@ -373,7 +388,8 @@ class Ntuple:
 
     ###########################################################################
     def _filltrkOL(self, pre: "str", prt):
-        """Find number of shared track lhcbIDs between h- and h+.
+        """
+        Find number of shared track lhcbIDs between h- and h+.
 
         Accessed through dihadron candidate.
         """
-- 
GitLab


From bd90538e37c87c8de093d89c1b0dc9d7c65615bf Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 7 Aug 2024 13:53:56 +0100
Subject: [PATCH 23/70] remove obselete code

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 79 --------------------
 1 file changed, 79 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 83e95f7dd7..45e2273fdf 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -543,85 +543,6 @@ class MCEvent:
                 for ddp in dp.dl:
                     ddp.update(newbgtype=B.bgtype)
 
-    def bgtypequery(self, part):
-        """
-        Method to match an input particle to a TES particle and return the
-        input particle's decay type.
-
-        INPUTS
-        ------
-        part: particle to be matched [LHCb Particle object]
-
-        OUTPUTS
-        -------
-        dectype: decay type of the input particle [int]
-        """
-        dectype = -99
-        B = None
-        if ID(part) == 310:
-            dectype = ID(part)
-        elif part in self.Bstore:
-            for all_B in self.Bs:
-                if part == all_B.par:
-                    B = all_B
-                    break
-            if B != None:
-                K = B.dl[1]
-                hadron_minus = B.dl[0].dl[0]
-                hadron_plus = B.dl[0].dl[1]
-
-                fill_B_dectype = B.dectype # fill B decay type
-                fill_B_odectype = B.odectype # fill B decay type
-                try: hadron_minus_morvrt = hadron_minus.lpar.mother.orvrt
-                except: hadron_minus_morvrt = 99
-                try: hadron_plus_morvrt = hadron_plus.lpar.mother.orvrt
-                except: hadron_plus_morvrt = 99
-                K_orvrt = K.orvrt
-
-                try:
-                    fill_K_mother_dectype = K.lpar.mother.pid
-                except:
-                    fill_K_mother_dectype.pid = 0
-                if not B.corlinked or hadron_minus_morvrt == 99 or hadron_plus_morvrt == 99:
-                    dectype = 8
-                elif fill_B_dectype == 0:
-                    dectype = 0
-            else:
-                dectype = -33
-        else:
-            dectype = -66
-
-        return dectype
-
-    def drquery(self, part):
-        """
-        Method to match an input particle to a TES particle and return if the
-        input particle's MC truth matching was done by delta R matching.
-
-        INPUTS
-        ------
-        part: particle to be matched [LHCb Particle object]
-
-        OUTPUTS
-        -------
-        drmatch: whether particle was delta R matched [int (0: no; 1: yes; 99: error)]
-        """
-        drmatch = 99
-        B = None
-        if ID(part) == 310:
-            drmatch = ID(part)
-        elif part in self.Bstore:
-            for all_B in self.Bs:
-                if part == all_B.par:
-                    B = all_B
-                    break
-            if B != None:
-                if B.isdrmatched: drmatch = 1
-                else: drmatch = 0
-            else:
-                drmatch = 99
-
-        return drmatch
 
     def mcpquery(self, part):
         """
-- 
GitLab


From 88173cd76c0b90602dbc423fd2c9911f824f2fb4 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 7 Aug 2024 14:19:14 +0100
Subject: [PATCH 24/70] minor formatting

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index fb752aba32..7ed3d85d0b 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -127,7 +127,7 @@ class Ntuple:
 
         vrsMC = []
         if DaVinci().Simulation:
-            dps = ["hm", "hp", "K"]
+            dps = ["hm", "hp", "K"] #daughter particles
             params = ["mpid", "orvrt", "morvrt", "mmpid", "mmorvrt"] # mpid: mother pid, orvrt: origin vertex, morvrt: mother origin vertex, mmpid: mother mother pid, mmorvrt: mother mother origin vertex
             for dp in dps:
                 vrsMC += [dp + "_lpid"]
@@ -142,11 +142,13 @@ class Ntuple:
         self._vrs("tag", vrsIdx + vrsMom + ["pid"] + vrsVrt + vrsTag + vrsTrg + vrsMC)
         self._vrs("trk", vrsMom + ["pid"] + vrsTrk)
         self._vrs("pvr", vrsVrt)
+
         self.ntuple["pvr_n"] = array.array("i", [-1])
         self.ntuple["spd_n"] = array.array("i", [-1])
         self.ntuple["run_n"] = array.array("l", [-1])
         self.ntuple["evt_n"] = array.array("l", [-1])
         self.ntuple["evt_tck"] = array.array("l", [-1])
+        
         # tmap = {int: "/I", long: "/L", float: "/F"}
         tmap = {"i": "/I", "l": "/L", "f": "/F"}
         for key, val in self.ntuple.items():
@@ -562,16 +564,14 @@ class Ntuple:
 
         # MC BG type
         if mctool is not None:
-            mcprt = mctool.mcpquery(prt)
-
-            hh = "KK"
+            mcprt = mctool.mcpquery(prt) 
 
             if mcprt:
                 self._fillgenMomPID(pre, mcprt.dl[1], "K") # B's daughter: bachelor kaon
                 self._fillgenMomPID(pre, mcprt.dl[0].dl[0], "hadron0") # B's daughter, dark scalar,has two daughters itself, the first we will call hadron0
                 self._fillgenMomPID(pre, mcprt.dl[0].dl[1], "hadron1") # B's daughter: hadron 
             else:
-                self._fillgenMomPID(pre, mcprt, hh, "B")
+                self._fillgenMomPID(pre, mcprt, "B")
 
             try:
                 hm_mpid = int(mcprt.dl[0].dl[0].lpar.mother.pid) #hm_mpid: hadron minus mother pid
-- 
GitLab


From 1ee5ea1e67a312a80501b9c462ab556dfa6a62ba Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 17 Sep 2024 11:54:30 +0100
Subject: [PATCH 25/70] adding back mv stuff

---
 bu2kdarkscalar_darkscalar2hh/pars.root | Bin 0 -> 342006 bytes
 bu2kdarkscalar_darkscalar2hh/velo.C    | 782 ++++++++++++++++++++++++
 bu2kdarkscalar_darkscalar2hh/velo.h    | 799 +++++++++++++++++++++++++
 3 files changed, 1581 insertions(+)
 create mode 100644 bu2kdarkscalar_darkscalar2hh/pars.root
 create mode 100644 bu2kdarkscalar_darkscalar2hh/velo.C
 create mode 100644 bu2kdarkscalar_darkscalar2hh/velo.h

diff --git a/bu2kdarkscalar_darkscalar2hh/pars.root b/bu2kdarkscalar_darkscalar2hh/pars.root
new file mode 100644
index 0000000000000000000000000000000000000000..69780d2e1ce3e868f2d2164f9eccffe05eea421e
GIT binary patch
literal 342006
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
AQUCw|

literal 0
HcmV?d00001

diff --git a/bu2kdarkscalar_darkscalar2hh/velo.C b/bu2kdarkscalar_darkscalar2hh/velo.C
new file mode 100644
index 0000000000..a8840d4b3e
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/velo.C
@@ -0,0 +1,782 @@
+// Written by Philip Ilten and Mike Williams, 20/06/2017.
+// Toolset to check if a secondary vertex is consistent with having
+// originated from the VELO material. See README for an overview.
+#include "velo.h"
+
+//=============================================================================
+// ModuleMaterial::Sensor class.
+
+// Default constructor.
+ModuleMaterial::Sensor::Sensor() {;}
+
+// Primary constructor.
+ModuleMaterial::Sensor::Sensor(TFile &file, string mod, string sns) :
+  z(sns == "0" ? 4 : 7), half(0) {
+  TObjString *exp; TVectorD *par;
+  par = (TVectorD*)file.Get((mod + "_a_z_par").c_str());
+  if (!par || par->GetNrows() < z + 1) return;
+  z   = (*par)[z];
+  exp = (TObjString*)file.Get((mod + "_" + sns + "_l_fnc").c_str());
+  par = (TVectorD*)file.Get((mod + "_" + sns + "_l_par").c_str());
+  if (!exp || !par) return;
+  fncl = TF1(mod.c_str(), exp->GetString().Data(), -100, 100);
+  for (int idx = 0; idx < par->GetNrows(); ++idx)
+    fncl.SetParameter(idx, (*par)[idx]);
+  exp = (TObjString*)file.Get((mod + "_" + sns + "_u_fnc").c_str());
+  par = (TVectorD*)file.Get((mod + "_" + sns + "_u_par").c_str());
+  if (!exp || !par) return;
+  fncu = TF1(mod.c_str(), exp->GetString().Data(), -100, 100);
+  for (int idx = 0; idx < par->GetNrows(); ++idx)
+      fncu.SetParameter(idx, (*par)[idx]);
+  half = fncl.GetNpar() > fncu.GetNpar() ? 1 : -1;
+};
+
+// Operator for sorting by the given z-value.
+bool ModuleMaterial::Sensor::operator<(const Sensor& sns) const {
+  return z < sns.z;}
+
+// Configure the tool.
+void ModuleMaterial::Sensor::config(double xc, double yc, bool rel) {
+  if (rel) {yc = fncl.GetParameter(0) + yc; xc = fncl.GetParameter(1) + xc;}
+  fncl.SetParameter(0, yc); fncl.SetParameter(1, xc);
+  fncu.SetParameter(0, yc); fncu.SetParameter(1, xc);
+}
+
+// Configure the tool.
+void ModuleMaterial::Sensor::config(const TF1 &fnc) {
+  if (half > 0) fncl = TF1(fnc);
+  else fncu = TF1(fnc);
+}
+
+// Return if an x,y-point falls within a module sensor.
+bool ModuleMaterial::Sensor::inside(double x, double y) {
+  if (x < fncl.Eval(y)) return false;
+  if (x > fncu.Eval(y)) return false;
+  return true;
+}
+
+// Return the x-position for the edge of the sensor.
+double ModuleMaterial::Sensor::x(double y, int edge) {
+  if (edge == 0) return (half > 0 ? fncl : fncu).Eval(y);
+  else return (edge == -1 ? fncl : fncu).Eval(y);
+}
+
+// Return a parameter for the sensor function.
+double ModuleMaterial::Sensor::p(unsigned int par, int edge) {
+  if (edge == 0) return (half > 0 ? fncl : fncu).GetParameter(par);
+  else return (edge == -1 ? fncl : fncu).GetParameter(par);
+}
+
+//=============================================================================
+// ModuleMaterial::Integral class.
+
+// Return the probability integral for a given half.
+double ModuleMaterial::Integral::integral(int half) {
+  vector<double> xy0(2, -sigma), xy1(2, sigma);
+  double pre(0), vzmin(vz - abs(sigma*dvz)), vzmax(vz + abs(sigma*dvz));
+  double dmin(numeric_limits<double>::infinity());
+  geo = 0;
+  for (int sns = 0; sns < (int)mzs->size(); ++sns) {
+    if (mzs->at(sns).half != half) continue;
+    double mz(mzs->at(sns).z);
+    if (abs(mz - vz) < dmin) {dmin = abs(vz - mz); geo = &mzs->at(sns);}
+    if (vzmax < mz) break;
+    if (vzmin > mz) continue;
+    pre += ((TMath::Erf(sqrt(0.5)*(vz - (mz - width/2))/dvz) -
+	     TMath::Erf(sqrt(0.5)*(vz - (mz + width/2))/dvz))/2);
+  }
+  if (!geo) return 0;
+  else return pre*inr->Integral(&xy0[0], &xy1[0]);
+}
+
+// Constructor.
+ModuleMaterial::Integral::Integral(vector<Sensor> *mzsIn) :
+  mzs(mzsIn), fnc("", this, -100, 100, -100, 100, 0, ""), wrp(fnc), inr(0) {;}
+
+// Destructor.
+ModuleMaterial::Integral::~Integral() {if (inr) delete inr;}
+
+// Return the probability function for a given half.
+double ModuleMaterial::Integral::operator()(double *t, double *) {
+  double sx(t[0]), sy(t[1]);
+  if (geo->inside(sx*dvx + vx, sy*dvy + vy))
+    return TMath::Gaus(sx, 0, 1, true)*TMath::Gaus(sy, 0, 1, true);
+  else return 0;
+}
+
+// Configure the tool.
+void ModuleMaterial::Integral::config
+(double dvminIn, double sigmaIn, double widthIn, double tolIn,
+ ROOT::Math::IntegrationMultiDim::Type algIn) {
+  dvmin = abs(dvminIn); sigma = abs(sigmaIn);
+  width = abs(widthIn); tol = abs(tolIn);
+  if (alg != algIn || !inr) {
+    if (inr) delete inr;
+    alg = algIn; inr = new ROOT::Math::IntegratorMultiDim(alg);
+    inr->SetFunction(wrp);
+  }
+  inr->SetRelTolerance(tol);
+}
+
+// Return the probability integral.
+double ModuleMaterial::Integral::integral
+(double vxIn, double vyIn, double vzIn,
+ double dvxIn, double dvyIn, double dvzIn, int halfIn) {
+  vx = vxIn; vy = vyIn; vz = vzIn;
+  dvx = abs(dvxIn); dvy = abs(dvyIn), dvz = abs(dvzIn);
+  dvx = dvx > dvmin ? dvx : dvmin;
+  dvy = dvy > dvmin ? dvy : dvmin;
+  dvz = dvz > dvmin ? dvz : dvmin;
+  if (dvx == 0 || dvy == 0 || dvz == 0) return 0;
+  double ingr(0);
+  if (halfIn == 0 || halfIn == -1) ingr += integral(-1);
+  if (halfIn == 0 || halfIn == -1) ingr += integral( 1);
+  return ingr > 1 ? 1 : ingr;
+}
+
+//=============================================================================
+// ModuleMaterial::Distance class.
+
+// Return the distance for a given half.
+void ModuleMaterial::Distance::distance(int half, TLorentzVector &s) {
+  geo = 0;
+  for (int sns = 0; sns < (int)mzs->size(); ++sns) {
+    if (mzs->at(sns).half != half) continue;
+    if (abs(mzs->at(sns).z - vz) < s.T()) {
+      geo = &mzs->at(sns);
+      s.SetXYZT(0, 0, mzs->at(sns).z, abs(mzs->at(sns).z - vz));
+    }
+  }
+  double x(vx), y(vy), z(s.Z()), ymin, ymax;
+  if (geo && !geo->inside(vx, vy)) {
+    fnc.Update();
+    ymin = (geo->half > 0 ? geo->fncl : geo->fncu).GetParameter(0);
+    ymax = (geo->half < 0 ? geo->fncl : geo->fncu).GetParameter(2);
+    if (y < ymin) {ymax = -ymax; swap(ymin, ymax);}
+    y = fnc.GetMinimumX(ymin, ymax, tol, itr, logt);
+    x = geo->x(y, 0);
+  }
+  s.SetXYZT(x, y, z, 0);
+  x = (x - vx)/dvx; y = (y - vy)/dvy; z = (z - vz)/dvz;
+  s.SetT(sqrt(x*x + y*y + z*z));
+}
+
+// Default constructor.
+ModuleMaterial::Distance::Distance(vector<Sensor> *mzsIn) :
+  mzs(mzsIn), fnc("", this, -50, 50, 0, "") {fnc.SetNpx(1000);}
+
+// Return the transverse distance.
+double ModuleMaterial::Distance::operator()(double *t, double *) {
+  double x((geo->x(t[0], 0) - vx)/dvx), y((t[0] - vy)/dvy);
+  return sqrt(x*x + y*y);
+}
+
+// Configure the tool.
+void ModuleMaterial::Distance::config
+(double dvminIn, double tolIn, int itrIn, bool logtIn) {
+  dvmin = abs(dvminIn); tol = abs(tolIn); itr = abs(itrIn); logt = logtIn;
+}
+
+// Return the distance.
+TLorentzVector ModuleMaterial::Distance::distance
+(double vxIn, double vyIn, double vzIn, double dvxIn, double dvyIn,
+ double dvzIn, int halfIn) {
+  vx = vxIn; vy = vyIn; vz = vzIn;
+  dvx = abs(dvx); dvy = abs(dvy), dvz = abs(dvz);
+  dvx = dvxIn > dvmin ? dvxIn : dvmin;
+  dvy = dvyIn > dvmin ? dvyIn : dvmin;
+  dvz = dvzIn > dvmin ? dvzIn : dvmin;
+  TLorentzVector sl(0, 0, 0, numeric_limits<double>::infinity()),
+    su(0, 0, 0, numeric_limits<double>::infinity());
+  if (dvx == 0 || dvy == 0 || dvz == 0) return sl;
+  if (halfIn == 0 || halfIn == -1) distance(-1, sl);
+  if (halfIn == 0 || halfIn ==  1) distance( 1, su);
+  return sl.T() < su.T() ? sl : su;
+}
+
+//=============================================================================
+// ModuleMaterial class.
+
+// Constructor.
+ModuleMaterial::ModuleMaterial(string pars) : ingr(&mzs), dist(&mzs) {
+  configIntegral(); configDistance();
+  TFile file(pars.c_str());
+  TList *keys = file.GetListOfKeys();
+  for (TObjLink *lnk = keys->FirstLink(); lnk; lnk = lnk->Next()) {
+    TKey *key((TKey*)lnk->GetObject());
+    string name(key->GetName()), mod, sns;
+    if (name.find("module") == string::npos) continue;
+    if (name.find("_l_fnc") == string::npos) continue;
+    mod = name.substr(0, name.length() - 8);
+    sns = name.substr(name.length() - 7, 1);
+    mzs.push_back(Sensor(file, mod, sns));
+  }
+  file.Close();
+  sort(mzs.begin(), mzs.end());
+}
+
+// Return the index for the sensor nearest a given z-position.
+int ModuleMaterial::sensor(double z, int half) {
+  int idx(0); double dmin(numeric_limits<double>::infinity());
+  for (int sns = 0; sns < (int)mzs.size(); ++sns) {
+    if (half != 0 && mzs[sns].half != half) continue;
+    if (abs(mzs[sns].z - z) < dmin) {idx = sns; dmin = abs(mzs[sns].z - z);}
+  }
+  return idx;
+}
+
+// Return if an x,y-point falls within a module sensor.
+bool ModuleMaterial::inside(unsigned int idx, double x, double y) {
+  if (idx > mzs.size()) return false;
+  return mzs[idx].inside(x, y);
+}
+
+// Return the x-position for the edge of a module sensor.
+double ModuleMaterial::x(unsigned int idx, double y, int edge) {
+  if (idx > mzs.size()) return 0;
+  else return mzs[idx].x(y, edge);
+}
+
+// Return the z-position for a module sensor.
+double ModuleMaterial::z(unsigned int idx) {
+  if (idx > mzs.size()) return 0;
+  else return mzs[idx].z;
+}
+
+// Return a parameter for a module sensor function.
+double ModuleMaterial::p(unsigned int idx, int par, int edge) {
+  if (idx > mzs.size()) return 0;
+  else return mzs[idx].p(par, edge);
+}
+
+// Configure the technical sensor parameters.
+void ModuleMaterial::configSensor(double xc, double yc, bool rel, int half) {
+  for (int sns = 0; sns < (int)mzs.size(); ++sns) {
+    if (half != 0 && mzs[sns].half != half) continue;
+    mzs[sns].config(xc, yc, rel);
+  }
+}
+
+// Configure the technical sensor parameters.
+void ModuleMaterial::configSensor(FoilMaterial &foil) {
+  for (int sns = 0; sns < (int)mzs.size(); ++sns) {
+    vector<FoilMaterial::Segment> *fzs =
+      mzs[sns].half < 0 ? &foil.flzs : &foil.fuzs;
+    for (int seg = 0; seg < (int)fzs->size(); ++seg)
+      if ((*fzs)[seg].valid(mzs[sns].z)) {
+	(*fzs)[seg].x(0, mzs[sns].z); mzs[sns].config((*fzs)[seg].fnc); break;}
+  }
+}
+
+// Configure the technical probability integral parameters.
+void ModuleMaterial::configIntegral
+(double dvmin, double sigma, double width, double tol,
+ ROOT::Math::IntegrationMultiDim::Type alg) {
+  ingr.config(dvmin, sigma, width, tol, alg);
+}
+
+// Configure the technical distance parameters.
+void ModuleMaterial::configDistance
+(double dvmin, double tol, int itr, bool logt) {
+  dist.config(dvmin, tol, itr, logt);
+}
+
+// Return the probability integral.
+double ModuleMaterial::integral(double vx, double vy, double vz,
+				double dvx, double dvy, double dvz, int half) {
+  return ingr.integral(vx, vy, vz, dvx, dvy, dvz, half);
+}
+
+// Return the intersection.
+TLorentzVector ModuleMaterial::intersect(double vx, double vy, double vz,
+					 double fx, double fy, double fz,
+					 int half) {
+  TLorentzVector s(0, 0, 0, 0);
+  if (fz == 0) return s;
+  double f(sqrt(fx*fx + fy*fy + fz*fz)); f = f == 0 ? 1 : f;
+  fx /= f; fy /= f; fz /= f;
+  for (int sns = 0; sns < (int)mzs.size(); ++sns) {
+    if (half != 0 && mzs[sns].half != half) continue;
+    double mz(mzs[sns].z), t((mz - vz)/fz);
+    if (t > 0 && mzs[sns].inside(vx + fx*t, vy + fy*t) &&
+	(s.T() == 0 || t < abs(s.T())))
+      s.SetXYZT(vx + fx*t, vy + fy*t, mz, mzs[sns].half*t);
+  }
+  if (s.T() != 0) s.SetT(s.T() > 0 ? 1 : -1);
+  return s;
+}
+
+// Return the distance.
+TLorentzVector ModuleMaterial::distance(double vx, double vy, double vz,
+					double dvx, double dvy, double dvz,
+					int half) {
+  return dist.distance(vx, vy, vz, dvx, dvy, dvz, half);
+}
+
+//=============================================================================
+// FoilMaterial::Segment class.
+
+// Default constructor.
+FoilMaterial::Segment::Segment() {;}
+
+// Primary constructor.
+FoilMaterial::Segment::Segment(TFile &file, string pre) : zmin(-1), zmax(-1) {
+  TObjString *exp((TObjString*)file.Get((pre + "_fnc").c_str()));
+  TVectorD *lim((TVectorD*)file.Get((pre + "_lim").c_str())), *par(0);
+  TGraph *spl(0);
+  if (!exp || !lim || lim->GetNrows() != 2) return;
+  zmin = (*lim)[0]; zmax = (*lim)[1];
+  fnc = TF1(pre.c_str(), exp->GetString().Data(), -100, 100); pre += "_";
+  for (int idx = 0; idx < 6; ++idx) {
+    stringstream stridx; stridx << idx; exp = 0; par = 0;
+    exp = (TObjString*)file.Get((pre + stridx.str() + "_fnc").c_str());
+    par = (TVectorD*)file.Get((pre + stridx.str() + "_par").c_str());
+    spl = (TGraph*)file.Get((pre.substr(0, pre.size() - 2) + "a_"
+			     + stridx.str() + "_spl").c_str());
+    if (!exp || !par) return;
+    fncs.push_back(TF1((pre + stridx.str()).c_str(),
+		       exp->GetString().Data(), zmin, zmax));
+    if (spl)
+      spls.push_back(TSpline3((pre + stridx.str() + "_par").c_str(), spl));
+    else
+      spls.push_back(TSpline3());
+    mths.push_back(0);
+    for (int jdx = 0; jdx < par->GetNrows(); ++jdx)
+      fncs[idx].SetParameter(jdx, (*par)[jdx]);
+  }
+};
+
+// Configure the tool.
+void FoilMaterial::Segment::config(int par, int mth) {
+  if (abs(par) < (int)fncs.size()) mths[par] = mth;
+}
+
+// Return if a z-position is in the segment.
+bool FoilMaterial::Segment::valid(double &z) {return z >= zmin && z < zmax;}
+
+// Return the x-position for the segment.
+double FoilMaterial::Segment::x(double y, double z) {
+  for (int idx = 0; idx < (int)fncs.size(); ++idx) {
+    if (mths[idx] == 1 && z < spls[idx].GetXmax() && z > spls[idx].GetXmin())
+      fnc.SetParameter(idx, spls[idx].Eval(z));
+    else fnc.SetParameter(idx, fncs[idx].Eval(z));
+  }
+  return fnc.Eval(y);
+}
+
+// Return a parameter for the segment function.
+double FoilMaterial::Segment::p(unsigned int par, double z) {
+  if (par >= fncs.size()) return 0;
+  if (mths[par] == 1 && z < spls[par].GetXmax() && z > spls[par].GetXmin())
+    return spls[par].Eval(z);
+  return fncs[par].Eval(z);
+}
+
+//=============================================================================
+// FoilMaterial::Integral class.
+
+// Return the probability integral in one dimension.
+double FoilMaterial::Integral::integral
+(double v, double dv, double t, double dt) {
+  return (TMath::Erf(sqrt(0.5)*(v - (t - dt/2))/dv) -
+	  TMath::Erf(sqrt(0.5)*(v - (t + dt/2))/dv))/2;
+}
+
+// Default constructor.
+FoilMaterial::Integral::Integral(FoilMaterial *foilIn) :
+  foil(foilIn), fnc("", this, -100, 100, -100, 100, 0, ""), wrp(fnc), inr(0) {;}
+
+// Destructor.
+FoilMaterial::Integral::~Integral() {if (inr) delete inr;}
+
+// Return the probability function for a given half.
+double FoilMaterial::Integral::operator()(double *t, double *) {
+  double sy(t[0]), sz(t[1]);
+  double y(vy + sy*dvy), z(vz + sz*dvz), xf(foil->x(y, z, half));
+  return integral(vx, dvx, xf, width)*
+    TMath::Gaus(sy, 0, 1, true)*TMath::Gaus(sz, 0, 1, true);
+}
+
+// Configure the tool.
+void FoilMaterial::Integral::config
+(double dvminIn, double sigmaIn, double stepIn, double widthIn, double tolIn,
+ ROOT::Math::IntegrationMultiDim::Type algIn) {
+  dvmin = abs(dvminIn); sigma = abs(sigmaIn); step = abs(stepIn);
+  width = abs(widthIn); tol = abs(tolIn);
+  if (alg != algIn || !inr) {
+    if (inr) delete inr;
+    alg = algIn; inr = new ROOT::Math::IntegratorMultiDim(alg);
+    inr->SetFunction(wrp);
+  }
+  inr->SetRelTolerance(tol);
+}
+
+// Return the proibability integral.
+double FoilMaterial::Integral::integral(double vxIn, double vyIn, double vzIn,
+			      double dvxIn, double dvyIn, double dvzIn,
+			      int method) {
+  vx = vxIn; vy = vyIn; vz = vzIn;
+  dvx = abs(dvxIn); dvy = abs(dvyIn); dvz = abs(dvzIn);
+  dvx = dvx > dvmin ? dvx : dvmin; dvy = dvy > dvmin ? dvy : dvmin;
+  dvz = dvz > dvmin ? dvz : dvmin;
+  double ingr(0);
+  if (method == 0) {
+    vector<double> yz0(2, -sigma), yz1(2, sigma);
+    for (int z0 = -sigma; z0 < sigma; ++z0) {
+      yz0[1] = z0; yz1[1] = z0 + step;
+      half = -1; ingr += inr->Integral(&yz0[0], &yz1[0]);
+      half =  1; ingr += inr->Integral(&yz0[0], &yz1[0]);
+    }
+  } else if (method == 1) {
+    int yn(2*ceil(sigma*dvy/step)+1), zn(2*ceil(sigma*dvz/step)+1);
+    double ymin(vy-(yn-1)/2*step), zmin(vz-(zn-1)/2*step),
+      yds[yn], zd, y, z(zmin);
+    for (int yi = 0; yi < yn; ++yi)
+      yds[yi] = integral(vy, dvy, ymin + yi*step, step);
+    for (int zi = 0; zi < zn; ++zi) {
+      y = ymin; zd = integral(vz, dvz, z, step);
+      for (int yi = 0; yi < yn && zd != 0; ++yi) {
+	if (yds[yi] != 0) {
+	  ingr += zd*yds[yi]*(integral(vx, dvx, foil->x(y, z, -1), width) +
+			      integral(vx, dvx, foil->x(y, z,  1), width));
+	} y += step;
+      } z += step;
+    }
+  } else if (method == 2) {
+    ingr = TMath::Gaus(foil->x(vy, vz, -1)/dvx, 0, 1, true) +
+      TMath::Gaus(foil->x(vy, vz, 1)/dvx, 0, 1, true);
+  }
+  return ingr > 1 ? 1 : ingr;
+}
+
+//=============================================================================
+// FoilMaterial::Intersect class.
+
+// Return the intersection for a given half.
+TLorentzVector FoilMaterial::Intersect::intersect(int halfIn) {
+  half = halfIn;
+  double txmin(((half > 0 ? -5 : -15) - vx)),
+    txmax(((half > 0 ? 15 : 5) - vx)), tymin((-50 - vy)), tymax((50 - vy)),
+    tzmin((-316 - vz)), tzmax((550 - vz)), tmin(0);
+  if (fx != 0 && txmax/fx < txmin/fx) swap(txmin, txmax);
+  if (fy != 0 && tymax/fy < tymin/fy) swap(tymin, tymax);
+  if (fz != 0 && tzmax/fz < tzmin/fz) swap(tzmin, tzmax);
+  double tmax(fx == 0 ? 1e20 : txmax/fx);
+  if (fx != 0 && txmin/fx > tmin) tmin = txmin/fx;
+  if (fy != 0 && tymin/fy > tmin) tmin = tymin/fy;
+  if (fz != 0 && tzmin/fz > tmin) tmin = tzmin/fz;
+  if (fy != 0 && tymax/fy < tmax) tmax = tymax/fy;
+  if (fz != 0 && tzmax/fz < tmax) tmax = tzmax/fz;
+  double t(fnc.GetMinimumX(tmin, tmax, tol, itr, logt)), s(fnc.Eval(t));
+  if (tmax <= tmin) return TLorentzVector(0, 0, 0, -1);
+  if (s != s || s > 0.01) return TLorentzVector(0, 0, 0, -1);
+  else return TLorentzVector(vx + fx*t, vy + fy*t, vz + fz*t, t);
+}
+
+// Default constructor.
+FoilMaterial::Intersect::Intersect(FoilMaterial *foilIn) : foil(foilIn) {
+  stringstream str; str << this;
+  fnc = TF1(str.str().c_str(), this, 0, 1000, 0, "");
+}
+
+// Return the distance from the foil along the flight direction.
+double FoilMaterial::Intersect::operator()(double *t, double *) {
+  return abs(foil->x(vy+fy*t[0], vz+fz*t[0], half) - (vx+fx*t[0]));
+}
+
+// Configure the tool.
+void FoilMaterial::Intersect::config(double tolIn, int itrIn, bool logtIn) {
+  tol = abs(tolIn); itr = abs(itrIn); logt = logtIn;
+};
+
+// Return the intersection.
+TLorentzVector FoilMaterial::Intersect::intersect
+(double vxIn, double vyIn, double vzIn, double fxIn, double fyIn, double fzIn,
+ int halfIn) {
+  double f(sqrt(fxIn*fxIn + fyIn*fyIn + fzIn*fzIn)); f = f > 0 ? f : 1;
+  vx = vxIn; vy = vyIn; vz = vzIn; fx = fxIn/f; fy = fyIn/f; fz = fzIn/f;
+  if (halfIn == 0) {
+    TLorentzVector sl(intersect(-1)), su(intersect(1));
+    if (sl.T() >= 0 && (sl.T() < su.T() || su.T() < 0))
+      {sl.SetT(-1); return sl;}
+    else if (su.T() >= 0 && (su.T() < sl.T() || sl.T() < 0))
+      {su.SetT(1); return su;}
+    else return TLorentzVector(0, 0, 0, 0);
+  }
+  TLorentzVector s(intersect(halfIn));
+  if (s.T() >= 0) {s.SetT(halfIn); return s;}
+  else return TLorentzVector(0, 0, 0, 0);
+}
+
+//=============================================================================
+// FoilMaterial::Distance class.
+
+// Return the distance for a given half.
+void FoilMaterial::Distance::distance
+(int halfIn, int method, int dir, TLorentzVector &s, double &n, double &u) {
+  half = halfIn;
+  double d, dmin(numeric_limits<double>::infinity()), y(vy), z(vz),
+    zmax(vz + (dir != -1)*sigma*(dvz < dvmax ? dvz : dvmax));
+  double ymin(foil->p(0, vz, half)), ymax(50);
+  double t[2] = {y, z - (dir != 1)*sigma*(dvz < dvmax ? dvz : dvmax) - step};
+  if (y < ymin) {ymax = -ymax; ymin += 0.1; swap(ymin, ymax);}
+  else ymin -= 0.1;
+  min->SetLimitedVariable(0, "y", y, step, ymin, ymax);
+  while (t[1] <= zmax) {
+    t[1] += step; d = (*this)(t);
+    if (d < dmin) {dmin = d; z = t[1];}
+    if (method == 2) {
+      min->SetVariableValues(t); min->FixVariable(1); min->Minimize();
+      u += 1/(min->MinValue() < d ? min->MinValue() : d); ++n;
+      min->ReleaseVariable(1);
+    }
+  }
+  min->SetVariableValue(0, vy); min->SetVariableValue(1, vz); min->Minimize();
+  if (min->MinValue() < dmin) {
+    dmin = min->MinValue(); y = min->X()[0]; z = min->X()[1];}
+  min->SetVariableValue(0, y); min->SetVariableValue(1, z); min->Minimize();
+  if (min->MinValue() < dmin) {
+    dmin = min->MinValue(); y = min->X()[0]; z = min->X()[1];}
+  if (dmin < s.T()) s.SetXYZT(foil->x(y, z, half), y, z, dmin);
+  if (method == 1) {u += 1/dmin; ++n;}
+}
+
+// Default constructor.
+FoilMaterial::Distance::Distance(FoilMaterial *foilIn) :
+  foil(foilIn), fnc(this, &FoilMaterial::Distance::operator(), 2), min(0) {;}
+
+// Return the distance from the foil in uncertainty space.
+double FoilMaterial::Distance::operator()(const double *t) {
+  double x((vx - foil->x(t[0], t[1], half))/dvx), y((vy - t[0])/dvy),
+    z((vz - t[1])/dvz);
+  return sqrt(x*x + y*y + z*z);
+}
+
+// Configure the tool.
+void FoilMaterial::Distance::config
+(double dvminIn, double dvmaxIn, double sigmaIn, double stepIn,
+ double tolIn, int itrIn, string libIn, string algIn) {
+  dvmin = abs(dvminIn); dvmax = abs(dvmaxIn);
+  sigma = abs(sigmaIn); step = abs(stepIn);
+  if (libIn != lib || alg != algIn || !min) {
+    lib = libIn; alg = algIn;
+    min = ROOT::Math::Factory::CreateMinimizer(lib.c_str(), alg.c_str());
+  }
+  min->SetFunction(fnc); min->SetPrintLevel(0); min->SetValidError(false);
+  min->SetMaxIterations(itrIn); min->SetMaxFunctionCalls(itrIn);
+  min->SetTolerance(tolIn);
+}
+
+// Return the distance.
+TLorentzVector FoilMaterial::Distance::distance
+(double vxIn, double vyIn, double vzIn, double dvxIn, double dvyIn,
+ double dvzIn, int halfIn, int method, int dir) {
+  vx = vxIn; vy = vyIn; vz = vzIn;
+  dvx = abs(dvxIn); dvy = abs(dvyIn), dvz = abs(dvzIn);
+  dvx = dvx > dvmin ? dvx : dvmin;
+  dvy = dvy > dvmin ? dvy : dvmin;
+  dvz = dvz > dvmin ? dvz : dvmin;
+  min->SetLimitedVariable(0, "y", vy, step, vy - sigma*dvy, vy + sigma*dvy);
+  min->SetLimitedVariable(1, "z", vz, step,
+			  vz - (dir !=  1)*sigma*(dvz < dvmax ? dvz : dvmax),
+			  vz + (dir != -1)*sigma*(dvz < dvmax ? dvz : dvmax));
+  double n(0), u(0);
+  TLorentzVector s(0, 0, 0, numeric_limits<double>::infinity());
+  if (dvx == 0 || dvy == 0 || dvz == 0) return s;
+  level = gErrorIgnoreLevel;
+  gErrorIgnoreLevel = 1001;
+  if (halfIn == 0 || halfIn == -1) distance(-1, method, dir, s, n, u);
+  if (halfIn == 0 || halfIn ==  1) distance( 1, method, dir, s, n, u);
+  if (method != 0) s.SetT(n/(2*u));
+  gErrorIgnoreLevel = level;
+  return s;
+}
+
+//=============================================================================
+// FoilMaterial class.
+
+// Default constructor.
+FoilMaterial::FoilMaterial(string pars) : ingr(this), insc(this), dist(this) {
+  configIntegral(); configIntersect(); configDistance();
+  vector<string> segs(4, "b"); segs[1] = "c"; segs[2] = "t"; segs[3] = "f";
+  TFile file(pars.c_str());
+  for (int seg = 0; seg < (int)segs.size(); ++seg) {
+    flzs.push_back(Segment(file, "foil_l_" + segs[seg]));
+    fuzs.push_back(Segment(file, "foil_u_" + segs[seg]));
+  }
+  configSegment();
+  file.Close();
+}
+
+// Return the x-position of the foil.
+double FoilMaterial::x(double y, double z, int half) {
+  vector<Segment> *fzs = half < 0 ? &flzs : &fuzs;
+  for (int seg = 0; seg < (int)fzs->size(); ++seg)
+    if ((*fzs)[seg].valid(z)) return (*fzs)[seg].x(y, z);
+  return 0;
+}
+
+// Return a parameter for the foil function.
+double FoilMaterial::p(unsigned int par, double z, int half) {
+  vector<Segment> *fzs = half < 0 ? &flzs : &fuzs;
+  for (int seg = 0; seg < (int)fzs->size(); ++seg)
+    if ((*fzs)[seg].valid(z)) return (*fzs)[seg].p(par, z);
+  return 0;
+}
+
+// Configure the technical segment parameters.
+void FoilMaterial::configSegment(int half, string seg, int par, int mth) {
+  if (half == 0) {
+    configSegment(-1, seg, par, mth); configSegment(1, seg, par, mth); return;
+  }
+  if (seg == "a") {
+    vector<string> segs(4, "b"); segs[1] = "c"; segs[2] = "t"; segs[3] = "f";
+    for (int idx = 0; idx < (int)segs.size(); ++idx)
+      configSegment(half, segs[idx], par, mth); return;
+  }
+  if (par < 0) {
+    for (int idx = 0; idx < 6; ++idx) configSegment(half, seg, idx, mth);
+    return;
+  }
+  map<string, int> segs; segs["c"] = 1; segs["t"] = 2; segs["f"] = 3;
+  (half < 0 ? flzs : fuzs)[segs[seg]].config(par, mth);
+}
+
+// Configure the technical probability integral parameters.
+void FoilMaterial::configIntegral
+(double dvmin, double sigma, double step, double width, double tol,
+ ROOT::Math::IntegrationMultiDim::Type alg) {
+  ingr.config(dvmin, sigma, step, width, tol, alg);
+}
+
+
+// Configure the technical intersection parameters.
+void FoilMaterial::configIntersect(double tol, int itr, bool logt) {
+  insc.config(tol, itr, logt);
+}
+
+// Configure the technical distance parameters.
+void FoilMaterial::configDistance
+(double dvmin, double dvmax, double sigma, double step, double tol, int itr,
+ string lib, string alg) {
+  dist.config(dvmin, dvmax, sigma, step, tol, itr, lib, alg);
+}
+
+// Return the probability integral.
+double FoilMaterial::integral
+(double vx, double vy, double vz, double dvx, double dvy, double dvz,
+ int method) {
+  return ingr.integral(vx, vy, vz, dvx, dvy, dvz, method);
+}
+
+// Return the intersection.
+TLorentzVector FoilMaterial::intersect
+(double vx, double vy, double vz, double fx, double fy, double fz, int half) {
+  return insc.intersect(vx, vy, vz, fx, fy, fz, half);
+}
+
+// Return the distance.
+TLorentzVector FoilMaterial::distance
+(double vx, double vy, double vz, double dvx, double dvy, double dvz, int half,
+ int method, int dir) {
+  return dist.distance(vx, vy, vz, dvx, dvy, dvz, half, method, dir);
+}
+
+//=============================================================================
+// VeloMaterial class.
+
+// Default constructor.
+VeloMaterial::VeloMaterial(string pars) : foil(pars), modf(pars), modm(pars),
+  rfnc("fnc", "[0] + [1]*exp(-[2]*x) + [3]*exp(-[4]*x)", 0.04, 0.6) {
+  modf.configSensor(foil);
+  rfnc.SetParameters(0.184, 0.163, 0.266, 1.001, 2.173);
+}
+
+// Transform a vertex position.
+void VeloMaterial::transform(double &vx, double &vy, double &vz,
+			     int year, int run) {
+
+  // If no year is specified, do not perform shift.
+  if (year < 0) return;
+
+  // Start with 2016 shift, all other shifts relative to 2016.
+  // Applies reverse of 2016 shift to 2017 and 2018 data, then applies year/run
+  // number specific shift
+  if (year != 2016)                      {vx += 0.8368; vy -= 0.17431; vz -= 0.8551;}
+  if (year == 2017)                      {vx -= 0.8287; vy += 0.08594; vz -= 2.6381;}
+  else if (year == 2018 && run < 214390) {vx -= 0.8341; vy -= 0.09406; vz += 5.1581;}
+  else if (year == 2018)                 {vx -= 0.8622; vy -= 0.18155; vz += 5.0085;}
+
+}
+
+// Return the distance.
+double VeloMaterial::distance(double vx, double vy, double vz,
+			      double fx, double fy, double fz,
+			      double fx1, double fy1, double fz1,
+			      double fx2, double fy2, double fz2,
+			      double dvx, double dvy, double dvz,
+			      int year, int run) {
+
+  // Determine the material distance.
+  transform(vx, vy, vz, year, run);
+  if (dvz <= 1) dvz = 1;
+  if (vz > 300 && dvx < 0.5) dvx = 0.5;
+  if (vz > 300 && dvy < 0.5) dvy = 0.5;
+  double d = 1/(1/modf.distance(vx, vy, vz, dvx, dvy, dvz, -1).T() +
+		1/modf.distance(vx, vy, vz, dvx, dvy, dvz, +1).T() +
+		1/foil.distance(vx, vy, vz, dvx, dvy, dvz, -1, 0, -1).T() +
+		1/foil.distance(vx, vy, vz, dvx, dvy, dvz, -1, 0, +1).T() +
+		1/foil.distance(vx, vy, vz, dvx, dvy, dvz, +1, 0, -1).T() +
+		1/foil.distance(vx, vy, vz, dvx, dvy, dvz, +1, 0, +1).T());
+
+  // Determine the radial distance between daughter hits in first module.
+  double mz1 = modm.intersect(vx, vy, vz, fx1, fy1, fz1).Z();
+  double mz2 = modm.intersect(vx, vy, vz, fx2, fy2, fz2).Z();
+  double hzm = min(mz1 - vz, mz2 - vz);
+  double hx1 = vx + fx1/fz1*hzm;
+  double hy1 = vy + fy1/fz1*hzm;
+  double hx2 = vx + fx2/fz2*hzm;
+  double hy2 = vy + fy2/fz2*hzm;
+  double drh = sqrt(pow(hx1 - hx2, 2) + pow(hy1 - hy2, 2));
+
+  // Scale for r-dependence.
+  double rh = modm.intersect(vx, vy, vz, fx, fy, fz).Perp();
+  double rp = 0.04 + 0.05*(rh - 8)/(35 - 8);
+  double pp = rh > 18 ? 0.0023 : 0.0046;
+  d *= 0.65*0.23/min(0.23, max(0.7, rfnc.Eval(drh/sqrt(rp*rp +  rh*pp*rh*pp))));
+  if (rh > 0  && rh <= 8)  d /= 0.95;
+  if (rh > 8  && rh <= 11) d /= 0.72;
+  if (rh > 13 && rh <= 15) d /= 0.75;
+  if (rh > 16 && rh <= 18) d /= 1.45;
+  if (rh > 20)             d /= 0.78;
+  return d;
+}
+
+// Return true if the flight direction of a vertex intersects a foil tip.
+bool VeloMaterial::tip(double vx, double vy, double vz,
+		       double fx, double fy, double fz,
+		       int year, int run) {
+  transform(vx, vy, vz, year, run);
+  double mz(modf.z(modf.sensor(vz)));
+  return abs(foil.intersect(vx, vy, vz, fx, fy, fz).Z() - mz) < 1 ||
+    abs(foil.intersect(vx, vy, vz, -fx, -fy, -fz).Z() - mz) < 1;
+}
+
+// Return true if the expected first hit is missed.
+bool VeloMaterial::miss(double vx, double vy, double vz,
+			double fx, double fy, double fz, double mz,
+			int year, int run) {
+  transform(vx, vy, vz, year, run);
+  double hz(-numeric_limits<double>::infinity()), hr(0), z(vz);
+  while(hr < 8.170){
+    TLorentzVector d(modm.intersect(vx + (z - vz)*fx/fz, vy + (z - vz)*fy/fz,
+				    z, fx, fy, fz));
+    if(d.T() == 0) break;
+    int idx(modm.sensor(d.Z()));
+    double mx(modm.p(idx, 1)), my(modm.p(idx, 0));
+    hr = sqrt((d.X() - mx)*(d.X() - mx) + (d.Y() - my)*(d.Y() - my));
+    hz = d.Z();
+    z  = d.Z() + 1;
+  }
+  return abs(hz - mz) > 1;
+}
diff --git a/bu2kdarkscalar_darkscalar2hh/velo.h b/bu2kdarkscalar_darkscalar2hh/velo.h
new file mode 100644
index 0000000000..35170dbd89
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/velo.h
@@ -0,0 +1,799 @@
+// Written by Philip Ilten and Mike Williams, 20/06/2017.
+// Toolset to check if a secondary vertex is consistent with having
+// originated from the VELO material. See README for an overview.
+#ifndef VELOMATERIAL_H
+#define VELOMATERIAL_H
+#include <limits>
+#include <algorithm>
+#include "TFile.h"
+#include "TKey.h"
+#include "TObjString.h"
+#include "TVectorD.h"
+#include "TLorentzVector.h"
+#include "TF1.h"
+#include "TF2.h"
+#include "TMath.h"
+#include "TError.h"
+#include "TGraph.h"
+#include "TSpline.h"
+#include "Math/WrappedTF1.h"
+#include "Math/BrentMinimizer1D.h"
+#include "Math/WrappedMultiTF1.h"
+#include "Math/IntegratorMultiDim.h"
+#include "Math/Minimizer.h"
+#include "Math/Factory.h"
+#include "Math/Functor.h"
+#include "Minuit2/Minuit2Minimizer.h"
+using namespace std;
+
+// Pre-declare material class for sensor configuration.
+class FoilMaterial;
+
+//=============================================================================
+/*
+  Class to access the parameterized VELO module material.
+*/
+class ModuleMaterial {
+  
+public:
+
+  //===========================================================================
+  /*
+    Class to hold the module sensor geometry.
+
+    Details on the module sensor geometry description can be found in
+    the DBASE source:
+  
+    DBASE/Det/XmlDDDB/DDDB/Velo/Geom/LogVol/GenericModule.xml
+    DBASE/Det/XmlDDDB/DDDB/Velo/GeomParam/VeloSensorParam.xml
+    
+    Here, the module geometry was taken from the EDMS design
+    documents with number 401568 v.4 that can be found at the
+    following link.
+    
+    https://edms.cern.ch/ui/#!master/navigator/document?D:1100625139:
+    1100625139:subDocs
+  */
+  class Sensor {
+    
+  public:
+    
+    // Configurable Members.
+    TF1 fncl, fncu; ///< Functions defining the lower/upper sensor edges.
+    double z;       ///< Sensor z-position.
+    int half;       ///< Lower/upper VELO half.
+
+    // Methods.
+    /// Default constructor.
+    Sensor();
+    
+    /*
+      Primary constructor.
+      \param ifile: TFile containing all the needed parameters.
+      \param mod:   string of the module to build, e.g. "module_01".
+      \param sns:   string of the sensor to build from the module, e.g. "0".
+    */
+    Sensor(TFile &file, string mod, string sns);
+
+    /// Operator for sorting by the given z-value.
+    bool operator<(const Sensor& sns) const;
+
+    /// Configure the tool.
+    void config(double xc, double yc, bool rel = true);
+
+    /// Configure the tool.
+    void config(const TF1 &fnc);
+
+    /*
+      Return if an x,y-point falls within a module sensor.
+      \param [x,y]: x,y-position to evaluate.
+    */
+    bool inside(double x, double y);
+
+    /*
+      Return the x-position for the edge of the sensor.
+      \param y:    y-position to evaluate.
+      \param edge: -/+1 for the lower/upper edge, 0 for the inside edge.
+    */
+    double x(double y, int edge = 0);
+
+    /*
+      Return a parameter for the sensor function.
+      \param par:  parameter index.
+      \param edge: -/+1 for the lower/upper edge, 0 for the inside edge.
+    */
+    double p(unsigned int par, int edge = 0);
+  };
+
+  //===========================================================================
+  /*
+    Class to calculate the probability integral for a vertex to be
+    produced from VELO modules.
+
+    The probability density function for the vertex is assumed to be a
+    3D Gaussian and the integration is performed in the x,y-plane as
+    the z-direction pre-factor remains constant.
+  */
+  class Integral {
+    
+    // Members.
+    vector<Sensor> *mzs;                 ///< Module sensors.
+    Sensor         *geo;                 ///< Sensor geometry for integration.
+    TF2 fnc;                             ///< Function used for integration.
+    ROOT::Math::WrappedMultiTF1 wrp;     ///< Wrapper for the function.
+    ROOT::Math::IntegratorMultiDim *inr; ///< Integrator for the function.
+    double vx, vy, vz, dvx, dvy, dvz;    ///< Vertex position and uncertainty.
+
+    /*
+      Return the probability integral for a given half.
+      \param halfIn: -/+1 for the lower/upper VELO half in x.
+    */
+    double integral(int half);
+
+  public:  
+
+    // Configurable members.
+    double dvmin; ///< Minimum allowed vertex uncertainty.
+    double sigma; ///< Number of standard deviations to calculate over.
+    double width; ///< Width of the module in mm.
+    double tol;   ///< Integration tolerance.
+    /// Integration algorithm: adaptive, VEGAS, MISER, or plain.
+    ROOT::Math::IntegrationMultiDim::Type alg; 
+
+    // Methods.
+    /*
+      Default constructor.
+      \param mzsIn: module sensors.
+    */
+    Integral(vector<Sensor> *mzs);
+
+    ///< Destructor.
+    ~Integral(); 
+
+    /*
+      Return the probability function for a given half. The passed
+      coordinates are not in mm but are in sigma from the origin of a
+      2D normal distribution.
+      \param t: the variables sx and sy passed as an array of length 2.
+    */
+    double operator()(double *t, double *);
+    
+    /// Configure the tool.
+    void config(double dvminIn, double sigmaIn, double mwIn,
+		double tolIn, ROOT::Math::IntegrationMultiDim::Type algIn);
+
+    /// Return the probability integral.
+    double integral(double vxIn, double vyIn, double vzIn, double dvxIn,
+		    double dvyIn, double dvzIn, int halfIn);
+  };
+
+  //===========================================================================
+  /*
+    Class to calculate the minimum distance in uncertainty space
+    between a vertex and the VELO modules.
+
+    First the lower and upper modules which minimize the distance in z
+    are found. This is the same in normal or uncertainty space. Next,
+    the minimum transverse distance is found for each module in
+    uncertainty space. The minimum distance between the the lower and
+    upper modules is returned.
+  */
+  class Distance {
+    
+    // Members.
+    vector<Sensor> *mzs;              ///< Module sensors.
+    Sensor         *geo;              ///< Sensor geometry for intersection.
+    TF1 fnc;                          ///< Wrapped function to minimize.
+    double vx, vy, vz, dvx, dvy, dvz; ///< Vertex position and uncertianty.
+  
+    /*
+     Return the distance for a given half.
+     \param halfIn: -/+1 for the lower/upper VELO half in x.
+     \param mzs:    module z-values.
+     \param s:      distance vector for updating.
+    */
+    void distance(int half, TLorentzVector &s);
+ 
+  public:
+    
+    // Configurable members.
+    double dvmin; ///< Minimum allowed vertex uncertainty. 
+    double tol;   ///< Minimization tolerance.
+    int    itr;   ///< Minimization iterations.
+    bool   logt;  ///< Flag to use a log scale in minimization.
+
+    // Methods.
+    /*
+      Default constructor.
+      \param mzsIn: module sensors.
+    */ 
+   Distance(vector<Sensor> *mzsIn);
+    
+    /*
+      Return the transverse distance.
+      \param t: the variable sy passed as an array of length 1.
+    */
+    double operator()(double *t, double *);
+
+    /// Configure the tool.
+    void config(double dvminIn, double tolIn, int itrIn, bool logtIn);
+
+    /// Return the distance.
+    TLorentzVector distance(double vxIn, double vyIn, double vzIn,
+			    double dvxIn, double dvyIn, double dvzIn,
+			    int halfIn);
+  };
+
+  //===========================================================================
+private:
+
+  // Members.
+  vector<Sensor> mzs; ///< Module sensors.
+  Integral  ingr;     ///< Internal integral tool.
+  Distance  dist;     ///< Internal distance tool.
+
+public:
+
+  // Methods.
+  /*
+    Default constructor.
+    \param pars: name of the fit parameters file.
+  */
+  ModuleMaterial(string pars = "pars.root");
+
+  /*
+    Return the index for the sensor nearest a given z-position.
+    \param z:    z-position to evaluate.
+    \param half: -/+1 for the lower/upper VELO half in x, 0 for both.
+   */
+  int sensor(double z, int half = 0);
+
+  /*
+    Return if an x,y-point falls within a module sensor.
+    \param idx: index of the module sensor.
+    \param x:   x-position to evaluate.
+    \param y:   y-position to evaluate.
+  */
+  bool inside(unsigned int idx, double x, double y);
+
+  /*
+    Return the x-position for the edge of a module sensor.
+    \param idx:  index of the module sensor.
+    \param y:    y-position to evaluate.
+    \param edge: -/+1 for the lower/upper edge, 0 for the inside edge.
+   */
+  double x(unsigned int idx, double y, int edge = 0);
+
+  /*
+    Return the z-position for a module sensor.
+    \param idx:  index of the module sensor.
+   */
+  double z(unsigned int idx);
+
+  /*
+    Return a parameter for a module sensor function.
+    \param idx:  index of the module sensor.
+    \param par:  parameter index.
+    \param edge: -/+1 for the lower/upper edge, 0 for the inside edge.
+  */
+  double p(unsigned int idx, int par, int edge = 0);
+
+  /*
+    Configure the technical sensor parameters. This method either sets
+    the absolute x,y-position for the center of each sensor or shifts
+    the center from the nominal position. This can be applied to
+    either or both halves of the VELO sensors.
+    \param xc:   x-position of the sensor center in mm.
+    \param yc:   y-position of the sensor center in mm.
+    \param rel:  if true, shift the sensors from their nominal positions.
+    \param half: -/+1 for the lower/upper VELO half in x, 0 for both.
+   */ 
+  void configSensor(double xc = 0, double yc = 0, bool rel = true, 
+		    int half = 0);
+
+   /*
+    Configure the technical sensor parameters. The sensor edge is set
+    as the foil edge at the given z-position for each sensor.
+    \param foil: the foil material map.
+   */ 
+  void configSensor(FoilMaterial &foil);
+
+  /*
+    Configure the technical probability integral parameters.
+    \param dvmin: minimum allowed vertex uncertainty.
+    \param sigma: number of standard deviations to calculate over.
+    \param width: width of the module in mm.
+    \param tol:   integration tolerance.
+    \param alg:   integration algorithm: adaptive, VEGAS, MISER, or plain.
+  */
+  void configIntegral(double dvmin = 0.25, double sigma = 5,
+		      double width = 1, double tol = 0.01,
+		      ROOT::Math::IntegrationMultiDim::Type alg = 
+		      ROOT::Math::IntegrationMultiDim::kADAPTIVE);
+
+  /*
+    Configure the technical distance parameters.
+    \param dvmin: minimum allowed vertex uncertainty.
+    \param tol:   minimization tolerance.		  
+    \param itr:   minimization iterations		  
+    \param logt:  flag to use a log scale in minimization.
+  */
+  void configDistance(double dvmin = 0.25, double tol = 1e-10, int itr = 100,
+		      bool logt = false);
+
+  /*
+    Return the probability integral.
+    \param v[x,y,z]:    x,y,z-positions of the vertex.
+    \param d[vx,vy,vz]: uncertainties on the x,y,z-positions of the vertex.
+    \param half:        -/+1 for the lower/upper VELO half in x, 0 for both.
+  */
+  double integral(double vx, double vy, double vz,
+		  double dvx, double dvy, double dvz, int half);
+
+  /*
+    Return the intersection. A 4-vector of the intersection point is
+    returned, where the T (or E) component gives the VELO half (-/+1
+    for lower/upper) or 0 if no intersection is found.
+    \param v[x,y,z]: x,y,z-positions of the vertex.
+    \param f[x,y,z]: flight direction.
+    \param half:     -/+1 for the lower/upper VELO half in x, 0 for both.
+  */
+  TLorentzVector intersect(double vx, double vy, double vz,
+			   double fx, double fy, double fz, int half = 0);
+
+  /*
+    Return the distance. The point of minimum distance on the material
+    in uncertainty space is returned where the T (or E) component
+    gives the distance.
+    \param v[x,y,z]:    x,y,z-positions of the vertex.
+    \param d[vx,vy,vz]: x,y,z-uncertainties of the vertex position.
+    \param half:        -/+1 for the lower/upper VELO half in x, 0 for both.
+  */
+  TLorentzVector distance(double vx, double vy, double vz,
+			  double dvx = 1, double dvy = 1, double dvz = 1,
+			  int half = 0);
+};
+
+//=============================================================================
+/*
+  Class to access the parameterized VELO foil material.
+*/
+class FoilMaterial {
+  friend class ModuleMaterial;
+  
+public:
+
+  //===========================================================================
+  /*
+    Class to hold the foil segment geometry.
+
+    This class is built from the parameters and functions provided in
+    the input parameter file passed to the primary constructor. The
+    class holds the function for the x,y-slice as well as the
+    parameters for this slice as a function of z-position.
+  */
+  class Segment {
+    friend class ModuleMaterial;
+
+    // Members.
+    vector<TF1>      fncs; ///< Vector of functions for the slice parameters.
+    vector<TSpline3> spls; ///< Vector of splines for the slice parameters.
+    vector<int>      mths; ///< Vector of methods for parameter evaluation.
+    TF1 fnc;               ///< The slice function.
+    double zmin, zmax;     ///< Range of validity in z-position for the segment.
+    
+  public:
+    
+    // Methods.
+    /// Default constructor.
+    Segment();
+    
+    /*
+      Primary constructor.
+      \param ifile: TFile containing all the needed parameters.
+      \param pre:   string of the foil segment to build, e.g. "foil_l_c".
+    */
+    Segment(TFile &file, string pre);
+    
+    /// Configure the tool.
+    void config(int par, int mth);
+
+    /*
+      Return if a z-position is in the segment.
+      \param z: z-position to evaluate.
+    */
+    bool valid(double &z);
+
+    /*
+      Return the x-position for the segment.
+      \param [y,z]: y,z-position to evaluate.
+    */
+    double x(double y, double z);
+
+    /*
+      Return a parameter for the segment function.
+      \param par: parameter index.
+      \param z:   z-position to evaluate.
+    */
+    double p(unsigned int par, double z);
+  };
+  
+  //===========================================================================
+  /*
+    Class to calculate the probability integral for a vertex to be
+    produced from the VELO foil.
+
+    The probability density function for the vertex is assumed to be a
+    3D Gaussian and the integration is performed in the y,z-plane as
+    the x-direction pre-factor remains constant.
+  */
+  class Integral {
+    
+    // Members.
+    FoilMaterial *foil;                  ///< Foil geometry.
+    TF2 fnc;                             ///< Function used for integration.
+    ROOT::Math::WrappedMultiTF1 wrp;     ///< Wrapper for the function.
+    ROOT::Math::IntegratorMultiDim *inr; ///< Integrator for the function.
+    double vx, vy, vz, dvx, dvy, dvz;    ///< Vertex position and uncertainty.
+    int half;                            ///< Lower/upper VELO half to evaluate.
+
+    /*
+      Return the probability integral in one dimension.
+      \param v:  vertex position.
+      \param dv: vertex position uncertainty.
+      \param t:  material position.     
+      \param dt: material position width.
+    */
+    double integral(double v, double dv, double t, double dt);
+    
+  public:  
+
+    // Configurable members.
+    double dvmin; ///< Minimum allowed vertex uncertainty.
+    double sigma; ///< Number of standard deviations to calculate over.
+    double step;  ///< Step distance in sigma. 
+    double width; ///< Width of the foil in mm.
+    double tol;   ///< Integration tolerance.
+    /// Integration algorithm: adaptive, VEGAS, MISER, or plain.
+    ROOT::Math::IntegrationMultiDim::Type alg; 
+
+    // Methods.
+    /*
+      Default constructor.
+      \param foilIn: foil geometry.
+    */
+    Integral(FoilMaterial *foilIn);
+
+    ///< Destructor.
+    ~Integral(); 
+
+    /*
+      Return the probability function for a given half. The passed
+      coordinates are not in mm but are in sigma from the origin of a
+      2D normal distribution.
+      \param t: the variables sy and sz passed as an array of length 2.
+    */
+    double operator()(double *t, double *);
+
+    /// Configure the tool.
+    void config(double dvminIn, double sigmaIn, double stepIn, double widthIn,
+		double tolIn, ROOT::Math::IntegrationMultiDim::Type algIn);
+
+    /// Return the probability integral.
+    double integral(double vxIn, double vyIn, double vzIn, double dvxIn,
+		    double dvyIn, double dvzIn, int methodIn);
+  };
+
+  //===========================================================================
+  /*
+    Class to calculate the intersection of a particle, defined with a
+    vertex and flight direction, with the VELO foil.
+  */
+  class Intersect {
+    
+    // Members.
+    FoilMaterial *foil;            ///< Foil geometry.
+    TF1 fnc;                       ///< Wrapped function to minimize.
+    double vx, vy, vz, fx, fy, fz; ///< Vertex position and flight direction.
+    int half;                      ///< Lower/upper VELO half to evalulate.
+    
+    /*
+      Return the intersection for a given half.
+      \param halfIn: -/+1 for the lower/upper VELO half in x.
+    */
+    TLorentzVector intersect(int halfIn);
+
+  public:
+    
+    // Configurable members.
+    double tol;  ///< Minimization tolerance.
+    int    itr;  ///< Minimization iterations.
+    bool   logt; ///< Flag to use a log scale in minimization.
+
+    // Methods.
+    /*
+      Default constructor.
+      \param foilIn: foil geometry.
+    */
+    Intersect(FoilMaterial *foilIn);
+    
+    /*
+      Return the distance from the foil along the flight direction.
+      \param t: the variable t passed as an array of length 1.
+    */
+    double operator()(double *t, double *);
+
+    /// Configure the tool.
+    void config(double tolIn, int itrIn, bool logtIn);
+
+    /// Return the intersection.
+    TLorentzVector intersect(double vxIn, double vyIn, double vzIn,
+			     double fxIn, double fyIn, double fzIn,
+			     int halfIn);
+  };
+
+  //===========================================================================
+  /// Class to calculate the distance between a vertex and the foil.
+  class Distance {
+    
+    // Members.
+    FoilMaterial *foil;               ///< Representation of the foil.
+    ROOT::Math::Functor fnc;          ///< Wrapped function to minimize.
+    ROOT::Math::Minimizer *min;       ///< Minimizer.
+    double vx, vy, vz, dvx, dvy, dvz; ///< Vertex position and uncertainty.
+    int half;                         ///< Lower/upper VELO half to evaluate.
+    int level;                        ///< Saved ROOT reporting level.
+
+    /*
+      Return the distance for a given half.
+      \param halfIn: -1 for the lower half and +1 for the upper foil half.
+      \param method: distance method.
+      \param dir:    minimizing z-direction: 0 both, -/+1 backwards/forward.
+      \param s:      vector containt
+      \param n:      number of all distances.
+      \param u:      sum of all distances.
+    */
+    void distance(int halfIn, int method, int dir, TLorentzVector &s,
+		  double &n, double &u);
+    
+  public:
+    
+    // Configurable members.
+    double dvmin; ///< Minimum allowed vertex uncertainty.
+    double dvmax; ///< Maximum vertex uncertainty for minimization limits.
+    double sigma; ///< Number of standard deviations to calculate over.
+    double step;  ///< Minimization step size along z-direction in mm.
+    double tol;   ///< Minimization tolerance.
+    double itr;   ///< Minimization iterations.
+    string lib;   ///< Minimization library, see alg for options.
+    /*
+      Minimization algorithm. The available algorithms for each library are:
+      \param Minuit2:     Migrad, Simplex, Combined, Scan, Fumili
+      \param GSLMultiMin: ConjugateFR, ConjugatePR, BFGS, BFGS2, 
+                          SteepestDescent
+      \param GSLMultiFit: 
+      \param GSLSimAn: 
+    */
+    string alg;
+    
+    // Methods.
+    /*
+      Default constructor.
+      \param foilIn: foil geometry.
+    */
+    Distance(FoilMaterial *foilIn);
+    
+    /*
+      Return the distance from the foil in uncertainty space.
+      \param t: the variables y and z passed as an array of length 2.
+    */
+    double operator()(const double *t);
+
+    /// Configure the tool.
+    void config(double dvminIn, double dvmax, double sigmaIn, double stepIn,
+		double tolIn, int itrIn, string libIn, string algIn);
+
+    /// Return the distance.
+    TLorentzVector distance(double vxIn, double vyIn, double vzIn,
+			    double dvxIn, double dvyIn, double dvzIn,
+			    int halfIn, int method, int dir);
+  };
+
+  //===========================================================================
+protected:
+
+  // Members.
+  vector<Segment> flzs, fuzs; ///< Lower/upper foil segment functions.
+  Integral  ingr;             ///< Internal integral tool.
+  Intersect insc;             ///< Internal intersection tool.
+  Distance  dist;             ///< Internal distance tool.
+
+public:
+
+  // Methods.
+  /*
+    Default constructor.
+    \param pars: name of the fit parameters file.
+  */
+  FoilMaterial(string pars = "pars.root");
+  
+  /*
+    Return the x-position of the foil.
+    \param [y,z]: y,z-position to evaluate.
+    \param half:  -/+1 for the lower/upper VELO half in x.
+  */
+  double x(double y, double z, int half);
+
+  /*
+    Return a parameter for the foil function.
+    \param par:  parameter index.
+    \param z:    z-position to evaluate.
+    \param half: -/+1 for the lower/upper VELO half in x.
+  */
+  double p(unsigned int par, double z, int half);
+
+  /*
+    Configure the technical segment parameters.
+    \param half: -/+1 for the lower/upper VELO half in x, 0 for both.
+    \param seg:  name of the segment: "b", "c", "t", "f". If "a" all segments 
+                 are configured.
+    \param par:  parameter to configure, -1 for all.
+    \param mth:  method for parameter evaluation: 0 for fitted function and
+                 1 for interpolation.
+  */
+  void configSegment(int half = 0, string seg = "a", int par = -1, int mth = 0);
+
+  /*
+    Configure the technical probability integral parameters.
+    \param dvmin: minimum allowed vertex uncertainty.
+    \param sigma: number of standard deviations to calculate over.
+    \param step:  integration step size along z-direction in sigma. 
+    \param width: width of the foil in mm.
+    \param tol:   integration tolerance.
+    \param alg:   integration algorithm.
+  */
+  void configIntegral(double dvmin = 0.25, double sigma = 5, double step = 1, 
+		      double width = 1, double tol = 1e-2,
+		      ROOT::Math::IntegrationMultiDim::Type alg = 
+		      ROOT::Math::IntegrationMultiDim::kADAPTIVE);
+
+  /*
+    Configure the technical intersection parameters.
+    \param tol:  minimization tolerance.
+    \param itr:  minimization iterations
+    \param logt: flag to use a log scale in minimization.
+  */
+  void configIntersect(double tol = 1e-10, int itr = 100, bool logt = false);
+
+  /*
+    Configure the technical distance parameters.
+    \param dvmin: minimum allowed vertex uncertainty.
+    \param dvmax: maximum vertex uncertainty for minimization limits.
+    \param sigma: number of standard deviations to calculate over.
+    \param step:  minimization step size along z-direction in mm.
+    \param tol:   minimization tolerance.
+    \param itr:   minimization iterations.
+    \param lib:   library used for minimization.
+    \param alg:   algorithm used for minimization.
+  */
+  void configDistance(double dvmin = 0.25, double dvmax = 100,
+		      double sigma = 5, double step = 1,
+		      double tol =  1e-2, int itr = 100, 
+		      string lib = "Minuit2", string alg = "Migrad");
+
+  /*
+    Return the probability integral.
+    \param v[x,y,z]:    x,y,z-positions of the vertex.
+    \param d[vx,vy,vz]: uncertainties on the x,y,z-positions of the vertex.
+  */
+  double integral(double vx, double vy, double vz,
+		  double dvx, double dvy, double dvz, int method = 0);
+
+  /*
+    Return the intersection. A 4-vector of the intersection point is
+    returned, where the T (or E) component gives the VELO half (-/+1
+    for lower/upper) or 0 if no intersection is found.
+    \param v[x,y,z]: x,y,z-positions of the vertex.
+    \param f[x,y,z]: flight direction.
+    \param half:     -/+1 for the lower/upper VELO half in x, 0 for both.
+  */
+  TLorentzVector intersect(double vx, double vy, double vz,
+			   double fx, double fy, double fz, int half = 0);
+
+  /*
+    Return the distance. The point of minimum distance on the material
+    in uncertainty space is returned where the T (or E) component
+    gives the distance.
+    \param v[x,y,z]:    x,y,z-positions of the vertex.
+    \param d[vx,vy,vz]: x,y,z-uncertainties of the vertex position.
+    \param half:        -/+1 for the lower/upper VELO half in x, 0 for both.
+    \param method:      distance method.
+    \param dir:         minimizing z-direction: 0 both, -/+1 backwards/forward.
+    Three distance methods are implemented. (1) The minimum
+    distance. (2) The inverse of the sum of lower and upper minimum
+    distance reciprocals. (3) Same as the previous method, but now
+    rather than the minimum distances, it is summed over all distances.
+  */
+  TLorentzVector distance(double vx, double vy, double vz,
+			  double dvx = 1, double dvy = 1, double dvz = 1,
+			  int half = 0, int method = 0, int dir = 0);
+};
+
+//=============================================================================
+/*
+  Class to access the parameterized VELO material, both module and
+  foil, as implemented in the initial inclusive dimuon dark photon
+  analysis, LHCb-ANA-2017-027.
+*/
+class VeloMaterial {
+
+public:
+
+  /*
+    Default constructor.
+    \param pars: name of the fit parameters file.
+  */
+  VeloMaterial(string pars = "pars.root");
+
+  /*
+    Transform a vertex relative to the VELO for a given the run number.
+    \param year: data taking year for VELO shift, if 0 do not shift.
+    \param run:  run number for VELO shift.
+  */
+  void transform(double &vx, double &vy, double &vz, int year, int run);
+
+  /*
+    Return the distance. This is the harmonic mean of the following
+    six distances: upper module, lower module, forward upper foil,
+    forward lower foil, backward upper foil, backward lower foil.
+    \param v[x,y,z]:    x,y,z-positions of the vertex.
+    \param f[x,y,z]:    flight direction for the vertex.
+    \param f[x,y,z]1:   flight direction for the first daughter.
+    \param f[x,y,z]1:   flight direction for the second daughter.
+    \param d[vx,vy,vz]: x,y,z-uncertainties of the vertex position.
+    \param year:        data taking year for VELO shift.
+    \param run:         run number for VELO shift.
+  */
+  double distance(double vx, double vy, double vz,
+		  double fx, double fy, double fz,
+		  double fx1, double fy1, double fz1,
+		  double fx2, double fy2, double fz2,
+		  double dvx, double dvy, double dvz,
+		  int year, int run);
+  
+  /*
+    Return true if the flight direction of a vertex intersects a foil
+    tip, i.e. intersects the foil within 1 mm of where the modules are
+    located.
+    \param v[x,y,z]: x,y,z-positions of the vertex.
+    \param f[x,y,z]: flight direction.
+    \param year:     data taking year for VELO shift.
+    \param run:      run number for VELO shift.
+   */
+  bool tip(double vx, double vy, double vz,
+	   double fx, double fy, double fz,
+	   int year, int run);
+  
+  /*
+    Return true if the expected first hit is missed, given a flight direction
+    and vertex. The active area of the sensors begins at 8.170 mm.
+    \param v[x,y,z]: x,y,z-positions of the vertex.
+    \param f[x,y,z]: flight direction.
+    \param mz:       z-position of the module containing the first hit.
+    \param year:     data taking year for VELO shift.
+    \param run:      run number for VELO shift.
+  */
+  bool miss(double vx, double vy, double vz,
+	    double fx, double fy, double fz, double mz,
+	    int year, int run);
+  
+ private:
+
+  // Members.
+  FoilMaterial   foil; ///< Foil material tool.
+  ModuleMaterial modf; ///< Module material tool extended to the foil.
+  ModuleMaterial modm; ///< Module material tool with standard geometry.
+  TF1            rfnc; ///< Function used for r-dependence.
+};
+
+#endif // VELOMATERIAL_H
-- 
GitLab


From c61622acbfe70ff50ab3c02642d3edaf8768a770 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 27 Sep 2024 14:51:15 +0100
Subject: [PATCH 26/70] reduce print statements and clean up README

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py |  28 ++---
 bu2kdarkscalar_darkscalar2hh/README.md | 138 +++++++++++--------------
 bu2kdarkscalar_darkscalar2hh/job.py    |   6 +-
 3 files changed, 78 insertions(+), 94 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 7ed3d85d0b..16152ce1c8 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -344,20 +344,20 @@ class Ntuple:
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                print(f"mcp.pid is set to {mcp.pid}")
+                #print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
                     if mcp.pid in (-211, -321):
                         dptype = "hm"
-                        print(f"found mcp particle which is hm with pid {mcp.pid}")
+                        #print(f"found mcp particle which is hm with pid {mcp.pid}")
                     elif mcp.pid in (211, 321):
                         dptype = "hp" 
-                        print(f"found mcp particle which is hp with pid {mcp.pid}")
+                        #print(f"found mcp particle which is hp with pid {mcp.pid}")
                 elif dptype == "K":
                     if mcp.pid in (321, -321):
                         dptype = "K"
-                        print(f"found mcp particle which is K with pid {mcp.pid}")
+                        #print(f"found mcp particle which is K with pid {mcp.pid}")
                 pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
@@ -842,20 +842,20 @@ def fill_ntuple(
     hh: "str",
     genTool,
 ):
-    print(f"hh is {hh}")
+    #print(f"hh is {hh}")
     """Assign values to the ntuple."""
     year = int(DaVinci().DataType)
 
     def get_particles(candloc):
-        print(f"candidate_loc is {candloc}")
+        #print(f"candidate_loc is {candloc}")
         try:
             particles = tes[candloc]
             #print(particles)
             len(particles)
             size = len(particles)
-            print("found {0} particles".format(size))
+            #print("found {0} particles".format(size))
         except:
-            print("no particles found")
+            #print("no particles found")
             particles = []
         return particles
 
@@ -872,14 +872,14 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    #print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
         #print(mct)
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
-        print(f"got {len(mcpstore)} B mesons from mcp store")
+        #print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
@@ -889,20 +889,20 @@ def fill_ntuple(
     isfilled = False
   
     for all_Bparticle in all_Bparticles:
-        print("its working")
+        #print("its working")
         args, kwargs = [all_Bparticle], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
-        print("I find bool is {0}".format(boolVal))
+        #print("I find bool is {0}".format(boolVal))
 
         # if not all parricles are linked 
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
             isfilled = True
-            print("isfilled has been set to {0}".format(isfilled))
+            #print("isfilled has been set to {0}".format(isfilled))
 
     if len(all_Bparticles) > 0 and isfilled:
-        print("conditions for filling tuple met")
+        #print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
 
diff --git a/bu2kdarkscalar_darkscalar2hh/README.md b/bu2kdarkscalar_darkscalar2hh/README.md
index 053db7f67e..f31cb6f5e5 100644
--- a/bu2kdarkscalar_darkscalar2hh/README.md
+++ b/bu2kdarkscalar_darkscalar2hh/README.md
@@ -48,81 +48,65 @@ the data for the first daughter particle (prt0) would be stored at `tree.trk_<va
 
 ### List of branches added to the ntuple (INCOMPLETE)
 
-*Br    0 :tag_idx_pvr : vector       Vector for tags in the event giving the index of the associated pv in the array of associated ‘pvr’ objects found in this event. There should be one entry per tag.
-
-*Br    1 :tag_idx_prt0 : vector      Vector for tags in the event giving the index of the first daughter particle
-*Br    2 :tag_idx_prt1 : vector      …second daughter…
-
-*Br    3 :tag_pre_prt0 : vector      Vector for tags in the event giving the prefix of the first daughter (0=tag, 1=trk)
-*Br    4 :tag_pre_prt1 : vector      …second daughter…
-
-*Br    5 :tag_pid   : vector         Vector for tags in the event giving the particle ID number.
-
-*Br    6 :tag_px    : vector          x momentum of the tag
-*Br    7 :tag_py    : vector          y
-*Br    8 :tag_pz    : vector          z
-*Br    9 :tag_e     : vector          computed energy using particle ID and four-momentum
-
-*Br   10 :tag_x     : vector          x position of the endvertex associated to the tag
-*Br   11 :tag_y     : vector          y
-*Br   12 :tag_z     : vector          z
-
-*Br   13 :tag_dx    : vector          uncertainty on x position, determined from its covariance matrix
-*Br   14 :tag_dy    : vector
-*Br   15 :tag_dz    : vector
-
-*Br   16 :tag_m     : vector         mass after vertex-fit
-*Br   17 :tag_dm    : vector        ‘error’ on the vertex fit mass
-
-
-*Br   18 :tag_mm    : vector        ‘measured-mass’ (i.e. before vertex fit)
-*Br   19 :tag_dm    : vector        ‘error’ on the measured mass
-
-*Br   20 :tag_doca  : vector        maximum doca between the momenta of the daughters of this vertex
-*Br   21 :tag_chi2  : vector        chi2 of the vertex fit
-
-*Br   20 :tag_dtf_chi2 : vector   chi2 of the DTF refit which requires that the particle should originate from its PV. -1 if fails
-
-*Br   21 :tag_ip    : vector           use loki distance calculator to find IP wrt associated PV
-*Br   22 :tag_ip_chi2 : vector    chi2 of that IP
-
-*Br   23 :tag_fd    : vector          uses same calculator to find distance between this vertex and pv
-*Br   24 :tag_fd_chi2 : vector     chi2 of that FD
-
-*Br   25 :tag_vt_tip : vector        returns true if flight distance of a vertex intercepts a foil tip
-*Br   26 :tag_vt_d  : vector         (offset, uncertainty weighted, scaled) material distance
-*Br   27 :tag_tos0  : vector         the index corresponds to the L0, Hlt1, or Hlt2 triggers
-*Br   31 :tag_tis0  : vector          ???
-
-*Br   32 :trk_idx_pvr : vector         index of the associated pvr in the list of pvr’s found for this event
-*Br   33 :trk_pid   : vector              pid of the charged particles: always 11 (electron)
-*Br   34 :trk_px    : vector           momentum component before any refitting
-*Br   35 :trk_py    : vector
-*Br   36 :trk_pz    : vector
-*Br   37 :trk_e     : vector
-*Br   38 :trk_pnn_e : vector        probnne
-*Br   39 :trk_pnn_pi : vector       probnnpi
-*Br   40 :trk_pnn_ghost : vector probnnghost
-*Br   41 :trk_ip    : vector            ip with respect to associated PV, calculated using the LoKi distance calculator
-*Br   42 :trk_ip_chi2 : vector      ipchi2 as above
-*Br   43 :trk_vt_miss : vector     returns true if the expected first hit of a track is missed, given a flight direction and vertex
-
-*Br   44 :trk_x0    : vector           ??? position for first hit in the VELO
-*Br   45 :trk_y0    : vector            y…
-*Br   46 :trk_z0    : vector            z…
-*Br   47 :trk_t0    : vector
-*Br   48 :trk_p0    : vector
-
-*Br   49 :trk_x1    : vector           ??? position for second hit in the VELO
-*Br   50 :trk_y1    : vector
-*Br   51 :trk_z1    : vector
-*Br   52 :trk_t1    : vector
-*Br   53 :trk_p1    : vector
-
-*Br   59 :pvr_x     : vector            position and uncertainty on any associated primary vertex related to a filled particle
-*Br   60 :pvr_y     : vector
-*Br   61 :pvr_z     : vector
-*Br   62 :pvr_dx    : vector
-*Br   63 :pvr_dy    : vector
-*Br   64 :pvr_dz    : vector
+| Branch Number | Branch Name   | Associated Data Type | Description |
+|:----:|:-------------:|:------:|:----------------------------------:|
+|    0 | tag_idx_pvr   | vector | each element of vector corresponds to a tag in the event and gives the index of the tag's associated PV in the array of associated ‘pvr’ objects found in this event. There should be one entry per tag! |
+|    1 | tag_idx_prt0  | vector | each element of vector corresponds to a tag in the event and gives the index of the first daughter particle |
+|    2 | tag_idx_prt1 | vector | each element of vector corresponds to a tag in the event and gives the index of the second daughter particle |
+|    3 | tag_pre_prt0 | vector | each element of vector corresponds to a tag in the event and gives the prefix of the first daughter (0=tag, 1=trk) |
+|    4 | tag_pre_prt1 | vector | each element of vector corresponds to a tag in the event and gives the prefix of the second daughter (0=tag, 1=trk) |
+|    5 | tag_pid   | vector | each element of vector corresponds to a tag in the event and gives the particle ID number of that tag |
+|    6 | tag_px    | vector | x momentum of the tag |
+|    7 | tag_py    | vector | y momentum of the tag |
+|    8 | tag_pz    | vector | z momentum of the tag |
+|    9 | tag_e     | vector | computed energy using particle ID and four-momentum of the tag |
+|   10 | tag_x     | vector | x position of the end vertex associated to the tag |
+|   11 | tag_y     | vector | y position of the end vertex associated to the tag |
+|   12 | tag_z     | vector | z position of the end vertex associated to the tag |
+|   13 | tag_dx    | vector | uncertainty on x position of the end vertex associated to the tag, determined from its covariance matrix |
+|   14 | tag_dy    | vector | uncertainty on y position of the end vertex associated to the tag, determined from its covariance matrix |
+|   15 | tag_dz    | vector | uncertainty on z position of the end vertex associated to the tag, determined from its covariance matrix |
+|   16 | tag_m     | vector | mass after vertex fit |
+|   17 | tag_dm    | vector | uncertainty on the vertex fit mass |
+|   18 | tag_mm    | vector | measured mass (i.e. before vertex fit) |
+|   19 | tag_dm    | vector | uncertainty on the measured mass |
+|   20 | tag_doca  | vector | maximum doca between the momenta of the daughters of tag |
+|   21 | tag_chi2  | vector | chi2 of the vertex fit |
+|   20 | tag_dtf_chi2 | vector | chi2 of the DTF refit which requires that the particle should originate from its PV. -1 if fails |
+|   21 | tag_ip    | vector | use LoKi distance calculator to find IP wrt associated PV |
+|   22 | tag_ip_chi2 | vector | chi2 of IP |
+|   23 | tag_fd    | vector | use LoKi distance calculator to find distance between this vertex and PV |
+|   24 | tag_fd_chi2 | vector | chi2 of flight distance |
+|   25 | tag_vt_tip | vector | returns true if flight distance of a vertex intercepts a foil tip |
+|   26 | tag_vt_d  | vector | (offset, uncertainty weighted, scaled) material distance |
+|   27 | tag_tos0  | vector |        the index corresponds to the L0, Hlt1, or Hlt2 triggers
+|   31 | tag_tis0  | vector |         ???
+|   32 | trk_idx_pvr | vector |        index of the associated pvr in the list of pvr’s found for this event
+|   33 | trk_pid   | vector | pid of the charged particle tracks (should be pion or kaon) |
+|   34 | trk_px    | vector | x 4-momentum component before any refitting |
+|   35 | trk_py    | vector | y 4-momentum component before any refitting |
+|   36 | trk_pz    | vector | z 4-momentum component before any refitting |
+|   37 | trk_e     | vector | energy 4-momentum component before any refitting |
+|   38 | trk_pnn_e | vector | probnne |
+|   39 | trk_pnn_pi | vector | probnnpi |
+|   40 | trk_pnn_ghost | vector | probnnghost |
+|   41 | trk_ip    | vector | IP with respect to associated PV, calculated using the LoKi distance calculator
+|   42 | trk_ip_chi2 | vector |     ipchi2 as above
+|   43 | trk_vt_miss | vector |    returns true if the expected first hit of a track is missed, given a flight direction and vertex
+|   44 | trk_x0    | vector | x position of first hit in the VELO |
+|   45 | trk_y0    | vector | y position of first hit in the VELO |
+|   46 | trk_z0    | vector | z position of first hit in the VELO |
+|   47 | trk_t0    | vector | time position of first hit in the VELO |
+|   48 | trk_p0    | vector | momentum of first hit in the VELO |
+|   49 | trk_x1    | vector | x position of second hit in the VELO |
+|   50 | trk_y1    | vector | y position of second hit in the VELO |
+|   51 | trk_z1    | vector | z position of second hit in the VELO |
+|   52 | trk_t1    | vector | time position of second hit in the VELO |
+|   53 | trk_p1    | vector | momentum position of second hit in the VELO |
+|   59 | pvr_x     | vector | x position of any associated primary vertex related to a filled particle |
+|   60 | pvr_y     | vector | y position of any associated primary vertex related to a filled particle|
+|   61 | pvr_z     | vector | z position of any associated primary vertex related to a filled particle|
+|   62 | pvr_dx    | vector | uncertainty on x positon of any associated primary vertex related to a filled particle |
+|   63 | pvr_dy    | vector | uncertainty on y positon of any associated primary vertex related to a filled particle |
+|   64 | pvr_dz    | vector | uncertainty on z positon of any associated primary vertex related to a filled particle |
 
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 4f83d69785..fb7c28691f 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -93,7 +93,7 @@ try:
     shutil.copy(this_dir / "pars.root", Path.cwd())
 except ModuleNotFoundError:
     NOfEvents = DaVinci().EvtMax
-    print(f"number of events is {NOfEvents}")
+    #print(f"number of events is {NOfEvents}")
     output_filename = DaVinci().TupleFile
 
 # FIXME: Turn off lumi tuple or it overwrites ntuple. Cleverer solution possible
@@ -155,10 +155,10 @@ while (NOfEvents == -1) or (event < NOfEvents):
     if not bool(tes["/Event"]):
         break
     event += 1
-    print(f"found event {event}")
+    #print(f"found event {event}")
 
     fill_ntuple(ntuple, tes, candloc, hh, genTool)
-    print("filled")
+    #print("filled")
 
 
 # Close.
-- 
GitLab


From a8cf00e26c19154b8c1ae9a53c46fe71db7bad11 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 2 Oct 2024 18:06:57 +0100
Subject: [PATCH 27/70] comment out print statements

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 46 ++++++++++----------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 45e2273fdf..8f9afeb0c6 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -184,7 +184,7 @@ class MCEvent:
                of MCEvent [bool]
         Bs  : list of combined all_Bs with daughter particles in daughter list [list(MCPart)]
         """
-        print(f"hh is {hh}")
+        #print(f"hh is {hh}")
         self.hcuts = False
         self.links = False
         self.iscategorized = False
@@ -205,7 +205,7 @@ class MCEvent:
                     for ddp in dp.endVertex().outgoingParticlesVector():
                         hadron = MCPart(ddp)
                         hadron.update(newpnnk=PROBNNk(ddp),newpnnpi=PROBNNpi(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
-                        print(hadron.pid)
+                        #print(hadron.pid)
 
                         if hh == "KK":
                             hhPID = 321
@@ -218,7 +218,7 @@ class MCEvent:
                     dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
             B = MCPart(all_B,dl=dps)
             self.Bs += [B]
-            print(f"self.Bs is {self.Bs}")
+            #print(f"self.Bs is {self.Bs}")
 
     def linkpars(self):
         """
@@ -254,12 +254,12 @@ class MCEvent:
                 if MCID(rel_K) == B.dl[1].pid: B.dl[1].update(newclink=True)
                 else: B.dl[1].update(newclink=False)
 
-            print(f"type of B dl dl is {type(B.dl[0].dl[0])}")
-            print(f"type of B is {type(B)}")
-            print(f"type is {type(B.dl[0])}")
-            print(f"B dl is {B.dl}")
-            print(f"B dl dl is {B.dl[0].dl}")
-            print(f"B is {B}")
+            #print(f"type of B dl dl is {type(B.dl[0].dl[0])}")
+            #print(f"type of B is {type(B)}")
+            #print(f"type is {type(B.dl[0])}")
+            #print(f"B dl is {B.dl}")
+            #print(f"B dl dl is {B.dl[0].dl}")
+            #print(f"B is {B}")
             rels = self.mctool.relatedMCPs(B.dl[0].dl[0].par)
             w = 0
             rel_hadron_minus = None
@@ -375,36 +375,36 @@ class MCEvent:
         if not self.links: self.linkpars()
 
         for B in self.Bs:
-            print("looping over Bs")
+            #print("looping over Bs")
             if not B.alllinked:
-                print("not all Bs are linked")
+                #print("not all Bs are linked")
                 for recp in [B.dl[1],B.dl[0].dl[0],B.dl[0].dl[1]]:
-                    print("looping over recps")
+                    #print("looping over recps")
                     if not recp.lpar:
-                        print("if recp has no linked particle")
+                        #print("if recp has no linked particle")
                         mindr = 99999999999
                         parlink = None
-                        print(f"mcp store is {mcpstore}")
+                        #print(f"mcp store is {mcpstore}")
                         #print(f"mcp store contains {len(mcpstore)} mc particles")
                         thereExistsMCPIDequalRECPID = False
                         for mcp in mcpstore:
-                            print(f"mc particle is {mcp}")
-                            print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
+                            #print(f"mc particle is {mcp}")
+                            #print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
                             if MCID(mcp) == recp.pid:
                                 thereExistsMCPIDequalRECPID = True
-                                print("mc pid is same as rec particle pid")
+                                #print("mc pid is same as rec particle pid")
                                 dphi = MCPHI(mcp) - PHI(recp.par)
                                 deta = MCETA(mcp) - ETA(recp.par)
                                 deltar = sqrt(dphi**2 + deta**2)
-                                print(f"deltar is {deltar}")
-                                print(f"mindr is {mindr}")
+                                #print(f"deltar is {deltar}")
+                                #print(f"mindr is {mindr}")
                                 if deltar < mindr: 
                                     mindr = deltar
-                                    print(f"mindr is {mindr}")
+                                    #print(f"mindr is {mindr}")
                                     parlink = mcp
-                                    print(f"parlink is {parlink}")
+                                    #print(f"parlink is {parlink}")
                         if thereExistsMCPIDequalRECPID == False:
-                            print("no mc particle with same pid as rec particle")
+                            #print("no mc particle with same pid as rec particle")
                             break
                         recp.update(newlpar=MCPart(parlink,orvrt=parlink.originVertex().type()))
                         if MCID(parlink) == recp.pid: recp.update(newclink=True)
@@ -425,7 +425,7 @@ class MCEvent:
                 # i guess L418 shouldn't be being called - is this checking if all particles have been linked?
                 # in which case we should be checking if all particles have been linked to the same particle type
                 if thereExistsMCPIDequalRECPID == False:
-                    print("no mc particle with same pid as rec particle")
+                    #print("no mc particle with same pid as rec particle")
                     break
 
                 if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar: 
-- 
GitLab


From 1c7acaedb6a6ab98c2b5445d8c8bdf7664e43790 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 4 Oct 2024 13:32:38 +0100
Subject: [PATCH 28/70] selreports not found for mc, comment out for now

---
 bu2kdarkscalar_darkscalar2hh/job.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index fb7c28691f..4f76ad366f 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -133,7 +133,8 @@ for stage in ("Hlt1", "Hlt2", "Strip/Phys"):
     ToolSvc().addTool(TriggerTisTos, stage + "TriggerTisTos")
     tool = getattr(ToolSvc(), stage + "TriggerTisTos")
     tool.HltDecReportsLocation = f"/Event/{stage}/DecReports"
-    tool.HltSelReportsLocation = f"/Event/{stage}/SelReports"
+    if not DaVinci().Simulation:
+       tool.HltSelReportsLocation = f"/Event/{stage}/SelReports"
 
 # =================================================================================
 # Run.
-- 
GitLab


From 1e6b548c65adf50058f55b5d9efa7c61f24b96d7 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 7 Oct 2024 14:31:02 +0100
Subject: [PATCH 29/70] minor

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

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 4f76ad366f..fb7c28691f 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -133,8 +133,7 @@ for stage in ("Hlt1", "Hlt2", "Strip/Phys"):
     ToolSvc().addTool(TriggerTisTos, stage + "TriggerTisTos")
     tool = getattr(ToolSvc(), stage + "TriggerTisTos")
     tool.HltDecReportsLocation = f"/Event/{stage}/DecReports"
-    if not DaVinci().Simulation:
-       tool.HltSelReportsLocation = f"/Event/{stage}/SelReports"
+    tool.HltSelReportsLocation = f"/Event/{stage}/SelReports"
 
 # =================================================================================
 # Run.
-- 
GitLab


From 92cc67a16d5f5cd816f5ce2d96f2500b36d2c167 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 11 Oct 2024 16:14:09 +0100
Subject: [PATCH 30/70] new jobs

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 27 ++------------------------
 1 file changed, 2 insertions(+), 25 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index acd6d538d9..fe7ae9b3b4 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,6 +1,5 @@
 {%- set polarities = ["Down", "Up"]%}
-{%- set datasets = ["PiPi", "KK"]%}
-{%- set MCdatasets = [('PiPi', 18, 12103024, 6500, '18', '34NoPrescalingFlagged')]%}
+{%- set MCdatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged')]%}
 
 {%- for polarity in polarities %}
 {%- for hh, year, eventnumber, energy, reco, strip in MCdatasets %}
@@ -13,7 +12,7 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   inform:
     - eleanor.whiter@cern.ch
   input:
-     bk_query: /MC/20{{year}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim09h/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/{{eventnumber}}/ALLSTREAMS.MDST
+     bk_query: /MC/20{{year}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim10d/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/{{eventnumber}}/ALLSTREAMS.MDST
   options:
      command:
       - python
@@ -24,26 +23,4 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
 
 {%- endfor %}
 
-
-{%- for hh in datasets %}
-
-my_B2KDarkScalar_DarkScalar2{{hh}}_2018_Mag{{polarity}}_Data_job:
-  application: DaVinci/v46r8
-  wg: QEE
-  automatically_configure: yes
-  turbo: no
-  inform:
-    - eleanor.whiter@cern.ch
-  input:
-    bk_query: "/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34r0p1/90000000/LEPTONIC.MDST"
-  options:
-    command:
-      - python
-    files:
-      - job.py
-      - hh_{{hh}}.py
-  output: b2kdarkscalar.root
-
-{%- endfor %}
-
 {%- endfor %}
\ No newline at end of file
-- 
GitLab


From 82789f3f142e444cc906f92256ad9fd715297270 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 6 Nov 2024 10:43:01 +0000
Subject: [PATCH 31/70] tweaks

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py |  2 ++
 bu2kdarkscalar_darkscalar2hh/info.yaml       | 27 +++++++++++++++++++-
 bu2kdarkscalar_darkscalar2hh/job.py          |  6 +++--
 3 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 8f9afeb0c6..2cc6a3d58f 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -535,6 +535,8 @@ class MCEvent:
                     if K.lpar.mother == hadron_minus.lpar.mother.mother.par == hadron_plus.lpar.mother.mother.par: # Check K, hm and hp all came from the same particle
                        if abs(K.lpar.mother.pid) == 521: # check this was a B
                           self.dec: B.update(newbgtype=0)
+
+                else: B.update(newbgtype=9)
                     
 
 
diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index fe7ae9b3b4..455cfcbfaf 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,5 +1,10 @@
 {%- set polarities = ["Down", "Up"]%}
-{%- set MCdatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged')]%}
+{%- set MCdatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged'),
+                      ('KK', 18, 12103047, 6500, '18', '34NoPrescalingFlagged'),
+                      ('KK', 18, 12103056, 6500, '18', '34NoPrescalingFlagged')]%}
+
+
+/MC/2018/12103047/Beam6500GeV-2018-MagDown-Nu1.6-25ns-Pythia8/Sim10d/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/ALLSTREAMS.MDST
 
 {%- for polarity in polarities %}
 {%- for hh, year, eventnumber, energy, reco, strip in MCdatasets %}
@@ -23,4 +28,24 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
 
 {%- endfor %}
 
+
+my_B2KDarkScalar_DarkScalar2{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
+  application: DaVinci/v46r8
+  wg: QEE
+  automatically_configure: yes
+  turbo: no
+  inform:
+    - eleanor.whiter@cern.ch
+  input:
+     bk_query: /MC/20{{year}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim10d/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/{{eventnumber}}/ALLSTREAMS.MDST
+  options:
+     command:
+      - python
+     files:
+      - job.py
+      - hh_{{hh}}.py
+  output: b2kdarkscalar_darkscalar2hh.root
+
+{%- endfor %}
+
 {%- endfor %}
\ No newline at end of file
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index fb7c28691f..96467ab384 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -121,9 +121,11 @@ elif DaVinci().InputType == "DST":
    stream = 'AllStreams' """
 
 if hh == "KK":
-    candloc = '/Event/' + stream + '/Phys/B2KX2KKDarkBosonLine/Particles'
+    line ='B2KX2KKDarkBosonLine'
 elif hh == "PiPi":
-    candloc = '/Event/' + stream + '/Phys/B2KX2PiPiDarkBosonLine/Particles'
+    line = 'B2KX2PiPiDarkBosonLine'
+
+candloc = '/Event/' + stream + '/Phys/' + line + '/Particles'
 
 print(f"Using candidate location: {candloc}")
 
-- 
GitLab


From 914d9fa26ad4f5e3e073994a03ef1aad756428f6 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 6 Nov 2024 10:50:21 +0000
Subject: [PATCH 32/70] change format

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 455cfcbfaf..4c2e93d1c3 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,13 +1,13 @@
 {%- set polarities = ["Down", "Up"]%}
-{%- set MCdatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged'),
-                      ('KK', 18, 12103047, 6500, '18', '34NoPrescalingFlagged'),
+{%- set MCnormalisationDatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged')]%}
+{%- set MCsignalDatasets = [('KK', 18, 12103047, 6500, '18', '34NoPrescalingFlagged'),
                       ('KK', 18, 12103056, 6500, '18', '34NoPrescalingFlagged')]%}
 
 
 /MC/2018/12103047/Beam6500GeV-2018-MagDown-Nu1.6-25ns-Pythia8/Sim10d/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/ALLSTREAMS.MDST
 
 {%- for polarity in polarities %}
-{%- for hh, year, eventnumber, energy, reco, strip in MCdatasets %}
+{%- for hh, year, eventnumber, energy, reco, strip in MCnormalisationDatasets %}
 
 my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   application: DaVinci/v46r8
@@ -28,6 +28,7 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
 
 {%- endfor %}
 
+{%- for hh, year, eventnumber, energy, reco, strip in MCsignalDatasets %}
 
 my_B2KDarkScalar_DarkScalar2{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   application: DaVinci/v46r8
-- 
GitLab


From 742d3dd23f1ac11363885d526a2b62156d67737f Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 6 Nov 2024 11:09:35 +0000
Subject: [PATCH 33/70] fix

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 4c2e93d1c3..d9a2b7d37a 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,10 +1,9 @@
 {%- set polarities = ["Down", "Up"]%}
 {%- set MCnormalisationDatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged')]%}
 {%- set MCsignalDatasets = [('KK', 18, 12103047, 6500, '18', '34NoPrescalingFlagged'),
-                      ('KK', 18, 12103056, 6500, '18', '34NoPrescalingFlagged')]%}
+                            ('PiPi', 18, 12103056, 6500, '18', '34NoPrescalingFlagged')]%}
 
 
-/MC/2018/12103047/Beam6500GeV-2018-MagDown-Nu1.6-25ns-Pythia8/Sim10d/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/ALLSTREAMS.MDST
 
 {%- for polarity in polarities %}
 {%- for hh, year, eventnumber, energy, reco, strip in MCnormalisationDatasets %}
-- 
GitLab


From 73e6a7cb6f95cd823109f8fcc470b9b0894a66a5 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 11 Nov 2024 15:45:24 +0000
Subject: [PATCH 34/70] test

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index d9a2b7d37a..ae377d3eec 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -3,8 +3,6 @@
 {%- set MCsignalDatasets = [('KK', 18, 12103047, 6500, '18', '34NoPrescalingFlagged'),
                             ('PiPi', 18, 12103056, 6500, '18', '34NoPrescalingFlagged')]%}
 
-
-
 {%- for polarity in polarities %}
 {%- for hh, year, eventnumber, energy, reco, strip in MCnormalisationDatasets %}
 
-- 
GitLab


From cee258e09a1fc1a910681204b02abbe5c893d61c Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 12 Nov 2024 10:26:12 +0000
Subject: [PATCH 35/70] debug

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 48 ++++++++++----------
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 32 ++++++-------
 bu2kdarkscalar_darkscalar2hh/job.py          |  6 +--
 3 files changed, 43 insertions(+), 43 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 2cc6a3d58f..a0eca08aac 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -184,7 +184,7 @@ class MCEvent:
                of MCEvent [bool]
         Bs  : list of combined all_Bs with daughter particles in daughter list [list(MCPart)]
         """
-        #print(f"hh is {hh}")
+        print(f"hh is {hh}")
         self.hcuts = False
         self.links = False
         self.iscategorized = False
@@ -205,7 +205,7 @@ class MCEvent:
                     for ddp in dp.endVertex().outgoingParticlesVector():
                         hadron = MCPart(ddp)
                         hadron.update(newpnnk=PROBNNk(ddp),newpnnpi=PROBNNpi(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
-                        #print(hadron.pid)
+                        print(hadron.pid)
 
                         if hh == "KK":
                             hhPID = 321
@@ -218,7 +218,7 @@ class MCEvent:
                     dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
             B = MCPart(all_B,dl=dps)
             self.Bs += [B]
-            #print(f"self.Bs is {self.Bs}")
+            print(f"self.Bs is {self.Bs}")
 
     def linkpars(self):
         """
@@ -254,12 +254,12 @@ class MCEvent:
                 if MCID(rel_K) == B.dl[1].pid: B.dl[1].update(newclink=True)
                 else: B.dl[1].update(newclink=False)
 
-            #print(f"type of B dl dl is {type(B.dl[0].dl[0])}")
-            #print(f"type of B is {type(B)}")
-            #print(f"type is {type(B.dl[0])}")
-            #print(f"B dl is {B.dl}")
-            #print(f"B dl dl is {B.dl[0].dl}")
-            #print(f"B is {B}")
+            print(f"type of B dl dl is {type(B.dl[0].dl[0])}")
+            print(f"type of B is {type(B)}")
+            print(f"type is {type(B.dl[0])}")
+            print(f"B dl is {B.dl}")
+            print(f"B dl dl is {B.dl[0].dl}")
+            print(f"B is {B}")
             rels = self.mctool.relatedMCPs(B.dl[0].dl[0].par)
             w = 0
             rel_hadron_minus = None
@@ -375,36 +375,36 @@ class MCEvent:
         if not self.links: self.linkpars()
 
         for B in self.Bs:
-            #print("looping over Bs")
+            print("looping over Bs")
             if not B.alllinked:
-                #print("not all Bs are linked")
+                print("not all Bs are linked")
                 for recp in [B.dl[1],B.dl[0].dl[0],B.dl[0].dl[1]]:
-                    #print("looping over recps")
+                    print("looping over recps")
                     if not recp.lpar:
-                        #print("if recp has no linked particle")
+                        print("if recp has no linked particle")
                         mindr = 99999999999
                         parlink = None
-                        #print(f"mcp store is {mcpstore}")
-                        #print(f"mcp store contains {len(mcpstore)} mc particles")
+                        print(f"mcp store is {mcpstore}")
+                        print(f"mcp store contains {len(mcpstore)} mc particles")
                         thereExistsMCPIDequalRECPID = False
                         for mcp in mcpstore:
-                            #print(f"mc particle is {mcp}")
-                            #print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
+                            print(f"mc particle is {mcp}")
+                            print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
                             if MCID(mcp) == recp.pid:
                                 thereExistsMCPIDequalRECPID = True
-                                #print("mc pid is same as rec particle pid")
+                                print("mc pid is same as rec particle pid")
                                 dphi = MCPHI(mcp) - PHI(recp.par)
                                 deta = MCETA(mcp) - ETA(recp.par)
                                 deltar = sqrt(dphi**2 + deta**2)
-                                #print(f"deltar is {deltar}")
-                                #print(f"mindr is {mindr}")
+                                print(f"deltar is {deltar}")
+                                print(f"mindr is {mindr}")
                                 if deltar < mindr: 
                                     mindr = deltar
-                                    #print(f"mindr is {mindr}")
+                                    print(f"mindr is {mindr}")
                                     parlink = mcp
-                                    #print(f"parlink is {parlink}")
+                                    print(f"parlink is {parlink}")
                         if thereExistsMCPIDequalRECPID == False:
-                            #print("no mc particle with same pid as rec particle")
+                            print("no mc particle with same pid as rec particle")
                             break
                         recp.update(newlpar=MCPart(parlink,orvrt=parlink.originVertex().type()))
                         if MCID(parlink) == recp.pid: recp.update(newclink=True)
@@ -425,7 +425,7 @@ class MCEvent:
                 # i guess L418 shouldn't be being called - is this checking if all particles have been linked?
                 # in which case we should be checking if all particles have been linked to the same particle type
                 if thereExistsMCPIDequalRECPID == False:
-                    #print("no mc particle with same pid as rec particle")
+                    print("no mc particle with same pid as rec particle")
                     break
 
                 if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar: 
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 16152ce1c8..a841c1285c 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -344,20 +344,20 @@ class Ntuple:
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                #print(f"mcp.pid is set to {mcp.pid}")
+                print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
                     if mcp.pid in (-211, -321):
                         dptype = "hm"
-                        #print(f"found mcp particle which is hm with pid {mcp.pid}")
+                        print(f"found mcp particle which is hm with pid {mcp.pid}")
                     elif mcp.pid in (211, 321):
                         dptype = "hp" 
-                        #print(f"found mcp particle which is hp with pid {mcp.pid}")
+                        print(f"found mcp particle which is hp with pid {mcp.pid}")
                 elif dptype == "K":
                     if mcp.pid in (321, -321):
                         dptype = "K"
-                        #print(f"found mcp particle which is K with pid {mcp.pid}")
+                        print(f"found mcp particle which is K with pid {mcp.pid}")
                 pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
@@ -842,20 +842,20 @@ def fill_ntuple(
     hh: "str",
     genTool,
 ):
-    #print(f"hh is {hh}")
+    print(f"hh is {hh}")
     """Assign values to the ntuple."""
     year = int(DaVinci().DataType)
 
     def get_particles(candloc):
-        #print(f"candidate_loc is {candloc}")
+        print(f"candidate_loc is {candloc}")
         try:
             particles = tes[candloc]
-            #print(particles)
+            print(particles)
             len(particles)
             size = len(particles)
-            #print("found {0} particles".format(size))
+            print("found {0} particles".format(size))
         except:
-            #print("no particles found")
+            print("no particles found")
             particles = []
         return particles
 
@@ -872,14 +872,14 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    #print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
-        #print(mct)
+        print(mct)
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
-        #print(f"got {len(mcpstore)} B mesons from mcp store")
+        print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
@@ -889,20 +889,20 @@ def fill_ntuple(
     isfilled = False
   
     for all_Bparticle in all_Bparticles:
-        #print("its working")
+        print("its working")
         args, kwargs = [all_Bparticle], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
-        #print("I find bool is {0}".format(boolVal))
+        print("I find bool is {0}".format(boolVal))
 
         # if not all parricles are linked 
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
             isfilled = True
-            #print("isfilled has been set to {0}".format(isfilled))
+            print("isfilled has been set to {0}".format(isfilled))
 
     if len(all_Bparticles) > 0 and isfilled:
-        #print("conditions for filling tuple met")
+        print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
 
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 96467ab384..b33ad14a7c 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -93,7 +93,7 @@ try:
     shutil.copy(this_dir / "pars.root", Path.cwd())
 except ModuleNotFoundError:
     NOfEvents = DaVinci().EvtMax
-    #print(f"number of events is {NOfEvents}")
+    print(f"number of events is {NOfEvents}")
     output_filename = DaVinci().TupleFile
 
 # FIXME: Turn off lumi tuple or it overwrites ntuple. Cleverer solution possible
@@ -157,10 +157,10 @@ while (NOfEvents == -1) or (event < NOfEvents):
     if not bool(tes["/Event"]):
         break
     event += 1
-    #print(f"found event {event}")
+    print(f"found event {event}")
 
     fill_ntuple(ntuple, tes, candloc, hh, genTool)
-    #print("filled")
+    print("filled")
 
 
 # Close.
-- 
GitLab


From 84aebcc6a5b9ab370d1e21442a8b9f6746ec0f09 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 18 Nov 2024 09:57:51 +0000
Subject: [PATCH 36/70] add break statement to stop multiple linking

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 70 ++++++++++++--------
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 32 ++++-----
 bu2kdarkscalar_darkscalar2hh/job.py          |  8 +--
 3 files changed, 62 insertions(+), 48 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index a0eca08aac..69ca1317ff 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -184,7 +184,7 @@ class MCEvent:
                of MCEvent [bool]
         Bs  : list of combined all_Bs with daughter particles in daughter list [list(MCPart)]
         """
-        print(f"hh is {hh}")
+        #(f"hh is {hh}")
         self.hcuts = False
         self.links = False
         self.iscategorized = False
@@ -205,7 +205,7 @@ class MCEvent:
                     for ddp in dp.endVertex().outgoingParticlesVector():
                         hadron = MCPart(ddp)
                         hadron.update(newpnnk=PROBNNk(ddp),newpnnpi=PROBNNpi(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
-                        print(hadron.pid)
+                        #print(hadron.pid)
 
                         if hh == "KK":
                             hhPID = 321
@@ -218,7 +218,7 @@ class MCEvent:
                     dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
             B = MCPart(all_B,dl=dps)
             self.Bs += [B]
-            print(f"self.Bs is {self.Bs}")
+            #print(f"self.Bs is {self.Bs}")
 
     def linkpars(self):
         """
@@ -231,7 +231,9 @@ class MCEvent:
         """
         self.allreglinked = True
         for B in self.Bs:
-            rels = self.mctool.relatedMCPs(B.dl[1].par)
+            rels = self.mctool.relatedMCPs(B.dl[1].par, '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles')
+            #rels = self.mctool.relatedMCPs()
+            #print(f"rels is {rels}")
             w = 0
             rel_K = None
             for rel in rels:
@@ -254,13 +256,7 @@ class MCEvent:
                 if MCID(rel_K) == B.dl[1].pid: B.dl[1].update(newclink=True)
                 else: B.dl[1].update(newclink=False)
 
-            print(f"type of B dl dl is {type(B.dl[0].dl[0])}")
-            print(f"type of B is {type(B)}")
-            print(f"type is {type(B.dl[0])}")
-            print(f"B dl is {B.dl}")
-            print(f"B dl dl is {B.dl[0].dl}")
-            print(f"B is {B}")
-            rels = self.mctool.relatedMCPs(B.dl[0].dl[0].par)
+            rels = self.mctool.relatedMCPs(B.dl[0].dl[0].par, '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles')
             w = 0
             rel_hadron_minus = None
             for rel in rels:
@@ -282,7 +278,7 @@ class MCEvent:
                 if MCID(rel_hadron_minus) == B.dl[0].dl[0].pid: B.dl[0].dl[0].update(newclink=True)
                 else: B.dl[0].dl[0].update(newclink=False)
 
-            rels = self.mctool.relatedMCPs(B.dl[0].dl[1].par)
+            rels = self.mctool.relatedMCPs(B.dl[0].dl[1].par, '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles')
             w = 0
             rel_hadron_plus = None
             for rel in rels:
@@ -372,39 +368,44 @@ class MCEvent:
         self: MCEvent instance
         mcpstore: list of MC particles from the TES
         """
-        if not self.links: self.linkpars()
+        if not self.links: self.linkpars() # if haven't run linkpars run it
 
+        count = 1
         for B in self.Bs:
-            print("looping over Bs")
+            #print(f"looping over number {count} B particles stored in stripping line")
+            count += 1
             if not B.alllinked:
-                print("not all Bs are linked")
+                #print("not all Bs are linked to MC particles already by linkpars so we need delta r matching") 
+                recpcount = 0
                 for recp in [B.dl[1],B.dl[0].dl[0],B.dl[0].dl[1]]:
-                    print("looping over recps")
+                    #print(f"looping over {recpcount} recps")
+                    recpcount += 1
                     if not recp.lpar:
-                        print("if recp has no linked particle")
+                        #print(f"if {abs(recp.pid)} has no linked particle")
                         mindr = 99999999999
                         parlink = None
-                        print(f"mcp store is {mcpstore}")
-                        print(f"mcp store contains {len(mcpstore)} mc particles")
+                        #print(f"mcp store is {mcpstore}")
+                        #print(f"mcp store contains {len(mcpstore)} mc particles")
                         thereExistsMCPIDequalRECPID = False
                         for mcp in mcpstore:
-                            print(f"mc particle is {mcp}")
-                            print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
+                            #print(f"mc particle is {mcp}")
+                            #print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
                             if MCID(mcp) == recp.pid:
                                 thereExistsMCPIDequalRECPID = True
-                                print("mc pid is same as rec particle pid")
+                                #print("found mc particle with same pid is same as rec particle pid")
                                 dphi = MCPHI(mcp) - PHI(recp.par)
                                 deta = MCETA(mcp) - ETA(recp.par)
                                 deltar = sqrt(dphi**2 + deta**2)
-                                print(f"deltar is {deltar}")
-                                print(f"mindr is {mindr}")
+                                #print(f"deltar is {deltar}")
+                                #print(f"mindr is {mindr}")
                                 if deltar < mindr: 
                                     mindr = deltar
-                                    print(f"mindr is {mindr}")
+                                    #print(f"mindr is {mindr}")
                                     parlink = mcp
-                                    print(f"parlink is {parlink}")
+                                    #print(f"assign the rec particle this mc particle which is {parlink}")
+                                    break
                         if thereExistsMCPIDequalRECPID == False:
-                            print("no mc particle with same pid as rec particle")
+                            #print("no mc particle with same pid as rec particle")
                             break
                         recp.update(newlpar=MCPart(parlink,orvrt=parlink.originVertex().type()))
                         if MCID(parlink) == recp.pid: recp.update(newclink=True)
@@ -413,22 +414,29 @@ class MCEvent:
                             try:
                                 parlink.mother().originVertex().type()
                                 recp.lpar.update(newmother=MCPart(parlink.mother(),orvrt=parlink.mother().originVertex().type()))
+                                if parlink.mother().originVertex().type() == 1:
+                                    #print("WARNING mother has origin vertex from pp collision")
                                 if parlink.mother().originVertex().type() != 1:
+                                    print("mother has origin vertex type != 1. i.e. not from pp collision")
                                     try:
                                         parlink.mother().mother().originVertex().type()
                                         recp.lpar.mother.update(newmother=MCPart(parlink.mother().mother(),orvrt=parlink.mother().mother().originVertex().type()))
+                                        #print("updating mother")
+                                        #print(f"mother of {recp.pid} is {recp.lpar.mother}")
                                     except:
                                         recp.lpar.mother.update(newmother=None)
+                                        #print("WARNING recp has no mother")
                             except:
                                 recp.lpar.update(newmother=None)
 
                 # i guess L418 shouldn't be being called - is this checking if all particles have been linked?
                 # in which case we should be checking if all particles have been linked to the same particle type
                 if thereExistsMCPIDequalRECPID == False:
-                    print("no mc particle with same pid as rec particle")
+                    #print("no mc particle with same pid as rec particle")
                     break
 
                 if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar: 
+                    #print("all particles have been linked")
                     B.update(newisdrmatched=True)
                     if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
 
@@ -516,9 +524,13 @@ class MCEvent:
         1: MC normalisation (B+/- -> K+/- h- h+)
         9: there was an error in MC truth matching
         """
+
+        #print("begin categorizing")
         if not self.links: self.linkpars()
 
         for B in self.Bs:
+            #print("categorise")
+
             if self.corlin(B):
                 K = B.dl[1]
                 hadron_minus = B.dl[0].dl[0]
@@ -526,6 +538,8 @@ class MCEvent:
                 try: fillKpid = K.lpar.mother.pid
                 except: fillKpid = 0
 
+                #print(f"kaons mum is {K.lpar.mother}")
+
                 if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(K.lpar.par.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle and B (accessed by K origin vertex) has 3 decay products
                     #if K is K+ this must be a B+, if K is K- this must be a B-
                     if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=1)
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index a841c1285c..16152ce1c8 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -344,20 +344,20 @@ class Ntuple:
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                print(f"mcp.pid is set to {mcp.pid}")
+                #print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
                     if mcp.pid in (-211, -321):
                         dptype = "hm"
-                        print(f"found mcp particle which is hm with pid {mcp.pid}")
+                        #print(f"found mcp particle which is hm with pid {mcp.pid}")
                     elif mcp.pid in (211, 321):
                         dptype = "hp" 
-                        print(f"found mcp particle which is hp with pid {mcp.pid}")
+                        #print(f"found mcp particle which is hp with pid {mcp.pid}")
                 elif dptype == "K":
                     if mcp.pid in (321, -321):
                         dptype = "K"
-                        print(f"found mcp particle which is K with pid {mcp.pid}")
+                        #print(f"found mcp particle which is K with pid {mcp.pid}")
                 pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
@@ -842,20 +842,20 @@ def fill_ntuple(
     hh: "str",
     genTool,
 ):
-    print(f"hh is {hh}")
+    #print(f"hh is {hh}")
     """Assign values to the ntuple."""
     year = int(DaVinci().DataType)
 
     def get_particles(candloc):
-        print(f"candidate_loc is {candloc}")
+        #print(f"candidate_loc is {candloc}")
         try:
             particles = tes[candloc]
-            print(particles)
+            #print(particles)
             len(particles)
             size = len(particles)
-            print("found {0} particles".format(size))
+            #print("found {0} particles".format(size))
         except:
-            print("no particles found")
+            #print("no particles found")
             particles = []
         return particles
 
@@ -872,14 +872,14 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    #print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
-        print(mct)
+        #print(mct)
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
-        print(f"got {len(mcpstore)} B mesons from mcp store")
+        #print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
@@ -889,20 +889,20 @@ def fill_ntuple(
     isfilled = False
   
     for all_Bparticle in all_Bparticles:
-        print("its working")
+        #print("its working")
         args, kwargs = [all_Bparticle], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
-        print("I find bool is {0}".format(boolVal))
+        #print("I find bool is {0}".format(boolVal))
 
         # if not all parricles are linked 
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
             isfilled = True
-            print("isfilled has been set to {0}".format(isfilled))
+            #print("isfilled has been set to {0}".format(isfilled))
 
     if len(all_Bparticles) > 0 and isfilled:
-        print("conditions for filling tuple met")
+        #print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
 
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index b33ad14a7c..2c29a56ec3 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -12,8 +12,8 @@ import ROOT
 
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
-#import sys
-#sys.path.append("../")
+import sys
+sys.path.append("../")
 
 
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
@@ -157,10 +157,10 @@ while (NOfEvents == -1) or (event < NOfEvents):
     if not bool(tes["/Event"]):
         break
     event += 1
-    print(f"found event {event}")
+    #print(f"found event {event}")
 
     fill_ntuple(ntuple, tes, candloc, hh, genTool)
-    print("filled")
+    #print("filled")
 
 
 # Close.
-- 
GitLab


From 74806a6e947d0ed10932c80d5243de5a3653dd57 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 18 Nov 2024 10:02:26 +0000
Subject: [PATCH 37/70] remove uneccasry line

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 69ca1317ff..015ca6d64f 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -233,7 +233,8 @@ class MCEvent:
         for B in self.Bs:
             rels = self.mctool.relatedMCPs(B.dl[1].par, '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles')
             #rels = self.mctool.relatedMCPs()
-            #print(f"rels is {rels}")
+            print(f"rels is {rels}")
+            print(f"type rels is {type(rels)}")
             w = 0
             rel_K = None
             for rel in rels:
@@ -414,7 +415,6 @@ class MCEvent:
                             try:
                                 parlink.mother().originVertex().type()
                                 recp.lpar.update(newmother=MCPart(parlink.mother(),orvrt=parlink.mother().originVertex().type()))
-                                if parlink.mother().originVertex().type() == 1:
                                     #print("WARNING mother has origin vertex from pp collision")
                                 if parlink.mother().originVertex().type() != 1:
                                     print("mother has origin vertex type != 1. i.e. not from pp collision")
-- 
GitLab


From 6c0f7915e96c028a30cf5f9d0dbe6cd60448da53 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 18 Nov 2024 10:07:50 +0000
Subject: [PATCH 38/70] remove print

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 015ca6d64f..b54e6a1723 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -417,7 +417,7 @@ class MCEvent:
                                 recp.lpar.update(newmother=MCPart(parlink.mother(),orvrt=parlink.mother().originVertex().type()))
                                     #print("WARNING mother has origin vertex from pp collision")
                                 if parlink.mother().originVertex().type() != 1:
-                                    print("mother has origin vertex type != 1. i.e. not from pp collision")
+                                    #print("mother has origin vertex type != 1. i.e. not from pp collision")
                                     try:
                                         parlink.mother().mother().originVertex().type()
                                         recp.lpar.mother.update(newmother=MCPart(parlink.mother().mother(),orvrt=parlink.mother().mother().originVertex().type()))
-- 
GitLab


From a893f6d2d18b1d4d38ac176fdff802e6637a3eb9 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 18 Nov 2024 10:10:33 +0000
Subject: [PATCH 39/70] comment out lines when running on grid

---
 bu2kdarkscalar_darkscalar2hh/job.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 2c29a56ec3..0ba52fe587 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -12,8 +12,8 @@ import ROOT
 
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
-import sys
-sys.path.append("../")
+#import sys
+#sys.path.append("../")
 
 
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
-- 
GitLab


From 690a9e7c9e127ea2e612bcc08b66348ab1fa3bbc Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 4 Dec 2024 16:08:52 +0000
Subject: [PATCH 40/70] minor

---
 bu2kdarkscalar_darkscalar2hh/job.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 0ba52fe587..8d82cfa7ea 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -9,11 +9,10 @@ from typing import Union
 from Configurables import DaVinci, ToolSvc, TriggerTisTos
 import GaudiPython
 import ROOT
-
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
-#import sys
-#sys.path.append("../")
+import sys
+sys.path.append("../")
 
 
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
-- 
GitLab


From f73c1cea7bd061e54535fb238f2d9bbfe152a6b4 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 4 Dec 2024 16:10:54 +0000
Subject: [PATCH 41/70] these lines comment out when remote

---
 bu2kdarkscalar_darkscalar2hh/job.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 8d82cfa7ea..8edce87696 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -11,8 +11,8 @@ import GaudiPython
 import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
-import sys
-sys.path.append("../")
+#import sys
+#sys.path.append("../")
 
 
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
-- 
GitLab


From 480ce123057318a4585dd74f1f27083635468f74 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 6 Dec 2024 16:37:49 +0000
Subject: [PATCH 42/70] with comments - event 22!

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 2 +-
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 4 ++--
 bu2kdarkscalar_darkscalar2hh/job.py          | 6 +++---
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index b54e6a1723..684c36b1ca 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -231,7 +231,7 @@ class MCEvent:
         """
         self.allreglinked = True
         for B in self.Bs:
-            rels = self.mctool.relatedMCPs(B.dl[1].par, '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles')
+            rels = self.mctool.relatedMCPs(B.dl[1].par)
             #rels = self.mctool.relatedMCPs()
             print(f"rels is {rels}")
             print(f"type rels is {type(rels)}")
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 16152ce1c8..7c0a79bfd9 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -872,14 +872,14 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    #print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
         #print(mct)
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
-        #print(f"got {len(mcpstore)} B mesons from mcp store")
+        print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 8edce87696..e940dd3f36 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -11,8 +11,8 @@ import GaudiPython
 import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
-#import sys
-#sys.path.append("../")
+import sys
+sys.path.append("../")
 
 
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
@@ -156,7 +156,7 @@ while (NOfEvents == -1) or (event < NOfEvents):
     if not bool(tes["/Event"]):
         break
     event += 1
-    #print(f"found event {event}")
+    print(f"found event {event}")
 
     fill_ntuple(ntuple, tes, candloc, hh, genTool)
     #print("filled")
-- 
GitLab


From 952e2b879bd51b3d5bcbcc43274b61386ee8caac Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 21 Jan 2025 11:15:44 +0000
Subject: [PATCH 43/70] test

---
 bu2kdarkscalar_darkscalar2hh/job.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index e940dd3f36..6a9f252b55 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -125,7 +125,7 @@ elif hh == "PiPi":
     line = 'B2KX2PiPiDarkBosonLine'
 
 candloc = '/Event/' + stream + '/Phys/' + line + '/Particles'
-
+#candloc = '/Event/' + '/Phys/' + line + '/Particles'
 print(f"Using candidate location: {candloc}")
 
 # =================================================================================
-- 
GitLab


From 1118f17209403c7c59a7600e64412fabb51b7cad Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 21 Jan 2025 11:32:26 +0000
Subject: [PATCH 44/70] correct

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 684c36b1ca..b440ec7599 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -257,7 +257,7 @@ class MCEvent:
                 if MCID(rel_K) == B.dl[1].pid: B.dl[1].update(newclink=True)
                 else: B.dl[1].update(newclink=False)
 
-            rels = self.mctool.relatedMCPs(B.dl[0].dl[0].par, '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles')
+            rels = self.mctool.relatedMCPs(B.dl[0].dl[0].par)
             w = 0
             rel_hadron_minus = None
             for rel in rels:
@@ -279,7 +279,7 @@ class MCEvent:
                 if MCID(rel_hadron_minus) == B.dl[0].dl[0].pid: B.dl[0].dl[0].update(newclink=True)
                 else: B.dl[0].dl[0].update(newclink=False)
 
-            rels = self.mctool.relatedMCPs(B.dl[0].dl[1].par, '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles')
+            rels = self.mctool.relatedMCPs(B.dl[0].dl[1].par)
             w = 0
             rel_hadron_plus = None
             for rel in rels:
-- 
GitLab


From b3f64792796f9ba09d99b08524e7ede62a487d31 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 22 Jan 2025 12:03:20 +0000
Subject: [PATCH 45/70] fix for when K mother none

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 34 ++++++++++++--------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index b440ec7599..f9cd99b99d 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -382,7 +382,7 @@ class MCEvent:
                     #print(f"looping over {recpcount} recps")
                     recpcount += 1
                     if not recp.lpar:
-                        #print(f"if {abs(recp.pid)} has no linked particle")
+                        print(f"if {abs(recp.pid)} has no linked particle")
                         mindr = 99999999999
                         parlink = None
                         #print(f"mcp store is {mcpstore}")
@@ -415,7 +415,7 @@ class MCEvent:
                             try:
                                 parlink.mother().originVertex().type()
                                 recp.lpar.update(newmother=MCPart(parlink.mother(),orvrt=parlink.mother().originVertex().type()))
-                                    #print("WARNING mother has origin vertex from pp collision")
+                            #    print("WARNING mother has origin vertex from pp collision")
                                 if parlink.mother().originVertex().type() != 1:
                                     #print("mother has origin vertex type != 1. i.e. not from pp collision")
                                     try:
@@ -428,15 +428,16 @@ class MCEvent:
                                         #print("WARNING recp has no mother")
                             except:
                                 recp.lpar.update(newmother=None)
+                                #print("except")
 
                 # i guess L418 shouldn't be being called - is this checking if all particles have been linked?
                 # in which case we should be checking if all particles have been linked to the same particle type
                 if thereExistsMCPIDequalRECPID == False:
-                    #print("no mc particle with same pid as rec particle")
+                    print("no mc particle with same pid as rec particle")
                     break
 
                 if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar: 
-                    #print("all particles have been linked")
+                    print("all particles have been linked")
                     B.update(newisdrmatched=True)
                     if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
 
@@ -535,20 +536,25 @@ class MCEvent:
                 K = B.dl[1]
                 hadron_minus = B.dl[0].dl[0]
                 hadron_plus = B.dl[0].dl[1]
-                try: fillKpid = K.lpar.mother.pid
-                except: fillKpid = 0
+                try: Kmotherpid = K.lpar.mother.pid
+                except: Kmotherpid = 0
 
-                #print(f"kaons mum is {K.lpar.mother}")
+                # Note the reason I write this as a try except is because I don't know if the mother of K will always exist
 
-                if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(K.lpar.par.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle and B (accessed by K origin vertex) has 3 decay products
+                print(f"kaons mum is {K.lpar.mother}")
+
+                if Kmotherpid == 0: 
+                    B.update(newbgtype=9)
+
+                elif abs(Kmotherpid) == 521: #if K mother is a B
+                    if hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par == K.lpar.mother.par and len(K.lpar.par.originVertex().products()) == 3: # if h+ and h- and K have the same mother particle and B (accessed by K origin vertex) has 3 decay products
                     #if K is K+ this must be a B+, if K is K- this must be a B-
-                    if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=1)
-                    elif K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=1)
+                       if K.lpar.mother.pid == hadron_minus.lpar.mother.pid == +521: self.dec: B.update(newbgtype=1)
+                       elif K.lpar.mother.pid == hadron_minus.lpar.mother.pid == -521: self.dec: B.update(newbgtype=1)
 
-                elif hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par and hadron_minus.lpar.mother.pid == 310: # Check h+ and h- came from the same particle and that particle was a Ks
-                    if K.lpar.mother == hadron_minus.lpar.mother.mother.par == hadron_plus.lpar.mother.mother.par: # Check K, hm and hp all came from the same particle
-                       if abs(K.lpar.mother.pid) == 521: # check this was a B
-                          self.dec: B.update(newbgtype=0)
+                    elif hadron_minus.lpar.mother.par == hadron_plus.lpar.mother.par and hadron_minus.lpar.mother.pid == 310: # Check h+ and h- came from the same particle and that particle was a Ks
+                        if K.lpar.mother == hadron_minus.lpar.mother.mother.par == hadron_plus.lpar.mother.mother.par and abs(K.lpar.mother.pid) == 521: # Check K, hm mother (Ks) and hp mother (Ks) all came from the same particle and check this was a B
+                            self.dec: B.update(newbgtype=0)
 
                 else: B.update(newbgtype=9)
                     
-- 
GitLab


From f49909b221f1101efef548170137557f9ef1f7f4 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Thu, 23 Jan 2025 12:49:49 +0000
Subject: [PATCH 46/70] removed print statements

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 8 ++++----
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 4 ++--
 bu2kdarkscalar_darkscalar2hh/job.py          | 2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index f9cd99b99d..a821778424 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -233,8 +233,8 @@ class MCEvent:
         for B in self.Bs:
             rels = self.mctool.relatedMCPs(B.dl[1].par)
             #rels = self.mctool.relatedMCPs()
-            print(f"rels is {rels}")
-            print(f"type rels is {type(rels)}")
+            #print(f"rels is {rels}")
+            #print(f"type rels is {type(rels)}")
             w = 0
             rel_K = None
             for rel in rels:
@@ -433,11 +433,11 @@ class MCEvent:
                 # i guess L418 shouldn't be being called - is this checking if all particles have been linked?
                 # in which case we should be checking if all particles have been linked to the same particle type
                 if thereExistsMCPIDequalRECPID == False:
-                    print("no mc particle with same pid as rec particle")
+                    #print("no mc particle with same pid as rec particle")
                     break
 
                 if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar: 
-                    print("all particles have been linked")
+                    #print("all particles have been linked")
                     B.update(newisdrmatched=True)
                     if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
 
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 7c0a79bfd9..16152ce1c8 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -872,14 +872,14 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    #print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
         #print(mct)
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
-        print(f"got {len(mcpstore)} B mesons from mcp store")
+        #print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 6a9f252b55..736e947087 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -156,7 +156,7 @@ while (NOfEvents == -1) or (event < NOfEvents):
     if not bool(tes["/Event"]):
         break
     event += 1
-    print(f"found event {event}")
+    #print(f"found event {event}")
 
     fill_ntuple(ntuple, tes, candloc, hh, genTool)
     #print("filled")
-- 
GitLab


From d51030c9a1b0c5d503fbb149a333e31104b9c1bd Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Thu, 23 Jan 2025 15:28:10 +0000
Subject: [PATCH 47/70] removed print

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index a821778424..8e5dae3035 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -382,7 +382,7 @@ class MCEvent:
                     #print(f"looping over {recpcount} recps")
                     recpcount += 1
                     if not recp.lpar:
-                        print(f"if {abs(recp.pid)} has no linked particle")
+                        #print(f"if {abs(recp.pid)} has no linked particle")
                         mindr = 99999999999
                         parlink = None
                         #print(f"mcp store is {mcpstore}")
@@ -541,7 +541,7 @@ class MCEvent:
 
                 # Note the reason I write this as a try except is because I don't know if the mother of K will always exist
 
-                print(f"kaons mum is {K.lpar.mother}")
+                #print(f"kaons mum is {K.lpar.mother}")
 
                 if Kmotherpid == 0: 
                     B.update(newbgtype=9)
-- 
GitLab


From 17565053c80c0261e7d2d4c6cc6b66f0db4dd173 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 28 Jan 2025 13:57:38 +0000
Subject: [PATCH 48/70] configure dv sa and change sel reports loc

---
 bu2kdarkscalar_darkscalar2hh/job.py | 34 ++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 736e947087..423eac6814 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -6,7 +6,7 @@ from pathlib import Path
 import shutil
 from typing import Union
 
-from Configurables import DaVinci, ToolSvc, TriggerTisTos
+from Configurables import DaVinci, ToolSvc, TriggerTisTos, DaVinciSmartAssociator, P2MCPFromProtoP, BackgroundCategory
 import GaudiPython
 import ROOT
 #when running locally you need to uncomment the following lines
@@ -101,9 +101,7 @@ DaVinci().Lumi = False
 # =================================================================================
 
 #candidate locations
-# IMPORTANT WARNING!!!
-# is the data is saved in microDST format we must use '/Event/AllStreams/Phys/B2KX2KKDarkBosonLine/Particles'
-#
+
 if DaVinci().Simulation:
     stream = 'AllStreams'
     DaVinci().RootInTES = "/Event/AllStreams"
@@ -111,21 +109,15 @@ if DaVinci().Simulation:
 
 else:
     stream = 'Leptonic'
-    #DaVinci().RootInTES = "/Event/AllStreams"
     print(f"stream set as {stream}")
 
-""" if DaVinci().InputType == "MDST":
-   stream = 'Leptonic'
-elif DaVinci().InputType == "DST":
-   stream = 'AllStreams' """
-
 if hh == "KK":
     line ='B2KX2KKDarkBosonLine'
 elif hh == "PiPi":
     line = 'B2KX2PiPiDarkBosonLine'
 
 candloc = '/Event/' + stream + '/Phys/' + line + '/Particles'
-#candloc = '/Event/' + '/Phys/' + line + '/Particles'
+
 print(f"Using candidate location: {candloc}")
 
 # =================================================================================
@@ -133,8 +125,24 @@ print(f"Using candidate location: {candloc}")
 for stage in ("Hlt1", "Hlt2", "Strip/Phys"):
     ToolSvc().addTool(TriggerTisTos, stage + "TriggerTisTos")
     tool = getattr(ToolSvc(), stage + "TriggerTisTos")
-    tool.HltDecReportsLocation = f"/Event/{stage}/DecReports"
-    tool.HltSelReportsLocation = f"/Event/{stage}/SelReports"
+    tool.HltDecReportsLocation = f"/Event/{stream}/{stage}/DecReports"
+    tool.HltSelReportsLocation = f"/Event/{stream}/{stage}/SelReports"
+
+# =================================================================================
+# Configure smart associator.
+
+ToolSvc().addTool(DaVinciSmartAssociator)
+ToolSvc().DaVinciSmartAssociator.addTool(P2MCPFromProtoP)
+ToolSvc().DaVinciSmartAssociator.addTool(BackgroundCategory)
+ToolSvc().DaVinciSmartAssociator.BackgroundCategory.addTool(P2MCPFromProtoP)
+
+if "MDST" == DaVinci().InputType:
+    ToolSvc().DaVinciSmartAssociator.P2MCPFromProtoP.Locations = ["AllStreams/Relations/Rec/ProtoP/Charged"'AllStreams/Relations/Rec/ProtoP/Upstream',
+                                                      'AllStreams/Relations/Rec/ProtoP/Neutrals']
+    ToolSvc().DaVinciSmartAssociator.BackgroundCategory.P2MCPFromProtoP.Locations = ['AllStreams/Relations/Rec/ProtoP/Charged',
+                                                    'AllStreams/Relations/Rec/ProtoP/Upstream',
+                                                         'AllStreams/Relations/Rec/ProtoP/Neutrals']
+
 
 # =================================================================================
 # Run.
-- 
GitLab


From d8ae9b14002ec45da290e183e2492ab34f9fdb09 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 28 Jan 2025 14:54:20 +0000
Subject: [PATCH 49/70] add debug flag, comment lines when running via AP

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 61 +++++++++-----------
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 34 +++++------
 bu2kdarkscalar_darkscalar2hh/job.py          | 24 ++++++--
 3 files changed, 63 insertions(+), 56 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 8e5dae3035..5ed8166220 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -8,6 +8,8 @@ from LoKiPhys.decorators import M, PX, PY, PZ, E, ID, ABSID, PROBNNk, PROBNNpi,
 from array import array
 from math import sqrt
 
+from bu2kdarkscalar_darkscalar2hh.job import debug_print
+
 class MCPart:
     """
     Simple class for storing rec and gen mc particles.
@@ -205,7 +207,7 @@ class MCEvent:
                     for ddp in dp.endVertex().outgoingParticlesVector():
                         hadron = MCPart(ddp)
                         hadron.update(newpnnk=PROBNNk(ddp),newpnnpi=PROBNNpi(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
-                        #print(hadron.pid)
+                        debug_print(hadron.pid)
 
                         if hh == "KK":
                             hhPID = 321
@@ -218,7 +220,7 @@ class MCEvent:
                     dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
             B = MCPart(all_B,dl=dps)
             self.Bs += [B]
-            #print(f"self.Bs is {self.Bs}")
+            debug_print(f"self.Bs is {self.Bs}")
 
     def linkpars(self):
         """
@@ -232,9 +234,8 @@ class MCEvent:
         self.allreglinked = True
         for B in self.Bs:
             rels = self.mctool.relatedMCPs(B.dl[1].par)
-            #rels = self.mctool.relatedMCPs()
-            #print(f"rels is {rels}")
-            #print(f"type rels is {type(rels)}")
+            debug_print(f"rels is {rels}")
+            debug_print(f"type rels is {type(rels)}")
             w = 0
             rel_K = None
             for rel in rels:
@@ -373,40 +374,40 @@ class MCEvent:
 
         count = 1
         for B in self.Bs:
-            #print(f"looping over number {count} B particles stored in stripping line")
+            debug_print(f"looping over number {count} B particles stored in stripping line")
             count += 1
             if not B.alllinked:
-                #print("not all Bs are linked to MC particles already by linkpars so we need delta r matching") 
+                debug_print("not all Bs are linked to MC particles already by linkpars so we need delta r matching") 
                 recpcount = 0
                 for recp in [B.dl[1],B.dl[0].dl[0],B.dl[0].dl[1]]:
-                    #print(f"looping over {recpcount} recps")
+                    debug_print(f"looping over {recpcount} recps")
                     recpcount += 1
                     if not recp.lpar:
-                        #print(f"if {abs(recp.pid)} has no linked particle")
+                        debug_print(f"if {abs(recp.pid)} has no linked particle")
                         mindr = 99999999999
                         parlink = None
-                        #print(f"mcp store is {mcpstore}")
-                        #print(f"mcp store contains {len(mcpstore)} mc particles")
+                        debug_print(f"mcp store is {mcpstore}")
+                        debug_print(f"mcp store contains {len(mcpstore)} mc particles")
                         thereExistsMCPIDequalRECPID = False
                         for mcp in mcpstore:
-                            #print(f"mc particle is {mcp}")
-                            #print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
+                            debug_print(f"mc particle is {mcp}")
+                            debug_print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
                             if MCID(mcp) == recp.pid:
                                 thereExistsMCPIDequalRECPID = True
-                                #print("found mc particle with same pid is same as rec particle pid")
+                                debug_print("found mc particle with same pid is same as rec particle pid")
                                 dphi = MCPHI(mcp) - PHI(recp.par)
                                 deta = MCETA(mcp) - ETA(recp.par)
                                 deltar = sqrt(dphi**2 + deta**2)
-                                #print(f"deltar is {deltar}")
-                                #print(f"mindr is {mindr}")
+                                debug_print(f"deltar is {deltar}")
+                                debug_print(f"mindr is {mindr}")
                                 if deltar < mindr: 
                                     mindr = deltar
-                                    #print(f"mindr is {mindr}")
+                                    debug_print(f"mindr is {mindr}")
                                     parlink = mcp
-                                    #print(f"assign the rec particle this mc particle which is {parlink}")
+                                    debug_print(f"assign the rec particle this mc particle which is {parlink}")
                                     break
                         if thereExistsMCPIDequalRECPID == False:
-                            #print("no mc particle with same pid as rec particle")
+                            debug_print("no mc particle with same pid as rec particle")
                             break
                         recp.update(newlpar=MCPart(parlink,orvrt=parlink.originVertex().type()))
                         if MCID(parlink) == recp.pid: recp.update(newclink=True)
@@ -415,29 +416,25 @@ class MCEvent:
                             try:
                                 parlink.mother().originVertex().type()
                                 recp.lpar.update(newmother=MCPart(parlink.mother(),orvrt=parlink.mother().originVertex().type()))
-                            #    print("WARNING mother has origin vertex from pp collision")
                                 if parlink.mother().originVertex().type() != 1:
-                                    #print("mother has origin vertex type != 1. i.e. not from pp collision")
+                                    debug_print("mother has origin vertex type != 1. i.e. not from pp collision")
                                     try:
                                         parlink.mother().mother().originVertex().type()
                                         recp.lpar.mother.update(newmother=MCPart(parlink.mother().mother(),orvrt=parlink.mother().mother().originVertex().type()))
-                                        #print("updating mother")
-                                        #print(f"mother of {recp.pid} is {recp.lpar.mother}")
+                                        debug_print("updating mother")
+                                        debug_print(f"mother of {recp.pid} is {recp.lpar.mother}")
                                     except:
                                         recp.lpar.mother.update(newmother=None)
-                                        #print("WARNING recp has no mother")
+                                        debug_print("WARNING recp has no mother")
                             except:
                                 recp.lpar.update(newmother=None)
-                                #print("except")
 
-                # i guess L418 shouldn't be being called - is this checking if all particles have been linked?
-                # in which case we should be checking if all particles have been linked to the same particle type
                 if thereExistsMCPIDequalRECPID == False:
-                    #print("no mc particle with same pid as rec particle")
+                    debug_print("no mc particle with same pid as rec particle")
                     break
 
                 if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar: 
-                    #print("all particles have been linked")
+                    debug_print("all particles have been linked")
                     B.update(newisdrmatched=True)
                     if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
 
@@ -526,12 +523,10 @@ class MCEvent:
         9: there was an error in MC truth matching
         """
 
-        #print("begin categorizing")
+        debug_print("begin categorisation")
         if not self.links: self.linkpars()
 
         for B in self.Bs:
-            #print("categorise")
-
             if self.corlin(B):
                 K = B.dl[1]
                 hadron_minus = B.dl[0].dl[0]
@@ -541,7 +536,7 @@ class MCEvent:
 
                 # Note the reason I write this as a try except is because I don't know if the mother of K will always exist
 
-                #print(f"kaons mum is {K.lpar.mother}")
+                debug_print(f"kaons mum is {K.lpar.mother}")
 
                 if Kmotherpid == 0: 
                     B.update(newbgtype=9)
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 16152ce1c8..d2221f6458 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -15,6 +15,8 @@ import ROOT
 from dtf import dtf #dtf: decay tree fitter
 import MCEventTools
 
+from bu2kdarkscalar_darkscalar2hh.job import debug_print
+
 class Ntuple:
     """Class for storing an ntuple."""
 
@@ -344,20 +346,20 @@ class Ntuple:
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                #print(f"mcp.pid is set to {mcp.pid}")
+                debug_print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
                     if mcp.pid in (-211, -321):
                         dptype = "hm"
-                        #print(f"found mcp particle which is hm with pid {mcp.pid}")
+                        debug_print(f"found mcp particle which is hm with pid {mcp.pid}")
                     elif mcp.pid in (211, 321):
                         dptype = "hp" 
-                        #print(f"found mcp particle which is hp with pid {mcp.pid}")
+                        debug_print(f"found mcp particle which is hp with pid {mcp.pid}")
                 elif dptype == "K":
                     if mcp.pid in (321, -321):
                         dptype = "K"
-                        #print(f"found mcp particle which is K with pid {mcp.pid}")
+                        debug_print(f"found mcp particle which is K with pid {mcp.pid}")
                 pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
@@ -842,20 +844,17 @@ def fill_ntuple(
     hh: "str",
     genTool,
 ):
-    #print(f"hh is {hh}")
+    debug_print(f"hh is {hh}")
     """Assign values to the ntuple."""
     year = int(DaVinci().DataType)
 
     def get_particles(candloc):
-        #print(f"candidate_loc is {candloc}")
+        debug_print(f"candidate location is {candloc}")
         try:
             particles = tes[candloc]
-            #print(particles)
-            len(particles)
-            size = len(particles)
-            #print("found {0} particles".format(size))
+            debug_print(f"found {len(particles)} particles in {candloc}")
         except:
-            #print("no particles found")
+            debug_print(f"no particles found in {candloc}")
             particles = []
         return particles
 
@@ -872,14 +871,13 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    #print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    debug_print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
-        #print(mct)
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
-        #print(f"got {len(mcpstore)} B mesons from mcp store")
+        debug_print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
@@ -889,20 +887,18 @@ def fill_ntuple(
     isfilled = False
   
     for all_Bparticle in all_Bparticles:
-        #print("its working")
         args, kwargs = [all_Bparticle], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
-        #print("I find bool is {0}".format(boolVal))
+        debug_print(f"I find bool is {boolVal}")
 
-        # if not all parricles are linked 
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
             isfilled = True
-            #print("isfilled has been set to {0}".format(isfilled))
+            debug_print(f"isfilled has been set to {isfilled}")
 
     if len(all_Bparticles) > 0 and isfilled:
-        #print("conditions for filling tuple met")
+        debug_print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
 
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 423eac6814..73592d4664 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -11,10 +11,16 @@ import GaudiPython
 import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
-import sys
-sys.path.append("../")
+#import sys
+#sys.path.append("../")
 
 
+DEBUG = True  # Set to False to disable debug output
+
+def debug_print(*args):
+    if DEBUG:
+        print(*args)
+
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
 
 # =================================================================================
@@ -34,8 +40,11 @@ def parse_args() -> "tuple[Union[str, None], bool]":
         type=Path,
         help="Additional options files to load before starting Gaudi Python",
     )
+    parser.add_argument("--debug", action="store_true", help="Enable debug output")
     args = parser.parse_args()
 
+    DEBUG = args.debug
+
     allowed_hh = ("PiPi", "KK")
     hh = None
 
@@ -71,6 +80,13 @@ def parse_args() -> "tuple[Union[str, None], bool]":
 # passed to the script need to be executed to set up input data and other state
 
 hh = parse_args()
+
+# =================================================================================
+
+def debug_print(*args):
+    if DEBUG:
+        print(*args)
+
 # =================================================================================
 # Set up material tool
 print("About to compile velo material tool")
@@ -164,10 +180,10 @@ while (NOfEvents == -1) or (event < NOfEvents):
     if not bool(tes["/Event"]):
         break
     event += 1
-    #print(f"found event {event}")
+    debug_print(f"found event {event}")
 
     fill_ntuple(ntuple, tes, candloc, hh, genTool)
-    #print("filled")
+    debug_print("filled")
 
 
 # Close.
-- 
GitLab


From e06dc67697378807da67d7a2bd4e05b8e14c8720 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 29 Jan 2025 11:31:54 +0000
Subject: [PATCH 50/70] minor

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 56 ++++++++++----------
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 29 +++++-----
 bu2kdarkscalar_darkscalar2hh/job.py          | 26 ++++-----
 3 files changed, 57 insertions(+), 54 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 5ed8166220..9429a3b20f 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -8,7 +8,7 @@ from LoKiPhys.decorators import M, PX, PY, PZ, E, ID, ABSID, PROBNNk, PROBNNpi,
 from array import array
 from math import sqrt
 
-from bu2kdarkscalar_darkscalar2hh.job import debug_print
+
 
 class MCPart:
     """
@@ -207,7 +207,7 @@ class MCEvent:
                     for ddp in dp.endVertex().outgoingParticlesVector():
                         hadron = MCPart(ddp)
                         hadron.update(newpnnk=PROBNNk(ddp),newpnnpi=PROBNNpi(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
-                        debug_print(hadron.pid)
+                        #debug_print(hadron.pid)
 
                         if hh == "KK":
                             hhPID = 321
@@ -220,7 +220,7 @@ class MCEvent:
                     dps[0] = MCPart(dp,dl=hadrons,sv=svcoor)
             B = MCPart(all_B,dl=dps)
             self.Bs += [B]
-            debug_print(f"self.Bs is {self.Bs}")
+            #debug_print(f"self.Bs is {self.Bs}")
 
     def linkpars(self):
         """
@@ -233,9 +233,9 @@ class MCEvent:
         """
         self.allreglinked = True
         for B in self.Bs:
-            rels = self.mctool.relatedMCPs(B.dl[1].par)
-            debug_print(f"rels is {rels}")
-            debug_print(f"type rels is {type(rels)}")
+            rels = self.mctool.relatedMCPs(B.dl[1].par, '/Event/AllStreams/MC/Particles')
+            print(f"rels is {rels}")
+            print(f"type rels is {type(rels)}")
             w = 0
             rel_K = None
             for rel in rels:
@@ -374,40 +374,40 @@ class MCEvent:
 
         count = 1
         for B in self.Bs:
-            debug_print(f"looping over number {count} B particles stored in stripping line")
+            #debug_print(f"looping over number {count} B particles stored in stripping line")
             count += 1
             if not B.alllinked:
-                debug_print("not all Bs are linked to MC particles already by linkpars so we need delta r matching") 
+                #debug_print("not all Bs are linked to MC particles already by linkpars so we need delta r matching") 
                 recpcount = 0
                 for recp in [B.dl[1],B.dl[0].dl[0],B.dl[0].dl[1]]:
-                    debug_print(f"looping over {recpcount} recps")
+                    #debug_print(f"looping over {recpcount} recps")
                     recpcount += 1
                     if not recp.lpar:
-                        debug_print(f"if {abs(recp.pid)} has no linked particle")
+                        #debug_print(f"if {abs(recp.pid)} has no linked particle")
                         mindr = 99999999999
                         parlink = None
-                        debug_print(f"mcp store is {mcpstore}")
-                        debug_print(f"mcp store contains {len(mcpstore)} mc particles")
+                        #debug_print(f"mcp store is {mcpstore}")
+                        #debug_print(f"mcp store contains {len(mcpstore)} mc particles")
                         thereExistsMCPIDequalRECPID = False
                         for mcp in mcpstore:
-                            debug_print(f"mc particle is {mcp}")
-                            debug_print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
+                            #debug_print(f"mc particle is {mcp}")
+                            #debug_print(f" MCID is {MCID(mcp)} and recp.pid is {recp.pid}")
                             if MCID(mcp) == recp.pid:
                                 thereExistsMCPIDequalRECPID = True
-                                debug_print("found mc particle with same pid is same as rec particle pid")
+                                #debug_print("found mc particle with same pid is same as rec particle pid")
                                 dphi = MCPHI(mcp) - PHI(recp.par)
                                 deta = MCETA(mcp) - ETA(recp.par)
                                 deltar = sqrt(dphi**2 + deta**2)
-                                debug_print(f"deltar is {deltar}")
-                                debug_print(f"mindr is {mindr}")
+                                #debug_print(f"deltar is {deltar}")
+                                #debug_print(f"mindr is {mindr}")
                                 if deltar < mindr: 
                                     mindr = deltar
-                                    debug_print(f"mindr is {mindr}")
+                                    #debug_print(f"mindr is {mindr}")
                                     parlink = mcp
-                                    debug_print(f"assign the rec particle this mc particle which is {parlink}")
+                                    #debug_print(f"assign the rec particle this mc particle which is {parlink}")
                                     break
                         if thereExistsMCPIDequalRECPID == False:
-                            debug_print("no mc particle with same pid as rec particle")
+                            #debug_print("no mc particle with same pid as rec particle")
                             break
                         recp.update(newlpar=MCPart(parlink,orvrt=parlink.originVertex().type()))
                         if MCID(parlink) == recp.pid: recp.update(newclink=True)
@@ -417,24 +417,24 @@ class MCEvent:
                                 parlink.mother().originVertex().type()
                                 recp.lpar.update(newmother=MCPart(parlink.mother(),orvrt=parlink.mother().originVertex().type()))
                                 if parlink.mother().originVertex().type() != 1:
-                                    debug_print("mother has origin vertex type != 1. i.e. not from pp collision")
+                                    #debug_print("mother has origin vertex type != 1. i.e. not from pp collision")
                                     try:
                                         parlink.mother().mother().originVertex().type()
                                         recp.lpar.mother.update(newmother=MCPart(parlink.mother().mother(),orvrt=parlink.mother().mother().originVertex().type()))
-                                        debug_print("updating mother")
-                                        debug_print(f"mother of {recp.pid} is {recp.lpar.mother}")
+                                        #debug_print("updating mother")
+                                        #debug_print(f"mother of {recp.pid} is {recp.lpar.mother}")
                                     except:
                                         recp.lpar.mother.update(newmother=None)
-                                        debug_print("WARNING recp has no mother")
+                                        #debug_print("WARNING recp has no mother")
                             except:
                                 recp.lpar.update(newmother=None)
 
                 if thereExistsMCPIDequalRECPID == False:
-                    debug_print("no mc particle with same pid as rec particle")
+                    #debug_print("no mc particle with same pid as rec particle")
                     break
 
                 if B.dl[1].lpar and B.dl[0].dl[0].lpar and B.dl[0].dl[1].lpar: 
-                    debug_print("all particles have been linked")
+                    #debug_print("all particles have been linked")
                     B.update(newisdrmatched=True)
                     if B.dl[1].lpar.pid == B.dl[1].pid and B.dl[0].dl[0].lpar.pid == B.dl[0].dl[0].pid and B.dl[0].dl[1].lpar.pid == B.dl[0].dl[1].pid: B.update(newcorlinked=True)
 
@@ -523,7 +523,7 @@ class MCEvent:
         9: there was an error in MC truth matching
         """
 
-        debug_print("begin categorisation")
+        #debug_print("begin categorisation")
         if not self.links: self.linkpars()
 
         for B in self.Bs:
@@ -536,7 +536,7 @@ class MCEvent:
 
                 # Note the reason I write this as a try except is because I don't know if the mother of K will always exist
 
-                debug_print(f"kaons mum is {K.lpar.mother}")
+                #debug_print(f"kaons mum is {K.lpar.mother}")
 
                 if Kmotherpid == 0: 
                     B.update(newbgtype=9)
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index d2221f6458..aaefe24473 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -15,7 +15,9 @@ import ROOT
 from dtf import dtf #dtf: decay tree fitter
 import MCEventTools
 
-from bu2kdarkscalar_darkscalar2hh.job import debug_print
+
+
+
 
 class Ntuple:
     """Class for storing an ntuple."""
@@ -346,20 +348,20 @@ class Ntuple:
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                debug_print(f"mcp.pid is set to {mcp.pid}")
+                #debug_print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
                     if mcp.pid in (-211, -321):
                         dptype = "hm"
-                        debug_print(f"found mcp particle which is hm with pid {mcp.pid}")
+                        #debug_print(f"found mcp particle which is hm with pid {mcp.pid}")
                     elif mcp.pid in (211, 321):
                         dptype = "hp" 
-                        debug_print(f"found mcp particle which is hp with pid {mcp.pid}")
+                        #debug_print(f"found mcp particle which is hp with pid {mcp.pid}")
                 elif dptype == "K":
                     if mcp.pid in (321, -321):
                         dptype = "K"
-                        debug_print(f"found mcp particle which is K with pid {mcp.pid}")
+                        #debug_print(f"found mcp particle which is K with pid {mcp.pid}")
                 pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
@@ -844,17 +846,17 @@ def fill_ntuple(
     hh: "str",
     genTool,
 ):
-    debug_print(f"hh is {hh}")
+    #debug_print(f"hh is {hh}")
     """Assign values to the ntuple."""
     year = int(DaVinci().DataType)
 
     def get_particles(candloc):
-        debug_print(f"candidate location is {candloc}")
+        #debug_print(f"candidate location is {candloc}")
         try:
             particles = tes[candloc]
-            debug_print(f"found {len(particles)} particles in {candloc}")
+            print(f"found {len(particles)} particles in {candloc}")
         except:
-            debug_print(f"no particles found in {candloc}")
+            #debug_print(f"no particles found in {candloc}")
             particles = []
         return particles
 
@@ -871,13 +873,13 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    debug_print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    #debug_print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
     if DaVinci().Simulation:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
-        debug_print(f"got {len(mcpstore)} B mesons from mcp store")
+        #debug_print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
@@ -895,12 +897,13 @@ def fill_ntuple(
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
             isfilled = True
-            debug_print(f"isfilled has been set to {isfilled}")
+            #debug_print(f"isfilled has been set to {isfilled}")
 
     if len(all_Bparticles) > 0 and isfilled:
-        debug_print("conditions for filling tuple met")
+        #debug_print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
 
 # End of fill_ntuple function
 
+
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 73592d4664..2b0bd86948 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -5,21 +5,18 @@ import importlib.util
 from pathlib import Path
 import shutil
 from typing import Union
-
-from Configurables import DaVinci, ToolSvc, TriggerTisTos, DaVinciSmartAssociator, P2MCPFromProtoP, BackgroundCategory
+import sys
 import GaudiPython
+import os
+from GaudiConf import IOHelper
+from Configurables import DaVinci, ToolSvc, TriggerTisTos, DaVinciSmartAssociator, P2MCPFromProtoP, BackgroundCategory, CondDB, MessageSvc
 import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
-#import sys
+
 #sys.path.append("../")
 
 
-DEBUG = True  # Set to False to disable debug output
-
-def debug_print(*args):
-    if DEBUG:
-        print(*args)
 
 from bu2kdarkscalar_darkscalar2hh.Ntuple import fill_ntuple, Ntuple
 
@@ -43,8 +40,6 @@ def parse_args() -> "tuple[Union[str, None], bool]":
     parser.add_argument("--debug", action="store_true", help="Enable debug output")
     args = parser.parse_args()
 
-    DEBUG = args.debug
-
     allowed_hh = ("PiPi", "KK")
     hh = None
 
@@ -73,13 +68,16 @@ def parse_args() -> "tuple[Union[str, None], bool]":
             raise ValueError(f"hh must be one of {allowed_hh}")
         else:
             print(f"Running with hh == '{hh}'.")
-    return hh
+    return hh, args.debug
 
 
 # In order to use Run 1+2 GaudiPython with analysis productions the arguments
 # passed to the script need to be executed to set up input data and other state
 
-hh = parse_args()
+hh = parse_args()[0]
+DEBUG = parse_args()[1]
+
+print(f"debug is set to {DEBUG}")
 
 # =================================================================================
 
@@ -87,6 +85,7 @@ def debug_print(*args):
     if DEBUG:
         print(*args)
 
+
 # =================================================================================
 # Set up material tool
 print("About to compile velo material tool")
@@ -153,7 +152,8 @@ ToolSvc().DaVinciSmartAssociator.addTool(BackgroundCategory)
 ToolSvc().DaVinciSmartAssociator.BackgroundCategory.addTool(P2MCPFromProtoP)
 
 if "MDST" == DaVinci().InputType:
-    ToolSvc().DaVinciSmartAssociator.P2MCPFromProtoP.Locations = ["AllStreams/Relations/Rec/ProtoP/Charged"'AllStreams/Relations/Rec/ProtoP/Upstream',
+    ToolSvc().DaVinciSmartAssociator.P2MCPFromProtoP.Locations = ['AllStreams/Relations/Rec/ProtoP/Charged',
+                                                                  'AllStreams/Relations/Rec/ProtoP/Upstream',
                                                       'AllStreams/Relations/Rec/ProtoP/Neutrals']
     ToolSvc().DaVinciSmartAssociator.BackgroundCategory.P2MCPFromProtoP.Locations = ['AllStreams/Relations/Rec/ProtoP/Charged',
                                                     'AllStreams/Relations/Rec/ProtoP/Upstream',
-- 
GitLab


From d745b4d585847809157de3a6b7c22cb6946a023c Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 29 Jan 2025 12:53:58 +0000
Subject: [PATCH 51/70] comment

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 4 ++--
 bu2kdarkscalar_darkscalar2hh/Ntuple.py       | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index 9429a3b20f..fb231e8cd3 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -234,8 +234,8 @@ class MCEvent:
         self.allreglinked = True
         for B in self.Bs:
             rels = self.mctool.relatedMCPs(B.dl[1].par, '/Event/AllStreams/MC/Particles')
-            print(f"rels is {rels}")
-            print(f"type rels is {type(rels)}")
+            #print(f"rels is {rels}")
+            #print(f"type rels is {type(rels)}")
             w = 0
             rel_K = None
             for rel in rels:
diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index aaefe24473..2adcec28d8 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -854,7 +854,7 @@ def fill_ntuple(
         #debug_print(f"candidate location is {candloc}")
         try:
             particles = tes[candloc]
-            print(f"found {len(particles)} particles in {candloc}")
+            #print(f"found {len(particles)} particles in {candloc}")
         except:
             #debug_print(f"no particles found in {candloc}")
             particles = []
@@ -892,7 +892,7 @@ def fill_ntuple(
         args, kwargs = [all_Bparticle], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
-        debug_print(f"I find bool is {boolVal}")
+        #debug_print(f"I find bool is {boolVal}")
 
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
-- 
GitLab


From fb055c3b1026dd47373cf154976fa8f497e4cda9 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Wed, 29 Jan 2025 14:35:16 +0000
Subject: [PATCH 52/70] stop mc truth matching when no candidates present

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 13 +++++++------
 bu2kdarkscalar_darkscalar2hh/job.py    |  2 +-
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 2adcec28d8..67adcf578f 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -854,7 +854,7 @@ def fill_ntuple(
         #debug_print(f"candidate location is {candloc}")
         try:
             particles = tes[candloc]
-            #print(f"found {len(particles)} particles in {candloc}")
+            print(f"found {len(particles)} particles in {candloc}")
         except:
             #debug_print(f"no particles found in {candloc}")
             particles = []
@@ -873,9 +873,10 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    #debug_print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
-    if DaVinci().Simulation:
+
+    if DaVinci().Simulation and len(all_Bparticles) > 0:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
@@ -892,15 +893,15 @@ def fill_ntuple(
         args, kwargs = [all_Bparticle], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
-        #debug_print(f"I find bool is {boolVal}")
+        print(f"I find bool is {boolVal}")
 
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
             isfilled = True
-            #debug_print(f"isfilled has been set to {isfilled}")
+            print(f"isfilled has been set to {isfilled}")
 
     if len(all_Bparticles) > 0 and isfilled:
-        #debug_print("conditions for filling tuple met")
+        print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
 
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 2b0bd86948..5e921fb0b5 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -14,7 +14,7 @@ import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
 
-#sys.path.append("../")
+sys.path.append("../")
 
 
 
-- 
GitLab


From efdbfd261b8f1c3a87a1bca608227be42c498378 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Thu, 30 Jan 2025 11:16:50 +0000
Subject: [PATCH 53/70] modify debug print outs

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 19 ++++++++++---------
 bu2kdarkscalar_darkscalar2hh/job.py    |  2 +-
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 67adcf578f..7e73c3024b 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -845,18 +845,19 @@ def fill_ntuple(
     candidate_loc: "str",
     hh: "str",
     genTool,
+    debug_print: "function"
 ):
-    #debug_print(f"hh is {hh}")
+    debug_print(f"hh is {hh}")
     """Assign values to the ntuple."""
     year = int(DaVinci().DataType)
 
     def get_particles(candloc):
-        #debug_print(f"candidate location is {candloc}")
+        debug_print(f"candidate location is {candloc}")
         try:
             particles = tes[candloc]
-            print(f"found {len(particles)} particles in {candloc}")
+            debug_print(f"found {len(particles)} particles in {candloc}")
         except:
-            #debug_print(f"no particles found in {candloc}")
+            debug_print(f"no particles found in {candloc}")
             particles = []
         return particles
 
@@ -873,14 +874,14 @@ def fill_ntuple(
 
     # Fill the particles.
     all_Bparticles = get_particles(candidate_loc) 
-    print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
+    debug_print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
 
     if DaVinci().Simulation and len(all_Bparticles) > 0:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
-        #debug_print(f"got {len(mcpstore)} B mesons from mcp store")
+        debug_print(f"got {len(mcpstore)} B mesons from mcp store")
         mct.deltarlink(mcpstore)
         mct.categorize()
     else:
@@ -893,15 +894,15 @@ def fill_ntuple(
         args, kwargs = [all_Bparticle], {"year": year, "run": rnum, "mctool": mct}
 
         boolVal = ntuple.fillPrt(*args, **kwargs, check=True)
-        print(f"I find bool is {boolVal}")
+        debug_print(f"I find bool is {boolVal}")
 
         if ntuple.fillPrt(*args, **kwargs, check=True):
             ntuple.fillPrt(*args, **kwargs)
             isfilled = True
-            print(f"isfilled has been set to {isfilled}")
+            debug_print(f"isfilled has been set to {isfilled}")
 
     if len(all_Bparticles) > 0 and isfilled:
-        print("conditions for filling tuple met")
+        debug_print("conditions for filling tuple met")
         ntuple.fill()
         ntuple.clear()
 
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 5e921fb0b5..cd6e437bfc 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -182,7 +182,7 @@ while (NOfEvents == -1) or (event < NOfEvents):
     event += 1
     debug_print(f"found event {event}")
 
-    fill_ntuple(ntuple, tes, candloc, hh, genTool)
+    fill_ntuple(ntuple, tes, candloc, hh, genTool, debug_print)
     debug_print("filled")
 
 
-- 
GitLab


From 6c369ec2fdc4b81fecf51bdd3863aa57b871a43d Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Thu, 30 Jan 2025 12:28:53 +0000
Subject: [PATCH 54/70] don't need this line when ap

---
 bu2kdarkscalar_darkscalar2hh/job.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index cd6e437bfc..1537fec627 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -14,7 +14,7 @@ import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
 
-sys.path.append("../")
+#sys.path.append("../")
 
 
 
-- 
GitLab


From 4f45e4098edfea8753034e39bd4e9d24262d56c1 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 31 Jan 2025 15:17:49 +0000
Subject: [PATCH 55/70] add deacy time, PT, dira and vtx chi2 branches

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 33 +++++++++++++++++++-------
 bu2kdarkscalar_darkscalar2hh/job.py    |  3 ++-
 2 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 7e73c3024b..ca7949649b 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -9,17 +9,14 @@ from typing import Any, Union
 from Configurables import DaVinci
 import GaudiPython
 from LoKiArrayFunctors.decorators import AMAXDOCA
-from LoKiMC.decorators import MCINANCESTORS, MCID
+from LoKiMC.decorators import MCINANCESTORS, MCID, DTF_FUN
+from LoKiPhys.decorators import DIRA
 import ROOT
 
 from dtf import dtf #dtf: decay tree fitter
 import MCEventTools
 
-
-
-
-
-class Ntuple:
+class Ntuple():
     """Class for storing an ntuple."""
 
     ###########################################################################
@@ -82,7 +79,7 @@ class Ntuple:
         else:
             self.pvrs = "/Event/Leptonic/" + self.pvrs
         vrsVrt = ["x", "y", "z", "dx", "dy", "dz"]
-        vrsMom = ["px", "py", "pz", "e"]
+        vrsMom = ["px", "py", "pz", "pt", "e"]
         vrsTrk = [
             "pnn_e",
             "pnn_mu",
@@ -99,6 +96,7 @@ class Ntuple:
             "dm",
             "idx_pvr",
             "veloCharge",
+            "dira",
         ]
         for h in range(0, self.nhit):
             vrsTrk += [f"x{h}", f"y{h}", f"z{h}", f"t{h}", f"p{h}"]
@@ -117,6 +115,9 @@ class Ntuple:
                 "vt_tip",
                 "vt_d",
                 "htrackOL",
+                "dira",
+                "decay_time",
+                "vtx_chi2",
             ]
             + [
                 f"{dtf}dtf_{x}"
@@ -283,11 +284,13 @@ class Ntuple:
             self.fill(f"{pre}_px", -1)
             self.fill(f"{pre}_py", -1)
             self.fill(f"{pre}_pz", -1)
+            self.fill(f"{pre}_pt", -1)
             self.fill(f"{pre}_e", -1)
         else:
             self.fill(f"{pre}_px", mom.Px())
             self.fill(f"{pre}_py", mom.Py())
             self.fill(f"{pre}_pz", mom.Pz())
+            self.fill(f"{pre}_pt", mom.perp())
             self.fill(f"{pre}_e", mom.E())
 
     ###########################################################################
@@ -348,7 +351,7 @@ class Ntuple:
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                #debug_print(f"mcp.pid is set to {mcp.pid}")
+                debug_print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
@@ -719,6 +722,14 @@ class Ntuple:
         self.fill(f"{pre}_ip", ip.value)
         self.fill(f"{pre}_ip_chi2", ipChi2.value)
 
+        # DIRA.
+        self.fill(f"{pre}_dira", (DIRA(pvr)(prt)))
+
+        # Decay time.
+        self.fill(f"{pre}_decay_time", DTF_FUN("CTAU")(prt))
+
+        # Vrtx chi 2.
+        self.fill(f"{pre}_vtx_chi2", vrt.chi2())
         return pvr
 
     ###########################################################################
@@ -784,6 +795,7 @@ class Ntuple:
             self._dstTool.distance(prt, pvr, ip, ipChi2)
         self.fill(f"{pre}_ip", ip.value)
         self.fill(f"{pre}_ip_chi2", ipChi2.value)
+        self.fill(f"{pre}_dira", (DIRA(pvr)(prt)))
         return pvr
 
     ###########################################################################
@@ -847,8 +859,11 @@ def fill_ntuple(
     genTool,
     debug_print: "function"
 ):
-    debug_print(f"hh is {hh}")
+
     """Assign values to the ntuple."""
+
+    debug_print(f"hh is {hh}")
+
     year = int(DaVinci().DataType)
 
     def get_particles(candloc):
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 1537fec627..6a39c00803 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -14,7 +14,7 @@ import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
 
-#sys.path.append("../")
+sys.path.append("../")
 
 
 
@@ -164,6 +164,7 @@ if "MDST" == DaVinci().InputType:
 # Run.
 gaudi = GaudiPython.AppMgr()
 tes = gaudi.evtsvc()
+
 ntuple = Ntuple(gaudi, output_filename)
 # Setting up tools for MC BG categorizing
 genTool = (
-- 
GitLab


From 061cb144113e103b65c622f3e85ba0dd2ab60653 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 31 Jan 2025 15:26:37 +0000
Subject: [PATCH 56/70] comment

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 8 ++++----
 bu2kdarkscalar_darkscalar2hh/job.py    | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index ca7949649b..b5976b5da5 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -9,8 +9,8 @@ from typing import Any, Union
 from Configurables import DaVinci
 import GaudiPython
 from LoKiArrayFunctors.decorators import AMAXDOCA
-from LoKiMC.decorators import MCINANCESTORS, MCID, DTF_FUN
-from LoKiPhys.decorators import DIRA
+from LoKiMC.decorators import MCINANCESTORS, MCID
+from LoKiPhys.decorators import DIRA, DTF_CTAU
 import ROOT
 
 from dtf import dtf #dtf: decay tree fitter
@@ -351,7 +351,7 @@ class Ntuple():
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                debug_print(f"mcp.pid is set to {mcp.pid}")
+                #debug_print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
@@ -726,7 +726,7 @@ class Ntuple():
         self.fill(f"{pre}_dira", (DIRA(pvr)(prt)))
 
         # Decay time.
-        self.fill(f"{pre}_decay_time", DTF_FUN("CTAU")(prt))
+        self.fill(f"{pre}_decay_time", DTF_CTAU(prt))
 
         # Vrtx chi 2.
         self.fill(f"{pre}_vtx_chi2", vrt.chi2())
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 6a39c00803..5a709966ed 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -14,7 +14,7 @@ import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
 
-sys.path.append("../")
+#sys.path.append("../")
 
 
 
-- 
GitLab


From 5dc35cb74a623b186d4fd851afcf2fabb9d40795 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 31 Jan 2025 15:40:37 +0000
Subject: [PATCH 57/70] calc pt correctly

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index b5976b5da5..313f70b6aa 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -10,7 +10,7 @@ from Configurables import DaVinci
 import GaudiPython
 from LoKiArrayFunctors.decorators import AMAXDOCA
 from LoKiMC.decorators import MCINANCESTORS, MCID
-from LoKiPhys.decorators import DIRA, DTF_CTAU
+from LoKiPhys.decorators import DIRA, DTF_CTAU, PT
 import ROOT
 
 from dtf import dtf #dtf: decay tree fitter
@@ -284,13 +284,11 @@ class Ntuple():
             self.fill(f"{pre}_px", -1)
             self.fill(f"{pre}_py", -1)
             self.fill(f"{pre}_pz", -1)
-            self.fill(f"{pre}_pt", -1)
             self.fill(f"{pre}_e", -1)
         else:
             self.fill(f"{pre}_px", mom.Px())
             self.fill(f"{pre}_py", mom.Py())
             self.fill(f"{pre}_pz", mom.Pz())
-            self.fill(f"{pre}_pt", mom.perp())
             self.fill(f"{pre}_e", mom.E())
 
     ###########################################################################
@@ -730,6 +728,9 @@ class Ntuple():
 
         # Vrtx chi 2.
         self.fill(f"{pre}_vtx_chi2", vrt.chi2())
+
+        # PT.
+        self.fill(f"{pre}_pt", PT(prt))
         return pvr
 
     ###########################################################################
@@ -796,6 +797,7 @@ class Ntuple():
         self.fill(f"{pre}_ip", ip.value)
         self.fill(f"{pre}_ip_chi2", ipChi2.value)
         self.fill(f"{pre}_dira", (DIRA(pvr)(prt)))
+        self.fill(f"{pre}_pt", PT(prt))
         return pvr
 
     ###########################################################################
-- 
GitLab


From 28e0241ff17f8bf38704551075bbd4ccc55329fd Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 31 Jan 2025 16:05:06 +0000
Subject: [PATCH 58/70] CTAU needs 2 args

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 313f70b6aa..0205ee358e 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -724,7 +724,7 @@ class Ntuple():
         self.fill(f"{pre}_dira", (DIRA(pvr)(prt)))
 
         # Decay time.
-        self.fill(f"{pre}_decay_time", DTF_CTAU(prt))
+        self.fill(f"{pre}_decay_time", DTF_CTAU(prt, True))
 
         # Vrtx chi 2.
         self.fill(f"{pre}_vtx_chi2", vrt.chi2())
-- 
GitLab


From a4b5d3d747a0fbac0d2a48f7c93fb04be7cdd414 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 3 Feb 2025 13:46:10 +0000
Subject: [PATCH 59/70] add ctau to dtf and modify debug # Please enter the
 commit message for your changes. Lines starting

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 40 ++++++++++++++++++--------
 bu2kdarkscalar_darkscalar2hh/debug.py  |  5 ++++
 bu2kdarkscalar_darkscalar2hh/dtf.py    |  9 ++++++
 bu2kdarkscalar_darkscalar2hh/job.py    |  1 -
 4 files changed, 42 insertions(+), 13 deletions(-)
 create mode 100644 bu2kdarkscalar_darkscalar2hh/debug.py

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 0205ee358e..4ca61a7a14 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -10,13 +10,25 @@ from Configurables import DaVinci
 import GaudiPython
 from LoKiArrayFunctors.decorators import AMAXDOCA
 from LoKiMC.decorators import MCINANCESTORS, MCID
-from LoKiPhys.decorators import DIRA, DTF_CTAU, PT
+from LoKiPhys.decorators import DIRA, PT
 import ROOT
 
 from dtf import dtf #dtf: decay tree fitter
 import MCEventTools
 
-class Ntuple():
+from bu2kdarkscalar_darkscalar2hh.debug import debug_print
+
+class Debuggable():
+    def __getattribute__(self, name):
+        attr = object.__getattribute__(self, name)
+        if callable(attr) and not name.startswith("__"):
+            def wrapper(*args, **kwargs):
+                debug_print(f"Calling method: {name} with args: {args} kwargs: {kwargs}")
+                return attr(*args, **kwargs)
+            return wrapper
+        return attr
+
+class Ntuple(Debuggable):
     """Class for storing an ntuple."""
 
     ###########################################################################
@@ -116,7 +128,7 @@ class Ntuple():
                 "vt_d",
                 "htrackOL",
                 "dira",
-                "decay_time",
+                "dtf_decay_time",
                 "vtx_chi2",
             ]
             + [
@@ -349,20 +361,20 @@ class Ntuple():
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                #debug_print(f"mcp.pid is set to {mcp.pid}")
+                debug_print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
                     if mcp.pid in (-211, -321):
                         dptype = "hm"
-                        #debug_print(f"found mcp particle which is hm with pid {mcp.pid}")
+                        debug_print(f"found mcp particle which is hm with pid {mcp.pid}")
                     elif mcp.pid in (211, 321):
                         dptype = "hp" 
-                        #debug_print(f"found mcp particle which is hp with pid {mcp.pid}")
+                        debug_print(f"found mcp particle which is hp with pid {mcp.pid}")
                 elif dptype == "K":
                     if mcp.pid in (321, -321):
                         dptype = "K"
-                        #debug_print(f"found mcp particle which is K with pid {mcp.pid}")
+                        debug_print(f"found mcp particle which is K with pid {mcp.pid}")
                 pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
@@ -532,8 +544,8 @@ class Ntuple():
                 return False
             return True
 
-        pdtf = dtf(prt, pvr, True)
-        ddtf = dtf(prt, pvr, False)
+        pdtf = dtf(prt, pvr, True) #decay tree fitter with mass constraint
+        ddtf = dtf(prt, pvr, False) #decay tree fitter without mass constraint
         if prt.particleID().pid() in (-521, 521):
             # B- or B+
             pdtf.fit()
@@ -541,6 +553,9 @@ class Ntuple():
             assert pdtf.dihadron == ddtf.dihadron
             assert pdtf.dihadron is not None
             dtrp = pdtf.dihadron.momentum()
+
+            #help(prt)
+
         elif prt.particleID().pid() == 310:
             # dihadron candidate
             dtrp = prt.momentum()
@@ -723,15 +738,16 @@ class Ntuple():
         # DIRA.
         self.fill(f"{pre}_dira", (DIRA(pvr)(prt)))
 
-        # Decay time.
-        self.fill(f"{pre}_decay_time", DTF_CTAU(prt, True))
-
         # Vrtx chi 2.
         self.fill(f"{pre}_vtx_chi2", vrt.chi2())
 
         # PT.
         self.fill(f"{pre}_pt", PT(prt))
+
+        self.fill(f"{pre}_ddtf_decay_time", ddtf.get_ctau())
+
         return pvr
+    
 
     ###########################################################################
     def _fillTrk(self, pre: str, prt, org, year: "int", run: "int"):
diff --git a/bu2kdarkscalar_darkscalar2hh/debug.py b/bu2kdarkscalar_darkscalar2hh/debug.py
new file mode 100644
index 0000000000..2ef3e72867
--- /dev/null
+++ b/bu2kdarkscalar_darkscalar2hh/debug.py
@@ -0,0 +1,5 @@
+
+DEBUG = False
+def debug_print(*args):
+    if DEBUG:
+        print(*args)
\ No newline at end of file
diff --git a/bu2kdarkscalar_darkscalar2hh/dtf.py b/bu2kdarkscalar_darkscalar2hh/dtf.py
index 826477d4e8..f756c006e5 100644
--- a/bu2kdarkscalar_darkscalar2hh/dtf.py
+++ b/bu2kdarkscalar_darkscalar2hh/dtf.py
@@ -14,6 +14,7 @@ class dtf:
 
         self._dtf = None  # the DecayTreeFitter (must be stored for persistency)
         self._dtf_mom = None  # the fitted B momentum
+        self._dtf_ctau = None  # the ctau
         self._dtf_cov = None  # the covariance matrix of the fitted position
         self._dtf_pos = None  # the fitted vertex position
         self._dtf_chi2 = None  # the chi2 of the fit
@@ -29,6 +30,7 @@ class dtf:
         self._reset_prompt()
         params = [
             self._dtf_mom,
+            self._dtf_ctau,
             self._dtf_cov,
             self._dtf_pos,
             self._dtf_chi2,
@@ -72,8 +74,10 @@ class dtf:
             if self._dtf.status() == self._dtf.Success:
                 dtf_params = self._dtf.fitParams(self.particle)
                 dtf_momentum = dtf_params.momentum()
+                dtf_ctau = dtf_params.ctau()
                 if dtf_momentum.m().error() != 0:
                     self._dtf_mom = dtf_momentum
+                    self._dtf_ctau = dtf_ctau
                     self._dtf_chi2 = self._dtf.chiSquare()
                     self._dtf_cov = dtf_params.posCovMatrix()
                     self._dtf_pos = dtf_params.position()
@@ -106,3 +110,8 @@ class dtf:
     def get_dih_momentum(self):
         """Return the fitted dihadron momentum."""
         return self._dtf_dtrp
+    
+    def get_ctau(self):
+        """Return the ctau."""
+        return self._dtf_ctau
+
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 5a709966ed..1537fec627 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -164,7 +164,6 @@ if "MDST" == DaVinci().InputType:
 # Run.
 gaudi = GaudiPython.AppMgr()
 tes = gaudi.evtsvc()
-
 ntuple = Ntuple(gaudi, output_filename)
 # Setting up tools for MC BG categorizing
 genTool = (
-- 
GitLab


From a13c00406a590438d9a45d3c54a21f8ef604e1c7 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 3 Feb 2025 14:03:48 +0000
Subject: [PATCH 60/70] decay time branches named wrong

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 4ca61a7a14..a62db2e17d 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -13,7 +13,7 @@ from LoKiMC.decorators import MCINANCESTORS, MCID
 from LoKiPhys.decorators import DIRA, PT
 import ROOT
 
-from dtf import dtf #dtf: decay tree fitter
+from dtf import dtf #dtf: decay tree fitter, this is defined in the dtf.py file, needed to add the branches which are dtf varibles
 import MCEventTools
 
 from bu2kdarkscalar_darkscalar2hh.debug import debug_print
@@ -128,13 +128,12 @@ class Ntuple(Debuggable):
                 "vt_d",
                 "htrackOL",
                 "dira",
-                "dtf_decay_time",
                 "vtx_chi2",
             ]
             + [
                 f"{dtf}dtf_{x}"
                 for dtf in ["p", "d"] # p: parent, d: daughter
-                for x in ["m", "dm", "chi2"]
+                for x in ["m", "dm", "chi2", "decay_time"]
                 + vrsMom
                 + vrsVrt
                 + [f"dih_{y}" for y in ["m"] + vrsMom]
@@ -744,7 +743,9 @@ class Ntuple(Debuggable):
         # PT.
         self.fill(f"{pre}_pt", PT(prt))
 
+        # Decay time.
         self.fill(f"{pre}_ddtf_decay_time", ddtf.get_ctau())
+        self.fill(f"{pre}_pdtf_decay_time", pdtf.get_ctau())
 
         return pvr
     
-- 
GitLab


From 8b836db79dab2f135ec69905ccdba24434b3c40e Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 3 Feb 2025 17:10:54 +0000
Subject: [PATCH 61/70] ctau correction now working

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 6 ++++--
 bu2kdarkscalar_darkscalar2hh/dtf.py    | 9 ++++++---
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index a62db2e17d..68270f24d5 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -744,8 +744,10 @@ class Ntuple(Debuggable):
         self.fill(f"{pre}_pt", PT(prt))
 
         # Decay time.
-        self.fill(f"{pre}_ddtf_decay_time", ddtf.get_ctau())
-        self.fill(f"{pre}_pdtf_decay_time", pdtf.get_ctau())
+        self.fill(f"{pre}_ddtf_decay_time", -1 if ddtf.get_ctau() is None else ddtf.get_ctau().value())
+
+
+        self.fill(f"{pre}_pdtf_decay_time", -1 if pdtf.get_ctau() is None else pdtf.get_ctau().value())
 
         return pvr
     
diff --git a/bu2kdarkscalar_darkscalar2hh/dtf.py b/bu2kdarkscalar_darkscalar2hh/dtf.py
index f756c006e5..117814acbd 100644
--- a/bu2kdarkscalar_darkscalar2hh/dtf.py
+++ b/bu2kdarkscalar_darkscalar2hh/dtf.py
@@ -3,6 +3,9 @@ from typing import Any
 
 import GaudiPython
 
+from GaudiKernel.PhysicalConstants import c_light
+
+
 
 class dtf:
     """Create a DecayTreeFitter and extract some information."""
@@ -14,7 +17,7 @@ class dtf:
 
         self._dtf = None  # the DecayTreeFitter (must be stored for persistency)
         self._dtf_mom = None  # the fitted B momentum
-        self._dtf_ctau = None  # the ctau
+        self._dtf_ctau = None  # the proper Decay Time
         self._dtf_cov = None  # the covariance matrix of the fitted position
         self._dtf_pos = None  # the fitted vertex position
         self._dtf_chi2 = None  # the chi2 of the fit
@@ -77,7 +80,7 @@ class dtf:
                 dtf_ctau = dtf_params.ctau()
                 if dtf_momentum.m().error() != 0:
                     self._dtf_mom = dtf_momentum
-                    self._dtf_ctau = dtf_ctau
+                    self._dtf_ctau = dtf_ctau/c_light
                     self._dtf_chi2 = self._dtf.chiSquare()
                     self._dtf_cov = dtf_params.posCovMatrix()
                     self._dtf_pos = dtf_params.position()
@@ -112,6 +115,6 @@ class dtf:
         return self._dtf_dtrp
     
     def get_ctau(self):
-        """Return the ctau."""
+        """Return the get the decay time in units of time."""
         return self._dtf_ctau
 
-- 
GitLab


From 399b24859395b387c1195f96751ac2bdf2a2c4b6 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 4 Feb 2025 15:30:50 +0000
Subject: [PATCH 62/70] test

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 22 +++-------------------
 bu2kdarkscalar_darkscalar2hh/debug.py  |  5 -----
 2 files changed, 3 insertions(+), 24 deletions(-)
 delete mode 100644 bu2kdarkscalar_darkscalar2hh/debug.py

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 68270f24d5..403d0af407 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -16,19 +16,7 @@ import ROOT
 from dtf import dtf #dtf: decay tree fitter, this is defined in the dtf.py file, needed to add the branches which are dtf varibles
 import MCEventTools
 
-from bu2kdarkscalar_darkscalar2hh.debug import debug_print
-
-class Debuggable():
-    def __getattribute__(self, name):
-        attr = object.__getattribute__(self, name)
-        if callable(attr) and not name.startswith("__"):
-            def wrapper(*args, **kwargs):
-                debug_print(f"Calling method: {name} with args: {args} kwargs: {kwargs}")
-                return attr(*args, **kwargs)
-            return wrapper
-        return attr
-
-class Ntuple(Debuggable):
+class Ntuple():
     """Class for storing an ntuple."""
 
     ###########################################################################
@@ -360,20 +348,16 @@ class Ntuple(Debuggable):
         """
         if mcp: # mcp: monte carlo particle, this is a boolean
             if mcp.pid in (310, 211, -211, 321, -321, 521, -521): #MC particle must be Ks, +/- pi, +/- K, +/- B
-                debug_print(f"mcp.pid is set to {mcp.pid}")
 
                 if dptype in ("hadron0", "hadron1"):
                     #only when we inspect pid do we know the charges associated to hadron0 and hadron1
                     if mcp.pid in (-211, -321):
                         dptype = "hm"
-                        debug_print(f"found mcp particle which is hm with pid {mcp.pid}")
                     elif mcp.pid in (211, 321):
-                        dptype = "hp" 
-                        debug_print(f"found mcp particle which is hp with pid {mcp.pid}")
+                        dptype = "hp"
                 elif dptype == "K":
                     if mcp.pid in (321, -321):
                         dptype = "K"
-                        debug_print(f"found mcp particle which is K with pid {mcp.pid}")
                 pass
             else:
                 raise ValueError(f"mcp.pid {mcp.pid} not recognized")
@@ -913,7 +897,7 @@ def fill_ntuple(
     debug_print(f"got {len(all_Bparticles)} B mesons from {candidate_loc}")
 
 
-    if DaVinci().Simulation and len(all_Bparticles) > 0:
+    if DaVinci().Simulation:
         mct = MCEventTools.MCEvent(all_Bparticles, genTool, hh) # mct: monte carlo tool
         mct.linkpars()
         mcpstore = get_particles('/Event/AllStreams/MC/Particles')
diff --git a/bu2kdarkscalar_darkscalar2hh/debug.py b/bu2kdarkscalar_darkscalar2hh/debug.py
deleted file mode 100644
index 2ef3e72867..0000000000
--- a/bu2kdarkscalar_darkscalar2hh/debug.py
+++ /dev/null
@@ -1,5 +0,0 @@
-
-DEBUG = False
-def debug_print(*args):
-    if DEBUG:
-        print(*args)
\ No newline at end of file
-- 
GitLab


From 455667b5a5d1c3b89dbedf71df8d6dfb4f9a0b75 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Fri, 7 Feb 2025 14:36:05 +0000
Subject: [PATCH 63/70] add new jobs

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index ae377d3eec..5df9c9b6b9 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,7 +1,9 @@
 {%- set polarities = ["Down", "Up"]%}
-{%- set MCnormalisationDatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged')]%}
-{%- set MCsignalDatasets = [('KK', 18, 12103047, 6500, '18', '34NoPrescalingFlagged'),
-                            ('PiPi', 18, 12103056, 6500, '18', '34NoPrescalingFlagged')]%}
+
+{%- set MCnormalisationDatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged'),
+                                   ('PiPi', 18, 12103024, 6500, '18', '34NoPrescalingFlagged')]%}
+{%- set MCsignalDatasets = [('KK', 18, 12103047, '1100', '20', 6500, '18', '34NoPrescalingFlagged'),
+                            ('PiPi', 18, 12103056, '1100', '20', 6500, '18', '34NoPrescalingFlagged')]%}
 
 {%- for polarity in polarities %}
 {%- for hh, year, eventnumber, energy, reco, strip in MCnormalisationDatasets %}
@@ -25,9 +27,9 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
 
 {%- endfor %}
 
-{%- for hh, year, eventnumber, energy, reco, strip in MCsignalDatasets %}
+{%- for hh, year, eventnumber, chiMass, chiLifetime, energy, reco, strip in MCsignalDatasets %}
 
-my_B2KDarkScalar_DarkScalar2{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
+my_B2KDarkScalar_DarkScalar2{{hh}}_{{massChi}}MeV{{lieftimeChi}}ps_20{{year}}_Mag{{polarity}}_MC_job:
   application: DaVinci/v46r8
   wg: QEE
   automatically_configure: yes
@@ -46,4 +48,17 @@ my_B2KDarkScalar_DarkScalar2{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
 
 {%- endfor %}
 
+
+
+my_20{{year}}_Mag{{polarity}}_{{hh}}_Data_job:
+  input:
+    bk_query: "/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34/90000000/LEPTONIC.MDST"
+  options:
+    command:
+      - python
+    files:
+      - job.py
+      - hh_{{hh}}.py
+
+
 {%- endfor %}
\ No newline at end of file
-- 
GitLab


From 97f794ba04386e7a4bc367bb613b5e44ab29e224 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 10 Feb 2025 09:31:26 +0000
Subject: [PATCH 64/70] fix typo

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

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 5df9c9b6b9..fd8ac69b67 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -29,7 +29,7 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
 
 {%- for hh, year, eventnumber, chiMass, chiLifetime, energy, reco, strip in MCsignalDatasets %}
 
-my_B2KDarkScalar_DarkScalar2{{hh}}_{{massChi}}MeV{{lieftimeChi}}ps_20{{year}}_Mag{{polarity}}_MC_job:
+my_B2KDarkScalar_DarkScalar2{{hh}}_{{chiMass}}MeV{{chiLifetime}}ps_20{{year}}_Mag{{polarity}}_MC_job:
   application: DaVinci/v46r8
   wg: QEE
   automatically_configure: yes
-- 
GitLab


From 68aade1209cfa6d9c44d17f815e7f8cac33a39ad Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 10 Feb 2025 09:53:40 +0000
Subject: [PATCH 65/70] restructure jobs

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index fd8ac69b67..58a3b6cfac 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -5,7 +5,11 @@
 {%- set MCsignalDatasets = [('KK', 18, 12103047, '1100', '20', 6500, '18', '34NoPrescalingFlagged'),
                             ('PiPi', 18, 12103056, '1100', '20', 6500, '18', '34NoPrescalingFlagged')]%}
 
+{%- set Datasets = [('KK', 18),
+                    ('PiPi', 18)]%}
+
 {%- for polarity in polarities %}
+
 {%- for hh, year, eventnumber, energy, reco, strip in MCnormalisationDatasets %}
 
 my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
@@ -48,7 +52,7 @@ my_B2KDarkScalar_DarkScalar2{{hh}}_{{chiMass}}MeV{{chiLifetime}}ps_20{{year}}_Ma
 
 {%- endfor %}
 
-
+{%- for hh, year in Datasets %}
 
 my_20{{year}}_Mag{{polarity}}_{{hh}}_Data_job:
   input:
@@ -59,6 +63,9 @@ my_20{{year}}_Mag{{polarity}}_{{hh}}_Data_job:
     files:
       - job.py
       - hh_{{hh}}.py
+  output: b2kdarkscalar_darkscalar2hh_data.root
 
 
+{%- endfor %}
+
 {%- endfor %}
\ No newline at end of file
-- 
GitLab


From 3044d0853df2466b0dfe299ea96d9f981ecb0606 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 10 Feb 2025 10:25:00 +0000
Subject: [PATCH 66/70] correct

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index 58a3b6cfac..eb441084b0 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -55,6 +55,12 @@ my_B2KDarkScalar_DarkScalar2{{hh}}_{{chiMass}}MeV{{chiLifetime}}ps_20{{year}}_Ma
 {%- for hh, year in Datasets %}
 
 my_20{{year}}_Mag{{polarity}}_{{hh}}_Data_job:
+  application: DaVinci/v46r8
+  wg: QEE
+  automatically_configure: yes
+  turbo: no
+  inform:
+    - eleanor.whiter@cern.ch
   input:
     bk_query: "/LHCb/Collision18/Beam6500GeV-VeloClosed-Mag{{polarity}}/Real Data/Reco18/Stripping34/90000000/LEPTONIC.MDST"
   options:
-- 
GitLab


From 39e390757d95832b09274e933fe3dc664ee8d3fe Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 10 Feb 2025 11:26:30 +0000
Subject: [PATCH 67/70] bk query correction

---
 bu2kdarkscalar_darkscalar2hh/info.yaml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index eb441084b0..f971249eed 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -1,7 +1,7 @@
 {%- set polarities = ["Down", "Up"]%}
 
-{%- set MCnormalisationDatasets = [('KK', 18, 12103012, 6500, '18', '34NoPrescalingFlagged'),
-                                   ('PiPi', 18, 12103024, 6500, '18', '34NoPrescalingFlagged')]%}
+{%- set MCnormalisationDatasets = [('KK', 18, 12103012, 6500, '10d', '18', '34NoPrescalingFlagged'),
+                                   ('PiPi', 18, 12103024, 6500, '09h', '18', '34NoPrescalingFlagged')]%}
 {%- set MCsignalDatasets = [('KK', 18, 12103047, '1100', '20', 6500, '18', '34NoPrescalingFlagged'),
                             ('PiPi', 18, 12103056, '1100', '20', 6500, '18', '34NoPrescalingFlagged')]%}
 
@@ -20,7 +20,7 @@ my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   inform:
     - eleanor.whiter@cern.ch
   input:
-     bk_query: /MC/20{{year}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim10d/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/{{eventnumber}}/ALLSTREAMS.MDST
+     bk_query: /MC/20{{year}}/Beam{{energy}}GeV-20{{year}}-Mag{{polarity}}-Nu1.6-25ns-Pythia8/Sim{{sim}}/Trig0x617d18a4/Reco{{year}}/Turbo05-WithTurcal/Stripping{{strip}}/{{eventnumber}}/ALLSTREAMS.MDST
   options:
      command:
       - python
-- 
GitLab


From 2f29e9d5534003872fd32a8719fa64d01a393483 Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Mon, 10 Feb 2025 13:03:47 +0000
Subject: [PATCH 68/70] correct info.yaml

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

diff --git a/bu2kdarkscalar_darkscalar2hh/info.yaml b/bu2kdarkscalar_darkscalar2hh/info.yaml
index f971249eed..e0c0241bc7 100644
--- a/bu2kdarkscalar_darkscalar2hh/info.yaml
+++ b/bu2kdarkscalar_darkscalar2hh/info.yaml
@@ -10,7 +10,7 @@
 
 {%- for polarity in polarities %}
 
-{%- for hh, year, eventnumber, energy, reco, strip in MCnormalisationDatasets %}
+{%- for hh, year, eventnumber, energy, sim, reco, strip in MCnormalisationDatasets %}
 
 my_B2K{{hh}}_20{{year}}_Mag{{polarity}}_MC_job:
   application: DaVinci/v46r8
-- 
GitLab


From 98561d3ec6b513f61cb88c13c108f9cea7acae4d Mon Sep 17 00:00:00 2001
From: Eleanor Whiter <eleanor.whiter@cern.ch>
Date: Tue, 11 Feb 2025 09:16:22 +0000
Subject: [PATCH 69/70] fix dira errors

---
 bu2kdarkscalar_darkscalar2hh/Ntuple.py | 2 --
 bu2kdarkscalar_darkscalar2hh/job.py    | 2 +-
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/Ntuple.py b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
index 403d0af407..79bcc8aaf7 100644
--- a/bu2kdarkscalar_darkscalar2hh/Ntuple.py
+++ b/bu2kdarkscalar_darkscalar2hh/Ntuple.py
@@ -96,7 +96,6 @@ class Ntuple():
             "dm",
             "idx_pvr",
             "veloCharge",
-            "dira",
         ]
         for h in range(0, self.nhit):
             vrsTrk += [f"x{h}", f"y{h}", f"z{h}", f"t{h}", f"p{h}"]
@@ -799,7 +798,6 @@ class Ntuple():
             self._dstTool.distance(prt, pvr, ip, ipChi2)
         self.fill(f"{pre}_ip", ip.value)
         self.fill(f"{pre}_ip_chi2", ipChi2.value)
-        self.fill(f"{pre}_dira", (DIRA(pvr)(prt)))
         self.fill(f"{pre}_pt", PT(prt))
         return pvr
 
diff --git a/bu2kdarkscalar_darkscalar2hh/job.py b/bu2kdarkscalar_darkscalar2hh/job.py
index 1537fec627..cd6e437bfc 100644
--- a/bu2kdarkscalar_darkscalar2hh/job.py
+++ b/bu2kdarkscalar_darkscalar2hh/job.py
@@ -14,7 +14,7 @@ import ROOT
 #when running locally you need to uncomment the following lines
 #but if you are running on the grid, you need to comment them
 
-#sys.path.append("../")
+sys.path.append("../")
 
 
 
-- 
GitLab


From 9b7239bcdb6664d16733e7bec37ac7e53a627345 Mon Sep 17 00:00:00 2001
From: Daniel Johnson <daniel.johnson@cern.ch>
Date: Tue, 11 Feb 2025 17:52:38 +0000
Subject: [PATCH 70/70] Fix memory leak (hopefully!)

---
 bu2kdarkscalar_darkscalar2hh/MCEventTools.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
index fb231e8cd3..d2cd954027 100644
--- a/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
+++ b/bu2kdarkscalar_darkscalar2hh/MCEventTools.py
@@ -198,13 +198,15 @@ class MCEvent:
             dps = [0,0]
             dpsv = None
             svcoor = None
-            for dp in all_B.daughters(): # loop over the daughters of the B+/B- particle
+            for i_dp in range(len(all_B.daughters())): # loop over the daughters of the B+/B- particle
+                dp = all_B.daughters()[i_dp]
                 if abs(ID(dp)) == 321:
                     dps[1] = MCPart(dp,pnnk=PROBNNk(dp),pnnpi=PROBNNpi(dp),pnng=PROBNNghost(dp),cl=CL(dp))
                 else:
                     hadrons = [0,0]
                     dpsv = dp.endVertex()
-                    for ddp in dp.endVertex().outgoingParticlesVector():
+                    for i_ddp in range(len(dp.endVertex().outgoingParticlesVector())):
+                        ddp = dp.endVertex().outgoingParticlesVector()[i_ddp]
                         hadron = MCPart(ddp)
                         hadron.update(newpnnk=PROBNNk(ddp),newpnnpi=PROBNNpi(ddp),newpnng=PROBNNghost(ddp),newtrgp=TRGHOSTPROB(ddp))
                         #debug_print(hadron.pid)
-- 
GitLab