###############################################################################
# (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. #
###############################################################################
"""The following lines are defined (charge conjugates are implied):
Lambda_c+ -> p+ (KS0 -> pi+ pi-)
Lambda_c+ -> p+ (KS0 -> pi+ pi-) K+ K-
Lambda_c+ -> p+ (KS0 -> pi+ pi-) K- pi+
Lambda_c+ -> p+ (KS0 -> pi+ pi-) K+ pi-
Lambda_c+ -> p+ (KS0 -> pi+ pi-) pi+ pi-
Lambda_c+ -> p+ (KS0 -> pi+ pi-) (KS0 -> pi+ pi-)
In the last line one KS0 is renamed as KL0 to avoid clash in having same
particles with two different containers.
Xic+ is reconstructed together with Lc+.
Both LL and DD modes of L0/KS0 are included as a separate lines.
Proponents: Miroslav Saur, Xiao-Rui Lyu, Ziyi Wang
TODO: Revisit all DD lines ; based on data move pion filters directly to KS builders ; remove decay descriptor from combine_lc_ks_ks_p when naming issue is solved
"""
import Functors as F
from Functors.math import in_range
from GaudiKernel.SystemOfUnits import GeV, MeV, mm
from Moore.config import register_line_builder
from Moore.lines import Hlt2Line
from RecoConf.reconstruction_objects import make_pvs
from ...standard_particles import (
make_has_rich_long_pions, make_has_rich_long_kaons,
make_has_rich_long_protons, make_has_rich_down_pions)
from ...algorithms_thor import ParticleCombiner, ParticleFilter
from .prefilters import charm_prefilters
all_lines = {}
###################
## track filters ##
###################
def filter_long_pions(pvs,
pt_min=300 * MeV,
p_min=2 * GeV,
mipchi2_min=5.,
pion_pidk_max=0.):
"""Filter long pions with P PT, MINIPCHI2CUT and pidp cuts."""
cut = F.require_all(F.PT > pt_min, F.P > p_min,
F.MINIPCHI2CUT(IPChi2Cut=mipchi2_min, Vertices=pvs),
F.PID_K < pion_pidk_max)
return ParticleFilter(make_has_rich_long_pions(), F.FILTER(cut))
def filter_long_pions_from_strange(pvs,
pt_min=100 * MeV,
p_min=2 * GeV,
mipchi2_min=15.,
pion_pidk_max=5.):
"""Filter long pions with P PT, MINIPCHI2CUT and pidp cuts."""
cut = F.require_all(F.PT > pt_min, F.P > p_min,
F.MINIPCHI2CUT(IPChi2Cut=mipchi2_min, Vertices=pvs),
F.PID_K < pion_pidk_max)
return ParticleFilter(make_has_rich_long_pions(), F.FILTER(cut))
def filter_long_kaons(pvs,
pt_min=400 * MeV,
p_min=3 * GeV,
mipchi2_min=5.,
pidk_min=3):
"""Filter long kaons with P PT, MINIPCHI2CUT and pidp cuts."""
cut = F.require_all(F.PT > pt_min, F.P > p_min,
F.MINIPCHI2CUT(IPChi2Cut=mipchi2_min, Vertices=pvs),
F.PID_K > pidk_min)
return ParticleFilter(make_has_rich_long_kaons(), F.FILTER(cut))
def filter_long_protons(pvs,
pt_min=400 * MeV,
p_min=9 * GeV,
mipchi2_min=6.,
pidp_min=3,
dllp_min=2):
"""Filter long protons with P PT, MINIPCHI2CUT and ProbNNp cuts.
Defaults tuned for Lambda selection.
"""
cut = F.require_all(F.PT > pt_min, F.P > p_min,
F.MINIPCHI2CUT(IPChi2Cut=mipchi2_min, Vertices=pvs),
F.PID_P > pidp_min, (F.PID_P - F.PID_K) > dllp_min)
return ParticleFilter(make_has_rich_long_protons(), F.FILTER(cut))
def filter_down_pions(pt_min=300 * MeV, p_min=2 * GeV, pion_pidk_max=3.):
"""Filter downstream pions with P PT, and PID_P cuts."""
cut = F.require_all(F.PT > pt_min, F.P > p_min, F.PID_K < pion_pidk_max)
return ParticleFilter(make_has_rich_down_pions(), F.FILTER(cut))
##########################
## KS0 and L0 combiners ##
##########################
# TODO: apply BPVLTIME when will be working
def make_ks_ll(
pions1,
pions2,
pvs,
name='Charm_LcToKsHOrKsHHH_make_ks_ll_{hash}',
comb_m_min=435 * MeV,
comb_m_max=560 * MeV,
m_min=450 * MeV,
m_max=545 * MeV,
comb_pt_min=300 * MeV,
pt_min=350 * MeV,
comb_p_min=3.5 * GeV,
p_min=4.0 * GeV,
doca_max=0.25 * mm,
vchi2pdof_max=10.,
bpvvdz_min=10 * mm,
bpvfdchi2_min=25.,
#bpvltime_min=1. * picosecond
):
"""Make KS -> pi+ pi- from long tracks."""
comb_cut = F.require_all(
F.MAXDOCACUT(doca_max), in_range(comb_m_min, F.MASS, comb_m_max),
F.PT > comb_pt_min, F.P > comb_p_min)
vertex_cut = F.require_all(
in_range(m_min, F.MASS, m_max),
F.PT > pt_min,
F.P > p_min,
F.CHI2DOF < vchi2pdof_max,
F.BPVVDZ(pvs) > bpvvdz_min,
F.BPVFDCHI2(pvs) > bpvfdchi2_min,
#F.BPVLTIME(pvs) > bpvltime_min #<-- not converging at all
)
return ParticleCombiner([pions1, pions2],
name=name,
DecayDescriptor="KS0 -> pi+ pi-",
CombinationCut=comb_cut,
CompositeCut=vertex_cut)
def make_ks_dd(
pions1,
pions2,
pvs,
name='Charm_LcToKsHOrKsHHH_make_ks_dd_{hash}',
comb_m_min=435 * MeV,
comb_m_max=560 * MeV,
m_min=450 * MeV,
m_max=545 * MeV,
comb_pt_min=300 * MeV,
pt_min=350 * MeV,
sum_pt_min=500 * MeV,
comb_p_min=4.5 * GeV,
p_min=5.0 * GeV,
doca_max=2 * mm,
docachi2_max=30.,
vchi2pdof_max=15.,
#bpvltime_min=1. * picosecond
):
"""Make KS -> pi+ pi- from downstream tracks."""
comb_cut = F.require_all(
F.MAXDOCACUT(doca_max), F.MAXDOCACHI2CUT(docachi2_max),
in_range(comb_m_min, F.MASS, comb_m_max), F.PT > comb_pt_min,
F.SUM(F.PT) > sum_pt_min, F.P > comb_p_min)
vertex_cut = F.require_all(
in_range(m_min, F.MASS, m_max),
F.PT > pt_min,
F.P > p_min,
F.CHI2DOF < vchi2pdof_max,
#F.BPVLTIME(pvs) > bpvltime_min --- not converging
)
return ParticleCombiner([pions1, pions2],
name=name,
DecayDescriptor="KS0 -> pi+ pi-",
CombinationCut=comb_cut,
CompositeCut=vertex_cut)
##########################
## Lc+ / Xic+ combiners ##
##########################
def combine_lc_ks_h(
protons,
ks0,
pvs,
decay_descriptor,
name='Charm_LcToKsHOrKsHHH_make_combine_lc_ks_h_{hash}',
comb_m_min=2206 * MeV,
comb_m_max=2540 * MeV,
m_min=2216 * MeV,
m_max=2527 * MeV,
comb_pt_min=0.9 * GeV,
pt_min=1.5 * GeV,
sum_pt_min=1 * GeV,
comb_p_min=15 * GeV,
p_min=16 * GeV,
doca_max=0.15 * mm, #LL: 0.5 * mm ; DD: 1 * mm
vchi2pdof_max=6.,
#bpvltime_min=0.2 * picosecond,
bpvvdz_min=0. * mm,
bpvfdchi2_min=5.,
bpvipchi2_max=12., #9
bpvdira_min=0.995,
dz2_min=6. * mm):
"""Combine KS0 with protons to form Lc+ or Xic+.
Make MASS, P, PT, SUM(PT), MAXDOCACUT cuts in the combination; MASS, P, PT,
CHI2DOF, BPVVDZ, BPVFDCHI2, BPVIPCHI2, BPVDIRA cuts after the vertex fit.
Cuts generally based on Run2 Turbo lines.
"""
comb_cut = F.require_all(
F.MAXSDOCACUT(doca_max), in_range(comb_m_min, F.MASS, comb_m_max),
F.PT > comb_pt_min,
F.SUM(F.PT) > sum_pt_min, F.P > comb_p_min)
vertex_cut = F.require_all(
in_range(m_min, F.MASS, m_max),
F.PT > pt_min,
F.P > p_min,
F.CHI2DOF < vchi2pdof_max,
#F.BPVLTIME(pvs) > bpvltime_min <-- currently does not work
F.BPVVDZ(pvs) > bpvvdz_min,
F.BPVFDCHI2(pvs) > bpvfdchi2_min, #<-- to be checked
F.BPVIPCHI2(pvs) < bpvipchi2_max, #<-- to be checked
F.BPVDIRA(pvs) > bpvdira_min,
F.CHILD(2, F.END_VZ) - F.END_VZ > dz2_min)
return ParticleCombiner([protons, ks0],
DecayDescriptor=decay_descriptor,
name=name,
CombinationCut=comb_cut,
CompositeCut=vertex_cut)
def combine_lc_ks_hhh(
protons,
ks0,
particle1,
particle2,
pvs,
decay_descriptor,
name='Charm_LcToKsHOrKsHHH_make_combine_lc_ks_hhh_{hash}',
comb_m_min=2216 * MeV,
comb_m_max=2530 * MeV,
m_min=2220 * MeV,
m_max=2517 * MeV,
comb_pt_min=0.9 * GeV,
pt_min=1 * GeV,
sum_pt_min=1 * GeV,
comb_p_min=15 * GeV,
p_min=16 * GeV,
doca_max=1 * mm,
vchi2pdof_max=5.,
#bpvltime_min=0.2 * picosecond,
bpvvdz_min=0.5 * mm,
#bpvfdchi2_min=6.,
bpvipchi2_max=12.,
bpvdira_min=0.99,
dz2_min=5. * mm):
"""Combine KS0 with protons and hh to form Lc+/Xic+.
Make MASS, P, PT, SUM(PT), MAXDOCACUT cuts in the combination; MASS, P, PT,
CHI2DOF, BPVVDZ, BPVFDCHI2, BPVIPCHI2, BPVDIRA cuts after the vertex fit.
Cuts generally based on Run2 Turbo lines.
"""
comb_cut = F.require_all(
F.MAXSDOCACUT(doca_max), in_range(comb_m_min, F.MASS, comb_m_max),
F.PT > comb_pt_min,
F.SUM(F.PT) > sum_pt_min, F.P > comb_p_min)
vertex_cut = F.require_all(
in_range(m_min, F.MASS, m_max),
F.PT > pt_min,
F.P > p_min,
F.CHI2DOF < vchi2pdof_max,
#F.BPVLTIME(pvs) > bpvltime_min <-- currently does not work
F.BPVVDZ(pvs) > bpvvdz_min,
#F.BPVFDCHI2(pvs) > bpvfdchi2_min, <-- to be checked
F.BPVIPCHI2(pvs) < bpvipchi2_max, #<-- to be checked
F.BPVDIRA(pvs) > bpvdira_min,
F.CHILD(2, F.END_VZ) - F.END_VZ > dz2_min)
return ParticleCombiner([protons, ks0, particle1, particle2],
DecayDescriptor=decay_descriptor,
name=name,
CombinationCut=comb_cut,
CompositeCut=vertex_cut)
def combine_lc_ks_ks_p(
protons,
ks01,
ks02,
pvs,
decay_descriptor,
name='Charm_LcToKsHOrKsHHH_make_combine_lc_ks_ks_h_{hash}',
comb_m_min=2216 * MeV,
comb_m_max=2530 * MeV,
m_min=2220 * MeV,
m_max=2517 * MeV,
comb_pt_min=0.9 * GeV,
pt_min=1 * GeV,
sum_pt_min=1 * GeV,
comb_p_min=15 * GeV,
p_min=16 * GeV,
doca_max=1.5 * mm,
vchi2pdof_max=5.,
#bpvltime_min=0.2 * picosecond,
bpvvdz_min=0.5 * mm,
#bpvfdchi2_min=6.,
bpvipchi2_max=12.,
bpvdira_min=0.99,
dz_ks_min=5. * mm):
"""Combine KS0, KS0 with protons to form Lc+/Xic+.
Make MASS, P, PT, SUM(PT), MAXDOCACUT cuts in the combination; MASS, P, PT,
CHI2DOF, BPVVDZ, BPVFDCHI2, BPVIPCHI2, BPVDIRA cuts after the vertex fit.
Cuts generally based on Run2 Turbo lines.
"""
comb_cut = F.require_all(
F.MAXSDOCACUT(doca_max), in_range(comb_m_min, F.MASS, comb_m_max),
F.PT > comb_pt_min,
F.SUM(F.PT) > sum_pt_min, F.P > comb_p_min)
vertex_cut = F.require_all(
in_range(m_min, F.MASS, m_max),
F.PT > pt_min,
F.P > p_min,
F.CHI2DOF < vchi2pdof_max,
#F.BPVLTIME(pvs) > bpvltime_min <-- currently does not work
F.BPVVDZ(pvs) > bpvvdz_min,
#F.BPVFDCHI2(pvs) > bpvfdchi2_min, <-- to be checked
F.BPVIPCHI2(pvs) < bpvipchi2_max, #<-- to be checked
F.BPVDIRA(pvs) > bpvdira_min,
F.CHILD(2, F.END_VZ) - F.END_VZ > dz_ks_min,
F.CHILD(3, F.END_VZ) - F.END_VZ > dz_ks_min)
return ParticleCombiner([protons, ks01, ks02],
DecayDescriptor=decay_descriptor,
name=name,
CombinationCut=comb_cut,
CompositeCut=vertex_cut)
###########################
## Hlt2 lines definition ##
###########################
[docs]@register_line_builder(all_lines)
def lc_to_ks0p_ll_line(name="Hlt2Charm_LcpXicpToPpKs_LL", prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_pions = filter_long_pions_from_strange(pvs)
ks_ll = make_ks_ll(long_pions, long_pions, pvs)
lc_ks0h = combine_lc_ks_h(long_protons, ks_ll, pvs,
"[Lambda_c+ -> p+ KS0]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_ll, lc_ks0h],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_ks0p_dd_line(name="Hlt2Charm_LcpXicpToPpKs_DD", prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
down_pions = filter_down_pions()
ks_dd = make_ks_dd(down_pions, down_pions, pvs)
lc_ks0h = combine_lc_ks_h(
long_protons, ks_dd, pvs, "[Lambda_c+ -> p+ KS0]cc", doca_max=1 * mm)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_dd, lc_ks0h],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_pks0kpkm_ll_line(name="Hlt2Charm_LcpXicpToPpKsKmKp_LL", prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_kaons = filter_long_kaons(pvs)
long_pions = filter_long_pions_from_strange(pvs)
ks_ll = make_ks_ll(long_pions, long_pions, pvs)
lc_ks0hhh = combine_lc_ks_hhh(long_protons, ks_ll, long_kaons, long_kaons,
pvs, "[Lambda_c+ -> p+ KS0 K- K+]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_ll, lc_ks0hhh],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_pks0kpkm_dd_line(name="Hlt2Charm_LcpXicpToPpKsKmKp_DD", prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_kaons = filter_long_kaons(pvs)
down_pions = filter_down_pions()
ks_dd = make_ks_dd(down_pions, down_pions, pvs)
lc_ks0hhh = combine_lc_ks_hhh(long_protons, ks_dd, long_kaons, long_kaons,
pvs, "[Lambda_c+ -> p+ KS0 K- K+]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_dd, lc_ks0hhh],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_pks0kmpip_ll_line(name="Hlt2Charm_LcpXicpToPpKsKmPip_LL",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_kaons = filter_long_kaons(pvs)
long_pions_ks = filter_long_pions_from_strange(pvs)
long_pions = filter_long_pions(pvs)
ks_ll = make_ks_ll(long_pions_ks, long_pions_ks, pvs)
lc_ks0hhh = combine_lc_ks_hhh(long_protons, ks_ll, long_kaons, long_pions,
pvs, "[Lambda_c+ -> p+ KS0 K- pi+]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_ll, lc_ks0hhh],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_pks0kmpip_dd_line(name="Hlt2Charm_LcpXicpToPpKsKmPip_DD",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_kaons = filter_long_kaons(pvs)
long_pions = filter_long_pions(pvs)
down_pions = filter_down_pions()
ks_dd = make_ks_dd(down_pions, down_pions, pvs)
lc_ks0hhh = combine_lc_ks_hhh(long_protons, ks_dd, long_kaons, long_pions,
pvs, "[Lambda_c+ -> p+ KS0 K- pi+]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_dd, lc_ks0hhh],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_pks0kppim_ll_line(name="Hlt2Charm_LcpXicpToPpKsKpPim_LL",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_pions_ks = filter_long_pions_from_strange(pvs)
long_kaons = filter_long_kaons(pvs)
long_pions = filter_long_pions(pvs)
ks_ll = make_ks_ll(long_pions_ks, long_pions_ks, pvs)
lc_ks0hhh = combine_lc_ks_hhh(long_protons, ks_ll, long_kaons, long_pions,
pvs, "[Lambda_c+ -> p+ KS0 K+ pi-]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_ll, lc_ks0hhh],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_pks0kppim_dd_line(name="Hlt2Charm_LcpXicpToPpKsKpPim_DD",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_kaons = filter_long_kaons(pvs)
long_pions = filter_long_pions(pvs)
down_pions = filter_down_pions()
ks_dd = make_ks_dd(down_pions, down_pions, pvs)
lc_ks0hhh = combine_lc_ks_hhh(long_protons, ks_dd, long_kaons, long_pions,
pvs, "[Lambda_c+ -> p+ KS0 K+ pi-]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_dd, lc_ks0hhh],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_pks0pimpip_ll_line(name="Hlt2Charm_LcpXicpToPpKsPimPip_LL",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_pions_ks = filter_long_pions_from_strange(pvs)
long_kaons = filter_long_kaons(pvs)
long_pions = filter_long_pions(pvs)
ks_ll = make_ks_ll(long_pions_ks, long_pions_ks, pvs)
lc_ks0hhh = combine_lc_ks_hhh(long_protons, ks_ll, long_kaons, long_pions,
pvs, "[Lambda_c+ -> p+ KS0 pi- pi+]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_ll, lc_ks0hhh],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lc_to_pks0pimpip_dd_line(name="Hlt2Charm_LcpXicpToPpKsPimPip_DD",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_kaons = filter_long_kaons(pvs)
long_pions = filter_long_pions(pvs)
down_pions = filter_down_pions()
ks_dd = make_ks_dd(down_pions, down_pions, pvs)
lc_ks0hhh = combine_lc_ks_hhh(long_protons, ks_dd, long_kaons, long_pions,
pvs, "[Lambda_c+ -> p+ KS0 pi- pi+]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_dd, lc_ks0hhh],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lcp_to_pks0ks0_llll_line(name="Hlt2Charm_LcpXicpToPpKsKs_LLLL",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_pions = filter_long_pions_from_strange(pvs)
ks_ll = make_ks_ll(long_pions, long_pions, pvs)
lc_ks0ks0h = combine_lc_ks_ks_p(long_protons, ks_ll, ks_ll, pvs,
"[Lambda_c+ -> p+ KS0 KS0]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_ll, lc_ks0ks0h],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lcp_to_pks0ks0_lldd_line(name="Hlt2Charm_LcpXicpToPpKsKs_LLDD",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
long_pions = filter_long_pions_from_strange(pvs)
down_pions = filter_down_pions()
ks_ll = make_ks_ll(long_pions, long_pions, pvs)
ks_dd = make_ks_dd(down_pions, down_pions, pvs)
lc_ks0ks0h = combine_lc_ks_ks_p(
long_protons, ks_ll, ks_dd, pvs, "[Lambda_c+ -> p+ KS0 KL0]cc"
) #One KS0 renamed as KL0 to avoid clash in having same particles with two different containers
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_ll, lc_ks0ks0h],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def lcp_to_pks0ks0_dddd_line(name="Hlt2Charm_LcpXicpToPpKsKs_DDDD",
prescale=1):
pvs = make_pvs()
long_protons = filter_long_protons(pvs)
down_pions = filter_down_pions()
ks_dd = make_ks_dd(down_pions, down_pions, pvs)
lc_ks0ks0h = combine_lc_ks_ks_p(long_protons, ks_dd, ks_dd, pvs,
"[Lambda_c+ -> p+ KS0 KS0]cc")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [ks_dd, lc_ks0ks0h],
prescale=prescale)