###############################################################################
# (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. #
###############################################################################
"""Definition of D0 -> h- h+ h- h+ HLT2 lines.
The D0 final states built are:
1. D0 -> K- pi+ pi+ pi- and its charge conjugate
2. D0 -> K+ pi- pi+ pi- and its charge conjugate
3. D0 -> K- K+ pi+ pi-
4. D0 -> pi- pi+ pi+ pi-
5. D0 -> K- K+ K- pi+ and its charge conjugate
6. D0 -> K- K+ K+ pi- and its charge conjugate
Each of the final states is tagged in the following ways:
1. D*(2010)+ -> D0 pi+ and its charge conjugate
2. B- -> D0 mu- and its charge conjugate
3. B0 -> D*(2010)- mu+ and its charge conjugate
The charge conjugates of D0 -> h- h+ pi+ pi- are not reconstructed to avoid
duplication of candidates. Therefore, the taggers employ modified (unphysical)
charge conjugates, e.g. D*(2010)- -> D0 pi- and B+ -> D0 mu+.
TODO: add HLT1 filters
"""
import Functors as F
from Functors.math import in_range
from GaudiKernel.SystemOfUnits import MeV, mm, GeV
from Moore.config import register_line_builder
from Moore.lines import Hlt2Line
from RecoConf.reconstruction_objects import make_pvs
from Hlt2Conf.algorithms_thor import (ParticleCombiner, ParticleFilter)
from Hlt2Conf.standard_particles import (make_has_rich_long_pions,
make_has_rich_long_kaons)
from .particle_properties import _PION_M, _KAON_M
from .prefilters import charm_prefilters
from .taggers import make_dstars, make_tagging_muons, make_sl_bs, make_dt_bs
all_lines = {}
def make_charm_pions():
"""Return pions maker for D0 decay."""
return ParticleFilter(
make_has_rich_long_pions(),
F.FILTER(
F.require_all(
F.MINIPCHI2CUT(IPChi2Cut=3.5, Vertices=make_pvs()),
F.PT > 250 * MeV,
# p_min=5 * GeV,
# trchi2dof_max=4,
# trg_ghost_prob_max=0.5,
F.PID_K < 5.,
), ),
)
def make_charm_kaons():
"""Return kaons maker for D0 decay."""
return ParticleFilter(
make_has_rich_long_kaons(),
F.FILTER(
F.require_all(
F.MINIPCHI2CUT(IPChi2Cut=3.5, Vertices=make_pvs()),
F.PT > 250 * MeV,
# p_min=5 * GeV,
# trchi2dof_max=4,
# trg_ghost_prob_max=0.5,
F.PID_K > 5.,
), ),
)
# These tracks have the same selection as the D0->hh ones.
# Shall we somehow use the same selection?
def make_charm_pions_for_b():
return ParticleFilter(
make_has_rich_long_pions(),
F.FILTER(
F.require_all(
F.MINIPCHI2CUT(IPChi2Cut=9., Vertices=make_pvs()),
F.PID_K < 0.,
F.PT > 200 * MeV,
F.P > 2 * GeV,
), ),
)
def make_charm_kaons_for_b():
return ParticleFilter(
make_has_rich_long_kaons(),
F.FILTER(
F.require_all(
F.MINIPCHI2CUT(IPChi2Cut=9., Vertices=make_pvs()),
F.PID_K > 0.,
F.PT > 200 * MeV,
F.P > 2 * GeV,
), ),
)
def make_dzeros(particle1,
particle2,
particle3,
particle4,
descriptor,
m3=_PION_M,
m4=_PION_M,
for_b=False):
"""Return D0 maker with selection tailored for four-body hadronic final
states.
Args:
particles (list of DataHandles): Input particles used in the
combination.
descriptor (string): Decay descriptor to be reconstructed.
for_b (bool, optional): Sets whether the requirements should be tuned
to prompt or SL decays. Defaults to False.
"""
if descriptor == '[D0 -> K- pi- pi+ pi+]cc':
name = "Charm_D0ToHHHH_BuilderD0ToKmPimPipPip_{hash}"
elif descriptor == '[D0 -> K+ pi- pi- pi+]cc':
name = "Charm_D0ToHHHH_BuilderD0ToKpPimPimPip_{hash}"
elif descriptor == 'D0 -> K- K+ pi- pi+':
name = "Charm_D0ToHHHH_BuilderD0ToKmKpPimPip_{hash}"
elif descriptor == 'D0 -> pi- pi- pi+ pi+':
name = "Charm_D0ToHHHH_BuilderD0ToPimPimPipPip_{hash}"
elif descriptor == '[D0 -> K- K- K+ pi+]cc':
name = "Charm_D0ToHHHH_BuilderD0ToKmKmKpPip_{hash}"
elif descriptor == '[D0 -> K- K+ K+ pi-]cc':
name = "Charm_D0ToHHHH_BuilderD0ToKmKpKpPim_{hash}"
else:
raise RuntimeError(
f"charm.d0_to_hhhh.make_dzeros called with unsupported decay descriptor '{descriptor}'"
)
if for_b:
name = f"{name}_ForSL"
comb_m_max = (1940 if for_b else 2100) * MeV
combination_cut = F.require_all(
in_range((1790 if for_b else 1700) * MeV, F.MASS, comb_m_max),
F.PT > (1700 if for_b else 1900) * MeV,
F.MAXSDOCACUT(0.1 * mm),
)
if not for_b:
combination_cut &= F.require_all(
F.P > 25 * GeV,
F.MAX(F.PT) > 1200 * MeV) # could be added if needed
composite_cut = F.require_all(
in_range((1800 if for_b else 1790) * MeV, F.MASS,
(1930 if for_b else 2010) * MeV),
F.PT > (1800 if for_b else 2500) * MeV,
F.CHI2DOF < (6. if for_b else 12.),
F.BPVFDCHI2(make_pvs()) > (100. if for_b else 25.),
# F.BPVLTIME(make_pvs()) > 0.1 * ps, # TODO once we know our detector better
F.BPVDIRA(make_pvs()) > (0.99 if for_b else 0.9998))
if not for_b:
composite_cut &= F.P > 30 * GeV
return ParticleCombiner(
[particle1, particle2, particle3, particle4],
DecayDescriptor=descriptor,
name=name,
Combination12Cut=F.require_all(
F.MASS < comb_m_max - m3 - m4,
F.MAXSDOCACUT(0.1 * mm),
),
Combination123Cut=F.require_all(
F.MASS < comb_m_max - m4,
F.MAXSDOCACUT(0.1 * mm),
),
CombinationCut=combination_cut,
CompositeCut=composite_cut,
)
##############################################################################
# Prompt D*+ -> D0 pi+ lines
##############################################################################
[docs]@register_line_builder(all_lines)
def dstarp2dzeropip_dzero2kmpippimpip_line(
name='Hlt2Charm_DstpToD0Pip_D0ToKmPimPipPip', prescale=1):
kaons = make_charm_kaons()
pions = make_charm_pions()
dzeros = make_dzeros(kaons, pions, pions, pions,
'[D0 -> K- pi- pi+ pi+]cc')
dstars = make_dstars(
dzeros, self_conjugate_d0_decay=False, d0_name="D0ToKPiPiPi")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [dzeros, dstars],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def dstarp2dzeropip_dzero2kppimpippim_line(
name='Hlt2Charm_DstpToD0Pip_D0ToKpPimPimPip', prescale=1):
kaons = make_charm_kaons()
pions = make_charm_pions()
dzeros = make_dzeros(kaons, pions, pions, pions,
'[D0 -> K+ pi- pi- pi+]cc')
dstars = make_dstars(
dzeros, self_conjugate_d0_decay=False, d0_name="D0ToKPiPiPiWS")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [dzeros, dstars],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def dstarp2dzeropip_dzero2kmkppimpip_line(
name='Hlt2Charm_DstpToD0Pip_D0ToKmKpPimPip', prescale=1):
kaons = make_charm_kaons()
pions = make_charm_pions()
dzeros = make_dzeros(kaons, kaons, pions, pions, 'D0 -> K- K+ pi- pi+')
dstars = make_dstars(
dzeros, self_conjugate_d0_decay=True, d0_name="D0ToKKPiPi")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [dzeros, dstars],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def dstarp2dzeropip_dzero2kmkpkmpip_line(
name='Hlt2Charm_DstpToD0Pip_D0ToKmKmKpPip', prescale=1):
kaons = make_charm_kaons()
pions = make_charm_pions()
dzeros = make_dzeros(
kaons, kaons, kaons, pions, '[D0 -> K- K- K+ pi+]cc', m3=_KAON_M)
dstars = make_dstars(
dzeros, self_conjugate_d0_decay=False, d0_name="D0ToKKKPi")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [dzeros, dstars],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def dstarp2dzeropip_dzero2kpkmkppim_line(
name='Hlt2Charm_DstpToD0Pip_D0ToKmKpKpPim', prescale=1):
kaons = make_charm_kaons()
pions = make_charm_pions()
dzeros = make_dzeros(
kaons, kaons, kaons, pions, '[D0 -> K- K+ K+ pi-]cc', m3=_KAON_M)
dstars = make_dstars(
dzeros, self_conjugate_d0_decay=False, d0_name="D0ToKKKPiWS")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [dzeros, dstars],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def dstarp2dzeropip_dzero2pimpippimpip_line(
name='Hlt2Charm_DstpToD0Pip_D0ToPimPimPipPip', prescale=1):
pions = make_charm_pions()
dzeros = make_dzeros(pions, pions, pions, pions, 'D0 -> pi- pi- pi+ pi+')
dstars = make_dstars(
dzeros, self_conjugate_d0_decay=True, d0_name="D0ToPiPiPiPi")
return Hlt2Line(
name=name,
algs=charm_prefilters() + [dzeros, dstars],
prescale=prescale)
###############################################################################
# Semi-leptonic singly tagged lines B -> D0 mu-
###############################################################################
[docs]@register_line_builder(all_lines)
def b2d0mu_dzero2kpipipi_line(name='Hlt2Charm_BToD0MumX_D0ToKmPimPipPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, pions, pions, pions, '[D0 -> K- pi- pi+ pi+]cc', for_b=True)
muons = make_tagging_muons()
bs = make_sl_bs(dzeros, muons, self_conjugate_d0_decay=False)
return Hlt2Line(
name=name, algs=charm_prefilters() + [muons, bs], prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2d0mu_dzero2kkpipi_line(name='Hlt2Charm_BToD0MumX_D0ToKmKpPimPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, kaons, pions, pions, 'D0 -> K- K+ pi- pi+', for_b=True)
muons = make_tagging_muons()
bs = make_sl_bs(dzeros, muons, self_conjugate_d0_decay=True)
return Hlt2Line(
name=name, algs=charm_prefilters() + [muons, bs], prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2d0mu_dzero2pipipipi_line(name='Hlt2Charm_BToD0MumX_D0ToPimPimPipPip',
prescale=1):
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
pions, pions, pions, pions, 'D0 -> pi- pi- pi+ pi+', for_b=True)
muons = make_tagging_muons()
bs = make_sl_bs(dzeros, muons, self_conjugate_d0_decay=True)
return Hlt2Line(
name=name, algs=charm_prefilters() + [muons, bs], prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2d0mu_dzero2kkkpi_line(name='Hlt2Charm_BToD0MumX_D0ToKmKmKpPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons,
kaons,
kaons,
pions,
'[D0 -> K- K- K+ pi+]cc',
m3=_KAON_M,
for_b=True)
muons = make_tagging_muons()
bs = make_sl_bs(dzeros, muons, self_conjugate_d0_decay=False)
return Hlt2Line(
name=name, algs=charm_prefilters() + [muons, bs], prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2d0mu_dzero2kpipipiws_line(name='Hlt2Charm_BToD0MumX_D0ToKpPimPimPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, pions, pions, pions, '[D0 -> K+ pi- pi- pi+]cc', for_b=True)
muons = make_tagging_muons()
bs = make_sl_bs(dzeros, muons, self_conjugate_d0_decay=False)
return Hlt2Line(
name=name, algs=charm_prefilters() + [muons, bs], prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2d0mu_dzero2kkkpiws_line(name='Hlt2Charm_BToD0MumX_D0ToKmKpKpPim',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons,
kaons,
kaons,
pions,
'[D0 -> K- K+ K+ pi-]cc',
m3=_KAON_M,
for_b=True)
muons = make_tagging_muons()
bs = make_sl_bs(dzeros, muons, self_conjugate_d0_decay=False)
return Hlt2Line(
name=name, algs=charm_prefilters() + [muons, bs], prescale=prescale)
###############################################################################
# Doubly tagged B -> D*(2010)+ mu+ lines (for combinatorial bkg)
###############################################################################
[docs]@register_line_builder(all_lines)
def b2dstarmu_dzero2kpipipi_line(name='Hlt2Charm_BToDstpMumX_D0ToKmPimPipPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, pions, pions, pions, '[D0 -> K- pi- pi+ pi+]cc', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=False,
d0_name='D0ToKmPimPipPip',
same_sign=False)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmu_dzero2kpipipiws_line(
name='Hlt2Charm_BToDstpMumX_D0ToKpPimPimPip', prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, pions, pions, pions, '[D0 -> K+ pi- pi- pi+]cc', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=False,
d0_name='D0ToKpPimPimPip',
same_sign=False)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmu_dzero2pipipipi_line(
name='Hlt2Charm_BToDstpMumX_D0ToPimPimPipPip', prescale=1):
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
pions, pions, pions, pions, 'D0 -> pi- pi- pi+ pi+', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=True,
d0_name='D0ToPimPimPipPip',
same_sign=False)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmu_dzero2kkpipi_line(name='Hlt2Charm_BToDstpMumX_D0ToKmKpPimPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, kaons, pions, pions, 'D0 -> K- K+ pi- pi+', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=True,
d0_name='D0ToKmKpPimPip',
same_sign=False)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmu_dzero2kkkpi_line(name='Hlt2Charm_BToDstpMumX_D0ToKmKmKpPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, kaons, kaons, pions, '[D0 -> K- K- K+ pi+]cc', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=False,
d0_name='D0ToKmKmKpPip',
same_sign=False)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmu_dzero2kkkpiws_line(name='Hlt2Charm_BToDstpMumX_D0ToKmKpKpPim',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, kaons, kaons, pions, '[D0 -> K- K+ K+ pi-]cc', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=False,
d0_name='D0ToKmKpKpPim',
same_sign=False)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
###############################################################################
# Same-sign doubly tagged B -> D*(2010)+ mu+ lines (for combinatorial bkg)
###############################################################################
[docs]@register_line_builder(all_lines)
def b2dstarmuWS_dzero2kpipipi_line(
name='Hlt2Charm_BToDstpMupX_D0ToKmPimPipPip', prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, pions, pions, pions, '[D0 -> K- pi- pi+ pi+]cc', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=False,
d0_name='D0ToKmPimPipPip',
same_sign=True)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmuWS_dzero2kpipipiws_line(
name='Hlt2Charm_BToDstpMupX_D0ToKpPimPimPip', prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, pions, pions, pions, '[D0 -> K+ pi- pi- pi+]cc', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=False,
d0_name='D0ToKpPimPimPip',
same_sign=True)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmuWS_dzero2pipipipi_line(
name='Hlt2Charm_BToDstpMupX_D0ToPimPimPipPip', prescale=1):
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
pions, pions, pions, pions, 'D0 -> pi- pi- pi+ pi+', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=True,
d0_name='D0ToPimPimPipPip',
same_sign=True)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmuWS_dzero2kkpipi_line(name='Hlt2Charm_BToDstpMupX_D0ToKmKpPimPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, kaons, pions, pions, 'D0 -> K- K+ pi- pi+', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=True,
d0_name='D0ToKmKpPimPip',
same_sign=True)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmuWS_dzero2kkkpi_line(name='Hlt2Charm_BToDstpMupX_D0ToKmKmKpPip',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, kaons, kaons, pions, '[D0 -> K- K- K+ pi+]cc', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=False,
d0_name='D0ToKmKmKpPip',
same_sign=True)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)
[docs]@register_line_builder(all_lines)
def b2dstarmuWS_dzero2kkkpiws_line(name='Hlt2Charm_BToDstpMupX_D0ToKmKpKpPim',
prescale=1):
kaons = make_charm_kaons_for_b()
pions = make_charm_pions_for_b()
dzeros = make_dzeros(
kaons, kaons, kaons, pions, '[D0 -> K- K+ K+ pi-]cc', for_b=True)
muons = make_tagging_muons()
bs = make_dt_bs(
dzeros,
muons,
self_conjugate_d0_decay=False,
d0_name='D0ToKmKpKpPim',
same_sign=True)
return Hlt2Line(
name=name,
algs=charm_prefilters() + [muons, dzeros, bs],
prescale=prescale)