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