Source code for skim.WGs.semileptonic

#!/usr/bin/env python3

##########################################################################
# basf2 (Belle II Analysis Software Framework)                           #
# Author: The Belle II Collaboration                                     #
#                                                                        #
# See git log for contributors and copyright holders.                    #
# This file is licensed under LGPL-3.0, see LICENSE.md.                  #
##########################################################################

"""(Semi-)Leptonic Working Group Skim list building functions for semi-leptonic analyses.
"""

import basf2 as b2
import modularAnalysis as ma
from skim.standardlists.charm import (loadKForBtoHadrons, loadPiForBtoHadrons,
                                      loadStdD0, loadStdDplus, loadStdDstar0,
                                      loadStdDstarPlus, loadPiSkimHighEff,
                                      loadKSkimHighEff, loadSlowPi,
                                      loadSkimHighEffD0_Kpi, loadSkimHighEffDstarPlus_D0pi_Kpi,
                                      loadSkimHighEffD0_Kpipipi, loadSkimHighEffDstarPlus_D0pi_Kpipipi,
                                      loadStdD0_eff20_Kpipi0, loadStdDstarPlus_D0pi_Kpipi0_eff20)
from skim.standardlists.lightmesons import loadStdPi0ForBToHadrons
from skim import BaseSkim, fancy_skim_header
from stdCharged import stdE, stdK, stdMu, stdPi
from stdPhotons import stdPhotons
from stdPi0s import stdPi0s
from stdV0s import stdKshorts
from variables import variables as vm
from ROOT import Belle2

__liaison__ = "Cameron Harris <cameron.harris@adelaide.edu.au>, Tommy Martinov <tommy.martinov@desy.de>"
_VALIDATION_SAMPLE = "mdst14.root"


[docs]@fancy_skim_header class PRsemileptonicUntagged(BaseSkim): """ Reconstructed decay modes: * :math:`B^0 \\to \\pi^- e^+` * :math:`B^0 \\to \\pi^- \\mu^+` Event-level cuts: * :math:`\\text{foxWolframR2} < 0.5` constructed using tracks with :math:`p_T>0.1\\,\\text{GeV}` and clusters with :math:`E>0.1\\,\\text{GeV}`. * :math:`n_{\\text{tracks}} > 4` Cuts on electrons: * :math:`\\text{electronID_noTOP} > 0.5` * :math:`p > 1.5\\,\\text{GeV}` in CMS frame Cuts on muons: * :math:`\\text{muonID} > 0.5` * :math:`p > 1.5\\,\\text{GeV}` in CMS frame Cuts on pions: * :math:`\\text{pionID}>0.5` * :math:`\\text{muonID}<0.2` * :math:`0.060\\,\\text{GeV}<p<0.220\\,\\text{GeV}` in CMS frame Cuts on partially reconstructed :math:`B` mesons: * :math:`\\cos\\theta_{\\ell,\\,\\pi}<0` in CMS frame. """ __authors__ = ["Lucien Cremaldi", "Racha Cheaib", "Romulus Godang"] __description__ = "Skim for partial reconstruction analysis in leptonic group." __contact__ = __liaison__ __category__ = "physics, semileptonic" ApplyHLTHadronCut = False validation_sample = _VALIDATION_SAMPLE
[docs] def load_standard_lists(self, path): stdE("all", path=path) stdMu("all", path=path) stdPi("all", path=path)
[docs] def build_lists(self, path): ma.cutAndCopyList("pi+:PRSL_eventshape", "pi+:all", cut="pt> 0.1", path=path) ma.fillParticleList(decayString="gamma:PRSL_eventshape", cut="E > 0.1", path=path) ma.buildEventShape(inputListNames=["pi+:PRSL_eventshape", "gamma:PRSL_eventshape"], allMoments=False, foxWolfram=True, harmonicMoments=False, cleoCones=False, thrust=False, collisionAxis=False, jets=False, sphericity=False, checkForDuplicates=False, path=path) path = self.skim_event_cuts("foxWolframR2<0.5 and nTracks>4", path=path) ma.cutAndCopyList("e+:PRSemileptonic_1", "e+:all", "useCMSFrame(p) > 1.50 and electronID_noTOP > 0.5", path=path) ma.cutAndCopyList("mu+:PRSemileptonic_1", "mu+:all", "useCMSFrame(p) > 1.50 and muonID > 0.5", path=path) ma.cutAndCopyList("pi-:PRSemileptonic_1", "pi-:all", "pionID>0.5 and muonID<0.2 and 0.060<useCMSFrame(p)<0.220", path=path) ma.cutAndCopyList("e+:PRSemileptonic_2", "e+:all", "0.600 < useCMSFrame(p) <= 1.50 and electronID_noTOP > 0.5", path=path) ma.cutAndCopyList("mu+:PRSemileptonic_2", "mu+:all", "0.350 < useCMSFrame(p) <= 1.50 and muonID > 0.5", path=path) ma.cutAndCopyList("pi-:PRSemileptonic_2", "pi-:all", "pionID>0.5 and muonID<0.2 and 0.060<useCMSFrame(p)<0.160", path=path) ma.reconstructDecay("B0:PRSemileptonic_1 -> pi-:PRSemileptonic_1 e+:PRSemileptonic_1", "useCMSFrame(cos(daughterAngle(0,1)))<0.00", 1, path=path) ma.reconstructDecay("B0:PRSemileptonic_2 -> pi-:PRSemileptonic_1 mu+:PRSemileptonic_1", "useCMSFrame(cos(daughterAngle(0,1)))<0.00", 2, path=path) ma.reconstructDecay("B0:PRSemileptonic_3 -> pi-:PRSemileptonic_2 e+:PRSemileptonic_2", "useCMSFrame(cos(daughterAngle(0,1)))<1.00", 3, path=path) ma.reconstructDecay("B0:PRSemileptonic_4 -> pi-:PRSemileptonic_2 mu+:PRSemileptonic_2", "useCMSFrame(cos(daughterAngle(0,1)))<1.00", 4, path=path) return ["B0:PRSemileptonic_1", "B0:PRSemileptonic_2"]
[docs] def validation_histograms(self, path): # NOTE: the validation package is not part of the light releases, so this import # must be made here rather than at the top of the file. from validation_tools.metadata import create_validation_histograms ma.copyLists('B0:all', self.SkimLists, path=path) ma.buildRestOfEvent('B0:all', path=path) ma.appendROEMask('B0:all', 'basic', 'pt>0.05 and dr<2 and -4.0<dz<4.0', 'E>0.05', path=path) vm.addAlias('d0_p', 'daughter(0, p)') vm.addAlias('d1_p', 'daughter(1, p)') vm.addAlias('MissM2', 'weMissM2(basic,0)') histogramFilename = f'{self}_Validation.root' create_validation_histograms( rootfile=histogramFilename, particlelist='B0:all', variables_1d=[ ('Mbc', 100, 4.0, 5.3, 'Mbc', __liaison__, '', ''), ('d0_p', 100, 0, 0.3, 'Signal-side pion momentum', __liaison__, '', ''), ('d1_p', 100, 1, 4, 'Signal-side lepton momentum', __liaison__, '', ''), ('MissM2', 100, -5, 5, 'Missing mass squared', __liaison__, '', '') ], variables_2d=[('deltaE', 100, -5, 5, 'Mbc', 100, 4.0, 5.3, 'Mbc vs deltaE', __liaison__, '', '')], path=path)
[docs]@fancy_skim_header class SLUntagged(BaseSkim): """ Cuts applied: * :math:`p_{\\ell} > 0.35\\,\\text{GeV}` * :math:`5.24 < M_{\\text{bc}} < 5.29` * :math:`|\\Delta E | < 0.5` * :math:`n_{\\text{tracks}} > 4` Reconstructed decays: * :math:`B^+ \\to \\overline{D}^{0} e^+` * :math:`B^+ \\to \\overline{D}^{0} \\mu^+` * :math:`B^+ \\to \\overline{D}^{*0} e^+` * :math:`B^+ \\to \\overline{D}^{*0} \\mu^+` * :math:`B^0 \\to D^{-} e^+` * :math:`B^0 \\to D^{-} \\mu^+` * :math:`B^0 \\to D^{*-} e^+` * :math:`B^0 \\to D^{*-} \\mu^+` """ __authors__ = ["Phillip Urquijo", "Racha Cheaib"] __description__ = ( "Skim for semileptonic decays, :math:`B` decays " "(:math:`B \\to D \\ell\\nu`, where :math:`\\ell=e,\\mu`)" ) __contact__ = __liaison__ __category__ = "physics, semileptonic" ApplyHLTHadronCut = False validation_sample = _VALIDATION_SAMPLE
[docs] def load_standard_lists(self, path): stdE("all", path=path) stdK("all", path=path) stdMu("all", path=path) stdPi("all", path=path) stdPi("loose", path=path) stdPhotons("loose", path=path) stdPi0s("eff40_May2020", path=path) stdKshorts(path=path) loadStdPi0ForBToHadrons(path=path) loadPiForBtoHadrons(path=path) loadKForBtoHadrons(path=path) loadStdD0(path=path) loadStdDstar0(path=path) loadStdDplus(path=path) loadStdDstarPlus(path=path)
[docs] def build_lists(self, path): ma.cutAndCopyList("e+:SLUntagged", "e+:all", "p>0.35", True, path=path) ma.cutAndCopyList("mu+:SLUntagged", "mu+:all", "p>0.35", True, path=path) Bcuts = "5.24 < Mbc < 5.29 and abs(deltaE) < 0.5" BplusChannels = ["anti-D0:all e+:SLUntagged", "anti-D0:all mu+:SLUntagged", "anti-D*0:all e+:SLUntagged", "anti-D*0:all mu+:SLUntagged" ] B0Channels = ["D-:all e+:SLUntagged", "D-:all mu+:SLUntagged", "D*-:all e+:SLUntagged", "D*-:all mu+:SLUntagged" ] bplusList = [] for chID, channel in enumerate(BplusChannels): ma.reconstructDecay(f"B+:SLUntagged_{chID} -> {channel}", Bcuts, chID, path=path) ma.applyCuts(f"B+:SLUntagged_{chID}", "nTracks>4", path=path) bplusList.append(f"B+:SLUntagged_{chID}") b0List = [] for chID, channel in enumerate(B0Channels): ma.reconstructDecay(f"B0:SLUntagged_{chID} -> {channel}", Bcuts, chID, path=path) ma.applyCuts(f"B0:SLUntagged_{chID}", "nTracks>4", path=path) b0List.append(f"B0:SLUntagged_{chID}") return b0List + bplusList
[docs] def validation_histograms(self, path): # NOTE: the validation package is not part of the light releases, so this import # must be made here rather than at the top of the file. from validation_tools.metadata import create_validation_histograms ma.copyLists('B+:all', [lst for lst in self.SkimLists if "B+" in lst], path=path) ma.buildRestOfEvent('B+:all', path=path) ma.appendROEMask('B+:all', 'basic', 'pt>0.05 and -2<dr<2 and -4.0<dz<4.0', 'E>0.05', path=path) vm.addAlias('d1_p', 'daughter(1,p)') vm.addAlias('MissM2', 'weMissM2(basic,0)') histogramFilename = f'{self}_Validation.root' create_validation_histograms( rootfile=histogramFilename, particlelist='B+:all', variables_1d=[ ('cosThetaBetweenParticleAndNominalB', 100, -3.0, 3.0, 'cosThetaBY', __liaison__, '', ''), ('Mbc', 100, 5.24, 5.3, 'Mbc', __liaison__, '', ''), ('d1_p', 100, 1, 4, 'Signal-side lepton momentum', __liaison__, '', ''), ('MissM2', 100, -5, 5, 'Missing mass squared', __liaison__, '', '') ], variables_2d=[('deltaE', 100, -1, 1, 'Mbc', 100, 5.2, 5.3, 'Mbc vs deltaE', __liaison__, '', '')], path=path)
[docs]@fancy_skim_header class B0toDstarl_Kpi_Kpipi0_Kpipipi(BaseSkim): """ Cuts applied: * ``SkimHighEff tracks thetaInCDCAcceptance AND dr < 2 AND abs(dz) < 5 AND PID>=0.01`` * ``slowPi tracks thetaInCDCAcceptance AND dr < 2 AND abs(dz) < 5 AND useCMSFrame(p) < 0.4`` * :math:`2.5 > p_{\\ell} > 1.1\\,\\text{GeV}` * ``lepton with abs(d0) < 0.5 AND abs(z0) < 2 AND thetaInCDCAcceptance AND ID >= 0.95 AND 1.1 < useCMSFrame(p) < 2.5`` * ``1.8 < M_D0 < 2.0`` * ``DM_Dstar_D < 0.16`` Reconstructed decays: * :math:`B^{0}\\to D^{*-} (D^{0} \\to K^+ \\pi^-) e^+`, * :math:`B^{0}\\to D^{*-} (D^{0} \\to K^+ \\pi^- \\pi^0) e^+`, * :math:`B^{0}\\to D^{*-} (D^{0} \\to K^+ \\pi^- \\pi^- \\pi^+) e^+`, * :math:`B^{0}\\to D^{*-} (D^{0} \\to K^+ \\pi^-) mu^+`, * :math:`B^{0}\\to D^{*-} (D^{0} \\to K^+ \\pi^- \\pi^0) mu^+`, * :math:`B^{0}\\to D^{*-} (D^{0} \\to K^+ \\pi^- \\pi^- \\pi^+) mu^+`, Note: This skim uses `skim.standardlists.charm.loadSkimHighEffD0_Kpi`, `skim.standardlists.charm.loadSkimHighEffD0_Kpipipi` and `skim.standardlists.charm.loadStdD0_eff20_Kpipi0`, where :math:`D^0` channel is defined. `skim.standardlists.charm.loadSkimHighEffDstarPlus_D0pi_Kpi`, `skim.standardlists.charm.loadSkimHighEffDstarPlus_D0pi_Kpipipi`, `skim.standardlists.charm.loadStdDstarPlus_D0pi_Kpipi0_eff20`,where the :math:`D^{*-}` channel is defined. The pion and kaon lists used to define :math:`D^0` and :math:`D^{*-}` are: `skim.standardlists.charm.loadPiSkimHighEff`, `skim.standardlists.charm.loadKSkimHighEff` and `skim.standardlists.charm.loadSlowPi` """ __authors__ = ["Bae Hanwook, Chiara La Licata"] __description__ = "" __contact__ = __liaison__ __category__ = "physics, semileptonic" ApplyHLTHadronCut = True produce_on_tau_samples = False # retention is very close to zero on taupair
[docs] def load_standard_lists(self, path): stdE("all", path=path) stdMu("all", path=path) stdPi("all", path=path) stdK("all", path=path) stdPi0s("eff20_May2020", path=path) loadPiSkimHighEff(path=path) loadKSkimHighEff(path=path) loadSlowPi(path=path) loadSkimHighEffD0_Kpi(path=path) loadSkimHighEffDstarPlus_D0pi_Kpi(path=path) loadSkimHighEffD0_Kpipipi(path=path) loadSkimHighEffDstarPlus_D0pi_Kpipipi(path=path) loadStdD0_eff20_Kpipi0(path=path) loadStdDstarPlus_D0pi_Kpipi0_eff20(path=path)
[docs] def build_lists(self, path): ma.cutAndCopyList( 'e+:sig', 'e+:all', 'abs(d0) < 0.5 and abs(z0) < 2 and thetaInCDCAcceptance and electronID_noTOP >= 0.95 and 1.1 < useCMSFrame(p) < 2.5 ', path=path) ma.cutAndCopyList( 'mu+:sig', 'mu+:all', 'abs(d0) < 0.5 and abs(z0) < 2 and thetaInCDCAcceptance and muonID >= 0.95 and 1.1 < useCMSFrame(p) < 2.5', path=path) B0_channels = ["D*-:D0_Kpi_skimhigheff e+:sig", "D*-:D0_Kpipi0_eff20 e+:sig", "D*-:D0_Kpipipi_skimhigheff e+:sig", "D*-:D0_Kpi_skimhigheff mu+:sig", "D*-:D0_Kpipi0_eff20 mu+:sig", "D*-:D0_Kpipipi_skimhigheff mu+:sig"] B0_list = [] for chID, channel in enumerate(B0_channels): ma.reconstructDecay("B0:Dstl_kpi_kpipi0_kpipipi" + str(chID) + " -> " + channel, "", chID, path=path) B0_list.append("B0:Dstl_kpi_kpipi0_kpipipi" + str(chID)) return B0_list
# new SLskim
[docs]@fancy_skim_header class BtoDl_and_ROE_e_or_mu_or_lowmult(BaseSkim): """ Reconstructed decay modes: * :math:`B^- \\to D^0 e^-`, :math:`B^- \\to D^0 \\mu^-` * anti-:math:`B^0 \\to D^+ e^-`, anti-:math:`B^0 \\to D^+ \\mu^-` * anti-:math:`B^0 \\to D^{*+}(D^0 \\pi^+) e^-`, anti-:math:`B^0 \\to D^{*+}(D^0 \\pi^+) \\mu^-` Additional ROE cuts: * The logical OR of the following: * identified :math:`e^{\\pm}` with :math:`p(CM) < 3.0` GeV * identified :math:`\\mu^{\\pm}` with :math:`p(CM) < 3.0` GeV * identified :math:`\\gamma` with :math:`E(CM) > 1.4` GeV * Two or fewer charged tracks * :math:`E_{ECL} < 2.0` GeV Cuts on electrons: * :math:`\\text{pidChargedBDTScore(11,all)} > 0.9` * :math:`p_t > 0.3\\,\\text{GeV}` in lab frame, :math:`p > 0.5\\,\\text{GeV}` in lab frame * :math:`dr < 0.5`, :math:`|dz| < 2` * :math:`\\text{thetaInCDCAcceptance}` Cuts on muons: * :math:`\\text{muonID_noSVD} > 0.9` * :math:`p_t > 0.4\\,\\text{GeV}` in lab frame, :math:`p > 0.7\\,\\text{GeV}` in lab frame * :math:`dr < 0.5`, :math:`|dz| < 2` Charged mask for ROE: * :math:`p_t>0.05\\,\\text{GeV}` * :math:`dr < 5\\,\\text{cm}`, :math:`|dz| < 10\\,\\text{cm}` ECL cluster mask for ROE: * :math:`\\text{clusterNHits}>1.5`, :math:`0.2967<\\theta<2.6180` * :math:`E>0.080,\\text{GeV}` """ __authors__ = ["Bob Kowalewski"] __description__ = "Skim for semileptonic tags with an ROE electron, muon, photon or a low-multiplicity signal decay" __contact__ = __liaison__ __category__ = "physics, semileptonic" ApplyHLTHadronCut = False TestSampleProcess = "charged" validation_sample = _VALIDATION_SAMPLE
[docs] def load_particle_lists(self, path): return
[docs] def build_lists(self, path): if self.analysisGlobaltag is None: b2.B2FATAL(f"The analysis globaltag is not set in the {self.name} skim.") b2.conditions.prepend_globaltag(self.analysisGlobaltag) eIDCut = "pidChargedBDTScore(11,all) > 0.9" muIDCut = "muonID_noSVD > 0.9" ePCut = "p > 0.5" ePtCut = "pt > 0.3" muPCut = "p > 0.7" muPtCut = "pt > 0.4" lepTrkCuts = "dr < 0.5 and abs(dz) < 2" hadTrkCuts = "dr < 2.0 and abs(dz) < 4" gammaCuts = "[clusterNHits>1.5] and [0.2967< clusterTheta<2.6180]" gammaECuts = "[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.025] or [clusterReg==3 and E>0.040]]" cleanMask = ('cleanMask', 'pt>0.05 and dr < 5 and abs(dz) < 10', f'{gammaCuts} and E>0.080 and minC2TDist>20.0 and abs(clusterTiming)<200') gammaSignalECut = "1.4" BSLRecoCut = "InvM > 2.5 and cosBY > -3.0 and cosBY < 1.5" BSLSkimCut = f"e_ROE_pCM < 3.0 or mu_ROE_pCM < 3.0 or gamma_ROE_ECM > {gammaSignalECut}" +\ " or nROE_Ch < 2.5 or E_extra_ROE < 1.6" vm.addAlias('pCM', 'useCMSFrame(p)') vm.addAlias('ECM', 'useCMSFrame(E)') vm.addAlias('cosBY', 'cosThetaBetweenParticleAndNominalB') # electrons and muons ma.fillParticleList("e-:sig", f"{lepTrkCuts} and thetaInCDCAcceptance and {ePtCut} and {ePCut}", path=path) ma.applyChargedPidMVA( particleLists=['e-:sig'], path=path, trainingMode=Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_Multiclass) ma.applyCuts('e-:sig', eIDCut, path=path) ma.fillParticleList("mu-:sig", f"{muIDCut} and {lepTrkCuts} and {muPtCut} and {muPCut}", path=path) total_leptons = "formula( nParticlesInList(e-:sig) + nParticlesInList(mu-:sig) )" # don't waste time if there are no leptons if (f"{total_leptons}" == "0"): return [] # charged K and pi candidates ma.fillParticleList("K-:loose", f"binaryPID(321,211) > 0.1 and {hadTrkCuts} and thetaInCDCAcceptance and pt>0.1", path=path) ma.fillParticleList( "pi+:loose", f"binaryPID(211,321) > 0.1 and {hadTrkCuts} and thetaInCDCAcceptance and pt>0.1", path=path) ma.fillParticleList("pi+:slow", f"{hadTrkCuts} and thetaInCDCAcceptance and p>0.05", path=path) # gamma and pi0 candidates ma.fillParticleList("gamma:eff50", f'{gammaCuts} and {gammaECuts}', path=path) ma.reconstructDecay("pi0:eff50 -> gamma:eff50 gamma:eff50", '0.114<InvM<0.150', path=path) ma.cutAndCopyList("gamma:e90", "gamma:eff50", "E>0.090", path=path) ma.reconstructDecay("pi0:e90 -> gamma:e90 gamma:e90", '0.118<InvM<0.148', path=path) # K0s -> pi+pi- candidates stdKshorts(path=path) ma.cutAndCopyList('K_S0:good', 'K_S0:merged', cut='significanceOfDistance>2.5', path=path) # D reconstruction - only clean modes ma.reconstructDecay("D0:Kpi -> K-:loose pi+:loose", cut="abs(dM) < 0.025", dmID=1, path=path) ma.rankByLowest("D0:Kpi", variable="abs(dM)", numBest=15, path=path) ma.reconstructDecay("D0:KK -> K-:loose K+:loose", cut="abs(dM) < 0.020", dmID=2, path=path) ma.rankByLowest("D0:KK", variable="abs(dM)", numBest=15, path=path) ma.reconstructDecay("D0:K3pi -> K-:loose pi+:loose pi-:loose pi+:loose", cut="abs(dM) < 0.020", dmID=3, path=path) ma.rankByLowest("D0:K3pi", variable="abs(dM)", numBest=15, path=path) ma.reconstructDecay("D0:Kpi0pi -> K-:loose pi0:e90 pi+:loose", cut="abs(dM)-0.005 < 0.050", dmID=4, path=path) ma.rankByLowest("D0:Kpi0pi", variable="abs(dM)", numBest=15, path=path) ma.reconstructDecay("D0:piKspi -> pi+:loose K_S0:good pi-:loose", cut="abs(dM) < 0.020", dmID=5, path=path) ma.rankByLowest("D0:piKspi", variable="abs(dM)", numBest=15, path=path) ma.reconstructDecay("D0:Kspi0 -> K_S0:good pi0:e90", cut="abs(dM)-0.005 < 0.050", dmID=6, path=path) ma.rankByLowest("D0:Kspi0", variable="abs(dM)", numBest=15, path=path) ma.copyLists("D0:sig", ['D0:Kpi', 'D0:KK', 'D0:K3pi', 'D0:Kpi0pi', 'D0:piKspi', 'D0:Kspi0'], path=path) ma.reconstructDecay("D+:Kpipi -> K-:loose pi+:loose pi+:loose", cut="abs(dM) < 0.020", dmID=1, path=path) ma.rankByLowest("D+:Kpipi", variable="abs(dM)", numBest=15, path=path) ma.reconstructDecay("D+:Kspi -> K_S0:good pi+:loose", cut="abs(dM) < 0.020", dmID=2, path=path) ma.rankByLowest("D+:Kspi", variable="abs(dM)", numBest=15, path=path) ma.reconstructDecay("D+:KKpi -> K-:loose K+:loose pi+:loose", cut="abs(dM) < 0.015", dmID=3, path=path) ma.rankByLowest("D+:KKpi", variable="abs(dM)", numBest=15, path=path) ma.copyLists("D+:sig", ['D+:Kpipi', 'D+:Kspi', 'D+:KKpi'], path=path) # No explicit reconstruction of D*0 to D0 pi0/gamma or D*+ to D0 pi+ (included in feeddown) ma.reconstructDecay("D*+:D0 -> pi+:slow D0:sig", cut="abs(dQ) < 0.0035", dmID=11, path=path) ma.rankByLowest("D*+:D0", variable="abs(dQ)", numBest=15, path=path) ma.copyLists("D*+:sig", ['D*+:D0'], path=path) # B reconstruction. Use wide cut on cosThetaBY. ma.reconstructDecay('anti-B0:Dpe -> e-:sig D+:sig ?nu ', BSLRecoCut, dmID=200, path=path) ma.reconstructDecay('anti-B0:Dpmu -> mu-:sig D+:sig ?nu ', BSLRecoCut, dmID=201, path=path) ma.copyLists('anti-B0:Dpl', ['anti-B0:Dpe', 'anti-B0:Dpmu'], path=path) ma.rankByHighest('anti-B0:Dpl', variable='InvM', numBest=9, path=path) ma.reconstructDecay('anti-B0:Dspe -> e-:sig D*+:sig ?nu ', BSLRecoCut, dmID=100, path=path) ma.reconstructDecay('anti-B0:Dspmu -> mu-:sig D*+:sig ?nu ', BSLRecoCut, dmID=101, path=path) ma.copyLists('anti-B0:Dspl', ['anti-B0:Dspe', 'anti-B0:Dspmu'], path=path) ma.rankByHighest('anti-B0:Dspl', variable='InvM', numBest=9, path=path) ma.reconstructDecay('B-:D0e -> e-:sig D0:sig ?nu ', BSLRecoCut, dmID=400, path=path) ma.reconstructDecay('B-:D0mu -> mu-:sig D0:sig ?nu ', BSLRecoCut, dmID=401, path=path) ma.copyLists('B-:D0l', ['B-:D0e', 'B-:D0mu'], path=path) ma.rankByHighest('B-:D0l', variable='InvM', numBest=9, path=path) # master SL B lists ma.copyLists('B-:SL', ['B-:D0l'], path=path) ma.copyLists('anti-B0:SL', ['anti-B0:Dspl', 'anti-B0:Dpl'], path=path) # Build ROE and look for e-, mu-, charged multiplicity and E_ECL for Btype in ['B-:SL', 'anti-B0:SL']: roe_path = b2.create_path() deadEndPath = b2.create_path() # Execute the filter module: ma.buildRestOfEvent(Btype, fillWithMostLikely=True, path=path) ma.appendROEMasks(Btype, [cleanMask], path=path) ma.signalSideParticleFilter(Btype, '', roe_path, deadEndPath) ma.fillParticleList( "e-:roeB", f"isInRestOfEvent == 1 and {eIDCut} and {lepTrkCuts} and thetaInCDCAcceptance and {ePtCut} and {ePCut}", path=roe_path) ma.fillParticleList( "mu-:roeB", f"isInRestOfEvent == 1 and {muIDCut} and {lepTrkCuts} and {muPtCut} and {muPCut}", path=roe_path) ma.fillParticleList("gamma:roeB", f'{gammaCuts} and ECM > {gammaSignalECut}', path=roe_path) ma.rankByHighest('e-:roeB', 'pCM', numBest=1, path=roe_path) ma.rankByHighest('mu-:roeB', 'pCM', numBest=1, path=roe_path) ma.rankByHighest('gamma:roeB', 'ECM', numBest=1, path=roe_path) ma.variableToSignalSideExtraInfo('e-:roeB', {'pCM': 'e_ROEB_pCM'}, path=roe_path) ma.variableToSignalSideExtraInfo('mu-:roeB', {'pCM': 'mu_ROEB_pCM'}, path=roe_path) ma.variableToSignalSideExtraInfo('gamma:roeB', {'ECM': 'gamma_ROEB_ECM'}, path=roe_path) path.for_each('RestOfEvent', 'RestOfEvents', path=roe_path) vm.addAlias('e_ROE_pCM', 'extraInfo(e_ROEB_pCM)') vm.addAlias('mu_ROE_pCM', 'extraInfo(mu_ROEB_pCM)') vm.addAlias('gamma_ROE_ECM', 'extraInfo(gamma_ROEB_ECM)') vm.addAlias('nROE_Ch', 'nROE_Charged(cleanMask)') vm.addAlias('E_extra_ROE', 'useCMSFrame(roeEextra(cleanMask))') # Only keep events whose ROE has an extra e or mu, or Ntrk<3, or E_ECL<2.0 GeV ma.applyCuts('B-:SL', f'passesCut({BSLSkimCut})', path=path) ma.applyCuts('anti-B0:SL', f'passesCut({BSLSkimCut})', path=path) b_sl_list = ['B-:SL', 'anti-B0:SL'] return b_sl_list
[docs] def validation_histograms(self, path): # NOTE: the validation package is not part of the light releases, so this import # must be made here rather than at the top of the file. from validation_tools.metadata import create_validation_histograms vm.addAlias('d0_p', 'daughter(0, p)') vm.addAlias('d1_p', 'daughter(1, p)') histogramFilename = f'{self}_Validation.root' create_validation_histograms( rootfile=histogramFilename, particlelist='B-:SL', variables_1d=[ ('cosBY', 90, -3.0, 1.5, 'cosThetaBY', __liaison__, 'Cosine of angle between the reconstructed B and the nominal B', '', 'cos#theta_{BY}', 'Candidates'), ('InvM', 100, 2.5, 5.3, 'M(D(*)+l)', __liaison__, 'Invariant mass distribution of D(*)l system', '', 'm(D(*)l) [GeV]', 'Candidates / 28 MeV'), ('useCMSFrame(d0_p)', 100, 0, 3.0, 'Tag lepton momentum in CMS', __liaison__, 'Momentum of tag-side lepton in CMS', '', 'p(l) [GeV]', 'Candidates / 30 MeV'), ('useCMSFrame(d1_p)', 100, 0, 3.0, 'Tag D(*) momentum in CMS', __liaison__, 'Momentum of tag-side D(*) meson in CMS', '', 'p(D(*)) [GeV]', 'Candidates / 30 MeV'), ('e_ROE_pCM', 100, 0, 3.0, 'ROE e momentum in CMS', __liaison__, 'Momentum of highest-momentum ROE electron in CMS', '', 'p(e) [GeV]', 'Candidates / 30 MeV'), ('mu_ROE_pCM', 100, 0, 3.0, 'ROE mu momentum in CMS', __liaison__, 'Momentum of highest-momentum ROE muon in CMS', '', 'p($\\mu$) [GeV]', 'Candidates / 30 MeV'), ('gamma_ROE_ECM', 100, 0, 5.0, 'ROE gamma energy in CMS', __liaison__, 'Energy of most-energetic ROE photon', '', 'E($\\gamma$) [GeV]', 'Candidates / 50 MeV'), ('nROE_Ch', 20, 0, 20.0, 'N(trk) in ROE', __liaison__, 'Number of tracks in ROE', '', 'tracks', 'Candidates'), ('E_extra_ROE', 100, 0, 2.5, 'E_ECL (CMS) in ROE', __liaison__, 'Extra energy in ROE', '', 'E_{extra} [GeV]', 'Candidates / 25 MeV'), ], path=path)