Belle II Software  release-05-01-25
flavorTagger.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 # ************* Flavor Tagging ************
5 # * Authors: Fernando Abudinen, Moritz Gelb *
6 # *..... and Thomas Keck *
7 # * This script is needed to train *
8 # * and to test the flavor tagger. *
9 # ********************************************
10 
11 from basf2 import B2INFO, B2FATAL
12 import basf2
13 import basf2_mva
14 import modularAnalysis as ma
15 from variables import utils
16 from ROOT import Belle2
17 import os
18 import glob
19 import b2bii
20 
21 
22 def getBelleOrBelle2():
23  """
24  Gets the global ModeCode.
25  """
26  if b2bii.isB2BII():
27  return 'Belle'
28  else:
29  return 'Belle2'
30 
31 
32 def setInteractionWithDatabase(downloadFromDatabaseIfNotFound=False, uploadToDatabaseAfterTraining=False):
33  """
34  Sets the interaction with the database: download trained weight files or upload weight files after training.
35  """
36 
37  global downloadFlag
38  global uploadFlag
39 
40  downloadFlag = downloadFromDatabaseIfNotFound
41  uploadFlag = uploadToDatabaseAfterTraining
42 
43 
44 # Default list of aliases that should be used to save the flavor tagging information using VariablesToNtuple
45 flavor_tagging = ['FBDT_qrCombined', 'FANN_qrCombined', 'qrMC', 'mcFlavorOfOtherB',
46  'qpElectron', 'hasTrueTargetElectron', 'isRightCategoryElectron',
47  'qpIntermediateElectron', 'hasTrueTargetIntermediateElectron', 'isRightCategoryIntermediateElectron',
48  'qpMuon', 'hasTrueTargetMuon', 'isRightCategoryMuon',
49  'qpIntermediateMuon', 'hasTrueTargetIntermediateMuon', 'isRightCategoryIntermediateMuon',
50  'qpKinLepton', 'hasTrueTargetKinLepton', 'isRightCategoryKinLepton',
51  'qpIntermediateKinLepton', 'hasTrueTargetIntermediateKinLepton', 'isRightCategoryIntermediateKinLepton',
52  'qpKaon', 'hasTrueTargetKaon', 'isRightCategoryKaon',
53  'qpSlowPion', 'hasTrueTargetSlowPion', 'isRightCategorySlowPion',
54  'qpFastHadron', 'hasTrueTargetFastHadron', 'isRightCategoryFastHadron',
55  'qpLambda', 'hasTrueTargetLambda', 'isRightCategoryLambda',
56  'qpFSC', 'hasTrueTargetFSC', 'isRightCategoryFSC',
57  'qpMaximumPstar', 'hasTrueTargetMaximumPstar', 'isRightCategoryMaximumPstar',
58  'qpKaonPion', 'hasTrueTargetKaonPion', 'isRightCategoryKaonPion']
59 
60 
61 def add_default_FlavorTagger_aliases():
62  """
63  This function adds the default aliases for flavor tagging variables
64  and defines the collection of flavor tagging variables.
65  """
66 
67  utils._variablemanager.addAlias('FBDT_qrCombined', 'qrOutput(FBDT)')
68  utils._variablemanager.addAlias('FANN_qrCombined', 'qrOutput(FANN)')
69  utils._variablemanager.addAlias('qrMC', 'isRelatedRestOfEventB0Flavor')
70 
71  for iCategory in AvailableCategories:
72  aliasForQp = 'qp' + iCategory
73  aliasForTrueTarget = 'hasTrueTarget' + iCategory
74  aliasForIsRightCategory = 'isRightCategory' + iCategory
75  utils._variablemanager.addAlias(aliasForQp, 'qpCategory(' + iCategory + ')')
76  utils._variablemanager.addAlias(aliasForTrueTarget, 'hasTrueTargets(' + iCategory + ')')
77  utils._variablemanager.addAlias(aliasForIsRightCategory, 'isTrueFTCategory(' + iCategory + ')')
78 
79  utils.add_collection(flavor_tagging, 'flavor_tagging')
80 
81 
82 def set_FlavorTagger_pid_aliases():
83  """
84  This function adds the pid aliases needed by the flavor tagger.
85  """
86  utils._variablemanager.addAlias('eid_TOP', 'ifNANgiveX(pidPairProbabilityExpert(11, 211, TOP), 0.5)')
87  utils._variablemanager.addAlias('eid_ARICH', 'ifNANgiveX(pidPairProbabilityExpert(11, 211, ARICH), 0.5)')
88  utils._variablemanager.addAlias('eid_ECL', 'ifNANgiveX(pidPairProbabilityExpert(11, 211, ECL), 0.5)')
89 
90  utils._variablemanager.addAlias('muid_TOP', 'ifNANgiveX(pidPairProbabilityExpert(13, 211, TOP), 0.5)')
91  utils._variablemanager.addAlias('muid_ARICH', 'ifNANgiveX(pidPairProbabilityExpert(13, 211, ARICH), 0.5)')
92  utils._variablemanager.addAlias('muid_KLM', 'ifNANgiveX(pidPairProbabilityExpert(13, 211, KLM), 0.5)')
93 
94  utils._variablemanager.addAlias('piid_TOP', 'ifNANgiveX(pidPairProbabilityExpert(211, 321, TOP), 0.5)')
95  utils._variablemanager.addAlias('piid_ARICH', 'ifNANgiveX(pidPairProbabilityExpert(211, 321, ARICH), 0.5)')
96 
97  utils._variablemanager.addAlias('Kid_TOP', 'ifNANgiveX(pidPairProbabilityExpert(321, 211, TOP), 0.5)')
98  utils._variablemanager.addAlias('Kid_ARICH', 'ifNANgiveX(pidPairProbabilityExpert(321, 211, ARICH), 0.5)')
99 
100  if getBelleOrBelle2() == "Belle":
101  utils._variablemanager.addAlias('eid_dEdx', 'ifNANgiveX(pidPairProbabilityExpert(11, 211, CDC, SVD), 0.5)')
102  utils._variablemanager.addAlias('muid_dEdx', 'ifNANgiveX(pidPairProbabilityExpert(13, 211, CDC, SVD), 0.5)')
103  utils._variablemanager.addAlias('piid_dEdx', 'ifNANgiveX(pidPairProbabilityExpert(211, 321, CDC, SVD), 0.5)')
104  utils._variablemanager.addAlias('pi_vs_edEdxid', 'ifNANgiveX(pidPairProbabilityExpert(211, 11, CDC, SVD), 0.5)')
105  utils._variablemanager.addAlias('Kid_dEdx', 'ifNANgiveX(pidPairProbabilityExpert(321, 211, CDC, SVD), 0.5)')
106  else:
107  # Removed SVD PID for Belle II MC and data as it is absent in release 4.
108  utils._variablemanager.addAlias('eid_dEdx', 'ifNANgiveX(pidPairProbabilityExpert(11, 211, CDC), 0.5)')
109  utils._variablemanager.addAlias('muid_dEdx', 'ifNANgiveX(pidPairProbabilityExpert(13, 211, CDC), 0.5)')
110  utils._variablemanager.addAlias('piid_dEdx', 'ifNANgiveX(pidPairProbabilityExpert(211, 321, CDC), 0.5)')
111  utils._variablemanager.addAlias('pi_vs_edEdxid', 'ifNANgiveX(pidPairProbabilityExpert(211, 11, CDC), 0.5)')
112  utils._variablemanager.addAlias('Kid_dEdx', 'ifNANgiveX(pidPairProbabilityExpert(321, 211, CDC), 0.5)')
113 
114 
115 # Options for Track and Event Levels
116 fastBDTCategories = basf2_mva.FastBDTOptions()
117 fastBDTCategories.m_nTrees = 500
118 fastBDTCategories.m_nCuts = 8
119 fastBDTCategories.m_nLevels = 3
120 fastBDTCategories.m_shrinkage = 0.10
121 fastBDTCategories.m_randRatio = 0.5
122 
123 # Options for Combiner Level
124 fastBDTCombiner = basf2_mva.FastBDTOptions()
125 fastBDTCombiner.m_nTrees = 500
126 fastBDTCombiner.m_nCuts = 8
127 fastBDTCombiner.m_nLevels = 3
128 fastBDTCombiner.m_shrinkage = 0.10
129 fastBDTCombiner.m_randRatio = 0.5
130 
131 mlpFANNCombiner = basf2_mva.FANNOptions()
132 mlpFANNCombiner.m_max_epochs = 10000
133 mlpFANNCombiner.m_hidden_layers_architecture = "3*N"
134 mlpFANNCombiner.m_hidden_activiation_function = "FANN_SIGMOID_SYMMETRIC"
135 mlpFANNCombiner.m_output_activiation_function = "FANN_SIGMOID_SYMMETRIC"
136 mlpFANNCombiner.m_error_function = "FANN_ERRORFUNC_LINEAR"
137 mlpFANNCombiner.m_training_method = "FANN_TRAIN_RPROP"
138 mlpFANNCombiner.m_validation_fraction = 0.5
139 mlpFANNCombiner.m_random_seeds = 10
140 mlpFANNCombiner.m_test_rate = 500
141 mlpFANNCombiner.m_number_of_threads = 8
142 mlpFANNCombiner.m_scale_features = True
143 mlpFANNCombiner.m_scale_target = False
144 # mlpFANNCombiner.m_scale_target = True
145 
146 # SignalFraction: FBDT feature
147 # For smooth output set to -1, this will break the calibration.
148 # For correct calibration set to -2, leads to peaky combiner output.
149 signalFraction = -2
150 
151 # Maximal number of events to train each method
152 maxEventsNumber = 0 # 0 takes all the sampled events. The number in the past was 500000
153 
154 # Definition of all available categories, 'standard category name':
155 # ['ParticleList', 'trackLevel category name', 'eventLevel category name',
156 # 'combinerLevel variable name', 'category code']
157 AvailableCategories = {
158  'Electron': [
159  'e+:inRoe',
160  'Electron',
161  'Electron',
162  'QpOf(e+:inRoe, isRightCategory(Electron), isRightCategory(Electron))',
163  0],
164  'IntermediateElectron': [
165  'e+:inRoe',
166  'IntermediateElectron',
167  'IntermediateElectron',
168  'QpOf(e+:inRoe, isRightCategory(IntermediateElectron), isRightCategory(IntermediateElectron))',
169  1],
170  'Muon': [
171  'mu+:inRoe',
172  'Muon',
173  'Muon',
174  'QpOf(mu+:inRoe, isRightCategory(Muon), isRightCategory(Muon))',
175  2],
176  'IntermediateMuon': [
177  'mu+:inRoe',
178  'IntermediateMuon',
179  'IntermediateMuon',
180  'QpOf(mu+:inRoe, isRightCategory(IntermediateMuon), isRightCategory(IntermediateMuon))',
181  3],
182  'KinLepton': [
183  'mu+:inRoe',
184  'KinLepton',
185  'KinLepton',
186  'QpOf(mu+:inRoe, isRightCategory(KinLepton), isRightCategory(KinLepton))',
187  4],
188  'IntermediateKinLepton': [
189  'mu+:inRoe',
190  'IntermediateKinLepton',
191  'IntermediateKinLepton',
192  'QpOf(mu+:inRoe, isRightCategory(IntermediateKinLepton), isRightCategory(IntermediateKinLepton))',
193  5],
194  'Kaon': [
195  'K+:inRoe',
196  'Kaon',
197  'Kaon',
198  'weightedQpOf(K+:inRoe, isRightCategory(Kaon), isRightCategory(Kaon))',
199  6],
200  'SlowPion': [
201  'pi+:inRoe',
202  'SlowPion',
203  'SlowPion',
204  'QpOf(pi+:inRoe, isRightCategory(SlowPion), isRightCategory(SlowPion))',
205  7],
206  'FastHadron': [
207  'pi+:inRoe',
208  'FastHadron',
209  'FastHadron',
210  'QpOf(pi+:inRoe, isRightCategory(FastHadron), isRightCategory(FastHadron))',
211  8],
212  'Lambda': [
213  'Lambda0:inRoe',
214  'Lambda',
215  'Lambda',
216  'weightedQpOf(Lambda0:inRoe, isRightCategory(Lambda), isRightCategory(Lambda))',
217  9],
218  'FSC': [
219  'pi+:inRoe',
220  'SlowPion',
221  'FSC',
222  'QpOf(pi+:inRoe, isRightCategory(FSC), isRightCategory(SlowPion))',
223  10],
224  'MaximumPstar': [
225  'pi+:inRoe',
226  'MaximumPstar',
227  'MaximumPstar',
228  'QpOf(pi+:inRoe, isRightCategory(MaximumPstar), isRightCategory(MaximumPstar))',
229  11],
230  'KaonPion': [
231  'K+:inRoe',
232  'Kaon',
233  'KaonPion',
234  'QpOf(K+:inRoe, isRightCategory(KaonPion), isRightCategory(Kaon))',
235  12],
236 }
237 
238 # Lists for each Step.
239 trackLevelParticleLists = []
240 eventLevelParticleLists = []
241 variablesCombinerLevel = []
242 
243 
244 def WhichCategories(categories=[
245  'Electron',
246  'Muon',
247  'KinLepton',
248  'Kaon',
249  'SlowPion',
250  'FastHadron',
251  'Lambda',
252  'FSC',
253  'MaximumPstar',
254  'KaonPion',
255 ]):
256  """
257  Selection of the Categories that are going to be used.
258  """
259 
260  if len(categories) > 13 or len(categories) < 2:
261  B2FATAL('Flavor Tagger: Invalid amount of categories. At least two are needed. No more than 13 are available'
262  )
263  B2FATAL(
264  'Flavor Tagger: Possible categories are "Electron", "IntermediateElectron", "Muon", "IntermediateMuon", '
265  '"KinLepton", "IntermediateKinLepton", "Kaon", "SlowPion", "FastHadron",'
266  '"Lambda", "FSC", "MaximumPstar" or "KaonPion" ')
267  categoriesCombination = []
268  for category in categories:
269  if category in AvailableCategories:
270  if category != 'MaximumPstar' and (AvailableCategories[category][0],
271  AvailableCategories[category][1]) \
272  not in trackLevelParticleLists:
273  trackLevelParticleLists.append((AvailableCategories[category][0],
274  AvailableCategories[category][1]))
275  if (AvailableCategories[category][0],
276  AvailableCategories[category][2], AvailableCategories[category][3]) \
277  not in eventLevelParticleLists:
278  eventLevelParticleLists.append((AvailableCategories[category][0],
279  AvailableCategories[category][2], AvailableCategories[category][3]))
280  variablesCombinerLevel.append(AvailableCategories[category][3])
281  categoriesCombination.append(AvailableCategories[category][4])
282  else:
283  B2FATAL('Flavor Tagger: ' + category + ' has been already given')
284  else:
285  B2FATAL('Flavor Tagger: ' + category + ' is not a valid category name given')
286  B2FATAL('Flavor Tagger: Available categories are "Electron", "IntermediateElectron", '
287  '"Muon", "IntermediateMuon", "KinLepton", "IntermediateKinLepton", "Kaon", "SlowPion", "FastHadron", '
288  '"Lambda", "FSC", "MaximumPstar" or "KaonPion" ')
289  global categoriesCombinationCode
290  categoriesCombinationCode = 'CatCode'
291  for code in sorted(categoriesCombination):
292  categoriesCombinationCode = categoriesCombinationCode + '%02d' % code
293 
294 
295 # Variables for categories on track level - are defined in variables.cc and MetaVariables.cc
296 variables = dict()
297 KId = {'Belle': 'ifNANgiveX(atcPIDBelle(3,2), 0.5)', 'Belle2': 'kaonID'}
298 muId = {'Belle': 'muIDBelle', 'Belle2': 'muonID'}
299 eId = {'Belle': 'eIDBelle', 'Belle2': 'electronID'}
300 
301 
302 def setVariables():
303  """
304  Sets the Variables used for Track and Event Levels.
305  """
306 
307  variables['Electron'] = [
308  'useCMSFrame(p)',
309  'useCMSFrame(pt)',
310  'p',
311  'pt',
312  'cosTheta',
313  eId[getBelleOrBelle2()],
314  'eid_TOP',
315  'eid_ARICH',
316  'eid_ECL',
317  'BtagToWBosonVariables(recoilMassSqrd)',
318  'BtagToWBosonVariables(pMissCMS)',
319  'BtagToWBosonVariables(cosThetaMissCMS)',
320  'BtagToWBosonVariables(EW90)',
321  'cosTPTO',
322  'chiProb',
323  ]
324  variables['IntermediateElectron'] = variables['Electron']
325  variables['Muon'] = [
326  'useCMSFrame(p)',
327  'useCMSFrame(pt)',
328  'p',
329  'pt',
330  'cosTheta',
331  muId[getBelleOrBelle2()],
332  'muid_TOP',
333  'muid_ARICH',
334  'muid_KLM',
335  'BtagToWBosonVariables(recoilMassSqrd)',
336  'BtagToWBosonVariables(pMissCMS)',
337  'BtagToWBosonVariables(cosThetaMissCMS)',
338  'BtagToWBosonVariables(EW90)',
339  'cosTPTO',
340  ]
341  variables['IntermediateMuon'] = [
342  'useCMSFrame(p)',
343  'useCMSFrame(pt)',
344  'p',
345  'pt',
346  'cosTheta',
347  muId[getBelleOrBelle2()],
348  'muid_TOP',
349  'muid_ARICH',
350  'muid_KLM',
351  'BtagToWBosonVariables(recoilMassSqrd)',
352  'BtagToWBosonVariables(pMissCMS)',
353  'BtagToWBosonVariables(cosThetaMissCMS)',
354  'BtagToWBosonVariables(EW90)',
355  'cosTPTO',
356  'chiProb',
357  ]
358  variables['KinLepton'] = [
359  'useCMSFrame(p)',
360  'useCMSFrame(pt)',
361  'p',
362  'pt',
363  'cosTheta',
364  muId[getBelleOrBelle2()],
365  'muid_TOP',
366  'muid_ARICH',
367  'muid_KLM',
368  eId[getBelleOrBelle2()],
369  'eid_TOP',
370  'eid_ARICH',
371  'eid_ECL',
372  'BtagToWBosonVariables(recoilMassSqrd)',
373  'BtagToWBosonVariables(pMissCMS)',
374  'BtagToWBosonVariables(cosThetaMissCMS)',
375  'BtagToWBosonVariables(EW90)',
376  'cosTPTO',
377  ]
378  variables['IntermediateKinLepton'] = [
379  'useCMSFrame(p)',
380  'useCMSFrame(pt)',
381  'p',
382  'pt',
383  'cosTheta',
384  muId[getBelleOrBelle2()],
385  'muid_TOP',
386  'muid_ARICH',
387  'muid_KLM',
388  eId[getBelleOrBelle2()],
389  'eid_TOP',
390  'eid_ARICH',
391  'eid_ECL',
392  'BtagToWBosonVariables(recoilMassSqrd)',
393  'BtagToWBosonVariables(pMissCMS)',
394  'BtagToWBosonVariables(cosThetaMissCMS)',
395  'BtagToWBosonVariables(EW90)',
396  'cosTPTO',
397  'chiProb',
398  ]
399  variables['Kaon'] = [
400  'useCMSFrame(p)',
401  'useCMSFrame(pt)',
402  'p',
403  'pt',
404  'cosTheta',
405  KId[getBelleOrBelle2()],
406  'Kid_dEdx',
407  'Kid_TOP',
408  'Kid_ARICH',
409  'NumberOfKShortsInRoe',
410  'ptTracksRoe',
411  'BtagToWBosonVariables(recoilMassSqrd)',
412  'BtagToWBosonVariables(pMissCMS)',
413  'BtagToWBosonVariables(cosThetaMissCMS)',
414  'BtagToWBosonVariables(EW90)',
415  'cosTPTO',
416  'chiProb',
417  ]
418  variables['SlowPion'] = [
419  'useCMSFrame(p)',
420  'useCMSFrame(pt)',
421  'cosTheta',
422  'p',
423  'pt',
424  'pionID',
425  'piid_TOP',
426  'piid_ARICH',
427  'pi_vs_edEdxid',
428  KId[getBelleOrBelle2()],
429  'Kid_dEdx',
430  'Kid_TOP',
431  'Kid_ARICH',
432  'NumberOfKShortsInRoe',
433  'ptTracksRoe',
434  eId[getBelleOrBelle2()],
435  'BtagToWBosonVariables(recoilMassSqrd)',
436  'BtagToWBosonVariables(EW90)',
437  'BtagToWBosonVariables(cosThetaMissCMS)',
438  'BtagToWBosonVariables(pMissCMS)',
439  'cosTPTO',
440  ]
441  variables['FastHadron'] = [
442  'useCMSFrame(p)',
443  'useCMSFrame(pt)',
444  'cosTheta',
445  'p',
446  'pt',
447  'pionID',
448  'piid_dEdx',
449  'piid_TOP',
450  'piid_ARICH',
451  'pi_vs_edEdxid',
452  KId[getBelleOrBelle2()],
453  'Kid_dEdx',
454  'Kid_TOP',
455  'Kid_ARICH',
456  'NumberOfKShortsInRoe',
457  'ptTracksRoe',
458  eId[getBelleOrBelle2()],
459  'BtagToWBosonVariables(recoilMassSqrd)',
460  'BtagToWBosonVariables(EW90)',
461  'BtagToWBosonVariables(cosThetaMissCMS)',
462  'cosTPTO',
463  ]
464  variables['Lambda'] = [
465  'lambdaFlavor',
466  'NumberOfKShortsInRoe',
467  'M',
468  'cosAngleBetweenMomentumAndVertexVector',
469  'lambdaZError',
470  'daughter(0,p)',
471  'daughter(0,useCMSFrame(p))',
472  'daughter(1,p)',
473  'daughter(1,useCMSFrame(p))',
474  'useCMSFrame(p)',
475  'p',
476  'chiProb',
477  ]
478  variables['MaximumPstar'] = [
479  'useCMSFrame(p)',
480  'useCMSFrame(pt)',
481  'p',
482  'pt',
483  'cosTPTO',
484  ]
485  variables['FSC'] = [
486  'useCMSFrame(p)',
487  'cosTPTO',
488  KId[getBelleOrBelle2()],
489  'FSCVariables(pFastCMS)',
490  'FSCVariables(cosSlowFast)',
491  'FSCVariables(cosTPTOFast)',
492  'FSCVariables(SlowFastHaveOpositeCharges)',
493  ]
494 
495  # For sampling and teaching in a second step
496  variables['KaonPion'] = ['extraInfo(isRightCategory(Kaon))',
497  'HighestProbInCat(pi+:inRoe, isRightCategory(SlowPion))',
498  'KaonPionVariables(cosKaonPion)', 'KaonPionVariables(HaveOpositeCharges)', KId[getBelleOrBelle2()]]
499 
500  # Special treatment for some input variables:
501  if getBelleOrBelle2() == "Belle2":
502  variables['Lambda'].append('daughter(1,protonID)') # protonID always 0 in B2BII check in future
503  variables['Lambda'].append('daughter(0,pionID)') # not very powerful in B2BII
504  else:
505  # Below we add some input variables in case of Belle B2BII samples.
506  # They are added only for Belle samples because they lead to large data/MC discrepancies at Belle II.
507  # Add them for Belle II samples, when their distributions will have good data/MC agreement.
508  variables['Electron'].append('eid_dEdx')
509  variables['Electron'].append('ImpactXY')
510  variables['Electron'].append('distance')
511 
512  variables['IntermediateElectron'].append('eid_dEdx')
513  variables['IntermediateElectron'].append('ImpactXY')
514  variables['IntermediateElectron'].append('distance')
515 
516  variables['Muon'].append('muid_dEdx')
517  variables['Muon'].append('ImpactXY')
518  variables['Muon'].append('distance')
519  variables['Muon'].append('chiProb')
520 
521  variables['IntermediateMuon'].append('muid_dEdx')
522  variables['IntermediateMuon'].append('ImpactXY')
523  variables['IntermediateMuon'].append('distance')
524 
525  variables['KinLepton'].append('muid_dEdx')
526  variables['KinLepton'].append('eid_dEdx')
527  variables['KinLepton'].append('ImpactXY')
528  variables['KinLepton'].append('distance')
529  variables['KinLepton'].append('chiProb')
530 
531  variables['IntermediateKinLepton'].append('muid_dEdx')
532  variables['IntermediateKinLepton'].append('eid_dEdx')
533  variables['IntermediateKinLepton'].append('ImpactXY')
534  variables['IntermediateKinLepton'].append('distance')
535 
536  variables['Kaon'].append('ImpactXY')
537  variables['Kaon'].append('distance')
538 
539  variables['SlowPion'].append('piid_dEdx')
540  variables['SlowPion'].append('ImpactXY')
541  variables['SlowPion'].append('distance')
542  variables['SlowPion'].append('chiProb')
543 
544  variables['FastHadron'].append('BtagToWBosonVariables(pMissCMS)')
545  variables['FastHadron'].append('ImpactXY')
546  variables['FastHadron'].append('distance')
547  variables['FastHadron'].append('chiProb')
548 
549  variables['Lambda'].append('distance')
550 
551  variables['MaximumPstar'].append('ImpactXY')
552  variables['MaximumPstar'].append('distance')
553 
554 
555 def FillParticleLists(mode='Expert', maskName='', path=None):
556  """
557  Fills the particle Lists for all categories.
558  """
559 
560  from vertex import kFit
561  readyParticleLists = []
562 
563  for (particleList, category) in trackLevelParticleLists:
564 
565  if particleList in readyParticleLists:
566  continue
567 
568  # Select particles in ROE for different categories according to mass hypothesis.
569  if particleList != 'Lambda0:inRoe' and particleList != 'K+:inRoe' and particleList != 'pi+:inRoe':
570 
571  # Filling particle list for actual category
572  ma.fillParticleList(particleList, 'isInRestOfEvent > 0.5 and passesROEMask(' + maskName + ') > 0.5 and ' +
573  'isNAN(p) !=1 and isInfinity(p) != 1', path=path)
574  readyParticleLists.append(particleList)
575 
576  else:
577  if 'pi+:inRoe' not in readyParticleLists:
578  ma.fillParticleList(
579  'pi+:inRoe', 'isInRestOfEvent > 0.5 and passesROEMask(' + maskName + ') > 0.5 and ' +
580  'isNAN(p) !=1 and isInfinity(p) != 1', path=path)
581  readyParticleLists.append('pi+:inRoe')
582 
583  if 'K_S0:inRoe' not in readyParticleLists:
584  if getBelleOrBelle2() == 'Belle':
585  ma.cutAndCopyList('K_S0:inRoe', 'K_S0:mdst', 'extraInfo(ksnbStandard) == 1 and isInRestOfEvent == 1', path=path)
586  else:
587  ma.reconstructDecay('K_S0:inRoe -> pi+:inRoe pi-:inRoe', '0.40<=M<=0.60', False, path=path)
588  kFit('K_S0:inRoe', 0.01, path=path)
589  readyParticleLists.append('K_S0:inRoe')
590 
591  if particleList == 'K+:inRoe':
592  ma.fillParticleList(
593  particleList, 'isInRestOfEvent > 0.5 and passesROEMask(' + maskName + ') > 0.5 and ' +
594  'isNAN(p) !=1 and isInfinity(p) != 1', path=path)
595  # Precut done to prevent from overtraining, found not necessary now
596  # applyCuts(particleList, '0.1<' + KId[getBelleOrBelle2()], path=path)
597  readyParticleLists.append(particleList)
598 
599  if particleList == 'Lambda0:inRoe':
600  ma.fillParticleList(
601  'p+:inRoe', 'isInRestOfEvent > 0.5 and passesROEMask(' + maskName + ') > 0.5 and ' +
602  'isNAN(p) !=1 and isInfinity(p) != 1', path=path)
603  ma.reconstructDecay(particleList + ' -> pi-:inRoe p+:inRoe', '1.00<=M<=1.23', False, path=path)
604  kFit(particleList, 0.01, path=path)
605  # if mode != 'Expert':
606  ma.matchMCTruth(particleList, path=path)
607  readyParticleLists.append(particleList)
608 
609  return True
610 
611 
612 def eventLevel(mode='Expert', weightFiles='B2JpsiKs_mu', path=None):
613  """
614  Samples data for training or tests all categories all categories at event level.
615  """
616 
617  from basf2 import create_path
618  from basf2 import register_module
619 
620  B2INFO('EVENT LEVEL')
621 
622  ReadyMethods = 0
623 
624  # Each category has its own Path in order to be skipped if the corresponding particle list is empty
625  identifiersExtraInfosDict = dict()
626  identifiersExtraInfosKaonPion = []
627 
628  for (particleList, category, combinerVariable) in eventLevelParticleLists:
629 
630  methodPrefixEventLevel = "FlavorTagger_" + getBelleOrBelle2() + "_" + weightFiles + 'EventLevel' + category + 'FBDT'
631  identifierEventLevel = methodPrefixEventLevel
632  targetVariable = 'isRightCategory(' + category + ')'
633  extraInfoName = targetVariable
634 
635  if mode == 'Expert':
636 
637  if downloadFlag or useOnlyLocalFlag:
638  identifierEventLevel = filesDirectory + '/' + methodPrefixEventLevel + '_1.root'
639  if not os.path.isfile(identifierEventLevel):
640  if downloadFlag:
641  basf2_mva.download(methodPrefixEventLevel, identifierEventLevel)
642  if not os.path.isfile(identifierEventLevel):
643  B2FATAL('Flavor Tagger: Weight file ' + identifierEventLevel +
644  ' was not downloaded from Database. Please check the buildOrRevision name. Stopped')
645  else:
646  B2FATAL(
647  'Flavor Tagger: ' + particleList + ' Eventlevel was not trained. Weight file ' +
648  identifierEventLevel + ' was not found. Stopped')
649 
650  else:
651  B2INFO('flavorTagger: MVAExpert ' + methodPrefixEventLevel + ' ready.')
652 
653  elif mode == 'Sampler':
654 
655  identifierEventLevel = filesDirectory + '/' + methodPrefixEventLevel + '_1.root'
656  if os.path.isfile(identifierEventLevel):
657  B2INFO('flavorTagger: MVAExpert ' + methodPrefixEventLevel + ' ready.')
658 
659  if 'KaonPion' in [row[1] for row in eventLevelParticleLists]:
660  methodPrefixEventLevelKaonPion = "FlavorTagger_" + getBelleOrBelle2() + \
661  "_" + weightFiles + 'EventLevelKaonPionFBDT'
662  identifierEventLevelKaonPion = filesDirectory + '/' + methodPrefixEventLevelKaonPion + '_1.root'
663  if not os.path.isfile(identifierEventLevelKaonPion):
664  # Slow Pion and Kaon categories are used if Kaon-Pion is lacking for
665  # sampling. The others are not needed and skipped
666  if category != "SlowPion" and category != "Kaon":
667  continue
668 
669  if mode == 'Expert' or (mode == 'Sampler' and os.path.isfile(identifierEventLevel)):
670 
671  B2INFO('flavorTagger: Applying MVAExpert ' + methodPrefixEventLevel + '.')
672 
673  if particleList not in identifiersExtraInfosDict and category != 'KaonPion':
674  identifiersExtraInfosDict[particleList] = [(extraInfoName, identifierEventLevel)]
675  elif category != 'KaonPion':
676  identifiersExtraInfosDict[particleList].append((extraInfoName, identifierEventLevel))
677  else:
678  identifiersExtraInfosKaonPion.append((extraInfoName, identifierEventLevel))
679 
680  ReadyMethods += 1
681 
682  # Each category has its own Path in order to be skipped if the corresponding particle list is empty
683  for particleList in identifiersExtraInfosDict:
684  eventLevelPath = create_path()
685  SkipEmptyParticleList = register_module("SkimFilter")
686  SkipEmptyParticleList.set_name('SkimFilter_EventLevel_' + particleList)
687  SkipEmptyParticleList.param('particleLists', particleList)
688  SkipEmptyParticleList.if_true(eventLevelPath, basf2.AfterConditionPath.CONTINUE)
689  path.add_module(SkipEmptyParticleList)
690 
691  mvaMultipleExperts = register_module('MVAMultipleExperts')
692  mvaMultipleExperts.set_name('MVAMultipleExperts_EventLevel_' + particleList)
693  mvaMultipleExperts.param('listNames', [particleList])
694  mvaMultipleExperts.param('extraInfoNames', [row[0] for row in identifiersExtraInfosDict[particleList]])
695  mvaMultipleExperts.param('signalFraction', signalFraction)
696  mvaMultipleExperts.param('identifiers', [row[1] for row in identifiersExtraInfosDict[particleList]])
697  eventLevelPath.add_module(mvaMultipleExperts)
698 
699  if 'KaonPion' in [row[1] for row in eventLevelParticleLists] and len(identifiersExtraInfosKaonPion) != 0:
700  eventLevelKaonPionPath = create_path()
701  SkipEmptyParticleList = register_module("SkimFilter")
702  SkipEmptyParticleList.set_name('SkimFilter_' + 'K+:inRoe')
703  SkipEmptyParticleList.param('particleLists', 'K+:inRoe')
704  SkipEmptyParticleList.if_true(eventLevelKaonPionPath, basf2.AfterConditionPath.CONTINUE)
705  path.add_module(SkipEmptyParticleList)
706 
707  mvaExpertKaonPion = register_module("MVAExpert")
708  mvaExpertKaonPion.set_name('MVAExpert_KaonPion_' + 'K+:inRoe')
709  mvaExpertKaonPion.param('listNames', ['K+:inRoe'])
710  mvaExpertKaonPion.param('extraInfoName', identifiersExtraInfosKaonPion[0][0])
711  mvaExpertKaonPion.param('signalFraction', signalFraction)
712  mvaExpertKaonPion.param('identifier', identifiersExtraInfosKaonPion[0][1])
713 
714  eventLevelKaonPionPath.add_module(mvaExpertKaonPion)
715 
716  for (particleList, category, combinerVariable) in eventLevelParticleLists:
717 
718  methodPrefixEventLevel = "FlavorTagger_" + getBelleOrBelle2() + "_" + weightFiles + 'EventLevel' + category + 'FBDT'
719  identifierEventLevel = filesDirectory + '/' + methodPrefixEventLevel + '_1.root'
720  targetVariable = 'isRightCategory(' + category + ')'
721 
722  if not os.path.isfile(identifierEventLevel) and mode == 'Sampler':
723 
724  if category == 'KaonPion':
725  methodPrefixEventLevelSlowPion = "FlavorTagger_" + getBelleOrBelle2() + "_" + weightFiles + 'EventLevelSlowPionFBDT'
726  identifierEventLevelSlowPion = filesDirectory + '/' + methodPrefixEventLevelSlowPion + '_1.root'
727  if not os.path.isfile(identifierEventLevelSlowPion):
728  B2INFO("Flavor Tagger: event level weight file for the Slow Pion category is absent." +
729  "It is required to sample the training information for the KaonPion category." +
730  "An additional sampling step will be needed after the following training step.")
731  continue
732 
733  B2INFO(
734  'flavorTagger: file ' + filesDirectory + '/' +
735  methodPrefixEventLevel + "sampled" + fileId + '.root will be saved.')
736 
737  ma.applyCuts(particleList, 'isRightCategory(mcAssociated) > 0', path)
738  eventLevelpath = create_path()
739  SkipEmptyParticleList = register_module("SkimFilter")
740  SkipEmptyParticleList.set_name('SkimFilter_EventLevel' + category)
741  SkipEmptyParticleList.param('particleLists', particleList)
742  SkipEmptyParticleList.if_true(eventLevelpath, basf2.AfterConditionPath.CONTINUE)
743  path.add_module(SkipEmptyParticleList)
744 
745  ntuple = register_module('VariablesToNtuple')
746  ntuple.param('fileName', filesDirectory + '/' + methodPrefixEventLevel + "sampled" + fileId + ".root")
747  ntuple.param('treeName', methodPrefixEventLevel + "_tree")
748  variablesToBeSaved = variables[category] + [targetVariable, 'ancestorHasWhichFlavor',
749  'isSignal', 'mcPDG', 'mcErrors', 'genMotherPDG',
750  'nMCMatches', 'B0mcErrors']
751  if category != 'KaonPion' and category != 'FSC':
752  variablesToBeSaved = variablesToBeSaved + \
753  ['extraInfo(isRightTrack(' + category + '))',
754  'hasHighestProbInCat(' + particleList + ', isRightTrack(' + category + '))']
755  ntuple.param('variables', variablesToBeSaved)
756  ntuple.param('particleList', particleList)
757  eventLevelpath.add_module(ntuple)
758 
759  if ReadyMethods != len(eventLevelParticleLists):
760  return False
761  else:
762  return True
763 
764 
765 def eventLevelTeacher(weightFiles='B2JpsiKs_mu'):
766  """
767  Trains all categories at event level.
768  """
769 
770  B2INFO('EVENT LEVEL TEACHER')
771 
772  ReadyMethods = 0
773 
774  for (particleList, category, combinerVariable) in eventLevelParticleLists:
775 
776  methodPrefixEventLevel = "FlavorTagger_" + getBelleOrBelle2() + "_" + weightFiles + 'EventLevel' + category + 'FBDT'
777  targetVariable = 'isRightCategory(' + category + ')'
778  weightFile = filesDirectory + '/' + methodPrefixEventLevel + "_1.root"
779 
780  if not os.path.isfile(weightFile):
781 
782  sampledFilesList = glob.glob(filesDirectory + '/' + methodPrefixEventLevel + 'sampled*.root')
783  if len(sampledFilesList) == 0:
784 
785  B2INFO('flavorTagger: eventLevelTeacher did not find any ' + methodPrefixEventLevel +
786  ".root" + ' file. Please run the flavorTagger in "Sampler" mode afterwards.')
787 
788  else:
789 
790  B2INFO('flavorTagger: MVA Teacher training' + methodPrefixEventLevel + ' .')
791  trainingOptionsEventLevel = basf2_mva.GeneralOptions()
792  trainingOptionsEventLevel.m_datafiles = basf2_mva.vector(*sampledFilesList)
793  trainingOptionsEventLevel.m_treename = methodPrefixEventLevel + "_tree"
794  trainingOptionsEventLevel.m_identifier = weightFile
795  trainingOptionsEventLevel.m_variables = basf2_mva.vector(*variables[category])
796  trainingOptionsEventLevel.m_target_variable = targetVariable
797  trainingOptionsEventLevel.m_max_events = maxEventsNumber
798 
799  basf2_mva.teacher(trainingOptionsEventLevel, fastBDTCategories)
800 
801  if uploadFlag:
802  basf2_mva.upload(weightFile, methodPrefixEventLevel)
803 
804  else:
805 
806  ReadyMethods += 1
807 
808  if ReadyMethods != len(eventLevelParticleLists):
809  return False
810  else:
811  return True
812 
813 
814 def combinerLevel(mode='Expert', weightFiles='B2JpsiKs_mu', path=None):
815  """
816  Samples the input data or tests the combiner according to the selected categories.
817  """
818 
819  B2INFO('COMBINER LEVEL')
820 
821  B2INFO("Flavor Tagger: Required Combiner for Categories:")
822  for (particleList, category, combinerVariable) in eventLevelParticleLists:
823  B2INFO(category)
824 
825  B2INFO("Flavor Tagger: which corresponds to a weight file with categories combination code " + categoriesCombinationCode)
826 
827  methodPrefixCombinerLevel = "FlavorTagger_" + getBelleOrBelle2() + "_" + weightFiles + 'Combiner' \
828  + categoriesCombinationCode
829 
830  if mode == 'Sampler':
831 
832  if not (
833  os.path.isfile(
834  filesDirectory + '/' + methodPrefixCombinerLevel + 'FBDT' + '_1.root') or os.path.isfile(
835  filesDirectory + '/' + methodPrefixCombinerLevel + 'FANN' + '_1.root')):
836  B2INFO('flavorTagger: Sampling Data on Combiner Level. File' +
837  methodPrefixCombinerLevel + ".root" + ' will be saved')
838 
839  ntuple = basf2.register_module('VariablesToNtuple')
840  ntuple.param('fileName', filesDirectory + '/' + methodPrefixCombinerLevel + "sampled" + fileId + ".root")
841  ntuple.param('treeName', methodPrefixCombinerLevel + 'FBDT' + "_tree")
842  ntuple.param('variables', variablesCombinerLevel + ['qrCombined'])
843  ntuple.param('particleList', "")
844  path.add_module(ntuple)
845 
846  return False
847 
848  else:
849  B2FATAL('flavorTagger: File' + methodPrefixCombinerLevel + 'FBDT' + "_1.root" + ' or ' + methodPrefixCombinerLevel +
850  'FANN' + '_1.root found. Please run the "Expert" mode or delete the file if a new sampling is desired.')
851 
852  if mode == 'Expert':
853 
854  if TMVAfbdt and not FANNmlp:
855 
856  identifier = methodPrefixCombinerLevel + 'FBDT'
857 
858  if downloadFlag or useOnlyLocalFlag:
859 
860  identifier = filesDirectory + '/' + methodPrefixCombinerLevel + 'FBDT' + '_1.root'
861  if not os.path.isfile(identifier):
862  if downloadFlag:
863  basf2_mva.download(methodPrefixCombinerLevel + 'FBDT', identifier)
864  if not os.path.isfile(identifier):
865  B2FATAL('Flavor Tagger: Weight file ' + methodPrefixCombinerLevel + 'FBDT' +
866  '_1.root was not downloaded from Database. Please check the buildOrRevision name. Stopped')
867  else:
868  B2FATAL(
869  'flavorTagger: Combinerlevel FastBDT was not trained with this combination of categories.' +
870  ' Weight file ' + methodPrefixCombinerLevel + 'FBDT' + '_1.root not found. Stopped')
871  else:
872  B2INFO('flavorTagger: Ready to be used with weightFile ' + methodPrefixCombinerLevel + 'FBDT' + '_1.root')
873 
874  B2INFO('flavorTagger: Apply FBDTMethod ' + methodPrefixCombinerLevel + 'FBDT')
875  path.add_module('MVAExpert', listNames=[], extraInfoName='qrCombined' + 'FBDT', signalFraction=signalFraction,
876  identifier=identifier)
877  return True
878 
879  if FANNmlp and not TMVAfbdt:
880 
881  identifier = methodPrefixCombinerLevel + 'FANN'
882 
883  if downloadFlag or useOnlyLocalFlag:
884  identifier = filesDirectory + '/' + methodPrefixCombinerLevel + 'FANN' + '_1.root'
885 
886  if not os.path.isfile(identifier):
887  if downloadFlag:
888  basf2_mva.download(methodPrefixCombinerLevel + 'FANN', identifier)
889  if not os.path.isfile(identifier):
890  B2FATAL('Flavor Tagger: Weight file ' + methodPrefixCombinerLevel + 'FANN' +
891  '_1.root was not downloaded from Database. Please check the buildOrRevision name. Stopped')
892  else:
893  B2FATAL(
894  'flavorTagger: Combinerlevel FANNMLP was not trained with this combination of categories. ' +
895  ' Weight file ' + methodPrefixCombinerLevel + 'FANN' + '_1.root not found. Stopped')
896  else:
897  B2INFO('flavorTagger: Ready to be used with weightFile ' + methodPrefixCombinerLevel + 'FANN' + '_1.root')
898 
899  B2INFO('flavorTagger: Apply FANNMethod on combiner level')
900  path.add_module('MVAExpert', listNames=[], extraInfoName='qrCombined' + 'FANN', signalFraction=signalFraction,
901  identifier=identifier)
902  return True
903 
904  if FANNmlp and TMVAfbdt:
905 
906  identifierFBDT = methodPrefixCombinerLevel + 'FBDT'
907  identifierFANN = methodPrefixCombinerLevel + 'FANN'
908 
909  if downloadFlag or useOnlyLocalFlag:
910  identifierFBDT = filesDirectory + '/' + methodPrefixCombinerLevel + 'FBDT' + '_1.root'
911  identifierFANN = filesDirectory + '/' + methodPrefixCombinerLevel + 'FANN' + '_1.root'
912 
913  if not os.path.isfile(identifierFBDT):
914  if downloadFlag:
915  basf2_mva.download(methodPrefixCombinerLevel + 'FBDT', identifierFBDT)
916  if not os.path.isfile(identifierFBDT):
917  B2FATAL('Flavor Tagger: Weight file ' + methodPrefixCombinerLevel + 'FBDT' +
918  '_1.root was not downloaded from Database. Please check the buildOrRevision name. Stopped')
919  else:
920  B2FATAL(
921  'flavorTagger: Combinerlevel FastBDT was not trained with this combination of categories. ' +
922  'Weight file ' + methodPrefixCombinerLevel + 'FBDT' + '_1.root not found. Stopped')
923 
924  if not os.path.isfile(identifierFANN):
925  if downloadFlag:
926  basf2_mva.download(methodPrefixCombinerLevel + 'FANN', identifierFANN)
927  if not os.path.isfile(identifierFANN):
928  B2FATAL('Flavor Tagger: Weight file ' + methodPrefixCombinerLevel + 'FANN' +
929  '_1.root was not downloaded from Database. Please check the buildOrRevision name. Stopped')
930  else:
931  B2FATAL(
932  'flavorTagger: Combinerlevel FANNMLP was not trained with this combination of categories. ' +
933  'Weight file ' + methodPrefixCombinerLevel + 'FANN' + '_1.root not found. Stopped')
934 
935  if os.path.isfile(identifierFBDT) and os.path.isfile(identifierFANN):
936  B2INFO('flavorTagger: Ready to be used with weightFiles ' + methodPrefixCombinerLevel +
937  'FBDT' + '_1.root and ' + methodPrefixCombinerLevel + 'FANN' + '_1.root')
938 
939  B2INFO('flavorTagger: Apply FANNMethod and FBDTMethod on combiner level')
940 
941  mvaMultipleExperts = basf2.register_module('MVAMultipleExperts')
942  mvaMultipleExperts.set_name('MVAMultipleExperts_Combiners')
943  mvaMultipleExperts.param('listNames', [])
944  mvaMultipleExperts.param('extraInfoNames', ['qrCombined' + 'FBDT', 'qrCombined' + 'FANN'])
945  mvaMultipleExperts.param('signalFraction', signalFraction)
946  mvaMultipleExperts.param('identifiers', [identifierFBDT, identifierFANN])
947  path.add_module(mvaMultipleExperts)
948 
949  return True
950 
951 
952 def combinerLevelTeacher(weightFiles='B2JpsiKs_mu'):
953  """
954  Trains the combiner according to the selected categories.
955  """
956 
957  B2INFO('COMBINER LEVEL TEACHER')
958 
959  methodPrefixCombinerLevel = "FlavorTagger_" + getBelleOrBelle2() + "_" + weightFiles + 'Combiner' \
960  + categoriesCombinationCode
961 
962  sampledFilesList = glob.glob(filesDirectory + '/' + methodPrefixCombinerLevel + 'sampled*.root')
963  if len(sampledFilesList) == 0:
964  B2FATAL('FlavorTagger: combinerLevelTeacher did not find any ' +
965  methodPrefixCombinerLevel + 'sampled*.root file. Please run the flavorTagger in "Sampler" mode.')
966 
967  ReadyTMVAfbdt = False
968  ReadyFANNmlp = False
969 
970  if TMVAfbdt:
971 
972  if not os.path.isfile(filesDirectory + '/' + methodPrefixCombinerLevel + 'FBDT' + '_1.root'):
973 
974  B2INFO('flavorTagger: MVA Teacher training a FastBDT on Combiner Level')
975 
976  trainingOptionsCombinerLevel = basf2_mva.GeneralOptions()
977  trainingOptionsCombinerLevel.m_datafiles = basf2_mva.vector(*sampledFilesList)
978  trainingOptionsCombinerLevel.m_treename = methodPrefixCombinerLevel + 'FBDT' + "_tree"
979  trainingOptionsCombinerLevel.m_identifier = filesDirectory + '/' + methodPrefixCombinerLevel + 'FBDT' + "_1.root"
980  trainingOptionsCombinerLevel.m_variables = basf2_mva.vector(*variablesCombinerLevel)
981  trainingOptionsCombinerLevel.m_target_variable = 'qrCombined'
982  trainingOptionsCombinerLevel.m_max_events = maxEventsNumber
983 
984  basf2_mva.teacher(trainingOptionsCombinerLevel, fastBDTCombiner)
985 
986  if uploadFlag:
987  basf2_mva.upload(filesDirectory + '/' + methodPrefixCombinerLevel +
988  'FBDT' + "_1.root", methodPrefixCombinerLevel + 'FBDT')
989 
990  elif FANNmlp and not os.path.isfile(filesDirectory + '/' + methodPrefixCombinerLevel + 'FANN' + '_1.root'):
991 
992  B2INFO('flavorTagger: Combinerlevel FBDT was already trained with this combination of categories. Weight file ' +
993  methodPrefixCombinerLevel + 'FBDT' + '_1.root has been found.')
994 
995  else:
996  B2FATAL('flavorTagger: Combinerlevel was already trained with this combination of categories. Weight files ' +
997  methodPrefixCombinerLevel + 'FBDT' + '_1.root and ' +
998  methodPrefixCombinerLevel + 'FANN' + '_1.root has been found. Please use the "Expert" mode')
999 
1000  if FANNmlp:
1001 
1002  if not os.path.isfile(filesDirectory + '/' + methodPrefixCombinerLevel + 'FANN' + '_1.root'):
1003 
1004  B2INFO('flavorTagger: MVA Teacher training a FANN MLP on Combiner Level')
1005 
1006  trainingOptionsCombinerLevel = basf2_mva.GeneralOptions()
1007  trainingOptionsCombinerLevel.m_datafiles = basf2_mva.vector(*sampledFilesList)
1008  trainingOptionsCombinerLevel.m_treename = methodPrefixCombinerLevel + 'FBDT' + "_tree"
1009  trainingOptionsCombinerLevel.m_identifier = filesDirectory + '/' + methodPrefixCombinerLevel + 'FANN' + "_1.root"
1010  trainingOptionsCombinerLevel.m_variables = basf2_mva.vector(*variablesCombinerLevel)
1011  trainingOptionsCombinerLevel.m_target_variable = 'qrCombined'
1012  trainingOptionsCombinerLevel.m_max_events = maxEventsNumber
1013 
1014  basf2_mva.teacher(trainingOptionsCombinerLevel, mlpFANNCombiner)
1015 
1016  if uploadFlag:
1017  basf2_mva.upload(filesDirectory + '/' + methodPrefixCombinerLevel +
1018  'FANN' + "_1.root", methodPrefixCombinerLevel + 'FANN')
1019 
1020  elif TMVAfbdt and not os.path.isfile(filesDirectory + '/' + methodPrefixCombinerLevel + 'FBDT' + '_1.root'):
1021 
1022  B2INFO('flavorTagger: Combinerlevel FBDT was already trained with this combination of categories. Weight file ' +
1023  methodPrefixCombinerLevel + 'FANN' + '_1.config has been found.')
1024 
1025  else:
1026  B2FATAL('flavorTagger: Combinerlevel was already trained with this combination of categories. Weight files ' +
1027  methodPrefixCombinerLevel + 'FBDT' + '_1.root and ' +
1028  methodPrefixCombinerLevel + 'FANN' + '_1.root has been found. Please use the "Expert" mode')
1029 
1030 
1031 def flavorTagger(
1032  particleLists=[],
1033  mode='Expert',
1034  weightFiles='B2nunubarBGx1',
1035  workingDirectory='.',
1036  combinerMethods=['TMVA-FBDT', 'FANN-MLP'],
1037  categories=[
1038  'Electron',
1039  'IntermediateElectron',
1040  'Muon',
1041  'IntermediateMuon',
1042  'KinLepton',
1043  'IntermediateKinLepton',
1044  'Kaon',
1045  'SlowPion',
1046  'FastHadron',
1047  'Lambda',
1048  'FSC',
1049  'MaximumPstar',
1050  'KaonPion'],
1051  maskName='',
1052  saveCategoriesInfo=True,
1053  useOnlyLocalWeightFiles=False,
1054  downloadFromDatabaseIfNotFound=False,
1055  uploadToDatabaseAfterTraining=False,
1056  samplerFileId='',
1057  path=None,
1058 ):
1059  """
1060  Defines the whole flavor tagging process for each selected Rest of Event (ROE) built in the steering file.
1061  The flavor is predicted by Multivariate Methods trained with Variables and MetaVariables which use
1062  Tracks, ECL- and KLMClusters from the corresponding RestOfEvent dataobject.
1063  This module can be used to sample the training information, to train and/or to test the flavorTagger.
1064 
1065  @param particleLists The ROEs for flavor tagging are selected from the given particle lists.
1066  @param mode The available modes are
1067  ``Expert`` (default), ``Sampler``, and ``Teacher``. In the ``Expert`` mode
1068  Flavor Tagging is applied to the analysis,. In the ``Sampler`` mode you save
1069  save the variables for training. In the ``Teacher`` mode the FlavorTagger is
1070  trained, for this step you do not reconstruct any particle or do any analysis,
1071  you just run the flavorTagger alone.
1072  @param weightFiles Weight files name. Default=
1073  ``B2nunubarBGx1`` (official weight files). If the user self
1074  wants to train the FlavorTagger, the weightfiles name should correspond to the
1075  analysed CP channel in order to avoid confusions. The default name
1076  ``B2nunubarBGx1`` corresponds to
1077  :math:`B^0_{\\rm sig}\\to \\nu \\overline{\\nu}`.
1078  and ``B2JpsiKs_muBGx1`` to
1079  :math:`B^0_{\\rm sig}\\to J/\\psi (\\to \\mu^+ \\mu^-) K_s (\\to \\pi^+ \\pi^-)`.
1080  BGx1 stays for events simulated with background.
1081  @param workingDirectory Path to the directory containing the FlavorTagging/ folder.
1082  @param combinerMethods MVAs for the combiner: ``TMVA-FBDT`` or ``FANN-MLP``. Both used by default.
1083  @param categories Categories used for flavor tagging. By default all are used.
1084  @param maskName Gets ROE particles from a specified ROE mask.
1085  @param saveCategoriesInfo Sets to save information of individual categories.
1086  @param useOnlyLocalWeightFiles [Expert] Uses only locally saved weight files.
1087  @param downloadFromDatabaseIfNotFound [Expert] Weight files are downloaded from
1088  the conditions database if not available in workingDirectory.
1089  @param uploadToDatabaseAfterTraining [Expert] For librarians only: uploads weight files to localdb after training.
1090  @param samplerFileId Identifier to paralellize
1091  sampling. Only used in ``Sampler`` mode. If you are training by yourself and
1092  want to parallelize the sampling, you can run several sampling scripts in
1093  parallel. By changing this parameter you will not overwrite an older sample.
1094  @param path Modules are added to this path
1095 
1096  """
1097 
1098  if mode != 'Sampler' and mode != 'Teacher' and mode != 'Expert':
1099  B2FATAL('flavorTagger: Wrong mode given: The available modes are "Sampler", "Teacher" or "Expert"')
1100 
1101  # Directory where the weights of the trained Methods are saved
1102  # workingDirectory = os.environ['BELLE2_LOCAL_DIR'] + '/analysis/data'
1103 
1104  if not Belle2.FileSystem.findFile(workingDirectory, True):
1105  B2FATAL('flavorTagger: THE GIVEN WORKING DIRECTORY "' + workingDirectory + '" DOES NOT EXIST! PLEASE SPECIFY A VALID PATH.')
1106 
1107  global filesDirectory
1108  filesDirectory = workingDirectory + '/FlavorTagging/TrainedMethods'
1109 
1110  if mode == 'Sampler' or (mode == 'Expert' and downloadFromDatabaseIfNotFound):
1111  if not Belle2.FileSystem.findFile(workingDirectory + '/FlavorTagging', True):
1112  os.mkdir(workingDirectory + '/FlavorTagging')
1113  os.mkdir(workingDirectory + '/FlavorTagging/TrainedMethods')
1114  elif not Belle2.FileSystem.findFile(workingDirectory + '/FlavorTagging/TrainedMethods', True):
1115  os.mkdir(workingDirectory + '/FlavorTagging/TrainedMethods')
1116  filesDirectory = workingDirectory + '/FlavorTagging/TrainedMethods'
1117 
1118  if len(combinerMethods) < 1 or len(combinerMethods) > 2:
1119  B2FATAL('flavorTagger: Invalid list of combinerMethods. The available methods are "TMVA-FBDT" and "FANN-MLP"')
1120 
1121  global FANNmlp
1122  global TMVAfbdt
1123 
1124  FANNmlp = False
1125  TMVAfbdt = False
1126 
1127  for method in combinerMethods:
1128  if method == 'TMVA-FBDT':
1129  TMVAfbdt = True
1130  elif method == 'FANN-MLP':
1131  FANNmlp = True
1132  else:
1133  B2FATAL('flavorTagger: Invalid list of combinerMethods. The available methods are "TMVA-FBDT" and "FANN-MLP"')
1134 
1135  global fileId
1136  fileId = samplerFileId
1137 
1138  global useOnlyLocalFlag
1139  useOnlyLocalFlag = useOnlyLocalWeightFiles
1140 
1141  B2INFO('*** FLAVOR TAGGING ***')
1142  B2INFO(' ')
1143  B2INFO(' Working directory is: ' + filesDirectory)
1144  B2INFO(' ')
1145 
1146  setInteractionWithDatabase(downloadFromDatabaseIfNotFound, uploadToDatabaseAfterTraining)
1147  WhichCategories(categories)
1148  set_FlavorTagger_pid_aliases()
1149  setVariables()
1150 
1151  roe_path = basf2.create_path()
1152  deadEndPath = basf2.create_path()
1153 
1154  # Events containing ROE without B-Meson (but not empty) are discarded for training
1155  if mode == 'Sampler':
1156  ma.signalSideParticleListsFilter(
1157  particleLists,
1158  'nROE_Charged(' + maskName + ', 0) > 0 and abs(qrCombined) == 1',
1159  roe_path,
1160  deadEndPath)
1161 
1162  # If trigger returns 1 jump into empty path skipping further modules in roe_path
1163  if mode == 'Expert':
1164  ma.signalSideParticleListsFilter(particleLists, 'nROE_Charged(' + maskName + ', 0) > 0', roe_path, deadEndPath)
1165  # Initialation of flavorTaggerInfo dataObject needs to be done in the main path
1166  flavorTaggerInfoBuilder = basf2.register_module('FlavorTaggerInfoBuilder')
1167  path.add_module(flavorTaggerInfoBuilder)
1168 
1169  # sampler or expert
1170  if mode == 'Sampler' or mode == 'Expert':
1171  if FillParticleLists(mode, maskName, roe_path):
1172  if eventLevel(mode, weightFiles, roe_path):
1173  combinerLevel(mode, weightFiles, roe_path)
1174  if mode == 'Expert':
1175  flavorTaggerInfoFiller = basf2.register_module('FlavorTaggerInfoFiller')
1176  flavorTaggerInfoFiller.param('trackLevelParticleLists', trackLevelParticleLists)
1177  flavorTaggerInfoFiller.param('eventLevelParticleLists', eventLevelParticleLists)
1178  flavorTaggerInfoFiller.param('TMVAfbdt', TMVAfbdt)
1179  flavorTaggerInfoFiller.param('FANNmlp', FANNmlp)
1180  flavorTaggerInfoFiller.param('qpCategories', saveCategoriesInfo)
1181  flavorTaggerInfoFiller.param('istrueCategories', saveCategoriesInfo)
1182  flavorTaggerInfoFiller.param('targetProb', False)
1183  flavorTaggerInfoFiller.param('trackPointers', False)
1184  roe_path.add_module(flavorTaggerInfoFiller) # Add FlavorTag Info filler to roe_path
1185  add_default_FlavorTagger_aliases()
1186 
1187  # Removes EventExtraInfos and ParticleExtraInfos of the EventParticleLists
1188  particleListsToRemoveExtraInfo = []
1189  for particleList in eventLevelParticleLists:
1190  if particleList[0] not in particleListsToRemoveExtraInfo:
1191  particleListsToRemoveExtraInfo.append(particleList[0])
1192 
1193  if mode == 'Expert':
1194  ma.removeExtraInfo(particleListsToRemoveExtraInfo, True, roe_path)
1195 
1196  elif mode == 'Sampler':
1197  ma.removeExtraInfo(particleListsToRemoveExtraInfo, False, roe_path)
1198 
1199  path.for_each('RestOfEvent', 'RestOfEvents', roe_path)
1200 
1201  if mode == 'Teacher':
1202  if eventLevelTeacher(weightFiles):
1203  combinerLevelTeacher(weightFiles)
1204 
1205 
1206 if __name__ == '__main__':
1207 
1208  desc_list = []
1209 
1210  function = globals()["flavorTagger"]
1211  signature = inspect.formatargspec(*inspect.getfullargspec(function))
1212  desc_list.append((function.__name__, signature + '\n' + function.__doc__))
1213 
1214  from terminal_utils import Pager
1215  from basf2.utils import pretty_print_description_list
1216  with Pager('Flavor Tagger function accepts the following arguments:'):
1217  pretty_print_description_list(desc_list)
b2bii.isB2BII
def isB2BII()
Definition: b2bii.py:6
basf2.utils
Definition: utils.py:1
flavorTagger
Definition: flavorTagger.py:1
Belle2::FileSystem::findFile
static std::string findFile(const std::string &path, bool silent=false)
Search for given file or directory in local or central release directory, and return absolute path if...
Definition: FileSystem.cc:147