跳转至

粒子组合器入门

学习目标

  • 理解LHCb中粒子组合器的工作原理
  • 学习如何筛选和组合径迹以形成衰变候选者

我们已经了解如何使用DaVinci将收集(或模拟)的数据处理为可用于分析的ROOT文件。但DaVinci软件的功能远不止于此。

在本课程中,我们将探讨粒子如何组合形成衰变描述符,以及如何对径迹或径迹组合应用不同的过滤器,以构建我们的物理分析案例。这是编写Sprucing或HLT2线路(将在专门课程中讲解)、对无偏置(NoBias)数据进行元组化(下一课将探讨)、以及在模拟样本中应用任何切割前检查不同选择条件的影响等能力的基础。

在Run 3中,DaVinci构建于Moore之上,Moore是配置HLT2的应用程序。这样做的一个优势是,我们可以使用Moore的函数构建自定义衰变,然后将输出写入ROOT文件以供检查。

以"首次分析步骤"课程中的示例为例,该示例处理的是通过HLT2线路选择的 \(B_s^0\to (D_s^- \to K^- K^+ \pi^-) \pi^+\) 模拟候选者。该线路本质上是选择三个强子径迹,两个K介子和一个π介子,并将它们拟合到一个共同顶点,我们将这个顶点与 \(D_s\^-\) 关联。然后,它将与该顶点关联的粒子与另一个π介子组合,将两者拟合到另一个顶点,关联到 \(B_s^0\) 介子。

此外,我们可以为每个径迹设置一些要求。例如,我们可能关注具有高IPCHI2的K介子和π介子(这样它们来自初级顶点(PV)的可能性更低);横动量(PT)也可用于此目的。我们可能还关注K介子的粒子鉴别信息,比如对PID_K设置切割。

然后,我们还可以对组合和顶点设置切割。由于我们希望强子来自 \(D_s^-\) ,可以通过将三个径迹的不变质量限制在母粒子质量范围内来实现这一点。我们还可以通过对CHI2DOF(卡方自由度比)设置切割来要求顶点拟合质量良好,并通过对两两径迹的最近距离(DOCA)设置切割来提高三个粒子来自同一点的可能性。

现在我们有了一个与良好顶点关联的ds对象,该顶点是两个K介子和一个π介子的起源。我们可以将这个对象与事件中的另一个π介子组合,形成 \(B_s^0\) 或 \(B^0\) 顶点。

以下是如何将三个强子组合形成 \(D_s^-\) ,然后将 \(D_s^-\) 与另一个π介子组合形成 \(B\) 介子的代码:

import Functors as F
from Functors.math import in_range
from RecoConf import standard_particles, algorithms_thor
from RecoConf.reconstruction_objects import make_pvs
from GaudiKernel.SystemOfUnits import GeV, MeV, mm, picosecond


def setup_selections() -> algorithms_thor.ParticleCombiner:
    '''
    Builds the D_s from two kaons and a pion with some basic selection
    Then builds the B_s from the D_s and a pion, also with basic selection
    Finally returns the B_s combination
    '''
    make_pions = standard_particles.make_long_pions()
    make_kaons = standard_particles.make_long_kaons()

    ## We need to import the PVs to calculate associated variables
    pvs = make_pvs()

    # Apply some cuts to the pions and kaons
    code_pions = F.require_all(F.PT > 250 * MeV, F.MINIPCHI2(pvs) > 4,)
    code_kaons = F.require_all(F.PT > 250 * MeV, F.MINIPCHI2(pvs) > 4, F.PID_K > 5) # Kaons can have an extra PID cut

    pions = algorithms_thor.ParticleFilter(make_pions, F.FILTER(code_pions))
    kaons = algorithms_thor.ParticleFilter(make_kaons, F.FILTER(code_kaons))

    # We now also apply cuts on the parent D_s
    ds_mass_bounds = in_range(1920 * MeV, F.MASS, 2010 * MeV)

    ds_combination = F.require_all(ds_mass_bounds, F.SDOCA(1, 3) < 0.2 * mm, 
                                F.SDOCA(2, 3) < 0.2 * mm)
    ds_vertex = F.require_all(ds_mass_bounds, F.CHI2DOF < 9)

    # Finally we combine the child particles into the parent
    ds = algorithms_thor.ParticleCombiner(
        [kaons, kaons, pions], ## The order is important here, must match that of the DecayDescriptor
        name="DsToKpKmPip",
        DecayDescriptor="[D_s- -> K+ K- pi-]cc",
        CombinationCut=ds_combination,
        CompositeCut=ds_vertex)

    # Cuts for the B_s (which we make from a pion and the D_s)
    b_mass_bounds = in_range(5050 * MeV, F.MASS, 5650 * MeV)

    b_combination = F.require_all(b_mass_bounds)
    b_vertex = F.require_all(b_mass_bounds, F.BPVIPCHI2(pvs) < 16,
                            F.BPVLTIME(pvs) > 0.2 * picosecond)

    # Combine the pion and the D_s
    bmeson = algorithms_thor.ParticleCombiner(
        [ds, pions],
        name="BToDsmPip",
        DecayDescriptor="[B0 -> D_s- pi+]cc",
        CombinationCut=b_combination,
        CompositeCut=b_vertex
    )

    return bmeson
我们可以使用此函数在模拟数据上构建自定义衰变:

'''
lb-run -c x86_64_v3-el9-gcc13+detdesc-opt+g DaVinci/v65r0 lbexec DV_advanced1:main DVoptions.yaml
'''
import Functors as F
import FunTuple.functorcollections as FC
from DaVinci import Options, make_config
from DaVinci.algorithms import create_lines_filter
from FunTuple import FunctorCollection
from FunTuple import FunTuple_Particles as Funtuple
from PyConf.reading import get_particles, get_pvs
from RecoConf.event_filters import require_pvs


def main(options: Options):
    bmeson = setup_selections() # Taken from the above snippet
    pvs = get_pvs()

    fields = {
        "Bs": "[B0 -> (D_s- -> K- K+ pi-) pi+]CC", #Note here, we call the parent a B0 even though it's a Bs, because it needs to match the reconstruction in the trigger line
        "Ds": "[B0 -> ^(D_s- -> K- K+ pi-) pi+]CC",
        "Bs_pi": "[B0 -> (D_s- -> K- K+ pi-) ^pi+]CC",
        "Ds_pi": "[B0 -> (D_s- -> K- K+ ^pi-) pi+]CC",
        "Km": "[B0 -> (D_s- -> ^K- K+ pi-) pi+]CC",
        "Kp": "[B0 -> (D_s- -> K- ^K+ pi-) pi+]CC",
    }

    all_vars = FunctorCollection({
        "M": F.MASS,
        "P": F.P,
        "PT": F.PT
    })

    variables = {"ALL": all_vars}

    funtuple = Funtuple(
        name="MyTuple",
        tuple_name="DecayTree",
        fields=fields,
        variables=variables,
        inputs=bmeson,
    )

    return make_config(options, [require_pvs(pvs), funtuple])

配置文件与之前的DaVinci课程相同:

input_files:
- root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp7/Run3SK/exampleDST/00257716_00000011_1.hlt2.dst
input_type: ROOT
output_type: ROOT
input_raw_format: 0.5
simulation: true
input_process: Hlt2
input_stream: b2oc
conddb_tag: sim10-2024.W37.39-v00.00-md100
dddb_tag: dddb-20240427
lumi: false
data_type: '2024'
evt_max: 1000
print_freq: 100
ntuple_file: tuple.root