###############################################################################
# (c) Copyright 2019 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. #
###############################################################################
"""
This defines HLT2 lines for B+(-)/B_c+(-) -> (X) mu N, N-> l l' nu where N is a neutral lepton
N has no lifetime hypothesis applied. Combination of the neutral lepton daugthers is limited between 200(to cut conversion)-7000 MeV
All leptons from B are Long. Daughters of the neutral lepton can be both Long and Downstream.
Loose and Tight lines have a different PID cut looseness on pions and electrons. Note, PID_E is applied to pions too, so there is a need for a no_brem added calibration.
Tight lines will hopefully have raw event information saved, specifically tracking infor.
List of lines (LL - Long, DD - downstream):
Hlt2QEE_BpToMajoMu_MajoToMuMu_LL_Tight: tight PID cut line for the B(_c)+ -> mu HNL(-> mu mu, LL)
Hlt2QEE_BpToMajoMu_MajoToMuMu_DD_Tight: tight PID cut line for the B(_c)+ -> mu HNL(-> mu mu, DD)
Hlt2QEE_BpToMajoMu_MajoToMuE_SS_LL_Tight: tight PID cut line for the B(_c)+ -> mu HNL(-> mu+ e, LL)
Hlt2QEE_BpToMajoMu_MajoToMuE_SS_DD_Tight: tight PID cut line for the B(_c)+ -> mu HNL(-> mu+ e, DD)
Hlt2QEE_BpToMajoMu_MajoToMuE_OS_LL_Tight: tight PID cut line for the B(_c)+ -> mu HNL(-> mu- e, LL)
Hlt2QEE_BpToMajoMu_MajoToMuE_OS_DD_Tight: tight PID cut line for the B(_c)+ -> mu HNL(-> mu- e, DD)
Hlt2QEE_BpToMajoE_MajoToMuMu_LL_Tight: tight PID cut line for the B(_c)+ -> e HNL(-> mu mu, LL)
Hlt2QEE_BpToMajoE_MajoToMuMu_DD_Tight: tight PID cut line for the B(_c)+ -> e HNL(-> mu mu, DD)
Hlt2QEE_BpToMajoE_MajoToMuE_SS_LL_Tight: tight PID cut line for the B(_c)+ -> e HNL(-> mu+ e, LL)
Hlt2QEE_BpToMajoE_MajoToMuE_SS_DD_Tight: tight PID cut line for the B(_c)+ -> e HNL(-> mu+ e, DD)
Hlt2QEE_BpToMajoE_MajoToMuE_OS_LL_Tight: tight PID cut line for the B(_c)+ -> e HNL(-> mu- e, LL)
Hlt2QEE_BpToMajoE_MajoToMuE_OS_DD_Tight: tight PID cut line for the B(_c)+ -> e HNL(-> mu- e, DD)
Contact: Louis Henry, louis.henry@cern.ch
"""
from Moore.config import register_line_builder
from Moore.lines import Hlt2Line
from GaudiKernel.SystemOfUnits import MeV, GeV
from Hlt2Conf.standard_particles import (make_long_muons,
make_long_electrons_with_brem)
from Functors.math import in_range
from Hlt2Conf.algorithms_thor import ParticleCombiner
from Hlt2Conf.lines.qee.qee_builders import hnl_prefilter, make_filter_tracks
import Functors as F
all_lines = {}
_HNL_MONITORING_VARIABLES = ("pt", "eta", "vchi2", "ipchi2", "n_candidates")
defaultCutDict = {
"AllTracks": {
"P": 2000. * MeV
},
"Children": {
"MINIPCHI2PV": 200
},
"Bachelor": {},
"Child1": {},
"Child2": {},
"Majo": {
"FDCHI2MIN": 2000,
"MASS": [0.2 * GeV, 6. * GeV],
"MINIPCHI2PV": 20,
},
"B": {
"MASS": [4. * GeV, 7. * GeV]
}
}
child_muon_pidCut = [F.ISMUON, F.PID_MU > 0.]
bach_muon_pidCut = [F.PID_MU > 2]
electron_pidCut = [F.PID_E > -2]
particle_makers = {"e": make_long_electrons_with_brem, "mu": make_long_muons}
#Build a cut from a list of functors
def buildFromList(cutList):
toReturn = F.ALL
for i in range(0, len(cutList)):
toReturn &= cutList[i]
return toReturn
#Build a cut from a dictionnary
def build_cut_on_track(cutDict, pvs):
listOfFunctors = []
for cut, cutVal in cutDict.items():
if cut == "PIDCuts":
listOfFunctors += cutVal
elif cut == "MASS":
listOfFunctors.append(in_range(cutVal[0], F.MASS, cutVal[1]))
else:
functors = {
"P": F.P,
"PT": F.PT,
"MINIPCHI2PV": F.MINIPCHI2(pvs()),
"FDCHI2MIN": F.BPVFDCHI2(pvs())
}
listOfFunctors.append(functors[cut] > cutVal)
#Build the cut
return buildFromList(listOfFunctors)
def build_combination_cut(cutDict, pvs):
listOfFunctors = []
for cut, cutVal in cutDict.items():
if cut == "MASS":
listOfFunctors.append(in_range(cutVal[0], F.MASS, cutVal[1]))
#Build the cut
return buildFromList(listOfFunctors)
def builder_BToMajoL_line(name,
bachelorName,
children,
cutDict={},
prescale=1,
persistreco=True):
from RecoConf.reconstruction_objects import make_pvs
pvs = make_pvs
# Interpret name into a B decay
majoDecayDescr = "KS0 -> " + children[0] + "+ " + children[1] + "-"
recoMode = "LL" if "LL" in name else "DD"
# Build the cut dictionnaries
# Add all default cuts
for key1, val1 in defaultCutDict.items():
if key1 not in cutDict:
cutDict[key1] = val1
else:
for key2, val2 in val1.items():
if key2 not in cutDict[key1]:
cutDict[key1][key2] = val2
# Apply Children and AllTracks cuts
for key, val in cutDict["Children"].items():
for child in ["Child1", "Child2"]:
if key not in cutDict[child]:
cutDict[child][key] = val
for key, val in cutDict["AllTracks"].items():
for recTrack in ["Bachelor", "Child1", "Child2"]:
if key not in cutDict[recTrack]:
cutDict[recTrack][key] = val
# Apply PID cuts
cutDict["Bachelor"][
"PIDCuts"] = bach_muon_pidCut if bachelorName == "mu" else electron_pidCut
cutDict["Child1"]["PIDCuts"] = child_muon_pidCut if children[
0] == "mu" else electron_pidCut
cutDict["Child2"]["PIDCuts"] = child_muon_pidCut if children[
1] == "mu" else electron_pidCut
# Make particles and decays
firstChild = make_filter_tracks(
make_particles=particle_makers[children[0]],
name="majo_" + children[0] + "_{hash}",
additionalCuts=build_cut_on_track(cutDict["Child1"], pvs))
secondChild = make_filter_tracks(
make_particles=particle_makers[children[1]],
name="majo_" + children[1] + "_{hash}",
additionalCuts=build_cut_on_track(cutDict["Child2"], pvs))
majo = ParticleCombiner(
[firstChild, secondChild],
name="Majo2" + children[0] + children[1] + "_" + recoMode + "_{hash}",
DecayDescriptor=majoDecayDescr,
CombinationCut=build_combination_cut(cutDict["Majo"], pvs),
CompositeCut=build_cut_on_track(cutDict["Majo"], pvs))
#Bachelor
bachelor = make_filter_tracks(
make_particles=particle_makers[bachelorName],
name="bachelor_{hash}",
additionalCuts=build_cut_on_track(cutDict["Bachelor"], pvs))
#Decay
b2LN = ParticleCombiner(
[majo, bachelor],
name=name + "_{hash}",
DecayDescriptor='[B+ -> KS0 ' + bachelorName + '+]cc',
CombinationCut=build_combination_cut(cutDict["B"], pvs),
CompositeCut=build_cut_on_track(cutDict["B"], pvs))
# Define monitoring
from SelAlgorithms.monitoring import monitor, histogram_1d
mons = []
for ptName, pt in [("Child1", firstChild), ("Child2", secondChild),
("N", majo)]:
hists = []
for var, varName, varRange in [(F.P, "P", (0, 10000)),
(F.PT, "PT", (0, 2000)),
(F.MINIPCHI2(pvs()), "MINIPCHI2",
(0, 1000))]:
hists.append(
histogram_1d(
name=f"/{name}/{ptName}_{varName}",
title=f"/{name}/{ptName}_{varName}",
label=varName,
functor=var,
bins=1000,
range=varRange))
mons.append(
monitor(
name=f"Monitor__{name}__{ptName}", data=pt, histograms=hists))
if ptName == "Child1" or ptName == "Child2":
child_specific_hists = []
for var, varName, varRange in [(F.CHI2DOF, "TRCHI2NDOF", (0, 50)),
(F.GHOSTPROB, "GhostProb", (0, 1))]:
child_specific_hists.append(
histogram_1d(
name=f"Monitor__{name}__{ptName}_{varName}",
title=f"{name}__{ptName}_{varName}",
label=varName,
functor=var,
bins=100,
range=varRange))
mons.append(
monitor(
name=f"Monitor__{name}__{ptName}__child_specific",
data=pt,
histograms=child_specific_hists))
return Hlt2Line(
name=name,
algs=hnl_prefilter(require_GEC=True) + [b2LN] + mons,
prescale=prescale,
monitoring_variables=_HNL_MONITORING_VARIABLES)
for bachelor in ["mu", "e"]:
for children in [("mu", "mu"), ("mu", "e"), ("e", "mu"), ("e", "e")]:
name = f"Hlt2QEE_BpToMajo{bachelor.capitalize()}_MajoTo{children[0].capitalize()}{children[1].capitalize()}_LL_Tight"
if children != ("e", "e"):
@register_line_builder(all_lines)
def make_line(name=name, bachelor=bachelor, children=children):
return builder_BToMajoL_line(name, bachelor, children)
else:
[docs] @register_line_builder(all_lines)
def make_line(name=name, bachelor=bachelor, children=children):
return builder_BToMajoL_line(
name,
bachelor,
children,
cutDict={
"Children": {
"MINIPCHI2PV": 500,
"PT": 500 * MeV
},
"Majo": {
"FDCHI2MIN": 3000,
},
})