From dbf25e3b7d6308c07257d8936fcde83c0d8ca2d2 Mon Sep 17 00:00:00 2001 From: Fabian Christoph Glaser <fabian.christoph.glaser@cern.ch> Date: Tue, 18 Jul 2023 10:43:13 +0200 Subject: [PATCH 1/7] add selection of Bu2Dst0MuNu --- B2munuee/Bu2Dst0MuNu_options.py | 127 ++++++++++++++++++++ B2munuee/__init__.py | 0 B2munuee/info.yaml | 25 ++++ B2munuee/my_utils.py | 206 ++++++++++++++++++++++++++++++++ 4 files changed, 358 insertions(+) create mode 100644 B2munuee/Bu2Dst0MuNu_options.py create mode 100644 B2munuee/__init__.py create mode 100644 B2munuee/info.yaml create mode 100644 B2munuee/my_utils.py diff --git a/B2munuee/Bu2Dst0MuNu_options.py b/B2munuee/Bu2Dst0MuNu_options.py new file mode 100644 index 0000000000..18201cd837 --- /dev/null +++ b/B2munuee/Bu2Dst0MuNu_options.py @@ -0,0 +1,127 @@ + +from Configurables import DaVinci +from Configurables import DecayTreeTuple +from Configurables import GaudiSequencer +from Configurables import TupleToolTISTOS, BackgroundCategory +from Configurables import LoKi__Hybrid__TupleTool + +from PhysSelPython.Wrappers import SelectionSequence + +from PhysSelPython.Wrappers import Selection, DataOnDemand, AutomaticData +from Configurables import FilterInTrees, FilterDesktop, CombineParticles +from Configurables import DiElectronMaker + +from CommonParticles.Utils import updateDoD +from GaudiKernel.SystemOfUnits import MeV + +from DecayTreeTuple.Configuration import addTupleTool, setDescriptorTemplate + +from B2munuee import my_utils as utils + +""" +Additional cuts wrt. B2Dst0MuNuDst0D0GammaLine to align with B23MuNu_MueeLine: + +leptons: TRCHI2DOF < 3 & TRGHP < 0.3 & (PID{lepton} - PIDK) > 0.0 +B candidate: BPVVDCHI2 > 30 & PT > 2000 & BPVCORRM > 2500 & BPVCORRM < 10000 +""" + +def GetMuon(stream, loc): + muon_cut = ("('mu+' == ABSID) & (TRCHI2DOF < 3) & (TRGHP < 0.3) & ((PIDmu - PIDK) > 0.0)") + + muon_filter = FilterInTrees('MuonFilter', Code=muon_cut) + muon = Selection("MuonsForB2DstMuNu", + Algorithm=muon_filter, + RequiredSelections=[DataOnDemand(Location=loc)]) + return muon + +def GetDiLepton(stream, loc): + electron_cut = ("('e+' == ABSID) & (TRCHI2DOF < 3) & (TRGHP < 0.3) & ((PIDe - PIDK) > 0.0)") + + electrons_filter = FilterInTrees('ElectronsForB2Dst0MuNu', + Inputs=[loc], + Code=electron_cut) + updateDoD(electrons_filter) + + #DiElectron + dieLL = DiElectronMaker('DiElectron') + dieLL.Particle = "J/psi(1S)" + + dieLL.ElectronInputs = [f'Phys/ElectronsForB2Dst0MuNu/Particles'] + + dieLL.DiElectronMassMax = 300.0*MeV + dieLL.DiElectronMassMin = 0.0*MeV + dieLL.DiElectronPtMin = 0.0*MeV + dieLL.ElectronPtMin = 0.0*MeV + + DiElectron = Selection('SelectDiElectron', Algorithm=dieLL) + + Filter_DiElectron = FilterDesktop('DiElectronFilter', + Code = "(M < 250) & (VFASPF(VCHI2/VDOF) < 5)") + Sel_DiElectron = Selection('Sel_DiElectron', + Algorithm = Filter_DiElectron, + RequiredSelections=[DiElectron]) + + return Sel_DiElectron + +def GetD0(stream, loc): + d0_filter = FilterInTrees('D0Filter', Code="('D0' == ABSID)") + D0 = Selection("D0ForB2DstMuNu", + Algorithm=d0_filter, + RequiredSelections=[DataOnDemand(Location=loc)]) + + return D0 + +def CombineAll(D0, DiLepton, muon): + #D*0 + Dst_combine = CombineParticles('CombineDst', + DecayDescriptor="[D*(2007)0 -> D0 J/psi(1S)]cc", + CombinationCut="(AM - ACHILD(1, M) < 350*MeV)", + MotherCut="(VFASPF(VCHI2/VDOF) < 6)") + Dst = Selection('SelectDst', Algorithm=Dst_combine, RequiredSelections=[D0, DiLepton]) + + #B + B_combine = CombineParticles('CombineB', + DecayDescriptor = "[B- -> D*(2007)0 mu-]cc", + CombinationCut = "(AM > 2200*MeV) & (AM < 6000*MeV)", + MotherCut = "(VFASPF(VCHI2/VDOF) < 6) & (BPVVDCHI2 > 30.) & (BPVDIRA > 0.99) & (PT > 2000) & " \ + "(BPVCORRM > 2500) & (BPVCORRM < 10000)") + + B = Selection('SelectB', Algorithm=B_combine, RequiredSelections=[Dst, muon]) + return B + + + +stream = 'Semileptonic' +loc = f'/Event/{stream}/Phys/B2Dst0MuNuDst0D0GammaLine/Particles' + +# select muons from stripping +muon = GetMuon(stream, loc) + +# select electrons from stripping and run DiElectronMaker +DiLepton = GetDiLepton(stream, loc) + +# select D0 from K and pi from std particle containers +D0 = GetD0(stream, loc) + +# Combine particles +B = CombineAll(D0, DiLepton, muon) + +# make nTuple +# for B2munuee the convention is 'ep' and 'mu' are of same sign +dtt = DecayTreeTuple('B2MuNuEE') +dtt.setDescriptorTemplate( + '${B}[B- -> ${Dst}(D*(2007)0 -> ${D0}(D0 -> ${K}K- ${pi}pi+) ${Jpsi}(J/psi(1S) -> ${em}e+ ${ep}e-)) ${mu}mu-]CC') +Seq = SelectionSequence('Sequence', TopSelection=B) +dtt.Inputs = Seq.outputLocations() + +_seq = GaudiSequencer('MySequencer') +_seq.Members += [Seq.sequence(), dtt] +DaVinci().appendToMainSequence([_seq]) + +utils.DefaultToolList(dtt) +utils.TriggerToolList(dtt) +utils.DefaultLoKi(dtt) +utils.AddDOCA(dtt) +utils.TupleToolConeIsolation(dtt) +utils.TupleToolSubstitution(dtt) +utils.TupleToolVeto(dtt) diff --git a/B2munuee/__init__.py b/B2munuee/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/B2munuee/info.yaml b/B2munuee/info.yaml new file mode 100644 index 0000000000..7f243fb4c8 --- /dev/null +++ b/B2munuee/info.yaml @@ -0,0 +1,25 @@ +defaults: + application: DaVinci/v46r4 + wg: SL + automatically_configure: yes + turbo: no + inform: + - fabian.christoph.glaser@cern.ch + +{%- set real_datasets = [ + ('16', '28r2'), + ('17', '29r2p1'), + ('18', '34r0p1'), +]%} + +{%- for year, stripping in real_datasets %} + {%- for polarity in ['MagDown','MagUp'] %} + +20{{year}}_{{polarity}}_Bu2Dst0MuNu: + input: + bk_query: /LHCb/Collision{{year}}/Beam6500GeV-VeloClosed-{{polarity}}/Real Data/Reco{{year}}/Stripping{{stripping}}/90000000/SEMILEPTONIC.DST + output: Bu2Dst0MuNu.ROOT + options: Bu2Dst0MuNu_options.py + + {%- endfor %} +{%- endfor %} \ No newline at end of file diff --git a/B2munuee/my_utils.py b/B2munuee/my_utils.py new file mode 100644 index 0000000000..c192bf5748 --- /dev/null +++ b/B2munuee/my_utils.py @@ -0,0 +1,206 @@ +from Configurables import TupleToolTISTOS +from Configurables import LoKi__Hybrid__TupleTool + + +def DefaultToolList(dtt): + '''Add default list of TupleTools''' + dtt.ToolList = [ + # default tools + "TupleToolKinematic", + "TupleToolEventInfo", + "TupleToolGeometry", + "TupleToolANNPID", + + # additional tools w/o configuration required + "TupleToolRecoStats", + "TupleToolPhotonInfo", + "TupleToolPropertime", + 'TupleToolCorrectedMass'] + + # add PID info + PID = dtt.addTupleTool("TupleToolPid") + PID.Verbose = True + + # add VELO track info + TrackInfo = dtt.addTupleTool('TupleToolTrackInfo') + TrackInfo.Verbose = True + + # add Brem info for single and di-eletcron + BremInfo = dtt.addTupleTool('TupleToolBremInfo') + BremInfo.fullDST = True + BremInfo.Particle = ['e+', 'J/psi(1S)'] + + # add tool for isolation + IsoGeneric = dtt.addTupleTool("TupleToolIsoGeneric") + IsoGeneric.Verbose = True + + # add info on missing momentum + NuReco = dtt.B.addTupleTool("TupleToolNeutrinoReco") + NuReco.Verbose = False + + dtt.ep.addTupleTool('TupleToolL0Calo/ep_L0Calo') + dtt.ep.ep_L0Calo.WhichCalo = "ECAL" + dtt.em.addTupleTool('TupleToolL0Calo/em_L0Calo') + dtt.em.em_L0Calo.WhichCalo = "ECAL" + + +def TriggerToolList(dtt): + '''Add trigger information''' + + L0trigger = ["L0ElectronDecision", + "L0MuonDecision", + "L0HadronDecision", + "L0PhotonDecision"] + + Hlt1trigger = ["Hlt1TrackMVADecision", + "Hlt1TwoTrackMVADecision", + "Hlt1TrackMVALooseDecision", + "Hlt1TwoTrackMVALooseDecision", + "Hlt1TrackMuonDecision", + "Hlt1TrackMuonMVADecision", + "Hlt1L0AnyDecision"] + + Hlt2trigger = [ + "Hlt2SingleMuonDecision", + # Topo + "Hlt2Topo2BodyDecision", + "Hlt2Topo3BodyDecision", + "Hlt2TopoE2BodyDecision", + "Hlt2TopoE3BodyDecision", + "Hlt2TopoEE2BodyDecision", + "Hlt2TopoEE3BodyDecision", + "Hlt2TopoMu2BodyDecision", + "Hlt2TopoMu3BodyDecision", + "Hlt2TopoMuE2BodyDecision", + "Hlt2TopoMuE3BodyDecision", + "Hlt2TopoMu2BodyBBDTDecision", + "Hlt2TopoMu3BodyBBDTDecision"] + + triggerList = L0trigger + Hlt1trigger + Hlt2trigger + + TISTOS = TupleToolTISTOS('TISTOS') + TISTOS.VerboseL0 = True + TISTOS.VerboseHlt1 = True + TISTOS.VerboseHlt2 = True + TISTOS.TriggerList = triggerList + dtt.B.addTupleTool(TISTOS) + + # for electrons and muon only need L0 information + TISTOS_Leptons = TupleToolTISTOS('TISTOS_Leptons') + TISTOS_Leptons.VerboseL0 = True + TISTOS_Leptons.VerboseHlt1 = False + TISTOS_Leptons.VerboseHlt2 = False + TISTOS_Leptons.TriggerList = L0trigger + dtt.ep.addTupleTool(TISTOS_Leptons) + dtt.em.addTupleTool(TISTOS_Leptons) + dtt.mu.addTupleTool(TISTOS_Leptons) + + +def DefaultLoKi(dtt): + ''' + Add default LoKi functors for decay topology and kinematics + ''' + + LoKi_All = dtt.addTupleTool("LoKi::Hybrid::TupleTool/LoKi_All") + LoKi_All.Variables = { + 'MINIPCHI2': "MIPCHI2DV(PRIMARY)", + 'MINIP': "MIPDV(PRIMARY)", + 'ETA': 'ETA', + 'PHI': 'PHI' + } + + # add track information + LoKi_Track = LoKi__Hybrid__TupleTool("LoKi_Track") + LoKi_Track.Preambulo = ["from LoKiTracks.decorators import *"] + LoKi_Track.Variables = { + "TrPX": "TRFUN(TrPX)", + "TrPY": "TRFUN(TrPY)", + "TrPZ": "TRFUN(TrPZ)", + "TrP": "TRFUN(TrP)", + } + + dtt.ep.ToolList += ["LoKi::Hybrid::TupleTool/LoKi_Track"] + dtt.ep.addTool(LoKi_Track) + dtt.em.ToolList += ["LoKi::Hybrid::TupleTool/LoKi_Track"] + dtt.em.addTool(LoKi_Track) + + LoKi_B = dtt.B.addTupleTool("LoKi::Hybrid::TupleTool/LoKi_B") + LoKi_B.Variables = { + 'DIRA_OWNPV': "BPVDIRA", + 'ENDVERTEX_CHI2': "VFASPF(VCHI2/VDOF)", + 'X_travelled': "VFASPF(VX)-BPV(VX)", + 'Y_travelled': "VFASPF(VY)-BPV(VY)", + 'Z_travelled': "VFASPF(VZ)-BPV(VZ)", + 'P_Parallel': "BPVDIRA*P", + 'P_Perp': "sin(acos(BPVDIRA))*P", + 'BPVVDZ': "BPVVDZ", + } + +def AddDOCA(dtt): + ''' + Add distance of closest approach DOCA for the three lepton tracks + ''' + + doca_name, location1, location2 = zip( + ['epem', + '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> ^e+ e-)) mu-]CC', + '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> e+ ^e-)) mu-]CC'], + ['epmu', + '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> e+ ^e-)) mu-]CC', + '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> e+ e-)) ^mu-]CC'], + ['emmu', + '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> ^e+ e-)) mu-]CC', + '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> e+ e-)) ^mu-]CC']) + + DOCA = dtt.B.addTupleTool("TupleToolDOCA") + DOCA.Name = list(doca_name) + DOCA.Location1 = list(location1) + DOCA.Location2 = list(location2) + +def TupleToolConeIsolation(dtt): + '''Add cone isolation variables''' + + dtt.Jpsi.addTupleTool('TupleToolConeIsolation') + + dtt.Jpsi.TupleToolConeIsolation.ExtraParticlesLocation = 'Phys/StdAllNoPIDsPions/Particles' + dtt.Jpsi.TupleToolConeIsolation.MaxPtParticlesLocation = 'Phys/StdAllLoosePions/Particles' + dtt.Jpsi.TupleToolConeIsolation.ExtraPhotonsLocation = 'Phys/StdLooseAllPhotons/Particles' + + dtt.Jpsi.TupleToolConeIsolation.MinConeSize = 0.4 + dtt.Jpsi.TupleToolConeIsolation.MaxConeSize = 0.6 + dtt.Jpsi.TupleToolConeIsolation.SizeStep = 0.2 + + dtt.Jpsi.TupleToolConeIsolation.FillCharged = True + dtt.Jpsi.TupleToolConeIsolation.FillNeutral = True + + dtt.Jpsi.TupleToolConeIsolation.FillAsymmetry = True + dtt.Jpsi.TupleToolConeIsolation.FillDeltas = True + dtt.Jpsi.TupleToolConeIsolation.FillIsolation = True + + dtt.Jpsi.TupleToolConeIsolation.FillMaxPt = True + dtt.Jpsi.TupleToolConeIsolation.FillComponents = True + dtt.Jpsi.TupleToolConeIsolation.FillPi0Info = False + dtt.Jpsi.TupleToolConeIsolation.FillMergedPi0Info = False + + +def TupleToolSubstitution(dtt): + '''Add variables for lepton -> hadron (double-)substitutions''' + + substitutions = [ + 'mu+ => K+', + 'mu+ => pi+', + 'mu+ => p+' + ] + SubstTool = dtt.B.addTupleTool('TupleToolSubMass/B_SubMass') + SubstTool.Substitution += substitutions + +def TupleToolVeto(dtt): + ''' Add tool for pi0 veto for single photons''' + + vetoContainersPi0 = ['Phys/StdLoosePi02gg/Particles', + 'Phys/StdLooseResolvedPi0/Particles', + 'Phys/StdLooseMergedPi0/Particles'] + + vetoTool = dtt.Jpsi.addTupleTool("TupleToolVeto") + vetoTool.Particle = 'J/psi(1S)' + vetoTool.Veto['_Pi0'] = vetoContainersPi0 -- GitLab From a61104c60ea427128b24438ce9f8b7c1bb360dbb Mon Sep 17 00:00:00 2001 From: Fabian Christoph Glaser <fabian.christoph.glaser@cern.ch> Date: Tue, 18 Jul 2023 16:22:43 +0200 Subject: [PATCH 2/7] few style changes --- B2munuee/Bu2Dst0MuNu_options.py | 123 +++++++++++++++++--------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/B2munuee/Bu2Dst0MuNu_options.py b/B2munuee/Bu2Dst0MuNu_options.py index 18201cd837..e4bb4ac8f1 100644 --- a/B2munuee/Bu2Dst0MuNu_options.py +++ b/B2munuee/Bu2Dst0MuNu_options.py @@ -1,3 +1,12 @@ +""" +Selection of B- -> D*0 (-> D0 gamma) mu nu as reference for B- -> mu nu gamma +Use B2Dst0MuNuDst0D0GammaLine to select the reference channel + +Additional cuts wrt. B2Dst0MuNuDst0D0GammaLine to align with B23MuNu_MueeLine: + +leptons: TRCHI2DOF < 3 & TRGHP < 0.3 & (PID{lepton} - PIDK) > 0.0 +B candidate: BPVVDCHI2 > 30 & PT > 2000 & BPVCORRM > 2500 & BPVCORRM < 10000 +""" from Configurables import DaVinci from Configurables import DecayTreeTuple @@ -18,99 +27,97 @@ from DecayTreeTuple.Configuration import addTupleTool, setDescriptorTemplate from B2munuee import my_utils as utils -""" -Additional cuts wrt. B2Dst0MuNuDst0D0GammaLine to align with B23MuNu_MueeLine: - -leptons: TRCHI2DOF < 3 & TRGHP < 0.3 & (PID{lepton} - PIDK) > 0.0 -B candidate: BPVVDCHI2 > 30 & PT > 2000 & BPVCORRM > 2500 & BPVCORRM < 10000 -""" -def GetMuon(stream, loc): - muon_cut = ("('mu+' == ABSID) & (TRCHI2DOF < 3) & (TRGHP < 0.3) & ((PIDmu - PIDK) > 0.0)") +def GetMuon(loc): + muon_cut = ( + "('mu+' == ABSID) & (TRCHI2DOF < 3) & (TRGHP < 0.3) & ((PIDmu - PIDK) > 0.0)") muon_filter = FilterInTrees('MuonFilter', Code=muon_cut) - muon = Selection("MuonsForB2DstMuNu", - Algorithm=muon_filter, + return Selection("MuonsForB2DstMuNu", Algorithm=muon_filter, RequiredSelections=[DataOnDemand(Location=loc)]) - return muon -def GetDiLepton(stream, loc): - electron_cut = ("('e+' == ABSID) & (TRCHI2DOF < 3) & (TRGHP < 0.3) & ((PIDe - PIDK) > 0.0)") - electrons_filter = FilterInTrees('ElectronsForB2Dst0MuNu', - Inputs=[loc], - Code=electron_cut) - updateDoD(electrons_filter) - - #DiElectron +def GetDiLepton(loc, tes): dieLL = DiElectronMaker('DiElectron') dieLL.Particle = "J/psi(1S)" - dieLL.ElectronInputs = [f'Phys/ElectronsForB2Dst0MuNu/Particles'] + dieLL.ElectronInputs = [f'Phys/{tes}/Particles'] - dieLL.DiElectronMassMax = 300.0*MeV - dieLL.DiElectronMassMin = 0.0*MeV - dieLL.DiElectronPtMin = 0.0*MeV - dieLL.ElectronPtMin = 0.0*MeV + dieLL.DiElectronMassMax = 300.0 * MeV + dieLL.DiElectronMassMin = 0.0 * MeV + dieLL.DiElectronPtMin = 0.0 * MeV + dieLL.ElectronPtMin = 0.0 * MeV - DiElectron = Selection('SelectDiElectron', Algorithm=dieLL) + dielectron = Selection('SelectDiElectron', Algorithm=dieLL) - Filter_DiElectron = FilterDesktop('DiElectronFilter', - Code = "(M < 250) & (VFASPF(VCHI2/VDOF) < 5)") - Sel_DiElectron = Selection('Sel_DiElectron', - Algorithm = Filter_DiElectron, - RequiredSelections=[DiElectron]) + dielectron_filter = FilterDesktop('DiElectronFilter', + Code="(M < 250) & (VFASPF(VCHI2/VDOF) < 5)") - return Sel_DiElectron + return Selection('Sel_DiElectron', Algorithm=dielectron_filter, + RequiredSelections=[dielectron]) -def GetD0(stream, loc): - d0_filter = FilterInTrees('D0Filter', Code="('D0' == ABSID)") - D0 = Selection("D0ForB2DstMuNu", - Algorithm=d0_filter, - RequiredSelections=[DataOnDemand(Location=loc)]) - return D0 +def GetD0(loc): + d0_filter = FilterInTrees('D0Filter', Code="('D0' == ABSID)") -def CombineAll(D0, DiLepton, muon): - #D*0 - Dst_combine = CombineParticles('CombineDst', - DecayDescriptor="[D*(2007)0 -> D0 J/psi(1S)]cc", - CombinationCut="(AM - ACHILD(1, M) < 350*MeV)", - MotherCut="(VFASPF(VCHI2/VDOF) < 6)") - Dst = Selection('SelectDst', Algorithm=Dst_combine, RequiredSelections=[D0, DiLepton]) + return Selection("D0ForB2DstMuNu", Algorithm=d0_filter, + RequiredSelections=[DataOnDemand(Location=loc)]) - #B - B_combine = CombineParticles('CombineB', - DecayDescriptor = "[B- -> D*(2007)0 mu-]cc", - CombinationCut = "(AM > 2200*MeV) & (AM < 6000*MeV)", - MotherCut = "(VFASPF(VCHI2/VDOF) < 6) & (BPVVDCHI2 > 30.) & (BPVDIRA > 0.99) & (PT > 2000) & " \ - "(BPVCORRM > 2500) & (BPVCORRM < 10000)") - - B = Selection('SelectB', Algorithm=B_combine, RequiredSelections=[Dst, muon]) - return B +def CombineAll(D0, DiLepton, muon): + # Make and select D*0 -> D0 gamma + dst_combine = CombineParticles('CombineDst', + DecayDescriptor="[D*(2007)0 -> D0 J/psi(1S)]cc", + CombinationCut="(AM - ACHILD(1, M) < 350*MeV)", + MotherCut="(VFASPF(VCHI2/VDOF) < 6)") + dst_selection = Selection( + 'SelectDst', + Algorithm=dst_combine, + RequiredSelections=[ + D0, + DiLepton]) + + # Make and select B- -> D*0 mu- + b_mother_cut = "(VFASPF(VCHI2/VDOF) < 6) & (BPVVDCHI2 > 30.) & (BPVDIRA > 0.99) & " \ + "(PT > 2000) & (BPVCORRM > 2500) & (BPVCORRM < 10000)" + + b_combine = CombineParticles('CombineB', + DecayDescriptor="[B- -> D*(2007)0 mu-]cc", + CombinationCut="(AM > 2200*MeV) & (AM < 6000*MeV)", + MotherCut=b_mother_cut) + + return Selection('SelectB', Algorithm=b_combine, + RequiredSelections=[dst_selection, muon]) stream = 'Semileptonic' loc = f'/Event/{stream}/Phys/B2Dst0MuNuDst0D0GammaLine/Particles' # select muons from stripping -muon = GetMuon(stream, loc) +muonFromB2Dst0MuNu = GetMuon(loc) + +# filter electrons from stripping selection to be passed to DiElectronMaker +electron_cut = "('e+' == ABSID) & (TRCHI2DOF < 3) & (TRGHP < 0.3) & ((PIDe - PIDK) > 0.0)" +electrons_tes = 'ElectronsFromB2Dst0MuNu' +electrons_filter = FilterInTrees(electrons_tes, + Inputs=[loc], + Code=electron_cut) +updateDoD(electrons_filter) # select electrons from stripping and run DiElectronMaker -DiLepton = GetDiLepton(stream, loc) +DiLeptonFromB2DstMuNu = GetDiLepton(loc, electrons_tes) # select D0 from K and pi from std particle containers -D0 = GetD0(stream, loc) +D0FromB2DstMuNu = GetD0(loc) # Combine particles -B = CombineAll(D0, DiLepton, muon) +B = CombineAll(D0FromB2DstMuNu, DiLeptonFromB2DstMuNu, muonFromB2Dst0MuNu) # make nTuple # for B2munuee the convention is 'ep' and 'mu' are of same sign dtt = DecayTreeTuple('B2MuNuEE') dtt.setDescriptorTemplate( - '${B}[B- -> ${Dst}(D*(2007)0 -> ${D0}(D0 -> ${K}K- ${pi}pi+) ${Jpsi}(J/psi(1S) -> ${em}e+ ${ep}e-)) ${mu}mu-]CC') + '${B}[B- -> ${Dst}(D*(2007)0 -> ${D0}(D0 -> ${K}K- ${pi}pi+) ${Jpsi}(J/psi(1S) -> ${em}e+ ${ep}e-)) ${mu}mu-]CC') Seq = SelectionSequence('Sequence', TopSelection=B) dtt.Inputs = Seq.outputLocations() -- GitLab From e53694540b8f903f082ef97319ec8d04974b1658 Mon Sep 17 00:00:00 2001 From: Fabian Christoph Glaser <fabian.christoph.glaser@cern.ch> Date: Mon, 18 Sep 2023 13:50:37 +0200 Subject: [PATCH 3/7] new production for latest MC samples --- B2munuee/B2Vub_MCoptions.py | 11 ++ B2munuee/Bc2munucc_MCoptions.py | 10 ++ B2munuee/Bu2Dst0MuNu_options.py | 134 ---------------- B2munuee/Bu2munuee_MCoptions.py | 8 + B2munuee/info.yaml | 84 ++++++++-- B2munuee/my_selections.py | 264 ++++++++++++++++++++++++++++++++ B2munuee/my_utils.py | 137 +++++++++++++++-- 7 files changed, 488 insertions(+), 160 deletions(-) create mode 100644 B2munuee/B2Vub_MCoptions.py create mode 100644 B2munuee/Bc2munucc_MCoptions.py delete mode 100644 B2munuee/Bu2Dst0MuNu_options.py create mode 100644 B2munuee/Bu2munuee_MCoptions.py create mode 100644 B2munuee/my_selections.py diff --git a/B2munuee/B2Vub_MCoptions.py b/B2munuee/B2Vub_MCoptions.py new file mode 100644 index 0000000000..e0288987eb --- /dev/null +++ b/B2munuee/B2Vub_MCoptions.py @@ -0,0 +1,11 @@ +from B2munuee import my_selections as selections + +# B+ -> mu nu Xu0 (-> X gamma), resonant +# B+ -> mu nu Xu0 (-> X gamma), non-resonant +# B0 -> mu nu Xu (-> X gamma), resonant +# B0 -> mu nu Xu (-> X gamma), non-resonant + +trees = ['default','SameSign','pions','eta'] +isMC=True +addJpsiConstraints=False +selections.MySelection(trees, isMC, addJpsiConstraints) \ No newline at end of file diff --git a/B2munuee/Bc2munucc_MCoptions.py b/B2munuee/Bc2munucc_MCoptions.py new file mode 100644 index 0000000000..f99d80384a --- /dev/null +++ b/B2munuee/Bc2munucc_MCoptions.py @@ -0,0 +1,10 @@ +from B2munuee import my_selections as selections + +# Bc -> mu nu chi_c (-> Jpsi gamma) +# Bc -> mu nu Psi2S (-> Jpsi X) +# Bc -> mu nu Psi2S (-> ee) + +trees = ['default', 'SameSign'] +isMC = True +addJpsiConstraints = True +selections.MySelection(trees, isMC, addJpsiConstraints) \ No newline at end of file diff --git a/B2munuee/Bu2Dst0MuNu_options.py b/B2munuee/Bu2Dst0MuNu_options.py deleted file mode 100644 index e4bb4ac8f1..0000000000 --- a/B2munuee/Bu2Dst0MuNu_options.py +++ /dev/null @@ -1,134 +0,0 @@ -""" -Selection of B- -> D*0 (-> D0 gamma) mu nu as reference for B- -> mu nu gamma -Use B2Dst0MuNuDst0D0GammaLine to select the reference channel - -Additional cuts wrt. B2Dst0MuNuDst0D0GammaLine to align with B23MuNu_MueeLine: - -leptons: TRCHI2DOF < 3 & TRGHP < 0.3 & (PID{lepton} - PIDK) > 0.0 -B candidate: BPVVDCHI2 > 30 & PT > 2000 & BPVCORRM > 2500 & BPVCORRM < 10000 -""" - -from Configurables import DaVinci -from Configurables import DecayTreeTuple -from Configurables import GaudiSequencer -from Configurables import TupleToolTISTOS, BackgroundCategory -from Configurables import LoKi__Hybrid__TupleTool - -from PhysSelPython.Wrappers import SelectionSequence - -from PhysSelPython.Wrappers import Selection, DataOnDemand, AutomaticData -from Configurables import FilterInTrees, FilterDesktop, CombineParticles -from Configurables import DiElectronMaker - -from CommonParticles.Utils import updateDoD -from GaudiKernel.SystemOfUnits import MeV - -from DecayTreeTuple.Configuration import addTupleTool, setDescriptorTemplate - -from B2munuee import my_utils as utils - - -def GetMuon(loc): - muon_cut = ( - "('mu+' == ABSID) & (TRCHI2DOF < 3) & (TRGHP < 0.3) & ((PIDmu - PIDK) > 0.0)") - - muon_filter = FilterInTrees('MuonFilter', Code=muon_cut) - return Selection("MuonsForB2DstMuNu", Algorithm=muon_filter, - RequiredSelections=[DataOnDemand(Location=loc)]) - - -def GetDiLepton(loc, tes): - dieLL = DiElectronMaker('DiElectron') - dieLL.Particle = "J/psi(1S)" - - dieLL.ElectronInputs = [f'Phys/{tes}/Particles'] - - dieLL.DiElectronMassMax = 300.0 * MeV - dieLL.DiElectronMassMin = 0.0 * MeV - dieLL.DiElectronPtMin = 0.0 * MeV - dieLL.ElectronPtMin = 0.0 * MeV - - dielectron = Selection('SelectDiElectron', Algorithm=dieLL) - - dielectron_filter = FilterDesktop('DiElectronFilter', - Code="(M < 250) & (VFASPF(VCHI2/VDOF) < 5)") - - return Selection('Sel_DiElectron', Algorithm=dielectron_filter, - RequiredSelections=[dielectron]) - - -def GetD0(loc): - d0_filter = FilterInTrees('D0Filter', Code="('D0' == ABSID)") - - return Selection("D0ForB2DstMuNu", Algorithm=d0_filter, - RequiredSelections=[DataOnDemand(Location=loc)]) - - -def CombineAll(D0, DiLepton, muon): - # Make and select D*0 -> D0 gamma - dst_combine = CombineParticles('CombineDst', - DecayDescriptor="[D*(2007)0 -> D0 J/psi(1S)]cc", - CombinationCut="(AM - ACHILD(1, M) < 350*MeV)", - MotherCut="(VFASPF(VCHI2/VDOF) < 6)") - dst_selection = Selection( - 'SelectDst', - Algorithm=dst_combine, - RequiredSelections=[ - D0, - DiLepton]) - - # Make and select B- -> D*0 mu- - b_mother_cut = "(VFASPF(VCHI2/VDOF) < 6) & (BPVVDCHI2 > 30.) & (BPVDIRA > 0.99) & " \ - "(PT > 2000) & (BPVCORRM > 2500) & (BPVCORRM < 10000)" - - b_combine = CombineParticles('CombineB', - DecayDescriptor="[B- -> D*(2007)0 mu-]cc", - CombinationCut="(AM > 2200*MeV) & (AM < 6000*MeV)", - MotherCut=b_mother_cut) - - return Selection('SelectB', Algorithm=b_combine, - RequiredSelections=[dst_selection, muon]) - - -stream = 'Semileptonic' -loc = f'/Event/{stream}/Phys/B2Dst0MuNuDst0D0GammaLine/Particles' - -# select muons from stripping -muonFromB2Dst0MuNu = GetMuon(loc) - -# filter electrons from stripping selection to be passed to DiElectronMaker -electron_cut = "('e+' == ABSID) & (TRCHI2DOF < 3) & (TRGHP < 0.3) & ((PIDe - PIDK) > 0.0)" -electrons_tes = 'ElectronsFromB2Dst0MuNu' -electrons_filter = FilterInTrees(electrons_tes, - Inputs=[loc], - Code=electron_cut) -updateDoD(electrons_filter) - -# select electrons from stripping and run DiElectronMaker -DiLeptonFromB2DstMuNu = GetDiLepton(loc, electrons_tes) - -# select D0 from K and pi from std particle containers -D0FromB2DstMuNu = GetD0(loc) - -# Combine particles -B = CombineAll(D0FromB2DstMuNu, DiLeptonFromB2DstMuNu, muonFromB2Dst0MuNu) - -# make nTuple -# for B2munuee the convention is 'ep' and 'mu' are of same sign -dtt = DecayTreeTuple('B2MuNuEE') -dtt.setDescriptorTemplate( - '${B}[B- -> ${Dst}(D*(2007)0 -> ${D0}(D0 -> ${K}K- ${pi}pi+) ${Jpsi}(J/psi(1S) -> ${em}e+ ${ep}e-)) ${mu}mu-]CC') -Seq = SelectionSequence('Sequence', TopSelection=B) -dtt.Inputs = Seq.outputLocations() - -_seq = GaudiSequencer('MySequencer') -_seq.Members += [Seq.sequence(), dtt] -DaVinci().appendToMainSequence([_seq]) - -utils.DefaultToolList(dtt) -utils.TriggerToolList(dtt) -utils.DefaultLoKi(dtt) -utils.AddDOCA(dtt) -utils.TupleToolConeIsolation(dtt) -utils.TupleToolSubstitution(dtt) -utils.TupleToolVeto(dtt) diff --git a/B2munuee/Bu2munuee_MCoptions.py b/B2munuee/Bu2munuee_MCoptions.py new file mode 100644 index 0000000000..042f16c834 --- /dev/null +++ b/B2munuee/Bu2munuee_MCoptions.py @@ -0,0 +1,8 @@ +from B2munuee import my_selections as selections + +# B+ -> mu nu eta' (-> e e gamma) + +trees = ['default', 'SameSign'] +isMC = True +addJpsiConstraints = False +selections.MySelection(trees, isMC, addJpsiConstraints) \ No newline at end of file diff --git a/B2munuee/info.yaml b/B2munuee/info.yaml index 7f243fb4c8..4a349339ed 100644 --- a/B2munuee/info.yaml +++ b/B2munuee/info.yaml @@ -6,20 +6,86 @@ defaults: inform: - fabian.christoph.glaser@cern.ch -{%- set real_datasets = [ - ('16', '28r2'), - ('17', '29r2p1'), - ('18', '34r0p1'), +{%- set mc_datasets = [ + ('2016', 'Sim09m', 'Trig0x6139160F', '16', '03a', '28r2p1'), + ('2017', 'Sim09m', 'Trig0x62661709', '17', '04a-WithTurcal', '29r2p2'), + ('2018', 'Sim09m', 'Trig0x617d18a4', '18', '05-WithTurcal', '34r0p2'), ]%} -{%- for year, stripping in real_datasets %} +{%- for year, sim, trig, reco, turbo, strip in mc_datasets %} {%- for polarity in ['MagDown','MagUp'] %} -20{{year}}_{{polarity}}_Bu2Dst0MuNu: + +{{year}}_{{polarity}}_MC_Bu2munuetap2eeg: + #B+ -> mu nu eta' (-> e+ e- gamma) input: - bk_query: /LHCb/Collision{{year}}/Beam6500GeV-VeloClosed-{{polarity}}/Real Data/Reco{{year}}/Stripping{{stripping}}/90000000/SEMILEPTONIC.DST - output: Bu2Dst0MuNu.ROOT - options: Bu2Dst0MuNu_options.py + bk_query: /MC/{{year}}/Beam6500GeV-{{year}}-{{polarity}}-Nu1.6-25ns-Pythia8/{{sim}}/{{trig}}/Reco{{reco}}/Turbo{{turbo}}/Stripping{{strip}}NoPrescalingFlagged/12513200/ALLSTREAMS.DST + output: Bu2munuetap2eeg_MC.ROOT + options: Bu2munuee_MCoptions.py + +{{year}}_{{polarity}}_MC_Bc2munuchic2Jpsi: + #Bc+ -> mu nu chi_c (-> Jpsi X) + input: + bk_query: /MC/{{year}}/Beam6500GeV-{{year}}-{{polarity}}-Nu1.6-25ns-BcVegPyPythia8/{{sim}}/{{trig}}/Reco{{reco}}/Turbo{{turbo}}/Stripping{{strip}}NoPrescalingFlagged/14643230/ALLSTREAMS.DST + output: Bc2munuchic2Jpsi_MC.ROOT + options: Bc2munucc_MCoptions.py + +{{year}}_{{polarity}}_MC_Bc2munuPsi2Jpsi: + #Bc+ -> mu nu psi(2S) (-> Jpsi X) + input: + bk_query: /MC/{{year}}/Beam6500GeV-{{year}}-{{polarity}}-Nu1.6-25ns-BcVegPyPythia8/{{sim}}/{{trig}}/Reco{{reco}}/Turbo{{turbo}}/Stripping{{strip}}NoPrescalingFlagged/14845020/ALLSTREAMS.DST + output: Bc2munuPsi2Jpsi_MC.ROOT + options: Bc2munucc_MCoptions.py + +{{year}}_{{polarity}}_MC_Bc2munuPsi2ee: + #Bc+ -> mu nu psi(2S) + input: + bk_query: /MC/{{year}}/Beam6500GeV-{{year}}-{{polarity}}-Nu1.6-25ns-BcVegPyPythia8/{{sim}}/{{trig}}/Reco{{reco}}/Turbo{{turbo}}/Stripping{{strip}}NoPrescalingFlagged/14543050/ALLSTREAMS.DST + output: Bc2munuPsi2ee_MC.ROOT + options: Bc2munucc_MCoptions.py + + {%- endfor %} +{%- endfor %} + + +###### +# MC samples generated using SplitSim for photon conversion +###### + +{%- set conversion_datasets = [ + ('2016', 'Sim09m-SplitSim01', 'Trig0x6139160F', '16', '03a', '28r2p1'), + ('2017', 'Sim09m-SplitSim01', 'Trig0x62661709', '17', '04a-WithTurcal', '29r2p2'), + ('2018', 'Sim09m-SplitSim01', 'Trig0x617d18a4', '18', '05-WithTurcal', '34r0p2'), +]%} + +{%- for year, sim, trig, reco, turbo, strip in conversion_datasets %} + {%- for polarity in ['MagDown','MagUp'] %} + + #B+ -> mu nu Xu resonant + #input: + # bk_query: /MC/{{year}}/Beam6500GeV-{{year}}-{{polarity}}-Nu1.6-25ns-Pythia8/{{sim}}/{{trig}}/Reco{{reco}}/Turbo{{turbo}}/Stripping{{strip}}NoPrescalingFlagged/12711000/ALLSTREAMS.DST + #output: Bu2munuXu_MC.ROOT + #options: B2Vub_MCoptions.py + + #B0 -> mu nu Xu resonant + #input: + # bk_query: /MC/{{year}}/Beam6500GeV-{{year}}-{{polarity}}-Nu1.6-25ns-Pythia8/{{sim}}/{{trig}}/Reco{{reco}}/Turbo{{turbo}}/Stripping{{strip}}NoPrescalingFlagged/11512400/ALLSTREAMS.DST + #output: Bd2munuXu_MC.ROOT + #options: B2Vub_MCoptions.py + +{{year}}_{{polarity}}_MC_Bu2munuVub: + #B+ -> mu nu Xu non-resonant + input: + bk_query: /MC/{{year}}/Beam6500GeV-{{year}}-{{polarity}}-Nu1.6-25ns-Pythia8/{{sim}}/{{trig}}/Reco{{reco}}/Turbo{{turbo}}/Stripping{{strip}}NoPrescalingFlagged/12511005/ALLSTREAMS.DST + output: Bu2munuVub_MC.ROOT + options: B2Vub_MCoptions.py + +{{year}}_{{polarity}}_MC_Bd2munuVub: + #B0 -> mu nu Xu non-resonant + input: + bk_query: /MC/{{year}}/Beam6500GeV-{{year}}-{{polarity}}-Nu1.6-25ns-Pythia8/{{sim}}/{{trig}}/Reco{{reco}}/Turbo{{turbo}}/Stripping{{strip}}NoPrescalingFlagged/11511003/ALLSTREAMS.DST + output: Bd2munuVub_MC.ROOT + options: B2Vub_MCoptions.py {%- endfor %} {%- endfor %} \ No newline at end of file diff --git a/B2munuee/my_selections.py b/B2munuee/my_selections.py new file mode 100644 index 0000000000..1369a39db5 --- /dev/null +++ b/B2munuee/my_selections.py @@ -0,0 +1,264 @@ +from Configurables import DaVinci, DecayTreeTuple, GaudiSequencer +from PhysSelPython.Wrappers import SelectionSequence +from DecayTreeTuple.Configuration import * + +from Configurables import FilterInTrees, CombineParticles, DiElectronMaker +from PhysSelPython.Wrappers import Selection, AutomaticData, CombineSelection + +from CommonParticles.Utils import updateDoD + +from GaudiKernel.SystemOfUnits import MeV +from B2munuee import my_utils as utils + +cuts = { + # B mother cuts + "CORRM_MIN": 2500.0 * MeV, + "CORRM_MAX": 10000.0 * MeV, + "DIRA": 0.99, + "BPT": 2000.0 * MeV, + "FlightChi2": 30.0, + "VertexChi2": 4.0, + "LOWERMASS": 0.0 * MeV, + "UPPERMASS": 7500.0 * MeV, + + # cuts on electron + "Electron_PT": 200.0 * MeV, + + # cuts on di-electron + "DiElectron_PT": 0.0 * MeV, + "DiElectron_MinMass": 0.0 * MeV, + "DiElectron_MaxMass": 6300.0 * MeV, + + # cuts for photon selection + "Pi0_gamma_PT": 250.0 * MeV, + "Pi0_Jpsi_M_lower": 90.0 * MeV, + "Pi0_Jpsi_M_upper": 210.0 * MeV, + + "Eta_gamma_PT": 400.0 * MeV, + "Eta_Jpsi_M_lower": 450.0 * MeV, + "Eta_Jpsi_M_upper": 650.0 * MeV, +} + + +def RunDiElectronMaker(tree): + ''' + Run DiElectronMaker on the electrons that passed the stripping selection + This instance does not use the proto-particles + ''' + dieLL = DiElectronMaker('DiElectron-' + tree) + dieLL.Particle = "J/psi(1S)" + + if tree in ['default', 'SameSign', 'pions', 'eta']: + dieLL.ElectronInputs = [f'Phys/Electrons_{tree}/Particles'] + else: + raise ValueError( + f'{tree} is not a valid option ro run DiElectronMaker') + + # some of these cuts do not differ from the default values + # but are implemented to allow easy configuration + # cut on electron pt is already applied in the selection for the input container + # is kept nonetheless in case the default requirement of DiElectronMaker + # is tighter than the custom requirement + dieLL.DiElectronMassMax = cuts['DiElectron_MaxMass'] + dieLL.DiElectronMassMin = cuts['DiElectron_MinMass'] + dieLL.DiElectronPtMin = cuts['DiElectron_PT'] + dieLL.ElectronPtMin = cuts['Electron_PT'] + dieLL.AddBrem = True + + if tree in ['SameSign']: + dieLL.OppositeSign = False + else: + dieLL.OppositeSign = True + + DiElectron = Selection('DiElectron_' + tree, Algorithm=dieLL) + + return DiElectron + +def MakePion(Dielectron): + ''' + Conbine di-electron with a photon that is compatible with coming from a pi0 decay + ''' + + pionDaughter_cuts = { + 'gamma': ("(PT > {Pi0_gamma_PT})").format(**cuts), + 'J/psi(1S)': ("(MM < {Pi0_Jpsi_M_upper})").format(**cuts) + } + pionCombination_cut = ("(AM > {Pi0_Jpsi_M_lower})" + " & (AM < {Pi0_Jpsi_M_upper})").format(**cuts) + + photons = AutomaticData('Phys/StdLooseAllPhotons/Particles') + + pion = CombineParticles( + "pion_withPhoton", + DecayDescriptor='pi0 -> J/psi(1S) gamma', + DaughtersCuts=pionDaughter_cuts, + CombinationCut=pionCombination_cut, + MotherCut=("(M > {Pi0_Jpsi_M_lower})" + " & (M < {Pi0_Jpsi_M_upper})").format(**cuts) + ) + + pion_sel = Selection( + 'pi0_selection', + Algorithm=pion, + RequiredSelections=[ + Dielectron, + photons]) + + return pion_sel + + +def MakeEta(Dielectron): + ''' + Conbine di-electron with a photon that is compatible with coming from a eta decay + ''' + etaDaughter_cuts = { + 'gamma': ("(PT > {Eta_gamma_PT})").format(**cuts), + 'J/psi(1S)': ("(MM < {Eta_Jpsi_M_upper})").format(**cuts) + } + etaCombination_cut = ("(AM > {Eta_Jpsi_M_lower})" + " & (AM < {Eta_Jpsi_M_upper})").format(**cuts) + + photons = AutomaticData('Phys/StdLooseAllPhotons/Particles') + + eta = CombineParticles( + "eta_withPhoton", + DecayDescriptor='eta -> J/psi(1S) gamma', + DaughtersCuts=etaDaughter_cuts, + CombinationCut=etaCombination_cut, + MotherCut=("(M > {Eta_Jpsi_M_lower})" + " & (M < {Eta_Jpsi_M_upper})").format(**cuts) + ) + + eta_sel = Selection( + 'eta_selection', + Algorithm=eta, + RequiredSelections=[ + Dielectron, + photons]) + + return eta_sel + + +def MakeMother(tree, Jpsi): + ''' + Combine di-electon object and muon to a B candidate and apply default cuts + ''' + BMotherCut = ( + "(BPVCORRM > {CORRM_MIN} *MeV) & " + "(BPVCORRM < {CORRM_MAX} *MeV) & " + "(BPVDIRA > {DIRA}) & " + "(PT > {BPT}) & " + "(BPVVDCHI2 > {FlightChi2}) & " + "(VFASPF(VCHI2/VDOF) < {VertexChi2}) &" + "(M > {LOWERMASS}) & " + "(M < {UPPERMASS})").format(**cuts) + + muons = AutomaticData(f'Phys/Muons_{tree}/Particles') + + if tree in ['pions']: + pi0 = MakePion(Jpsi) + B = CombineParticles('MakeMother_' + tree, + DecayDescriptor='[B+ -> pi0 mu+]cc', + MotherCut=BMotherCut) + B_sel = Selection('Sel_B_' + tree, Algorithm=B, + RequiredSelections=[pi0, muons]) + elif tree in ['eta']: + eta = MakeEta(Jpsi) + B = CombineParticles('MakeMother_' + tree, + DecayDescriptor='[B+ -> eta mu+]cc', + MotherCut=BMotherCut) + B_sel = Selection('Sel_B_' + tree, Algorithm=B, + RequiredSelections=[eta, muons]) + elif tree in ['SameSign']: + B = CombineParticles('MakeMother_' + tree, + DecayDescriptors=[ + '[B+ -> J/psi(1S) mu+]cc', '[B+ -> J/psi(1S) mu-]cc'], + MotherCut=BMotherCut) + B_sel = Selection('Sel_B_' + tree, Algorithm=B, + RequiredSelections=[Jpsi, muons]) + elif tree in ['default']: + B = CombineParticles('MakeMother_' + tree, + DecayDescriptors=['[B+ -> J/psi(1S) mu+]cc'], + MotherCut=BMotherCut) + B_sel = Selection('Sel_B_' + tree, Algorithm=B, + RequiredSelections=[Jpsi, muons]) + else: + raise ValueError( + f'{tree} is no valid tree for MakeMother') + + return B_sel + + +def MakeNTuples(B, name): + ''' + Make nTuples with di-lepton object + ''' + dtt = DecayTreeTuple('B2MuNuEE_' + name) + if name in ['default']: + dtt.setDescriptorTemplate( + '${B}[B+ -> ${Jpsi}(J/psi(1S) -> ${ep}e+ ${em}e-) ${mu}mu+]CC') + elif name in ['SameSign']: + dtt.setDescriptorTemplate( + '${B}[B+ -> ${Jpsi}(J/psi(1S) -> ${ep}e+ ${em}e+) ${mu}[mu+]cc]CC') + elif name in ['pions']: + dtt.setDescriptorTemplate( + '${B}[B+ -> ${pi}(pi0 -> ${Jpsi}(J/psi(1S) -> ${ep}e+ ${em}e-) ${gamma}gamma) ${mu}mu+]CC') + elif name in ['eta']: + dtt.setDescriptorTemplate( + '${B}[B+ -> ${eta}(eta -> ${Jpsi}(J/psi(1S) -> ${ep}e+ ${em}e-) ${gamma}gamma) ${mu}mu+]CC') + else: + raise ValueError( + f'{name} is not a valid option for MakeNTuples(B, name)') + + Seq = SelectionSequence('Sequence_' + name, TopSelection=B) + dtt.Inputs = Seq.outputLocations() + + _seq = GaudiSequencer('MySequencer_' + name) + _seq.Members += [Seq.sequence(), dtt] + DaVinci().appendToMainSequence([_seq]) + + return dtt + +def MySelection(trees, isMC, addJpsiConstraints): + if isMC: + stream = 'AllStreams' + else: + stream = 'Semileptonic' + + for tree in trees: + if tree not in ['default', 'SameSign', 'pions', 'eta']: + raise ValueError( + f'Selection for specified tree {tree} is not supported') + + # select muons from stripping or std container + muon_filter = FilterInTrees('Muons_'+tree, + Inputs=[f'/Event/{stream}/Phys/B23MuNu_MueeLine/Particles'], + Code="('mu+' == ABSID)") + updateDoD(muon_filter) + + # select electrons from stripping or std container + electrons_filter = FilterInTrees('Electrons_'+tree, + Inputs=[f'/Event/{stream}/Phys/B23MuNu_MueeLine/Particles'], + Code="('e+' == ABSID)") + updateDoD(electrons_filter) + + # run dieelctron maker + DiLepton = RunDiElectronMaker(tree) + + # make Mother particle + mother = MakeMother(tree, DiLepton) + + # make nTuple + dtt = MakeNTuples(mother, tree) + + # now fill the tuples + utils.DefaultToolList(dtt) + if isMC: + utils.MCToolList(dtt) + utils.TriggerToolList(dtt) + utils.DefaultLoKi(dtt) + utils.AddDOCA(dtt) + if tree in ['default'] and addJpsiConstraints: + utils.JpsiConstraints(dtt) + utils.TupleToolConeIsolation(dtt) + utils.TupleToolSubstitution(dtt) \ No newline at end of file diff --git a/B2munuee/my_utils.py b/B2munuee/my_utils.py index c192bf5748..fe69168d0b 100644 --- a/B2munuee/my_utils.py +++ b/B2munuee/my_utils.py @@ -1,5 +1,5 @@ -from Configurables import TupleToolTISTOS -from Configurables import LoKi__Hybrid__TupleTool +from Configurables import TupleToolTISTOS, BackgroundCategory +from Configurables import LoKi__Hybrid__TupleTool, LoKi__Hybrid__Dict2Tuple, LoKi__Hybrid__DTFDict, LoKi__Hybrid__DictOfFunctors def DefaultToolList(dtt): @@ -34,15 +34,17 @@ def DefaultToolList(dtt): IsoGeneric = dtt.addTupleTool("TupleToolIsoGeneric") IsoGeneric.Verbose = True - # add info on missing momentum - NuReco = dtt.B.addTupleTool("TupleToolNeutrinoReco") - NuReco.Verbose = False - dtt.ep.addTupleTool('TupleToolL0Calo/ep_L0Calo') dtt.ep.ep_L0Calo.WhichCalo = "ECAL" dtt.em.addTupleTool('TupleToolL0Calo/em_L0Calo') dtt.em.em_L0Calo.WhichCalo = "ECAL" +def MCToolList(dtt): + backgroundinfo = dtt.addTupleTool("TupleToolMCBackgroundInfo") + backgroundinfo.addTool(BackgroundCategory('BackgroundCategory')) + + MCTruth = dtt.addTupleTool("TupleToolMCTruth") + MCTruth.addTupleTool("MCTupleToolHierarchy") def TriggerToolList(dtt): '''Add trigger information''' @@ -136,27 +138,129 @@ def DefaultLoKi(dtt): 'BPVVDZ': "BPVVDZ", } +def AddProtoPInfo(dtt): + + LokiVars = { + "PP_CaloNeutralID": "PPINFO(LHCb.ProtoParticle.CaloNeutralID, -1000)", + "PP_CaloChargedID": "PPINFO(LHCb.ProtoParticle.CaloChargedID, -1000)", + "PP_CaloDepositID": "PPINFO(LHCb.ProtoParticle.CaloDepositID, -1000)", + "PP_CaloBremMatch": "PPINFO(LHCb.ProtoParticle.CaloBremMatch, -1000)", + "PP_CaloBremChi2": "PPINFO(LHCb.ProtoParticle.CaloBremChi2, -1000)", + } + + LoKi_ep = dtt.ep.addTupleTool("LoKi::Hybrid::TupleTool") + LoKi_ep.Variables = LokiVars + + LoKi_em = dtt.em.addTupleTool("LoKi::Hybrid::TupleTool") + LoKi_em.Variables = LokiVars + + if dtt.Decay in ['[B+ -> ^(pi0 -> ^(J/psi(1S) -> ^e+ ^e-) ^gamma) ^mu+]CC', + '[B+ -> ^(eta -> ^(J/psi(1S) -> ^e+ ^e-) ^gamma) ^mu+]CC']: + + LoKi_gamma = dtt.gamma.addTupleTool("LoKi::Hybrid::TupleTool") + LoKi_gamma.Variables = LokiVars + def AddDOCA(dtt): ''' Add distance of closest approach DOCA for the three lepton tracks ''' - - doca_name, location1, location2 = zip( + if dtt.Decay == '[B+ -> ^(J/psi(1S) -> ^e+ ^e-) ^mu+]CC': + doca_name, location1, location2 = zip( + ['epem', + '[B+ -> (J/psi(1S) -> ^e+ e-) mu+]CC', + '[B+ -> (J/psi(1S) -> e+ ^e-) mu+]CC'], + ['epmu', + '[B+ -> (J/psi(1S) -> ^e+ e-) mu+]CC', + '[B+ -> (J/psi(1S) -> e+ e-) ^mu+]CC'], + ['emmu', + '[B+ -> (J/psi(1S) -> e+ ^e-) mu+]CC', + '[B+ -> (J/psi(1S) -> e+ e-) ^mu+]CC']) + elif dtt.Decay == '[B+ -> ^(J/psi(1S) -> ^e+ ^e+) ^[mu+]cc]CC': + doca_name, location1, location2 = zip( ['epem', - '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> ^e+ e-)) mu-]CC', - '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> e+ ^e-)) mu-]CC'], + '[B+ -> (J/psi(1S) -> ^e+ e+) [mu+]cc]CC', + '[B+ -> (J/psi(1S) -> e+ ^e+) [mu+]cc]CC'], ['epmu', - '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> e+ ^e-)) mu-]CC', - '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> e+ e-)) ^mu-]CC'], + '[B+ -> (J/psi(1S) -> ^e+ e+) [mu+]cc]CC', + '[B+ -> (J/psi(1S) -> e+ e+) ^[mu+]cc]CC'], ['emmu', - '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> ^e+ e-)) mu-]CC', - '[B- -> (D*(2007)0 -> (D0 -> K- pi+) (J/psi(1S) -> e+ e-)) ^mu-]CC']) + '[B+ -> (J/psi(1S) -> e+ ^e+) [mu+]cc]CC', + '[B+ -> (J/psi(1S) -> e+ e+) ^[mu+]cc]CC']) + elif dtt.Decay == '[B+ -> ^(pi0 -> ^(J/psi(1S) -> ^e+ ^e-) ^gamma) ^mu+]CC': + doca_name, location1, location2 = zip( + ['epem', + '[B+ -> (pi0 -> (J/psi(1S) -> ^e+ e-) gamma) mu+]CC', + '[B+ -> (pi0 -> (J/psi(1S) -> e+ ^e-) gamma) mu+]CC'], + ['epmu', + '[B+ -> (pi0 -> (J/psi(1S) -> ^e+ e-) gamma) mu+]CC', + '[B+ -> (pi0 -> (J/psi(1S) -> e+ e-) gamma) ^mu+]CC'], + ['emmu', + '[B+ -> (pi0 -> (J/psi(1S) -> e+ ^e-) gamma) mu+]CC', + '[B+ -> (pi0 -> (J/psi(1S) -> e+ e-) gamma) ^mu+]CC']) + elif dtt.Decay == '[B+ -> ^(eta -> ^(J/psi(1S) -> ^e+ ^e-) ^gamma) ^mu+]CC': + doca_name, location1, location2 = zip( + ['epem', + '[B+ -> (eta -> (J/psi(1S) -> ^e+ e-) gamma) mu+]CC', + '[B+ -> (eta -> (J/psi(1S) -> e+ ^e-) gamma) mu+]CC'], + ['epmu', + '[B+ -> (eta -> (J/psi(1S) -> ^e+ e-) gamma) mu+]CC', + '[B+ -> (eta -> (J/psi(1S) -> e+ e-) gamma) ^mu+]CC'], + ['emmu', + '[B+ -> (eta -> (J/psi(1S) -> e+ ^e-) gamma) mu+]CC', + '[B+ -> (eta -> (J/psi(1S) -> e+ e-) gamma) ^mu+]CC']) + else: + raise ValueError('Decay decsriptor is not valid to call TupleToolDOCA') DOCA = dtt.B.addTupleTool("TupleToolDOCA") DOCA.Name = list(doca_name) DOCA.Location1 = list(location1) DOCA.Location2 = list(location2) +def JpsiConstraints(dtt): + ''' + Add variables with constraints on the di-electron mass + The variables listed allow to calculate a fully constrained m2miss offline + ''' + + if dtt.Decay not in [ + '[B+ -> ^(J/psi(1S) -> ^e+ ^e-) ^mu+]CC', + '[B+ -> ^(J/psi(1S) -> ^e+ ^e+) ^[mu+]cc]CC']: + raise ValueError( + 'Decay decsriptor is not valid to call JpsiConstraints') + + DTF_vars = { + 'M': 'M', + 'PX': 'PX', + 'PY': 'PY', + 'PZ': 'PZ', + 'PT': 'PT', + + 'Jpsi_M': 'CHILD(1, M)', + 'Jpsi_PX': 'CHILD(1, PX)', + 'Jpsi_PY': 'CHILD(1, PY)', + 'Jpsi_PZ': 'CHILD(1, PZ)', + + 'X_travelled': 'VFASPF(VX)-BPV(VX)', + 'Y_travelled': 'VFASPF(VY)-BPV(VY)', + 'Z_travelled': 'VFASPF(VZ)-BPV(VZ)', + + 'PVCORRM': 'BPVCORRM', + 'PVCORRMERR': 'BPVCORRMERROR', + } + + JpsiTuple = dtt.B.addTupleTool(LoKi__Hybrid__Dict2Tuple, 'JpsiTuple') + + JpsiTuple.addTool(LoKi__Hybrid__DTFDict, 'JpsiDTF') + JpsiTuple.Source = 'LoKi::Hybrid::DTFDict/JpsiDTF' + JpsiTuple.NumVar = 15 + JpsiTuple.JpsiDTF.constrainToOriginVertex = False + JpsiTuple.JpsiDTF.daughtersToConstrain = ['J/psi(1S)'] + + JpsiTuple.JpsiDTF.addTool(LoKi__Hybrid__DictOfFunctors, 'dict_Jpsi') + JpsiTuple.JpsiDTF.Source = 'LoKi::Hybrid::DictOfFunctors/dict_Jpsi' + JpsiTuple.JpsiDTF.dict_Jpsi.Variables = DTF_vars + + def TupleToolConeIsolation(dtt): '''Add cone isolation variables''' @@ -197,9 +301,8 @@ def TupleToolSubstitution(dtt): def TupleToolVeto(dtt): ''' Add tool for pi0 veto for single photons''' - vetoContainersPi0 = ['Phys/StdLoosePi02gg/Particles', - 'Phys/StdLooseResolvedPi0/Particles', - 'Phys/StdLooseMergedPi0/Particles'] + vetoContainersPi0 = ['Phys/StdLoosePi02gee/Particles', + 'Phys/StdLoosePi024e/Particles'] vetoTool = dtt.Jpsi.addTupleTool("TupleToolVeto") vetoTool.Particle = 'J/psi(1S)' -- GitLab From 65b8589c4c028c3a356a18b97eb024f74ec5dd8d Mon Sep 17 00:00:00 2001 From: Fabian Christoph Glaser <fabian.christoph.glaser@cern.ch> Date: Tue, 19 Sep 2023 16:22:53 +0200 Subject: [PATCH 4/7] add reference channel Bu2JpsiK MC production --- B2munuee/Bu2JpsiK2ee_MCoptions.py | 149 +++++++ B2munuee/StrippingB23MuNu.py | 627 ++++++++++++++++++++++++++++++ B2munuee/info.yaml | 30 +- 3 files changed, 805 insertions(+), 1 deletion(-) create mode 100644 B2munuee/Bu2JpsiK2ee_MCoptions.py create mode 100644 B2munuee/StrippingB23MuNu.py diff --git a/B2munuee/Bu2JpsiK2ee_MCoptions.py b/B2munuee/Bu2JpsiK2ee_MCoptions.py new file mode 100644 index 0000000000..7b80b8d357 --- /dev/null +++ b/B2munuee/Bu2JpsiK2ee_MCoptions.py @@ -0,0 +1,149 @@ +from Configurables import DaVinci, DecayTreeTuple, GaudiSequencer +from PhysSelPython.Wrappers import SelectionSequence +from DecayTreeTuple.Configuration import setDescriptorTemplate + +from Configurables import FilterInTrees, CombineParticles, DiElectronMaker +from PhysSelPython.Wrappers import Selection, AutomaticData, CombineSelection + +from CommonParticles.Utils import updateDoD +from GaudiKernel.SystemOfUnits import MeV +from B2munuee import my_utils as utils + +from StrippingConf.Configuration import StrippingConf, StrippingStream +from Configurables import EventNodeKiller, ProcStatusCheck + +from B2munuee import StrippingB23MuNu + +cuts = { + # B mother cuts + "CORRM_MIN": 2500.0 * MeV, + "CORRM_MAX": 10000.0 * MeV, + "DIRA": 0.99, + "BPT": 2000.0 * MeV, + "FlightChi2": 30.0, + "VertexChi2": 4.0, + "LOWERMASS": 0.0 * MeV, + "UPPERMASS": 7500.0 * MeV, + + # cuts on electron + "Electron_PT": 200.0 * MeV, + + # cuts on di-electron + "DiElectron_PT": 0.0 * MeV, + "DiElectron_MinMass": 0.0 * MeV, + "DiElectron_MaxMass": 6300.0 * MeV, +} + +STRIPPING_LINES = ['StrippingB23MuNu_MueeFakeLine'] + +STRIPPING_VERSIONS = { + '2016': 'Stripping28r2p1', + '2017': 'Stripping29r2p2', + '2018': 'Stripping34r0p1' +} +event_node_killer = EventNodeKiller('StripKiller') +event_node_killer.Nodes = ['/Event/AllStreams', '/Event/Strip'] + +# get year of MC +data_type = DaVinci().DataType + +stripping_version = STRIPPING_VERSIONS[data_type] + +# declare custom stream +custom_stream = StrippingStream('AllStreams') + +my_linebuilder = StrippingB23MuNu.B23MuNuConf( + 'B23MuNu', StrippingB23MuNu.default_config['CONFIG'] +) + +for line in my_linebuilder.lines(): + if line.name() in STRIPPING_LINES: + line._prescale = 1.0 + custom_stream.appendLines([line]) + +filterBadEvents = ProcStatusCheck() + +sc = StrippingConf(Streams=[custom_stream], + MaxCandidates=2000, + AcceptBadEvents=False, + BadEventSelection=filterBadEvents) + +DaVinci().appendToMainSequence([event_node_killer, sc.sequence()]) + +# select muons from stripping +muon_filter = FilterInTrees('Muons_MueeFake', + Inputs=['/Event/Phys/B23MuNu_MueeFakeLine/Particles'], + Code="('mu+' == ABSID)") +updateDoD(muon_filter) + +# select electrons from stripping +electrons_filter = FilterInTrees('Electrons_MueeFake', + Inputs=['/Event/Phys/B23MuNu_MueeFakeLine/Particles'], + Code="('e+' == ABSID)") +updateDoD(electrons_filter) + +# run dieelctron maker +dieLL = DiElectronMaker('DiElectronMaker_B23MuNu') +dieLL.Particle = "J/psi(1S)" + +dieLL.ElectronInputs = [f'Phys/Electrons_MueeFake/Particles'] + +# some of these cuts do not differ from the default values +# but are implemented to allow easy configuration +# cut on electron pt is already applied in the selection for the input container +# is kept nonetheless in case the default requirement of DiElectronMaker +# is tighter than the custom requirement +dieLL.DiElectronMassMax = cuts['DiElectron_MaxMass'] +dieLL.DiElectronMassMin = cuts['DiElectron_MinMass'] +dieLL.DiElectronPtMin = cuts['DiElectron_PT'] +dieLL.ElectronPtMin = cuts['Electron_PT'] +dieLL.AddBrem = True + +dieLL.OppositeSign = True + +Jpsi = Selection('DiElectron', Algorithm=dieLL) + +# make Mother particle +BMotherCut = ( + "(BPVCORRM > {CORRM_MIN} *MeV) & " + "(BPVCORRM < {CORRM_MAX} *MeV) & " + "(BPVDIRA > {DIRA}) & " + "(PT > {BPT}) & " + "(BPVVDCHI2 > {FlightChi2}) & " + "(VFASPF(VCHI2/VDOF) < {VertexChi2}) &" + "(M > {LOWERMASS}) & " + "(M < {UPPERMASS})").format(**cuts) + +muons = AutomaticData(f'Phys/Muons_MueeFake/Particles') + +B = CombineParticles('MakeMother', + DecayDescriptors=['[B+ -> J/psi(1S) mu+]cc'], + MotherCut=BMotherCut) +B_sel = Selection('Sel_B', Algorithm=B, + RequiredSelections=[Jpsi, muons]) + +# make nTuple +dtt = DecayTreeTuple('B2MuNuEE') +dtt.setDescriptorTemplate( + '${B}[B+ -> ${Jpsi}(J/psi(1S) -> ${ep}e+ ${em}e-) ${mu}mu+]CC') + +Seq = SelectionSequence('Sequence', TopSelection=B_sel) +dtt.Inputs = Seq.outputLocations() + +_seq = GaudiSequencer('MySequencer') +_seq.Members += [Seq.sequence(), dtt] +DaVinci().appendToMainSequence([_seq]) + +# now fill the tuples +utils.DefaultToolList(dtt) +utils.MCToolList(dtt) +utils.TriggerToolList(dtt) +utils.DefaultLoKi(dtt) +utils.AddDOCA(dtt) +utils.JpsiConstraints(dtt) +utils.TupleToolConeIsolation(dtt) +utils.TupleToolSubstitution(dtt) + + + + \ No newline at end of file diff --git a/B2munuee/StrippingB23MuNu.py b/B2munuee/StrippingB23MuNu.py new file mode 100644 index 0000000000..47886cd381 --- /dev/null +++ b/B2munuee/StrippingB23MuNu.py @@ -0,0 +1,627 @@ +############################################################################### +# (c) Copyright 2000-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. # +############################################################################### + +__author__ = 'P. Owen, T.Mombacher' +__date__ = '11/03/2021' +__version__ = '$Revision: 2.0 $' + +__all__ = ( 'B23MuNuConf', 'default_config' ) + +""" +Stripping selection for B to three muons and a neutrino. +""" + +from GaudiConfUtils.ConfigurableGenerators import CombineParticles, FilterDesktop + +from PhysSelPython.Wrappers import Selection, AutomaticData, MergedSelection +from StrippingConf.StrippingLine import StrippingLine +from StrippingUtils.Utils import LineBuilder + + +################# +# +# Define Cuts here +# +################# + +default_config = { + 'NAME' : 'B23MuNu', + 'WGs' : ['Semileptonic'], + 'BUILDERTYPE' : 'B23MuNuConf', + 'CONFIG' : { + # (dimu) cuts + 'FlightChi2' : 30.0, + 'DIRA' : 0.99, + 'BPT' : 2000.0, + 'VertexCHI2' : 4.0, + 'LOWERMASS' : 0.0, # MeV + 'UPPERMASS' : 7500.0, # MeV + 'CORRM_MIN' : 2500.0, # MeV + 'CORRM_MAX' : 10000.0, # MeV + # Track cuts + 'Track_CHI2nDOF' : 3.0, + 'Track_GhostProb' : 0.35, + + # Muon cuts + 'Muon_MinIPCHI2' : 9.0, + 'Muon_PIDmu' : 0.0, + 'Muon_PIDmuK' : 0.0, + 'Muon_PT' : 0.0, + + # Electron cuts + 'Electron_PIDe' : 2.0, + 'Electron_PIDeK' : 0.0, + 'Electron_MinIPCHI2' : 25.0, + 'Electron_PT' : 200.0, + + # GEC + 'SpdMult' : 900, + + 'MisIDPrescale' : 0.01, + }, + 'STREAMS' : ['Semileptonic'] +} + +defaultName = "B23MuNu" + + +class B23MuNuConf(LineBuilder) : + + __configuration_keys__ = default_config['CONFIG'].keys() + + def __init__(self, name, config) : + + + LineBuilder.__init__(self, name, config) + + self.name = name + + + self.TriMuCut = "(BPVCORRM > %(CORRM_MIN)s *MeV) & " \ + "(BPVCORRM < %(CORRM_MAX)s *MeV) & " \ + "(BPVDIRA > %(DIRA)s) & " \ + "(PT > %(BPT)s) & " \ + "(BPVVDCHI2 > %(FlightChi2)s) & " \ + "(VFASPF(VCHI2/VDOF) < %(VertexCHI2)s) & " \ + "(M > %(LOWERMASS)s) & " \ + "(M < %(UPPERMASS)s) " %config + + self.TrackCuts = "(TRCHI2DOF < %(Track_CHI2nDOF)s) & (TRGHP < %(Track_GhostProb)s)" \ + " & (MIPCHI2DV(PRIMARY) > %(Muon_MinIPCHI2)s) " \ + " & (PT > %(Muon_PT)s)" %config + + self.TrackCutsElectron = "(TRCHI2DOF < %(Track_CHI2nDOF)s) & (TRGHP < %(Track_GhostProb)s)" \ + " & (MIPCHI2DV(PRIMARY) > %(Electron_MinIPCHI2)s) " \ + " & (PT > %(Electron_PT)s)" %config + + + self.MuonCut = self.TrackCuts + "& (PIDmu> %(Muon_PIDmu)s) & " \ + " (PIDmu-PIDK> %(Muon_PIDmuK)s)" %config + + + self.ElectronCut = self.TrackCutsElectron + "& (PIDe> %(Electron_PIDe)s) & " \ + " (PIDe-PIDK> %(Electron_PIDeK)s)" %config + + + self.Muons = self.__Muons__(config) + self.Electrons = self.__Electrons__(config) + self.FakeMuons = self.__FakeMuons__(config) + self.FakeElectrons = self.__FakeElectrons__(config) + self.Jpsi = self.__Jpsi__(config) + self.Jpsiee = self.__Jpsiee__(config) + self.Trimu = self.__Trimu__(config) + self.Trie = self.__Trie__(config) + self.MuMue = self.__MuMue__(config) + self.Muee = self.__Muee__(config) + self.FakeTrimu = self.__FakeTrimu__(config) + self.FakeTrie = self.__FakeTrie__(config) + self.FakeMuMue = self.__FakeMuMue__(config) + self.FakeMuee = self.__FakeMuee__(config) + + RelInfoTools=[ + { "Type" : "RelInfoMuonIDPlus", + "Variables" : ["MU_BDT"], + "DaughterLocations" : { + "[B+ -> ^l+ l+ [l-]CC ]CC" : "Muon1BDT", + "[B+ -> l+ ^l+ [l-]CC ]CC" : "Muon2BDT", + "[B+ -> l+ l+ ^[l-]CC ]CC" : "Muon3BDT", + } + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_first', + 'Particles' : [0,1] + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_second', + 'Particles' : [1,2] + } + ] + + + self.TriMu_line = StrippingLine( + self.name+"_TriMuLine", + prescale = 1, + FILTER = { + 'Code' : " ( recSummary(LHCb.RecSummary.nSPDhits,'Raw/Spd/Digits') < %(SpdMult)s )" %config , + 'Preambulo' : [ + "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" + ] + }, + algos=[self.Trimu], + RelatedInfoTools = RelInfoTools + ) + + self.Trie_line = StrippingLine( + self.name+"_TrieLine", + prescale = 1, + FILTER = { + 'Code' : " ( recSummary(LHCb.RecSummary.nSPDhits,'Raw/Spd/Digits') < %(SpdMult)s )" %config , + 'Preambulo' : [ + "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" + ] + }, + algos=[self.Trie], + RelatedInfoTools = RelInfoTools + ) + + # specify leptons to identify the muon candidate + RelInfoTools=[ + { "Type" : "RelInfoMuonIDPlus", + "Variables" : ["MU_BDT"], + "DaughterLocations" : { + "[B+ -> ^[e+]CC mu+ [mu-]CC ]CC" : "Muon1BDT", + "[B+ -> [e+]CC ^mu+ [mu-]CC ]CC" : "Muon2BDT", + "[B+ -> [e+]CC mu+ ^[mu-]CC ]CC" : "Muon3BDT" + } + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_first', + 'Particles' : [0,1] + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_second', + 'Particles' : [1,2] + } + ] + + self.MuMue_line = StrippingLine( + self.name+"_MuMueLine", + prescale = 1, + FILTER = { + 'Code' : " ( recSummary(LHCb.RecSummary.nSPDhits,'Raw/Spd/Digits') < %(SpdMult)s )" %config , + 'Preambulo' : [ + "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" + ] + }, + algos=[self.MuMue], + RelatedInfoTools = RelInfoTools + ) + + # specify leptons to identify the muon candidate + RelInfoTools=[ + { "Type" : "RelInfoMuonIDPlus", + "Variables" : ["MU_BDT"], + "DaughterLocations" : { + "[B+ -> ^[mu+]CC e+ [e-]CC ]CC" : "Muon1BDT", + "[B+ -> [mu+]CC ^e+ [e-]CC ]CC" : "Muon2BDT", + "[B+ -> [mu+]CC e+ ^[e-]CC ]CC" : "Muon3BDT" + } + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_first', + 'Particles' : [0,1] + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_second', + 'Particles' : [1,2] + } + ] + + + self.Muee_line = StrippingLine( + self.name+"_MueeLine", + prescale = 1, + FILTER = { + 'Code' : " ( recSummary(LHCb.RecSummary.nSPDhits,'Raw/Spd/Digits') < %(SpdMult)s )" %config , + 'Preambulo' : [ + "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" + ] + }, + algos=[self.Muee], + RelatedInfoTools = RelInfoTools + ) + + + RelInfoTools_fake=[ + { "Type" : "RelInfoMuonIDPlus", + "Variables" : ["MU_BDT"], + "DaughterLocations" : { + "[B+ -> [J/psi(1S) -> ^l+ [l-]CC ]CC l+]CC" : "Muon1BDT", + "[B+ -> [J/psi(1S) -> l+ ^[l-]CC ]CC l+]CC" : "Muon2BDT", + "[B+ -> [J/psi(1S) -> l+ [l-]CC ]CC ^l+]CC" : "Muon3BDT", + } + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_first', + 'Particles' : [1,2] + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_second', + 'Particles' : [2,3] + } + ] + + + self.FakeTriMu_line = StrippingLine( + self.name+"_TriFakeMuLine", + prescale = config['MisIDPrescale'], + FILTER = { + 'Code' : " ( recSummary(LHCb.RecSummary.nSPDhits,'Raw/Spd/Digits') < %(SpdMult)s )" %config , + 'Preambulo' : [ + "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" + ] + }, + algos=[self.FakeTrimu], + RelatedInfoTools = RelInfoTools_fake + ) + + self.FakeTrie_line = StrippingLine( + self.name+"_TrieFakeLine", + prescale = config['MisIDPrescale'], + FILTER = { + 'Code' : " ( recSummary(LHCb.RecSummary.nSPDhits,'Raw/Spd/Digits') < %(SpdMult)s )" %config , + 'Preambulo' : [ + "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" + ] + }, + algos=[self.FakeTrie], + RelatedInfoTools = RelInfoTools_fake + ) + + # specify leptons to identify the muon candidate + RelInfoTools_fake_mumue = RelInfoTools_fake + # RelInfoTools_fake_mumue[0] = { "Type" : "RelInfoMuonIDPlus", + # "Variables" : ["MU_BDT"], + # "DaughterLocations" : { + # "[B+ -> [J/psi(1S) -> ^mu+ [mu-]CC ]CC e+]CC" : "Muon1BDT", + # "[B+ -> [J/psi(1S) -> mu+ ^[mu-]CC ]CC e+]CC" : "Muon2BDT", + # "[B+ -> [J/psi(1S) -> mu+ [mu-]CC ]CC ^e+]CC" : "Muon3BDT"} + # } + RelInfoTools_fake=[ + { "Type" : "RelInfoMuonIDPlus", + "Variables" : ["MU_BDT"], + "DaughterLocations" : { + "[B+ -> [J/psi(1S) -> ^mu+ [mu-]CC ]CC e+]CC" : "Muon1BDT", + "[B+ -> [J/psi(1S) -> mu+ ^[mu-]CC ]CC e+]CC" : "Muon2BDT", + "[B+ -> [J/psi(1S) -> mu+ [mu-]CC ]CC ^e+]CC" : "Muon3BDT" + } + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_first', + 'Particles' : [1,2] + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_second', + 'Particles' : [2,3] + } + ] + + + self.FakeMuMue_line = StrippingLine( + self.name+"_MuMueFakeLine", + prescale = config['MisIDPrescale'], + FILTER = { + 'Code' : " ( recSummary(LHCb.RecSummary.nSPDhits,'Raw/Spd/Digits') < %(SpdMult)s )" %config , + 'Preambulo' : [ + "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" + ] + }, + algos=[self.FakeMuMue], + RelatedInfoTools = RelInfoTools_fake + ) + + # specify leptons to identify the muon candidate + RelInfoTools_fake=[ + { "Type" : "RelInfoMuonIDPlus", + "Variables" : ["MU_BDT"], + "DaughterLocations" : { + "[B+ -> [J/psi(1S) -> ^e+ [e-]CC ]CC mu+]CC" : "Muon1BDT", + "[B+ -> [J/psi(1S) -> e+ ^[e-]CC ]CC mu+]CC" : "Muon2BDT", + "[B+ -> [J/psi(1S) -> e+ [e-]CC ]CC ^mu+]CC" : "Muon3BDT" + } + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_first', + 'Particles' : [1,2] + }, + {'Type' : 'RelInfoTrackIsolationBDT2', + 'Location' : 'TrackIsolationBDT2_second', + 'Particles' : [2,3] + } + ] + + + self.FakeMuee_line = StrippingLine( + self.name+"_MueeFakeLine", + prescale = config['MisIDPrescale'], + FILTER = { + 'Code' : " ( recSummary(LHCb.RecSummary.nSPDhits,'Raw/Spd/Digits') < %(SpdMult)s )" %config , + 'Preambulo' : [ + "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" + ] + }, + algos=[self.FakeMuee], + #RelatedInfoTools = RelInfoTools_fake + ) + + + self.registerLine( self.TriMu_line ) + self.registerLine( self.Trie_line ) + self.registerLine( self.Muee_line ) + self.registerLine( self.MuMue_line ) + self.registerLine( self.FakeTriMu_line ) + self.registerLine( self.FakeTrie_line ) + self.registerLine( self.FakeMuMue_line ) + self.registerLine( self.FakeMuee_line ) + + + + def __Muons__(self, conf): + """ + Filter muons from StdAllLooseMuons + """ + from StandardParticles import StdAllLooseMuons + _muons = StdAllLooseMuons + _filter = FilterDesktop(Code = self.MuonCut) + _sel = Selection("Selection_"+self.name+"_Muons", + RequiredSelections = [ _muons ] , + Algorithm = _filter) + return _sel + + def __Electrons__(self, conf): + """ + Filter Electrons from StdLooseElectrons + """ + from StandardParticles import StdAllLooseElectrons + _electrons = StdAllLooseElectrons + _filter = FilterDesktop(Code = self.ElectronCut) + _sel = Selection("Selection_"+self.name+"_Electrons", + RequiredSelections = [ _electrons ] , + Algorithm = _filter) + return _sel + + + def __FakeMuons__(self, conf): + """ + Filter muons from StdAllNoPIDsMuons + """ + from StandardParticles import StdAllNoPIDsMuons + _fakemuons = StdAllNoPIDsMuons + _filter = FilterDesktop(Code = self.TrackCuts) + _sel = Selection("Selection_"+self.name+"_FakeMuons", + RequiredSelections = [ _fakemuons ] , + Algorithm = _filter) + return _sel + + def __FakeElectrons__(self, conf): + """ + Filter electrons from StdAllNoPIDsElectrons + """ + from StandardParticles import StdAllNoPIDsElectrons + _fakeelectrons = StdAllNoPIDsElectrons + _filter = FilterDesktop(Code = self.TrackCutsElectron) + _sel = Selection("Selection_"+self.name+"_FakeElectrons", + RequiredSelections = [ _fakeelectrons ] , + Algorithm = _filter) + return _sel + + + def __Jpsi__(self, conf): + """ + Creates Jpsi as proxy for dimuon + """ + from PhysSelPython.Wrappers import AutomaticData, Selection, SelectionSequence, DataOnDemand, MergedSelection + from GaudiConfUtils.ConfigurableGenerators import CombineParticles + #from Configurables import CombineParticles + + CombineJpsi= CombineParticles(DecayDescriptors = ["J/psi(1S) -> mu+ mu-","[J/psi(1S) -> mu+ mu+]cc"], + MotherCut = "ALL") + + sel_name = "Jpsi" + + from PhysSelPython.Wrappers import Selection + SelJpsi = Selection("Sel_" + self.name + "_Jpsi", Algorithm = CombineJpsi, + RequiredSelections = [ self.Muons ] ) + return SelJpsi + + def __Jpsiee__(self, conf): + """ + Creates Jpsi as proxy for dielectron + """ + from PhysSelPython.Wrappers import AutomaticData, Selection, SelectionSequence, DataOnDemand, MergedSelection + from GaudiConfUtils.ConfigurableGenerators import CombineParticles + #from Configurables import CombineParticles + + CombineJpsi= CombineParticles(DecayDescriptors = ["J/psi(1S) -> e+ e-","[J/psi(1S) -> e+ e+]cc"], + MotherCut = "ALL") + + sel_name = "Jpsi" + + from PhysSelPython.Wrappers import Selection + SelJpsi = Selection("Sel_" + self.name + "_Jpsiee", Algorithm = CombineJpsi, + RequiredSelections = [ self.Electrons ] ) + return SelJpsi + + + + def __Trimu__(self, conf): + ''' + Create trimuon + ''' + from GaudiConfUtils.ConfigurableGenerators import CombineParticles + CombineTriMuon = CombineParticles() + CombineTriMuon.DecayDescriptors = ["[B+ -> mu+ mu+ mu-]cc", "[B+ -> mu+ mu+ mu+]cc"] + sel_name="TriMu" + CombineTriMuon.MotherCut = self.TriMuCut + # choose + + from PhysSelPython.Wrappers import Selection + SelTriMuon = Selection("Sel_" + self.name + "_"+sel_name, + Algorithm = CombineTriMuon, + RequiredSelections = [ self.Muons ] ) + return SelTriMuon + + def __Trie__(self, conf): + ''' + Create trielectron + ''' + from GaudiConfUtils.ConfigurableGenerators import CombineParticles + CombineTriMuon = CombineParticles() + CombineTriMuon.DecayDescriptors = ["[B+ -> e+ e+ e-]cc", "[B+ -> e+ e+ e+]cc"] + sel_name="Trie" + CombineTriMuon.MotherCut = self.TriMuCut + # choose + + from PhysSelPython.Wrappers import Selection + SelTriMuon = Selection("Sel_" + self.name + "_"+sel_name, + Algorithm = CombineTriMuon, + RequiredSelections = [ self.Electrons ] ) + return SelTriMuon + + + def __MuMue__(self, conf): + ''' + Create MuMue combination + ''' + from GaudiConfUtils.ConfigurableGenerators import CombineParticles + CombineTriMuon = CombineParticles() + CombineTriMuon.DecayDescriptors = ["[B+ -> e+ mu+ mu-]cc","[B+ -> mu+ mu+ e-]cc", "[B+ -> mu+ mu+ e+]cc"] + sel_name="MuMue" + CombineTriMuon.MotherCut = self.TriMuCut + # choose + + from PhysSelPython.Wrappers import Selection + SelTriMuon = Selection("Sel_" + self.name + "_"+sel_name, + Algorithm = CombineTriMuon, + RequiredSelections = [ self.Muons, self.Electrons ] ) + return SelTriMuon + + + def __Muee__(self, conf): + ''' + Create Muee combination + ''' + from GaudiConfUtils.ConfigurableGenerators import CombineParticles + CombineTriMuon = CombineParticles() + CombineTriMuon.DecayDescriptors = ["[B+ -> mu+ e+ e-]cc", "[B+ -> e+ e+ mu-]cc", "[B+ -> mu+ e+ e+]cc"] + sel_name="Muee" + CombineTriMuon.MotherCut = self.TriMuCut + # choose + + from PhysSelPython.Wrappers import Selection + SelTriMuon = Selection("Sel_" + self.name + "_"+sel_name, + Algorithm = CombineTriMuon, + RequiredSelections = [ self.Muons, self.Electrons ] ) + return SelTriMuon + + + def __FakeTrimu__(self, conf): + """ + Create fake trimuon + """ + + CombineTriMuon = CombineParticles() + CombineTriMuon.DecayDescriptor = "[B+ -> J/psi(1S) mu+]cc" + sel_name="FakeTriMu" + #CombineTriMuon.CombinationCut = self.TriMuLowQ2CombCut + #["[B+ ->mu+ mu+ mu-]cc", "[B+ ->mu+ mu+ mu+]cc"] + CombineTriMuon.MotherCut = self.TriMuCut + # choose + + from PhysSelPython.Wrappers import Selection + #SelTriMuon = Selection("Sel_" + self.name + "_"+sel_name, Algorithm = CombineTriMuon, + # RequiredSelections = [self.Jpsi, self.FakeMuon ]) + SelTriMuon = Selection(sel_name, + Algorithm = CombineTriMuon, + RequiredSelections = [ self.FakeMuons, self.Jpsi ]) + + + return SelTriMuon + + def __FakeTrie__(self, conf): + """ + Create fake trielectron + """ + + CombineTriMuon = CombineParticles() + CombineTriMuon.DecayDescriptor = "[B+ -> J/psi(1S) e+]cc" + sel_name="FakeTrie" + #CombineTriMuon.CombinationCut = self.TriMuLowQ2CombCut + #["[B+ ->mu+ mu+ mu-]cc", "[B+ ->mu+ mu+ mu+]cc"] + CombineTriMuon.MotherCut = self.TriMuCut + # choose + + from PhysSelPython.Wrappers import Selection + #SelTriMuon = Selection("Sel_" + self.name + "_"+sel_name, Algorithm = CombineTriMuon, + # RequiredSelections = [self.Jpsi, self.FakeMuon ]) + SelTriMuon = Selection(sel_name, + Algorithm = CombineTriMuon, + RequiredSelections = [ self.FakeElectrons, self.Jpsiee ]) + + + return SelTriMuon + + + def __FakeMuMue__(self, conf): + """ + Create fake MuMue + """ + + CombineTriMuon = CombineParticles() + CombineTriMuon.DecayDescriptor = "[B+ -> J/psi(1S) e+]cc" + sel_name="FakeMuMue" + #CombineTriMuon.CombinationCut = self.TriMuLowQ2CombCut + #["[B+ ->mu+ mu+ mu-]cc", "[B+ ->mu+ mu+ mu+]cc"] + CombineTriMuon.MotherCut = self.TriMuCut + # choose + + from PhysSelPython.Wrappers import Selection + #SelTriMuon = Selection("Sel_" + self.name + "_"+sel_name, Algorithm = CombineTriMuon, + # RequiredSelections = [self.Jpsi, self.FakeMuon ]) + SelTriMuon = Selection(sel_name, + Algorithm = CombineTriMuon, + RequiredSelections = [ self.FakeElectrons, self.Jpsi ]) + + + return SelTriMuon + + def __FakeMuee__(self, conf): + """ + Create fake Muee + """ + + CombineTriMuon = CombineParticles() + CombineTriMuon.DecayDescriptor = "[B+ -> J/psi(1S) mu+]cc" + sel_name="FakeMuee" + #CombineTriMuon.CombinationCut = self.TriMuLowQ2CombCut + #["[B+ ->mu+ mu+ mu-]cc", "[B+ ->mu+ mu+ mu+]cc"] + CombineTriMuon.MotherCut = self.TriMuCut + # choose + + from PhysSelPython.Wrappers import Selection + #SelTriMuon = Selection("Sel_" + self.name + "_"+sel_name, Algorithm = CombineTriMuon, + # RequiredSelections = [self.Jpsi, self.FakeMuon ]) + SelTriMuon = Selection(sel_name, + Algorithm = CombineTriMuon, + RequiredSelections = [ self.FakeMuons, self.Jpsiee ]) + + + return SelTriMuon diff --git a/B2munuee/info.yaml b/B2munuee/info.yaml index 4a349339ed..bed17f7904 100644 --- a/B2munuee/info.yaml +++ b/B2munuee/info.yaml @@ -15,7 +15,6 @@ defaults: {%- for year, sim, trig, reco, turbo, strip in mc_datasets %} {%- for polarity in ['MagDown','MagUp'] %} - {{year}}_{{polarity}}_MC_Bu2munuetap2eeg: #B+ -> mu nu eta' (-> e+ e- gamma) input: @@ -88,4 +87,33 @@ defaults: options: B2Vub_MCoptions.py {%- endfor %} +{%- endfor %} + +###### +# MC samples of B+ -> Jpsi K reference channel +###### + +{%- for polarity in ['MagDown','MagUp'] %} + +2016_{{polarity}}_MC_Bu2JpsiK2ee: + #B+ -> Jpsi (-> e+ e-) K+ + input: + bk_query: /MC/2016/Beam6500GeV-2016-{{polarity}}-Nu1.6-25ns-Pythia8/Sim09g/Trig0x6139160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/12153001/ALLSTREAMS.DST + output: Bu2JpsiK2ee_MC.ROOT + options: Bu2JpsiK2ee_MCoptions.py + +2017_{{polarity}}_MC_Bu2JpsiK2ee: + #B+ -> Jpsi (-> e+ e-) K+ + input: + bk_query: /MC/2017/Beam6500GeV-2017-{{polarity}}-Nu1.6-25ns-Pythia8/Sim09i/Trig0x62661709/Reco17/Turbo04a-WithTurcal/Stripping29r2NoPrescalingFlagged/12153001/ALLSTREAMS.DST + output: Bu2JpsiK2ee_MC.ROOT + options: Bu2JpsiK2ee_MCoptions.py + +2018_{{polarity}}_MC_Bu2JpsiK2ee: + #B+ -> Jpsi (-> e+ e-) K+ + input: + bk_query: /MC/2018/Beam6500GeV-2018-{{polarity}}-Nu1.6-25ns-Pythia8/Sim09i/Trig0x617d18a4/Reco18/Turbo05-WithTurcal/Stripping34NoPrescalingFlagged/12153001/ALLSTREAMS.DST + output: Bu2JpsiK2ee_MC.ROOT + options: Bu2JpsiK2ee_MCoptions.py + {%- endfor %} \ No newline at end of file -- GitLab From eabf2faf978a6378d1391b81404578287d8a0d4c Mon Sep 17 00:00:00 2001 From: Fabian Christoph Glaser <fabian.christoph.glaser@cern.ch> Date: Fri, 22 Sep 2023 10:38:08 +0200 Subject: [PATCH 5/7] more streamlined selection of JpsiKee --- B2munuee/B2Vub_MCoptions.py | 3 +- B2munuee/Bc2munucc_MCoptions.py | 3 +- B2munuee/Bu2JpsiK2ee_MCoptions.py | 154 ++------------------------ B2munuee/Bu2munuee_MCoptions.py | 3 +- B2munuee/my_selections.py | 178 +++++++++++++++++++++++------- B2munuee/my_utils.py | 9 -- 6 files changed, 150 insertions(+), 200 deletions(-) diff --git a/B2munuee/B2Vub_MCoptions.py b/B2munuee/B2Vub_MCoptions.py index e0288987eb..e5046506ae 100644 --- a/B2munuee/B2Vub_MCoptions.py +++ b/B2munuee/B2Vub_MCoptions.py @@ -8,4 +8,5 @@ from B2munuee import my_selections as selections trees = ['default','SameSign','pions','eta'] isMC=True addJpsiConstraints=False -selections.MySelection(trees, isMC, addJpsiConstraints) \ No newline at end of file +run_stripping = False +selections.MySelection(trees, isMC, run_stripping, addJpsiConstraints) \ No newline at end of file diff --git a/B2munuee/Bc2munucc_MCoptions.py b/B2munuee/Bc2munucc_MCoptions.py index f99d80384a..110e2a6c13 100644 --- a/B2munuee/Bc2munucc_MCoptions.py +++ b/B2munuee/Bc2munucc_MCoptions.py @@ -7,4 +7,5 @@ from B2munuee import my_selections as selections trees = ['default', 'SameSign'] isMC = True addJpsiConstraints = True -selections.MySelection(trees, isMC, addJpsiConstraints) \ No newline at end of file +run_stripping = False +selections.MySelection(trees, isMC, run_stripping, addJpsiConstraints) \ No newline at end of file diff --git a/B2munuee/Bu2JpsiK2ee_MCoptions.py b/B2munuee/Bu2JpsiK2ee_MCoptions.py index 7b80b8d357..b5edcef425 100644 --- a/B2munuee/Bu2JpsiK2ee_MCoptions.py +++ b/B2munuee/Bu2JpsiK2ee_MCoptions.py @@ -1,149 +1,9 @@ -from Configurables import DaVinci, DecayTreeTuple, GaudiSequencer -from PhysSelPython.Wrappers import SelectionSequence -from DecayTreeTuple.Configuration import setDescriptorTemplate +from B2munuee import my_selections as selections -from Configurables import FilterInTrees, CombineParticles, DiElectronMaker -from PhysSelPython.Wrappers import Selection, AutomaticData, CombineSelection +# B+ -> mu nu eta' (-> e e gamma) -from CommonParticles.Utils import updateDoD -from GaudiKernel.SystemOfUnits import MeV -from B2munuee import my_utils as utils - -from StrippingConf.Configuration import StrippingConf, StrippingStream -from Configurables import EventNodeKiller, ProcStatusCheck - -from B2munuee import StrippingB23MuNu - -cuts = { - # B mother cuts - "CORRM_MIN": 2500.0 * MeV, - "CORRM_MAX": 10000.0 * MeV, - "DIRA": 0.99, - "BPT": 2000.0 * MeV, - "FlightChi2": 30.0, - "VertexChi2": 4.0, - "LOWERMASS": 0.0 * MeV, - "UPPERMASS": 7500.0 * MeV, - - # cuts on electron - "Electron_PT": 200.0 * MeV, - - # cuts on di-electron - "DiElectron_PT": 0.0 * MeV, - "DiElectron_MinMass": 0.0 * MeV, - "DiElectron_MaxMass": 6300.0 * MeV, -} - -STRIPPING_LINES = ['StrippingB23MuNu_MueeFakeLine'] - -STRIPPING_VERSIONS = { - '2016': 'Stripping28r2p1', - '2017': 'Stripping29r2p2', - '2018': 'Stripping34r0p1' -} -event_node_killer = EventNodeKiller('StripKiller') -event_node_killer.Nodes = ['/Event/AllStreams', '/Event/Strip'] - -# get year of MC -data_type = DaVinci().DataType - -stripping_version = STRIPPING_VERSIONS[data_type] - -# declare custom stream -custom_stream = StrippingStream('AllStreams') - -my_linebuilder = StrippingB23MuNu.B23MuNuConf( - 'B23MuNu', StrippingB23MuNu.default_config['CONFIG'] -) - -for line in my_linebuilder.lines(): - if line.name() in STRIPPING_LINES: - line._prescale = 1.0 - custom_stream.appendLines([line]) - -filterBadEvents = ProcStatusCheck() - -sc = StrippingConf(Streams=[custom_stream], - MaxCandidates=2000, - AcceptBadEvents=False, - BadEventSelection=filterBadEvents) - -DaVinci().appendToMainSequence([event_node_killer, sc.sequence()]) - -# select muons from stripping -muon_filter = FilterInTrees('Muons_MueeFake', - Inputs=['/Event/Phys/B23MuNu_MueeFakeLine/Particles'], - Code="('mu+' == ABSID)") -updateDoD(muon_filter) - -# select electrons from stripping -electrons_filter = FilterInTrees('Electrons_MueeFake', - Inputs=['/Event/Phys/B23MuNu_MueeFakeLine/Particles'], - Code="('e+' == ABSID)") -updateDoD(electrons_filter) - -# run dieelctron maker -dieLL = DiElectronMaker('DiElectronMaker_B23MuNu') -dieLL.Particle = "J/psi(1S)" - -dieLL.ElectronInputs = [f'Phys/Electrons_MueeFake/Particles'] - -# some of these cuts do not differ from the default values -# but are implemented to allow easy configuration -# cut on electron pt is already applied in the selection for the input container -# is kept nonetheless in case the default requirement of DiElectronMaker -# is tighter than the custom requirement -dieLL.DiElectronMassMax = cuts['DiElectron_MaxMass'] -dieLL.DiElectronMassMin = cuts['DiElectron_MinMass'] -dieLL.DiElectronPtMin = cuts['DiElectron_PT'] -dieLL.ElectronPtMin = cuts['Electron_PT'] -dieLL.AddBrem = True - -dieLL.OppositeSign = True - -Jpsi = Selection('DiElectron', Algorithm=dieLL) - -# make Mother particle -BMotherCut = ( - "(BPVCORRM > {CORRM_MIN} *MeV) & " - "(BPVCORRM < {CORRM_MAX} *MeV) & " - "(BPVDIRA > {DIRA}) & " - "(PT > {BPT}) & " - "(BPVVDCHI2 > {FlightChi2}) & " - "(VFASPF(VCHI2/VDOF) < {VertexChi2}) &" - "(M > {LOWERMASS}) & " - "(M < {UPPERMASS})").format(**cuts) - -muons = AutomaticData(f'Phys/Muons_MueeFake/Particles') - -B = CombineParticles('MakeMother', - DecayDescriptors=['[B+ -> J/psi(1S) mu+]cc'], - MotherCut=BMotherCut) -B_sel = Selection('Sel_B', Algorithm=B, - RequiredSelections=[Jpsi, muons]) - -# make nTuple -dtt = DecayTreeTuple('B2MuNuEE') -dtt.setDescriptorTemplate( - '${B}[B+ -> ${Jpsi}(J/psi(1S) -> ${ep}e+ ${em}e-) ${mu}mu+]CC') - -Seq = SelectionSequence('Sequence', TopSelection=B_sel) -dtt.Inputs = Seq.outputLocations() - -_seq = GaudiSequencer('MySequencer') -_seq.Members += [Seq.sequence(), dtt] -DaVinci().appendToMainSequence([_seq]) - -# now fill the tuples -utils.DefaultToolList(dtt) -utils.MCToolList(dtt) -utils.TriggerToolList(dtt) -utils.DefaultLoKi(dtt) -utils.AddDOCA(dtt) -utils.JpsiConstraints(dtt) -utils.TupleToolConeIsolation(dtt) -utils.TupleToolSubstitution(dtt) - - - - \ No newline at end of file +trees = ['JpsiKee'] +isMC = True +addJpsiConstraints = True +run_stripping = True +selections.MySelection(trees, isMC, run_stripping, addJpsiConstraints) \ No newline at end of file diff --git a/B2munuee/Bu2munuee_MCoptions.py b/B2munuee/Bu2munuee_MCoptions.py index 042f16c834..4f12913a23 100644 --- a/B2munuee/Bu2munuee_MCoptions.py +++ b/B2munuee/Bu2munuee_MCoptions.py @@ -5,4 +5,5 @@ from B2munuee import my_selections as selections trees = ['default', 'SameSign'] isMC = True addJpsiConstraints = False -selections.MySelection(trees, isMC, addJpsiConstraints) \ No newline at end of file +run_stripping = False +selections.MySelection(trees, isMC, run_stripping, addJpsiConstraints) \ No newline at end of file diff --git a/B2munuee/my_selections.py b/B2munuee/my_selections.py index 1369a39db5..542216b5c1 100644 --- a/B2munuee/my_selections.py +++ b/B2munuee/my_selections.py @@ -3,13 +3,18 @@ from PhysSelPython.Wrappers import SelectionSequence from DecayTreeTuple.Configuration import * from Configurables import FilterInTrees, CombineParticles, DiElectronMaker -from PhysSelPython.Wrappers import Selection, AutomaticData, CombineSelection +from PhysSelPython.Wrappers import Selection, AutomaticData from CommonParticles.Utils import updateDoD from GaudiKernel.SystemOfUnits import MeV from B2munuee import my_utils as utils +from StrippingConf.Configuration import StrippingConf, StrippingStream +from Configurables import EventNodeKiller, ProcStatusCheck + +from B2munuee import StrippingB23MuNu + cuts = { # B mother cuts "CORRM_MIN": 2500.0 * MeV, @@ -39,20 +44,55 @@ cuts = { "Eta_Jpsi_M_upper": 650.0 * MeV, } +def RunB23MuNuStripping(B23MuNu_lines): + STRIPPING_LINES = ['Stripping'+l for l in B23MuNu_lines] + + STRIPPING_VERSIONS = { + '2016': 'Stripping28r2p1', + '2017': 'Stripping29r2p2', + '2018': 'Stripping34r0p1' + } + event_node_killer = EventNodeKiller('StripKiller') + event_node_killer.Nodes = ['/Event/AllStreams', '/Event/Strip'] + + # get year of MC + data_type = DaVinci().DataType + + stripping_version = STRIPPING_VERSIONS[data_type] + + # declare custom stream + custom_stream = StrippingStream('AllStreams') + + my_linebuilder = StrippingB23MuNu.B23MuNuConf( + 'B23MuNu', StrippingB23MuNu.default_config['CONFIG'] + ) + + for line in my_linebuilder.lines(): + if line.name() in STRIPPING_LINES: + line._prescale = 1.0 + custom_stream.appendLines([line]) + + filterBadEvents = ProcStatusCheck() -def RunDiElectronMaker(tree): + sc = StrippingConf(Streams=[custom_stream], + MaxCandidates=2000, + AcceptBadEvents=False, + BadEventSelection=filterBadEvents) + + DaVinci().appendToMainSequence([event_node_killer, sc.sequence()]) + +def RunDiElectronMaker(line, oppositeSign=True): ''' Run DiElectronMaker on the electrons that passed the stripping selection This instance does not use the proto-particles ''' - dieLL = DiElectronMaker('DiElectron-' + tree) - dieLL.Particle = "J/psi(1S)" - - if tree in ['default', 'SameSign', 'pions', 'eta']: - dieLL.ElectronInputs = [f'Phys/Electrons_{tree}/Particles'] + if oppositeSign: + dieLL = DiElectronMaker('DiElectron_' + line) else: - raise ValueError( - f'{tree} is not a valid option ro run DiElectronMaker') + dieLL = DiElectronMaker('DiElectron_' + line + '_SS') + + dieLL.Particle = "J/psi(1S)" + dieLL.ElectronInputs = [f'Phys/Electrons_{line}/Particles'] # some of these cuts do not differ from the default values # but are implemented to allow easy configuration @@ -64,15 +104,9 @@ def RunDiElectronMaker(tree): dieLL.DiElectronPtMin = cuts['DiElectron_PT'] dieLL.ElectronPtMin = cuts['Electron_PT'] dieLL.AddBrem = True + dieLL.OppositeSign = oppositeSign - if tree in ['SameSign']: - dieLL.OppositeSign = False - else: - dieLL.OppositeSign = True - - DiElectron = Selection('DiElectron_' + tree, Algorithm=dieLL) - - return DiElectron + updateDoD(dieLL) def MakePion(Dielectron): ''' @@ -139,7 +173,7 @@ def MakeEta(Dielectron): return eta_sel -def MakeMother(tree, Jpsi): +def MakeMother(tree): ''' Combine di-electon object and muon to a B candidate and apply default cuts ''' @@ -153,9 +187,10 @@ def MakeMother(tree, Jpsi): "(M > {LOWERMASS}) & " "(M < {UPPERMASS})").format(**cuts) - muons = AutomaticData(f'Phys/Muons_{tree}/Particles') - if tree in ['pions']: + muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeLine/Particles') + Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeLine/Particles') + pi0 = MakePion(Jpsi) B = CombineParticles('MakeMother_' + tree, DecayDescriptor='[B+ -> pi0 mu+]cc', @@ -163,6 +198,9 @@ def MakeMother(tree, Jpsi): B_sel = Selection('Sel_B_' + tree, Algorithm=B, RequiredSelections=[pi0, muons]) elif tree in ['eta']: + muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeLine/Particles') + Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeLine/Particles') + eta = MakeEta(Jpsi) B = CombineParticles('MakeMother_' + tree, DecayDescriptor='[B+ -> eta mu+]cc', @@ -170,6 +208,9 @@ def MakeMother(tree, Jpsi): B_sel = Selection('Sel_B_' + tree, Algorithm=B, RequiredSelections=[eta, muons]) elif tree in ['SameSign']: + muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeLine/Particles') + Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeLine_SS/Particles') + B = CombineParticles('MakeMother_' + tree, DecayDescriptors=[ '[B+ -> J/psi(1S) mu+]cc', '[B+ -> J/psi(1S) mu-]cc'], @@ -177,6 +218,18 @@ def MakeMother(tree, Jpsi): B_sel = Selection('Sel_B_' + tree, Algorithm=B, RequiredSelections=[Jpsi, muons]) elif tree in ['default']: + muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeLine/Particles') + Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeLine/Particles') + + B = CombineParticles('MakeMother_' + tree, + DecayDescriptors=['[B+ -> J/psi(1S) mu+]cc'], + MotherCut=BMotherCut) + B_sel = Selection('Sel_B_' + tree, Algorithm=B, + RequiredSelections=[Jpsi, muons]) + elif tree in ['JpsiKee']: + muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeFakeLine/Particles') + Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeFakeLine/Particles') + B = CombineParticles('MakeMother_' + tree, DecayDescriptors=['[B+ -> J/psi(1S) mu+]cc'], MotherCut=BMotherCut) @@ -192,9 +245,10 @@ def MakeMother(tree, Jpsi): def MakeNTuples(B, name): ''' Make nTuples with di-lepton object + Reference channels follow the naming convention of the respective signal channel ''' dtt = DecayTreeTuple('B2MuNuEE_' + name) - if name in ['default']: + if name in ['default','JpsiKee']: dtt.setDescriptorTemplate( '${B}[B+ -> ${Jpsi}(J/psi(1S) -> ${ep}e+ ${em}e-) ${mu}mu+]CC') elif name in ['SameSign']: @@ -219,34 +273,74 @@ def MakeNTuples(B, name): return dtt -def MySelection(trees, isMC, addJpsiConstraints): - if isMC: - stream = 'AllStreams' +def MySelection(trees, isMC, run_stripping, addJpsiConstraints): + + if isMC and run_stripping: + stream = 'Phys' + elif isMC and not run_stripping: + stream = '/Event/AllStreams/Phys' else: - stream = 'Semileptonic' + stream = '/Event/Semileptonic/Phys' + + # check if trees are valid + valid_trees = ['default', 'SameSign', 'pions', 'eta', 'JpsiKee'] + if not all(item in valid_trees for item in trees): + raise ValueError('At least one requested tree is not supported') + + # run restripping if required + if run_stripping is True: + lines = [] + if any(item in ['default','pions','eta','SameSign'] for item in trees): + lines.append('B23MuNu_MueeLine') + if 'JpsiKee' in trees: + lines.append('B23MuNu_MueeFakeLine') + RunB23MuNuStripping(lines) + + # make filter for MueeLine if used in any tree + if any(item in ['default','pions','eta','SameSign'] for item in trees): + # select muons from default MueeLine + muon_Muee = FilterInTrees('Muons_B23MuNu_MueeLine', + Inputs=[f'{stream}/B23MuNu_MueeLine/Particles'], + Code="('mu+' == ABSID)") + updateDoD(muon_Muee) + + # select electrons from default MueeLine + electrons_Muee = FilterInTrees('Electrons_B23MuNu_MueeLine', + Inputs=[f'{stream}/B23MuNu_MueeLine/Particles'], + Code="('e+' == ABSID)") + updateDoD(electrons_Muee) + + # run DiElectronMaker for electrons from MueeLine if used in any tree + if any(item in ['default','pions','eta'] for item in trees): + RunDiElectronMaker('B23MuNu_MueeLine') + for tree in trees: - if tree not in ['default', 'SameSign', 'pions', 'eta']: - raise ValueError( - f'Selection for specified tree {tree} is not supported') + # if tree does not use MueeLine + if tree in ['JpsiKee']: + line = 'B23MuNu_MueeFakeLine' - # select muons from stripping or std container - muon_filter = FilterInTrees('Muons_'+tree, - Inputs=[f'/Event/{stream}/Phys/B23MuNu_MueeLine/Particles'], - Code="('mu+' == ABSID)") - updateDoD(muon_filter) + # select muons from stripping or std container + muon_filter = FilterInTrees('Muons_'+line, + Inputs=[f'{stream}/{line}/Particles'], + Code="('mu+' == ABSID)") + updateDoD(muon_filter) - # select electrons from stripping or std container - electrons_filter = FilterInTrees('Electrons_'+tree, - Inputs=[f'/Event/{stream}/Phys/B23MuNu_MueeLine/Particles'], - Code="('e+' == ABSID)") - updateDoD(electrons_filter) + # select electrons from stripping or std container + electrons_filter = FilterInTrees('Electrons_'+line, + Inputs=[f'{stream}/{line}/Particles'], + Code="('e+' == ABSID)") + updateDoD(electrons_filter) + + # run dieelctron maker + RunDiElectronMaker('B23MuNu_MueeFakeLine') - # run dieelctron maker - DiLepton = RunDiElectronMaker(tree) + # if SameSign also need to run DiElectronMaker again + if tree == 'SameSign': + RunDiElectronMaker('B23MuNu_MueeLine', oppositeSign=False) # make Mother particle - mother = MakeMother(tree, DiLepton) + mother = MakeMother(tree) # make nTuple dtt = MakeNTuples(mother, tree) @@ -257,6 +351,8 @@ def MySelection(trees, isMC, addJpsiConstraints): utils.MCToolList(dtt) utils.TriggerToolList(dtt) utils.DefaultLoKi(dtt) + if tree in ['pions','eta']: + utils.AddProtoPInfo(dtt) utils.AddDOCA(dtt) if tree in ['default'] and addJpsiConstraints: utils.JpsiConstraints(dtt) diff --git a/B2munuee/my_utils.py b/B2munuee/my_utils.py index fe69168d0b..dc2c402519 100644 --- a/B2munuee/my_utils.py +++ b/B2munuee/my_utils.py @@ -298,12 +298,3 @@ def TupleToolSubstitution(dtt): SubstTool = dtt.B.addTupleTool('TupleToolSubMass/B_SubMass') SubstTool.Substitution += substitutions -def TupleToolVeto(dtt): - ''' Add tool for pi0 veto for single photons''' - - vetoContainersPi0 = ['Phys/StdLoosePi02gee/Particles', - 'Phys/StdLoosePi024e/Particles'] - - vetoTool = dtt.Jpsi.addTupleTool("TupleToolVeto") - vetoTool.Particle = 'J/psi(1S)' - vetoTool.Veto['_Pi0'] = vetoContainersPi0 -- GitLab From 7ebee8592b67ce61bc9b75f22b3bddaf66552e5d Mon Sep 17 00:00:00 2001 From: Fabian Christoph Glaser <fabian.christoph.glaser@cern.ch> Date: Fri, 22 Sep 2023 16:56:49 +0200 Subject: [PATCH 6/7] minor style changes --- B2munuee/my_selections.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/B2munuee/my_selections.py b/B2munuee/my_selections.py index 542216b5c1..101d6a5961 100644 --- a/B2munuee/my_selections.py +++ b/B2munuee/my_selections.py @@ -92,7 +92,7 @@ def RunDiElectronMaker(line, oppositeSign=True): dieLL = DiElectronMaker('DiElectron_' + line + '_SS') dieLL.Particle = "J/psi(1S)" - dieLL.ElectronInputs = [f'Phys/Electrons_{line}/Particles'] + dieLL.ElectronInputs = ['Phys/Electrons_'+line+'/Particles'] # some of these cuts do not differ from the default values # but are implemented to allow easy configuration @@ -188,8 +188,8 @@ def MakeMother(tree): "(M < {UPPERMASS})").format(**cuts) if tree in ['pions']: - muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeLine/Particles') - Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeLine/Particles') + muons = AutomaticData('Phys/Muons_B23MuNu_MueeLine/Particles') + Jpsi = AutomaticData('Phys/DiElectron_B23MuNu_MueeLine/Particles') pi0 = MakePion(Jpsi) B = CombineParticles('MakeMother_' + tree, @@ -198,8 +198,8 @@ def MakeMother(tree): B_sel = Selection('Sel_B_' + tree, Algorithm=B, RequiredSelections=[pi0, muons]) elif tree in ['eta']: - muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeLine/Particles') - Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeLine/Particles') + muons = AutomaticData('Phys/Muons_B23MuNu_MueeLine/Particles') + Jpsi = AutomaticData('Phys/DiElectron_B23MuNu_MueeLine/Particles') eta = MakeEta(Jpsi) B = CombineParticles('MakeMother_' + tree, @@ -208,8 +208,8 @@ def MakeMother(tree): B_sel = Selection('Sel_B_' + tree, Algorithm=B, RequiredSelections=[eta, muons]) elif tree in ['SameSign']: - muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeLine/Particles') - Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeLine_SS/Particles') + muons = AutomaticData('Phys/Muons_B23MuNu_MueeLine/Particles') + Jpsi = AutomaticData('Phys/DiElectron_B23MuNu_MueeLine_SS/Particles') B = CombineParticles('MakeMother_' + tree, DecayDescriptors=[ @@ -218,8 +218,8 @@ def MakeMother(tree): B_sel = Selection('Sel_B_' + tree, Algorithm=B, RequiredSelections=[Jpsi, muons]) elif tree in ['default']: - muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeLine/Particles') - Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeLine/Particles') + muons = AutomaticData('Phys/Muons_B23MuNu_MueeLine/Particles') + Jpsi = AutomaticData('Phys/DiElectron_B23MuNu_MueeLine/Particles') B = CombineParticles('MakeMother_' + tree, DecayDescriptors=['[B+ -> J/psi(1S) mu+]cc'], @@ -227,8 +227,8 @@ def MakeMother(tree): B_sel = Selection('Sel_B_' + tree, Algorithm=B, RequiredSelections=[Jpsi, muons]) elif tree in ['JpsiKee']: - muons = AutomaticData(f'Phys/Muons_B23MuNu_MueeFakeLine/Particles') - Jpsi = AutomaticData(f'Phys/DiElectron_B23MuNu_MueeFakeLine/Particles') + muons = AutomaticData('Phys/Muons_B23MuNu_MueeFakeLine/Particles') + Jpsi = AutomaticData('Phys/DiElectron_B23MuNu_MueeFakeLine/Particles') B = CombineParticles('MakeMother_' + tree, DecayDescriptors=['[B+ -> J/psi(1S) mu+]cc'], @@ -237,7 +237,7 @@ def MakeMother(tree): RequiredSelections=[Jpsi, muons]) else: raise ValueError( - f'{tree} is no valid tree for MakeMother') + tree + ' is no valid tree for MakeMother') return B_sel @@ -262,7 +262,7 @@ def MakeNTuples(B, name): '${B}[B+ -> ${eta}(eta -> ${Jpsi}(J/psi(1S) -> ${ep}e+ ${em}e-) ${gamma}gamma) ${mu}mu+]CC') else: raise ValueError( - f'{name} is not a valid option for MakeNTuples(B, name)') + name + ' is not a valid option for MakeNTuples(B, name)') Seq = SelectionSequence('Sequence_' + name, TopSelection=B) dtt.Inputs = Seq.outputLocations() @@ -300,13 +300,13 @@ def MySelection(trees, isMC, run_stripping, addJpsiConstraints): if any(item in ['default','pions','eta','SameSign'] for item in trees): # select muons from default MueeLine muon_Muee = FilterInTrees('Muons_B23MuNu_MueeLine', - Inputs=[f'{stream}/B23MuNu_MueeLine/Particles'], + Inputs=['{}/B23MuNu_MueeLine/Particles'.format(stream)], Code="('mu+' == ABSID)") updateDoD(muon_Muee) # select electrons from default MueeLine electrons_Muee = FilterInTrees('Electrons_B23MuNu_MueeLine', - Inputs=[f'{stream}/B23MuNu_MueeLine/Particles'], + Inputs=['{}/B23MuNu_MueeLine/Particles'.format(stream)], Code="('e+' == ABSID)") updateDoD(electrons_Muee) @@ -322,13 +322,13 @@ def MySelection(trees, isMC, run_stripping, addJpsiConstraints): # select muons from stripping or std container muon_filter = FilterInTrees('Muons_'+line, - Inputs=[f'{stream}/{line}/Particles'], + Inputs=['{}/{}/Particles'.format(stream, line)], Code="('mu+' == ABSID)") updateDoD(muon_filter) # select electrons from stripping or std container electrons_filter = FilterInTrees('Electrons_'+line, - Inputs=[f'{stream}/{line}/Particles'], + Inputs=['{}/{}/Particles'.format(stream, line)], Code="('e+' == ABSID)") updateDoD(electrons_filter) -- GitLab From c6f7ac0a777d2c26d99458da81e72da6fbf87191 Mon Sep 17 00:00:00 2001 From: Fabian Christoph Glaser <fabian.christoph.glaser@cern.ch> Date: Mon, 25 Sep 2023 09:44:52 +0200 Subject: [PATCH 7/7] Update documentation and change to DaVinci v46r7 --- B2munuee/StrippingB23MuNu.py | 171 ++++------------------------------- B2munuee/info.yaml | 2 +- B2munuee/my_selections.py | 6 ++ 3 files changed, 27 insertions(+), 152 deletions(-) diff --git a/B2munuee/StrippingB23MuNu.py b/B2munuee/StrippingB23MuNu.py index 47886cd381..858afff4b3 100644 --- a/B2munuee/StrippingB23MuNu.py +++ b/B2munuee/StrippingB23MuNu.py @@ -9,6 +9,15 @@ # or submit itself to any jurisdiction. # ############################################################################### + +############################################################################### +# Custom stripping selection of B23MuNu for restripping in Analysis Production# +# # +# The physics of the selection is identical to the selection of the published # +# version in S28r2p1, S29r2p2 and S34r0p1 but has no RelInfoTools added. # +# # +############################################################################### + __author__ = 'P. Owen, T.Mombacher' __date__ = '11/03/2021' __version__ = '$Revision: 2.0 $' @@ -126,26 +135,6 @@ class B23MuNuConf(LineBuilder) : self.FakeMuMue = self.__FakeMuMue__(config) self.FakeMuee = self.__FakeMuee__(config) - RelInfoTools=[ - { "Type" : "RelInfoMuonIDPlus", - "Variables" : ["MU_BDT"], - "DaughterLocations" : { - "[B+ -> ^l+ l+ [l-]CC ]CC" : "Muon1BDT", - "[B+ -> l+ ^l+ [l-]CC ]CC" : "Muon2BDT", - "[B+ -> l+ l+ ^[l-]CC ]CC" : "Muon3BDT", - } - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_first', - 'Particles' : [0,1] - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_second', - 'Particles' : [1,2] - } - ] - - self.TriMu_line = StrippingLine( self.name+"_TriMuLine", prescale = 1, @@ -155,8 +144,7 @@ class B23MuNuConf(LineBuilder) : "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" ] }, - algos=[self.Trimu], - RelatedInfoTools = RelInfoTools + algos=[self.Trimu] ) self.Trie_line = StrippingLine( @@ -168,29 +156,8 @@ class B23MuNuConf(LineBuilder) : "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" ] }, - algos=[self.Trie], - RelatedInfoTools = RelInfoTools - ) - - # specify leptons to identify the muon candidate - RelInfoTools=[ - { "Type" : "RelInfoMuonIDPlus", - "Variables" : ["MU_BDT"], - "DaughterLocations" : { - "[B+ -> ^[e+]CC mu+ [mu-]CC ]CC" : "Muon1BDT", - "[B+ -> [e+]CC ^mu+ [mu-]CC ]CC" : "Muon2BDT", - "[B+ -> [e+]CC mu+ ^[mu-]CC ]CC" : "Muon3BDT" - } - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_first', - 'Particles' : [0,1] - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_second', - 'Particles' : [1,2] - } - ] + algos=[self.Trie] + ) self.MuMue_line = StrippingLine( self.name+"_MuMueLine", @@ -201,30 +168,8 @@ class B23MuNuConf(LineBuilder) : "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" ] }, - algos=[self.MuMue], - RelatedInfoTools = RelInfoTools - ) - - # specify leptons to identify the muon candidate - RelInfoTools=[ - { "Type" : "RelInfoMuonIDPlus", - "Variables" : ["MU_BDT"], - "DaughterLocations" : { - "[B+ -> ^[mu+]CC e+ [e-]CC ]CC" : "Muon1BDT", - "[B+ -> [mu+]CC ^e+ [e-]CC ]CC" : "Muon2BDT", - "[B+ -> [mu+]CC e+ ^[e-]CC ]CC" : "Muon3BDT" - } - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_first', - 'Particles' : [0,1] - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_second', - 'Particles' : [1,2] - } - ] - + algos=[self.MuMue] + ) self.Muee_line = StrippingLine( self.name+"_MueeLine", @@ -235,30 +180,8 @@ class B23MuNuConf(LineBuilder) : "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" ] }, - algos=[self.Muee], - RelatedInfoTools = RelInfoTools - ) - - - RelInfoTools_fake=[ - { "Type" : "RelInfoMuonIDPlus", - "Variables" : ["MU_BDT"], - "DaughterLocations" : { - "[B+ -> [J/psi(1S) -> ^l+ [l-]CC ]CC l+]CC" : "Muon1BDT", - "[B+ -> [J/psi(1S) -> l+ ^[l-]CC ]CC l+]CC" : "Muon2BDT", - "[B+ -> [J/psi(1S) -> l+ [l-]CC ]CC ^l+]CC" : "Muon3BDT", - } - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_first', - 'Particles' : [1,2] - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_second', - 'Particles' : [2,3] - } - ] - + algos=[self.Muee] + ) self.FakeTriMu_line = StrippingLine( self.name+"_TriFakeMuLine", @@ -269,8 +192,7 @@ class B23MuNuConf(LineBuilder) : "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" ] }, - algos=[self.FakeTrimu], - RelatedInfoTools = RelInfoTools_fake + algos=[self.FakeTrimu] ) self.FakeTrie_line = StrippingLine( @@ -282,39 +204,9 @@ class B23MuNuConf(LineBuilder) : "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" ] }, - algos=[self.FakeTrie], - RelatedInfoTools = RelInfoTools_fake + algos=[self.FakeTrie] ) - # specify leptons to identify the muon candidate - RelInfoTools_fake_mumue = RelInfoTools_fake - # RelInfoTools_fake_mumue[0] = { "Type" : "RelInfoMuonIDPlus", - # "Variables" : ["MU_BDT"], - # "DaughterLocations" : { - # "[B+ -> [J/psi(1S) -> ^mu+ [mu-]CC ]CC e+]CC" : "Muon1BDT", - # "[B+ -> [J/psi(1S) -> mu+ ^[mu-]CC ]CC e+]CC" : "Muon2BDT", - # "[B+ -> [J/psi(1S) -> mu+ [mu-]CC ]CC ^e+]CC" : "Muon3BDT"} - # } - RelInfoTools_fake=[ - { "Type" : "RelInfoMuonIDPlus", - "Variables" : ["MU_BDT"], - "DaughterLocations" : { - "[B+ -> [J/psi(1S) -> ^mu+ [mu-]CC ]CC e+]CC" : "Muon1BDT", - "[B+ -> [J/psi(1S) -> mu+ ^[mu-]CC ]CC e+]CC" : "Muon2BDT", - "[B+ -> [J/psi(1S) -> mu+ [mu-]CC ]CC ^e+]CC" : "Muon3BDT" - } - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_first', - 'Particles' : [1,2] - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_second', - 'Particles' : [2,3] - } - ] - - self.FakeMuMue_line = StrippingLine( self.name+"_MuMueFakeLine", prescale = config['MisIDPrescale'], @@ -324,31 +216,9 @@ class B23MuNuConf(LineBuilder) : "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" ] }, - algos=[self.FakeMuMue], - RelatedInfoTools = RelInfoTools_fake + algos=[self.FakeMuMue] ) - # specify leptons to identify the muon candidate - RelInfoTools_fake=[ - { "Type" : "RelInfoMuonIDPlus", - "Variables" : ["MU_BDT"], - "DaughterLocations" : { - "[B+ -> [J/psi(1S) -> ^e+ [e-]CC ]CC mu+]CC" : "Muon1BDT", - "[B+ -> [J/psi(1S) -> e+ ^[e-]CC ]CC mu+]CC" : "Muon2BDT", - "[B+ -> [J/psi(1S) -> e+ [e-]CC ]CC ^mu+]CC" : "Muon3BDT" - } - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_first', - 'Particles' : [1,2] - }, - {'Type' : 'RelInfoTrackIsolationBDT2', - 'Location' : 'TrackIsolationBDT2_second', - 'Particles' : [2,3] - } - ] - - self.FakeMuee_line = StrippingLine( self.name+"_MueeFakeLine", prescale = config['MisIDPrescale'], @@ -358,8 +228,7 @@ class B23MuNuConf(LineBuilder) : "from LoKiNumbers.decorators import *", "from LoKiCore.basic import LHCb" ] }, - algos=[self.FakeMuee], - #RelatedInfoTools = RelInfoTools_fake + algos=[self.FakeMuee] ) diff --git a/B2munuee/info.yaml b/B2munuee/info.yaml index bed17f7904..80e4ed68c1 100644 --- a/B2munuee/info.yaml +++ b/B2munuee/info.yaml @@ -1,5 +1,5 @@ defaults: - application: DaVinci/v46r4 + application: DaVinci/v46r7 wg: SL automatically_configure: yes turbo: no diff --git a/B2munuee/my_selections.py b/B2munuee/my_selections.py index 101d6a5961..70213828ef 100644 --- a/B2munuee/my_selections.py +++ b/B2munuee/my_selections.py @@ -45,6 +45,12 @@ cuts = { } def RunB23MuNuStripping(B23MuNu_lines): + ''' + Run selected lines of the B23MuNu stripping on MC + Physics of the stripping selection is identical to the + published versions of S28r2p1, S29r2p2 and S34r0p1 + but has no RelInfoTool added due to missing muon raw coordinates + ''' STRIPPING_LINES = ['Stripping'+l for l in B23MuNu_lines] STRIPPING_VERSIONS = { -- GitLab