Belle II Software development
049_flavor_tagging.py
1#!/usr/bin/env python3
2
3import sys
4import basf2 as b2
5import modularAnalysis as ma
6import stdV0s
7import flavorTagger as ft # [S23|E23]
8from variables import variables as vm # shorthand for VariableManager
9import variables.collections as vc
10import variables.utils as vu
11
12# get input file number from the command line
13filenumber = sys.argv[1]
14
15# set analysis global tag (needed for flavor tagging) [S10]
16b2.conditions.prepend_globaltag(ma.getAnalysisGlobaltag()) # [E10]
17
18# create path
19main = b2.Path()
20
21# load input data from mdst/udst file
22ma.inputMdstList(
23 filelist=[b2.find_file(f"starterkit/2021/1111540100_eph3_BGx0_{filenumber}.root", "examples")],
24 path=main,
25)
26
27# fill final state particle lists
28ma.fillParticleList(
29 "e+:uncorrected",
30 "electronID > 0.1 and dr < 0.5 and abs(dz) < 2 and thetaInCDCAcceptance",
31 path=main,
32)
33stdV0s.stdKshorts(path=main)
34
35# apply Bremsstrahlung correction to electrons
36vm.addAlias(
37 "goodFWDGamma", "passesCut(clusterReg == 1 and clusterE > 0.075)"
38)
39vm.addAlias(
40 "goodBRLGamma", "passesCut(clusterReg == 2 and clusterE > 0.05)"
41)
42vm.addAlias(
43 "goodBWDGamma", "passesCut(clusterReg == 3 and clusterE > 0.1)"
44)
45vm.addAlias(
46 "goodGamma", "passesCut(goodFWDGamma or goodBRLGamma or goodBWDGamma)"
47)
48ma.fillParticleList("gamma:brems", "goodGamma", path=main)
49ma.correctBrems("e+:corrected", "e+:uncorrected", "gamma:brems", path=main)
50vm.addAlias("isBremsCorrected", "extraInfo(bremsCorrected)")
51
52# combine final state particles to form composite particles
53ma.reconstructDecay(
54 "J/psi:ee -> e+:corrected e-:corrected ?addbrems",
55 cut="abs(dM) < 0.11",
56 path=main,
57)
58
59# combine J/psi and KS candidates to form B0 candidates
60ma.reconstructDecay(
61 "B0 -> J/psi:ee K_S0:merged",
62 cut="Mbc > 5.2 and abs(deltaE) < 0.15",
63 path=main,
64)
65
66# match reconstructed with MC particles
67ma.matchMCTruth("B0", path=main)
68
69# build the rest of the event
70ma.buildRestOfEvent("B0", fillWithMostLikely=True, path=main)
71track_based_cuts = "thetaInCDCAcceptance and pt > 0.075 and dr < 5 and abs(dz) < 10"
72ecl_based_cuts = "thetaInCDCAcceptance and E > 0.05"
73roe_mask = ("my_mask", track_based_cuts, ecl_based_cuts)
74ma.appendROEMasks("B0", [roe_mask], path=main)
75
76# call flavor tagging [S20]
77ft.flavorTagger(["B0"], path=main) # [E20]
78
79# perform best candidate selection
80b2.set_random_seed("Belle II StarterKit")
81ma.rankByHighest("B0", variable="random", numBest=1, path=main)
82
83# Create list of variables to save into the output file
84b_vars = []
85
86standard_vars = vc.kinematics + vc.mc_kinematics + vc.mc_truth
87b_vars += vc.deltae_mbc
88b_vars += standard_vars
89
90# ROE variables
91roe_kinematics = ["roeE()", "roeM()", "roeP()", "roeMbc()", "roeDeltae()"]
92roe_multiplicities = [
93 "nROE_Charged()",
94 "nROE_Photons()",
95 "nROE_NeutralHadrons()",
96]
97b_vars += roe_kinematics + roe_multiplicities
98# Let's also add a version of the ROE variables that includes the mask:
99for roe_variable in roe_kinematics + roe_multiplicities:
100 # e.g. instead of 'roeE()' (no mask) we want 'roeE(my_mask)'
101 roe_variable_with_mask = roe_variable.replace("()", "(my_mask)")
102 b_vars.append(roe_variable_with_mask)
103
104b_vars += ft.flavor_tagging # [S43|E43]
105
106# Variables for final states (electrons, positrons, pions)
107fs_vars = vc.pid + vc.track + vc.track_hits + standard_vars
108b_vars += vu.create_aliases_for_selected(
109 fs_vars + ["isBremsCorrected"],
110 "B0 -> [J/psi -> ^e+ ^e-] K_S0",
111 prefix=["ep", "em"],
112)
113b_vars += vu.create_aliases_for_selected(
114 fs_vars, "B0 -> J/psi [K_S0 -> ^pi+ ^pi-]", prefix=["pip", "pim"]
115)
116# Variables for J/Psi, KS
117jpsi_ks_vars = vc.inv_mass + standard_vars
118b_vars += vu.create_aliases_for_selected(jpsi_ks_vars, "B0 -> ^J/psi ^K_S0")
119# Add the J/Psi mass calculated with uncorrected electrons:
120vm.addAlias(
121 "Jpsi_M_uncorrected", "daughter(0, daughterCombination(M,0:0,1:0))"
122)
123b_vars += ["Jpsi_M_uncorrected"]
124# Also add kinematic variables boosted to the center of mass frame (CMS)
125# for all particles
126cmskinematics = vu.create_aliases(
127 vc.kinematics, "useCMSFrame({variable})", "CMS"
128)
129b_vars += vu.create_aliases_for_selected(
130 cmskinematics, "^B0 -> [^J/psi -> ^e+ ^e-] [^K_S0 -> ^pi+ ^pi-]"
131)
132
133vm.addAlias(
134 "withBremsCorrection",
135 "passesCut(passesCut(ep_isBremsCorrected == 1) or passesCut(em_isBremsCorrected == 1))",
136)
137b_vars += ["withBremsCorrection"]
138
139# Save variables to an output file (ntuple)
140ma.variablesToNtuple(
141 "B0",
142 variables=b_vars,
143 filename="Bd2JpsiKS.root",
144 treename="tree",
145 path=main,
146)
147
148# Start the event loop (actually start processing things)
149b2.process(main)
150
151# print out the summary
152print(b2.statistics)
def stdKshorts(prioritiseV0=True, fitter='TreeFit', path=None, updateAllDaughters=False, writeOut=False)
Definition: stdV0s.py:17