Belle II Software development
B2A602-BestCandidateSelection.py
1#!/usr/bin/env python3
2
3
10
11
30
31import basf2 as b2
32import modularAnalysis as ma
33import variables.collections as vc
34import variables.utils as vu
35import vertex as vx
36import stdCharged as stdc
37import variables as va
38
39# create path
40my_path = b2.create_path()
41
42# load input ROOT file
43ma.inputMdst(filename=b2.find_file('B2pi0D_D2hh_D2hhh_B2munu.root', 'examples', False),
44 path=my_path)
45
46# use standard final state particle lists
47#
48# creates "pi+:all" ParticleList (and c.c.)
49stdc.stdPi('all', path=my_path)
50# rank all pions of the event by momentum magnitude
51# variable stored to extraInfo as pi_p_rank
52ma.rankByLowest(particleList='pi+:all',
53 variable='p',
54 outputVariable='pi_p_rank',
55 path=my_path)
56
57va.variables.addAlias('pi_p_rank', 'extraInfo(pi_p_rank)')
58
59# creates "K+:loose" ParticleList (and c.c.)
60stdc.stdK(listtype='loose', path=my_path)
61
62# keep only candidates with 1.8 < M(Kpi) < 1.9 GeV
63ma.reconstructDecay(decayString='D0 -> K-:loose pi+:all',
64 cut='1.8 < M < 1.9',
65 path=my_path)
66
67# perform MC matching (MC truth association)
68ma.matchMCTruth(list_name='D0', path=my_path)
69
70# perform D0 vertex fit
71# keep only candidates passing C.L. value of the fit > conf_level
72vx.treeFit(list_name='D0',
73 conf_level=0, # 0: keep only fit survivors, -1: keep all candidates; optimise this cut for your need
74 ipConstraint=True,
75 # pins the B0 PRODUCTION vertex to the IP (increases SIG and BKG rejection) use for better vertex resolution
76 updateAllDaughters=True, # update momenta of ALL particles
77 path=my_path)
78
79# smaller |M_rec - M| is better, add here a different output variable name, due to parentheses
80ma.rankByLowest(particleList='D0',
81 variable='abs(dM)',
82 outputVariable='abs_dM_rank',
83 path=my_path)
84
85# maybe not the best idea, but might cut away candidates with failed fits
86ma.rankByHighest(particleList='D0',
87 variable='chiProb',
88 path=my_path)
89
90# One can store quantities of candidates with specific ranks.
91# Here, we look at the PID of the pion for the D0 candidates with rank 1 and 2 and the difference of those values.
92# The second argument of getVariableByRank is the ordering variable of the previous ranking.
93va.variables.addAlias('D0_rank1_pi_PIDpi', 'getVariableByRank(D0, chiProb, daughter(1, pionID), 1)')
94va.variables.addAlias('D0_rank2_pi_PIDpi', 'getVariableByRank(D0, chiProb, daughter(1, pionID), 2)')
95
96# It makes sense to put these variables (or a combination of them) into an event-based ExtraInfo:
97ma.variablesToEventExtraInfo('D0', {'formula(D0_rank1_pi_PIDpi - D0_rank2_pi_PIDpi)': 'D0_pi_PIDpi_r1_minus_r2'}, path=my_path)
98va.variables.addAlias('D0_pi_PIDpi_r1_minus_r2', 'eventExtraInfo(D0_pi_PIDpi_r1_minus_r2)')
99
100# Now let's do mixed ranking:
101# First, we want to rank D candidates by the momentum of the pions
102# Second, we want to rank those D candidates that were built with the highest-p by the vertex Chi2
103# This doesn't have any sense, but shows how to work with consecutive rankings
104#
105# Let's add alias for the momentum rank of pions in D
106va.variables.addAlias('D1_pi_p_rank', 'daughter(1,pi_p_rank)')
107# Ranking D candidates by this variable.
108# Candidates built with the same pion get the same rank (allowMultiRank=True).
109ma.rankByHighest(particleList='D0',
110 variable='D1_pi_p_rank',
111 allowMultiRank=True,
112 outputVariable="first_D_rank",
113 path=my_path)
114va.variables.addAlias('first_D_rank', 'extraInfo(first_D_rank)')
115# Now let's rank by chiProb only those candidates that are built with the highest momentum pi
116# Other candidates will get this rank equal to -1
117ma.rankByHighest(particleList="D0",
118 variable="chiProb",
119 cut="first_D_rank == 1",
120 outputVariable="second_D_rank",
121 path=my_path)
122va.variables.addAlias('second_D_rank', 'extraInfo(second_D_rank)')
123
124# add rank variable aliases for easier use
125va.variables.addAlias('dM_rank', 'extraInfo(abs_dM_rank)')
126va.variables.addAlias('chiProb_rank', 'extraInfo(chiProb_rank)')
127
128# Select variables that we want to store to ntuple
129fs_hadron_vars = vu.create_aliases_for_selected(list_of_variables=vc.mc_truth, decay_string='D0 -> ^K- ^pi+')
130
131d0_vars = vc.vertex + \
132 vc.mc_vertex + \
133 vc.mc_truth + \
134 fs_hadron_vars + \
135 ['dM', 'chiProb', 'dM_rank', 'chiProb_rank', 'D1_pi_p_rank', 'first_D_rank', 'second_D_rank', 'D0_pi_PIDpi_r1_minus_r2']
136
137
138# Saving variables to ntuple
139output_file = 'B2A602-BestCandidateSelection.root'
140ma.variablesToNtuple(decayString='D0',
141 variables=d0_vars,
142 filename=output_file,
143 treename='D0',
144 path=my_path)
145
146
147# Process the events
148b2.process(my_path)
149
150# print out the summary
151print(b2.statistics)