Belle II Software  release-08-01-10
B2A602-BestCandidateSelection.py
1 #!/usr/bin/env python3
2 
3 
10 
11 
30 
31 import basf2 as b2
32 import modularAnalysis as ma
33 import variables.collections as vc
34 import variables.utils as vu
35 import vertex as vx
36 import stdCharged as stdc
37 import variables as va
38 
39 # create path
40 my_path = b2.create_path()
41 
42 # load input ROOT file
43 ma.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.)
49 stdc.stdPi('all', path=my_path)
50 # rank all pions of the event by momentum magnitude
51 # variable stored to extraInfo as pi_p_rank
52 ma.rankByLowest(particleList='pi+:all',
53  variable='p',
54  outputVariable='pi_p_rank',
55  path=my_path)
56 
57 va.variables.addAlias('pi_p_rank', 'extraInfo(pi_p_rank)')
58 
59 # creates "K+:loose" ParticleList (and c.c.)
60 stdc.stdK(listtype='loose', path=my_path)
61 
62 # keep only candidates with 1.8 < M(Kpi) < 1.9 GeV
63 ma.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)
68 ma.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
72 vx.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
80 ma.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
86 ma.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.
93 va.variables.addAlias('D0_rank1_pi_PIDpi', 'getVariableByRank(D0, chiProb, daughter(1, pionID), 1)')
94 va.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:
97 ma.variablesToEventExtraInfo('D0', {'formula(D0_rank1_pi_PIDpi - D0_rank2_pi_PIDpi)': 'D0_pi_PIDpi_r1_minus_r2'}, path=my_path)
98 va.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
106 va.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).
109 ma.rankByHighest(particleList='D0',
110  variable='D1_pi_p_rank',
111  allowMultiRank=True,
112  outputVariable="first_D_rank",
113  path=my_path)
114 va.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
117 ma.rankByHighest(particleList="D0",
118  variable="chiProb",
119  cut="first_D_rank == 1",
120  outputVariable="second_D_rank",
121  path=my_path)
122 va.variables.addAlias('second_D_rank', 'extraInfo(second_D_rank)')
123 
124 # add rank variable aliases for easier use
125 va.variables.addAlias('dM_rank', 'extraInfo(abs_dM_rank)')
126 va.variables.addAlias('chiProb_rank', 'extraInfo(chiProb_rank)')
127 
128 # Select variables that we want to store to ntuple
129 fs_hadron_vars = vu.create_aliases_for_selected(list_of_variables=vc.mc_truth, decay_string='D0 -> ^K- ^pi+')
130 
131 d0_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
139 output_file = 'B2A602-BestCandidateSelection.root'
140 ma.variablesToNtuple(decayString='D0',
141  variables=d0_vars,
142  filename=output_file,
143  treename='D0',
144  path=my_path)
145 
146 
147 # Process the events
148 b2.process(my_path)
149 
150 # print out the summary
151 print(b2.statistics)