Belle II Software development
LambdaSelector.py
1
8
9import modularAnalysis as ma
10import variables
11from variables import utils
12from basf2 import B2INFO, B2ERROR
13import basf2_mva
14# import torch as torch
15# Check if GPU is available
16# device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
17# print("Device is:",device)
18
19
20def add_default_lambda_Selector_aliases():
21 """
22 This function is used to set up variables aliases for lambda Selector variables.
23 """
24 variables.variables.addAlias('daughtersDeltaZ', 'daughterDiffOf(0, 1, dz)')
25 variables.variables.addAlias('cosVertexMomentum', 'cosAngleBetweenMomentumAndVertexVector')
26 variables.variables.addAlias('pro_nPXDHits', 'daughter(0,nPXDHits)')
27 variables.variables.addAlias('pin_nPXDHits', 'daughter(1,nPXDHits)')
28 variables.variables.addAlias('pro_nSVDHits', 'daughter(0,nSVDHits)')
29 variables.variables.addAlias('pin_nSVDHits', 'daughter(1,nSVDHits)')
30 variables.variables.addAlias('daughterAngleDiffInMother', 'useRestFrame(daughterAngle(0, 1))')
31 variables.variables.addAlias('pro_p', 'daughter(0,p)')
32 variables.variables.addAlias('pin_p', 'daughter(1,p)')
33 variables.variables.addAlias('pro_pt', 'daughter(0,pt)')
34 variables.variables.addAlias('pin_pt', 'daughter(1,pt)')
35 variables.variables.addAlias('pro_dr', 'daughter(0,dr)')
36 variables.variables.addAlias('pin_dr', 'daughter(1,dr)')
37 variables.variables.addAlias('pro_cosTheta', 'daughter(0,cosTheta)')
38 variables.variables.addAlias('pin_cosTheta', 'daughter(1,cosTheta)')
39 variables.variables.addAlias('pro_protonID', 'daughter(0,protonID)')
40 variables.variables.addAlias('pin_protonID', 'daughter(1,protonID)')
41 variables.variables.addAlias('proPDG', 'daughter(0,mcPDG)')
42 variables.variables.addAlias('pinPDG', 'daughter(1,mcPDG)')
43 variables.variables.addAlias("Mks_Hypo", "useAlternativeDaughterHypothesis(M, 0:pi+)")
44
45
46def add_variable_collection():
47 """
48 Call this function to add variable collection for lambdaSelector.
49 """
50 add_default_lambda_Selector_aliases()
51 inputVariablesList = [
52 'cosVertexMomentum',
53 'flightDistance',
54 'flightDistanceErr',
55 'significanceOfDistance',
56 'cosHelicityAngleMomentum',
57 'ImpactXY',
58 'decayAngle(0)',
59 'decayAngle(1)',
60 'daughterAngleDiffInMother',
61 'daughtersDeltaZ',
62 'pro_nSVDHits', 'pro_nPXDHits',
63 'pin_nSVDHits', 'pin_nPXDHits',
64 'pro_dr', 'pin_dr',
65 'pro_protonID', 'pin_protonID',
66 'pro_p', 'pin_p',
67 'pro_pt', 'pin_pt',
68 'pro_cosTheta', 'pin_cosTheta',
69 'pinPDG', 'proPDG',
70 'ArmenterosDaughter1Qt',
71 'ArmenterosDaughter2Qt',
72 'Mks_Hypo'
73 ]
74 utils.add_collection(inputVariablesList, 'lambda_selector_info')
75
76
77def V0Selector_Training(
78 train_data,
79 tree_name="tree",
80 mva_identifier="MVA_LightGBM_V0Selector.root",
81 target_variable="isSignal",
82 parameters={},
83 options={}
84 ):
85 """
86 Defines the configuration of V0Selector Training.
87 The training data should contain Lambda0 and misreconstructed Lambda0 without KS0.
88
89 @param train_data Root file containing Lambda information to be trained.
90 @param tree_name Tree name for variables.
91 @param mva_identifier Name for output MVA weight file.
92 @param target_variable Target variable for MVA training.
93 @param parameters hyperparameter for LGBM
94 @param options MVA options
95 """
96
97 # Create The GeneralOptions object as always
98 trainVars = [
99 'cosVertexMomentum',
100 'flightDistance',
101 'significanceOfDistance',
102 'cosHelicityAngleMomentum',
103 'ImpactXY',
104 'decayAngle(0)',
105 'decayAngle(1)',
106 'daughterAngleDiffInMother',
107 'daughtersDeltaZ',
108 'pro_nSVDHits', 'pro_nPXDHits',
109 'pin_nSVDHits', 'pin_nPXDHits',
110 'pro_dr', 'pin_dr',
111 ]
112
113 general_options = basf2_mva.GeneralOptions()
114 general_options.m_datafiles = basf2_mva.vector(train_data)
115 general_options.m_treename = tree_name
116 general_options.m_identifier = mva_identifier
117 general_options.m_variables = basf2_mva.vector(*trainVars)
118 general_options.m_target_variable = target_variable
119 general_options.m_max_events = 0 if 'max_events' not in options else options['max_events']
120
121 python_options = basf2_mva.PythonOptions()
122 python_options.m_framework = "lightgbm"
123
124 import json
125 param = {'num_leaves': 256,
126 'objective': 'cross_entropy',
127 'learning_rate': 0.1,
128 'device_type': "cpu",
129 'deterministic': True,
130 'metric': 'auc',
131 'num_round': 100,
132 # 'stop_round' : 30, mute this in case too early stop
133 'path': mva_identifier+'.txt',
134 'min_data_in_leaf': 1000,
135 'max_depth': 8,
136 'max_bin': 250,
137 'boosting': 'gbdt',
138 'trainFraction': 0.8,
139 'num_threads': 1
140 }
141 if isinstance(parameters, dict):
142 param.update(parameters)
143 config_string = json.dumps(param)
144 print("The json config string", config_string)
145 python_options.m_config = config_string
146
147 python_options.m_training_fraction = 1
148 python_options.m_normalize = False
149 python_options.m_nIterations = 1
150 python_options.m_mini_batch_size = 0
151
152 basf2_mva.teacher(general_options, python_options)
153
154
155def KsVeto_Training(
156 train_data,
157 tree_name="tree",
158 mva_identifier="MVA_LightGBM_KsVeto.root",
159 target_variable="isSignal",
160 parameters={},
161 options={}
162):
163 """
164 Defines the configuration of KsVeto Training.
165 The training data should contain only Lambda and Ks.
166
167 @param train_data Root file containing Ks information to be trained.
168 @param tree_name Tree name for variables.
169 @param mva_identifier Name for output MVA weight file.
170 @param target_variable Target variable for MVA training.
171 @param parameters hyperparameter for LGBM
172 @param options MVA options
173 """
174
175 # Create The GeneralOptions object as always
176 trainVars = [
177 'pro_protonID',
178 'pin_protonID',
179 'ArmenterosDaughter1Qt',
180 'ArmenterosDaughter2Qt',
181 'pro_cosTheta',
182 'pin_cosTheta',
183 'Mks_Hypo',
184 'ArmenterosLongitudinalMomentumAsymmetry',
185 ]
186
187 general_options = basf2_mva.GeneralOptions()
188 general_options.m_datafiles = basf2_mva.vector(train_data)
189 general_options.m_treename = tree_name
190 general_options.m_identifier = mva_identifier
191 general_options.m_variables = basf2_mva.vector(*trainVars)
192 general_options.m_target_variable = target_variable
193 general_options.m_max_events = 0 if 'max_events' not in options else options['max_events']
194
195 python_options = basf2_mva.PythonOptions()
196 python_options.m_framework = "lightgbm"
197
198 import json
199 param = {'num_leaves': 256,
200 'learning_rate': 0.05,
201 'device_type': "cpu",
202 'deterministic': True,
203 'metric': 'auc',
204 'num_round': 100,
205 # 'stop_round' : 10,
206 'path': mva_identifier+'.txt',
207 'max_bin': 250,
208 'boosting': 'gbdt',
209 'max_depth': 8,
210 'trainFraction': 0.8,
211 'min_data_in_leaf': 300,
212 'objective': 'cross_entropy',
213 'num_threads': 1
214 }
215 if isinstance(parameters, dict):
216 param.update(parameters)
217 config_string = json.dumps(param)
218 print("The json config string", config_string)
219 python_options.m_config = config_string
220
221 python_options.m_normalize = False # we do it inside MVA torch
222 python_options.m_nIterations = 1
223 python_options.m_mini_batch_size = 0
224
225 basf2_mva.teacher(general_options, python_options)
226
227# ****************************************
228# Lambda Selector MAIN FUNCTION
229# ****************************************
230
231
233 particleListName,
234 identifier_Lambda="Lambda_LGBM_V0Selector",
235 identifier_vKs="Lambda_LGBM_KsVeto",
236 output_label_name='',
237 extraInfoName_V0Selector='LambdaSelector_V0Selector',
238 extraInfoName_KsVeto='LambdaSelector_KsVeto',
239 useCustomThreshold=False,
240 threshold_V0Selector=0.72,
241 threshold_KsVeto=0.27,
242 path=None
243):
244 """
245 This function will apply Lambda0 selection MVA on the given particleList.
246 By default this function appends MVA output as a extraInfo for the given particleList.
247 You can apply preset cut or custom cut by giving parameters. In this case,
248 a new particleList is created from the original particleList applying cuts on the MVA output.
249
250 @param particleListName Reconstructed Lambda0 -> p+ pi- list.
251 @param output_label_name Label of the returned Lambda particleList.
252 When empty '', no cut is applied and new particleList is not created.
253 When custom name, the custom threshold is used, and useCustomThreshold
254 must be True.
255 When 'standard', 'tight', or 'loose', a cut with Ks efficiency
256 90%, 95%, and 85% is applied.
257 @param extraInfoName_V0Selector Variable name for V0Selector MVA output.
258 @param extraInfoName_KsVeto Variable name for KsVeto MVA output.
259 @param identifier_Lambda Identifier name for V0Selector weight file.
260 @param identifier_vKs Identifier name for KsVeto weight file.
261 @param useCustomThreshold Flag whether threshold_V0Selector and threshold_KsVeto are used.
262 @param threshold_V0Selector Threshold for V0Selector.
263 @param threshold_KsVeto Threshold for KsVeto.
264 @param path Basf2 path to execute.
265
266 """
267
268 add_default_lambda_Selector_aliases()
269
270 path.add_module('MVAMultipleExperts',
271 listNames=[particleListName],
272 extraInfoNames=[extraInfoName_V0Selector, extraInfoName_KsVeto],
273 identifiers=[identifier_Lambda, identifier_vKs])
274
275 _effnames = ['standard', 'tight', 'loose']
276 outputListName = ''
277
278 if useCustomThreshold:
279 if output_label_name in _effnames:
280 B2ERROR('LambdaSelector: Specify label name except for \'standard\', \'tight\', and \'loose\' '
281 'when you use custom threshold.')
282 elif output_label_name == '':
283 B2ERROR('LambdaSelector: Specify label name when you use custom threshold.')
284 else:
285 outputListName = particleListName.split(':')[0] + ':' + output_label_name
286 B2INFO('LambdaSelector: Custom Cut is applied on '+outputListName+'.')
287 V0_thr = threshold_V0Selector
288 Ks_thr = threshold_KsVeto
289 B2INFO('LambdaSelector: Threshold is (' + str(V0_thr) + ', ' + str(Ks_thr) + ')')
290 cut_string = 'extraInfo('+extraInfoName_V0Selector+')>'+str(V0_thr) + \
291 ' and extraInfo('+extraInfoName_KsVeto+')>'+str(Ks_thr)
292 ma.cutAndCopyLists(outputListName, particleListName, cut=cut_string, path=path)
293 else:
294 if output_label_name in _effnames:
295 outputListName = particleListName.split(':')[0] + ':' + output_label_name
296 V0_thr = 0
297 Ks_thr = 0
298 if output_label_name == 'standard':
299 B2INFO('LambdaSelector: Standard Cut is applied on '+outputListName+'.')
300 V0_thr = 0.72
301 Ks_thr = 0.27
302 elif output_label_name == 'tight':
303 B2INFO('LambdaSelector: Tight Cut is applied on '+outputListName+'.')
304 V0_thr = 0.88
305 Ks_thr = 0.63
306 elif output_label_name == 'loose':
307 B2INFO('LambdaSelector: Loose Cut is applied on '+outputListName+'.')
308 V0_thr = 0.25
309 Ks_thr = 0.11
310 B2INFO('LambdaSelector: Threshold is (' + str(V0_thr) + ', ' + str(Ks_thr) + ')')
311 cut_string = 'extraInfo('+extraInfoName_V0Selector+')>'+str(V0_thr) + \
312 ' and extraInfo('+extraInfoName_KsVeto+')>'+str(Ks_thr)
313 ma.cutAndCopyLists(outputListName, particleListName, cut=cut_string, path=path)
314 elif output_label_name == '':
315 outputListName = particleListName
316 else:
317 B2ERROR('LambdaSelector: Label should be \'\', \'standard\', \'tight\', or \'loose\' if you do'
318 'not apply custom threshold')
319
320 B2INFO('LambdaSelector: ParticleList '+outputListName+' is returned.')