Belle II Software  release-06-01-15
flavorTaggerVertexingValidation.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 
30 
31 import basf2 as b2
32 import modularAnalysis as ma
33 import flavorTagger as ft
34 from dft import DeepFlavorTagger
35 import vertex as vx
36 import variables.collections as vc
37 import variables.utils as vu
38 from ROOT import Belle2
39 import argparse
40 import os
41 
42 
43 def getCommandLineOptions():
44  """ Parses the command line options for the CPV validation and returns the corresponding arguments. """
45 
46  parser = argparse.ArgumentParser(description='Script for the validation of CPV tools:\
47  it defines the procedure to sample the training set, train and test the flavor tagger\
48  as well as to reconstruct the vertices of B0-> J/psi K_S0 and of the tag-side B0\
49  using the tagV module.\n\
50  Usage: basf2 -i inputMDST.root flavorTaggerVertexingValidation.py -- -m Sampler -dc JPsiKs')
51 
52  parser.add_argument('-bob2', '--belleOrBelle2Flag', dest='belleOrBelle2Flag',
53  type=str, default='Belle2', choices=['Belle', 'Belle2'],
54  help='Choose Belle for converted Belle data or MC, otherwise choose Belle2.')
55  parser.add_argument('-m', '--mode', dest='mode', type=str, required=True,
56  choices=['Sampler', 'Teacher', 'Expert'],
57  help='Working mode of the flavor tagger. Choose Sampler, Teacher or Expert.')
58  parser.add_argument('-trc', '--decayChannelTrainedOn', dest='decayChannelTrainedOn',
59  type=str, default='nunubar',
60  help='Decay channel of the weight files. Official samples available are JPsiKs or nunubar.')
61  parser.add_argument('-dc', '--decayChannel', dest='decayChannel', type=str, required=True,
62  choices=['JPsiKs', 'nunubar'], help='Decay channel that will be reconstructed. Choose JPsiKs or nunubar.')
63  parser.add_argument('-mct', '--mcType', dest='mcType', type=str, default='BGx1',
64  choices=['BGx0', 'BGx1'], help='Type of files. Choose BGx0 for background free Belle II MC. \n' +
65  'Otherwise choose BGx1 for BelleII MC with bkg. or for converted Belle data or MC.')
66  parser.add_argument('-fn', '--fileNumber', dest='fileNumber', type=str, default='',
67  help='A file number (when sampling in parallel).')
68  parser.add_argument('-wd', '--workingDirectory', dest='workingDirectory', type=str, default='.',
69  help='Path where the training samples and the weight files are saved.')
70  parser.add_argument('-sd', '--savingDirectory', dest='savingDirectory', type=str, default='.',
71  help='Path where the analyzed output files are saved.')
72  parser.add_argument('-dv', '--doVertex', dest='doVertex', type=bool, default=False,
73  help='Reconstruct B vertices True or False')
74  parser.add_argument('-bd', '--belleData', dest='belleData', type=str, default='',
75  choices=['', 'BelleDataConv'], help='Choose BelleDataConv only for Belle Data in Expert mode.')
76  args = parser.parse_args()
77 
78  if args.belleData == "BelleDataConv":
79  if args.belleOrBelle2Flag != "Belle":
80  b2.B2FATAL("BelleDataConv only for Belle Data.")
81  if args.mode != "Expert":
82  b2.B2FATAL("BelleDataConv only in Expert mode.")
83  if args.mcType != "BGx1":
84  b2.B2FATAL("When using BelleDataConv, mcType must be set to BGx1.")
85 
86  return args
87 
88 
89 def setEnvironment(belleOrBelle2Flag="Belle2"):
90  """
91  Sets the environment to analyse the mdst files for validation.'
92 
93  @param belleOrBelle2Flag Default is 'Belle2' but 'Belle' is possible.
94  """
95 
96  environmentType = "default"
97 
98  if belleOrBelle2Flag == "Belle":
99 
100  from b2biiConversion import convertBelleMdstToBelleIIMdst
101 
102  os.environ['BELLE_POSTGRES_SERVER'] = 'can51'
103  os.environ['USE_GRAND_REPROCESS_DATA'] = '1'
104 
105  environmentType = "Belle"
106 
107  inputFileList = []
108  for iFile in Belle2.Environment.Instance().getInputFilesOverride():
109  inputFileList.append(str(iFile))
110 
111  convertBelleMdstToBelleIIMdst(inputBelleMDSTFile=inputFileList, path=cp_val_path)
112 
113  else:
114  ma.inputMdstList(environmentType=environmentType, filelist=[], path=cp_val_path)
115 
116 
117 def reconstructB2JpsiKs_mu(belleOrBelle2Flag='Belle2'):
118  """
119  Defines the reconstruction procedure for the benchmark channel 'B0 -> J/psi K_S0'
120 
121  @param belleOrBelle2Flag Default is 'Belle2' but 'Belle' is possible.
122  """
123 
124  # reconstruct J/psi -> mu+ mu- decay using standard muon list and perform MC association
125  ma.fillParticleList(decayString='mu+:all', cut='', path=cp_val_path)
126  ma.reconstructDecay(decayString='J/psi:mumu -> mu+:all mu-:all', cut='abs(dM) < 0.11', path=cp_val_path)
127  ma.matchMCTruth(list_name='J/psi:mumu', path=cp_val_path)
128 
129  if belleOrBelle2Flag == "Belle":
130 
131  # use the existent K_S0:mdst list
132  ma.matchMCTruth(list_name='K_S0:mdst', path=cp_val_path)
133 
134  # reconstruct B0 -> J/psi Ks decay
135  ma.reconstructDecay(decayString='B0:sig -> J/psi:mumu K_S0:mdst', cut='Mbc > 5.2 and abs(deltaE) < 0.15', path=cp_val_path)
136 
137  if belleOrBelle2Flag == "Belle2":
138 
139  # reconstruct Ks from standard pi+ particle list
140  ma.fillParticleList(decayString='pi+:all', cut='', path=cp_val_path)
141  ma.reconstructDecay(decayString='K_S0:pipi -> pi+:all pi-:all', cut='abs(dM) < 0.25', path=cp_val_path)
142 
143  # reconstruct B0 -> J/psi Ks decay
144  ma.reconstructDecay(decayString='B0:sig -> J/psi:mumu K_S0:pipi', cut='Mbc > 5.2 and abs(deltaE) < 0.15', path=cp_val_path)
145 
146 
147 def reconstructB2nunubar():
148  """
149  Defines the procedure to create a B0 list for the benchmark channel 'B0 -> nu_tau anti-nu_tau'
150  """
151 
152  ma.fillParticleListFromMC('nu_tau:MC', '', path=cp_val_path)
153  ma.reconstructMCDecay('B0:sig -> nu_tau:MC anti-nu_tau:MC', '', writeOut=True, path=cp_val_path)
154 
155 
156 def mcMatchAndBuildROE(belleOrBelle2Flag='Belle2'):
157  """
158  Runs the mc matching and creates the rest of event for the signal particle list.'
159 
160  @param belleOrBelle2Flag Default is 'Belle2' but 'Belle' is possible.
161  """
162 
163  # perform MC matching (MC truth asociation). Always before TagV
164  ma.matchMCTruth(list_name='B0:sig', path=cp_val_path)
165 
166  # build the rest of the event associated to the B0
167  ma.buildRestOfEvent(target_list_name='B0:sig', path=cp_val_path)
168 
169 
170 def applyCPVTools(mode='Expert'):
171  """
172  Defines the procedure to use the flavor tagger and tagV on the signal 'B0:sig' list.
173  It saves also all variables to nTuples needed for evaluation of the performance
174 
175  @param mode Default is 'Expert' but also needed for 'Sampler' mode.
176  """
177 
178  if mode == 'Sampler':
179 
180  ft.flavorTagger(
181  particleLists=['B0:sig'],
182  mode=mode,
183  weightFiles='B2' + decayChannelTrainedOn + mcType,
184  combinerMethods=['TMVA-FBDT', 'FANN-MLP'],
185  useOnlyLocalWeightFiles=True,
186  downloadFromDatabaseIfNotFound=False,
187  workingDirectory=workingDirectory,
188  samplerFileId=str(fileNumber),
189  path=cp_val_path)
190 
191  if mode == 'Expert':
192 
193  ft.flavorTagger(
194  particleLists=['B0:sig'],
195  combinerMethods=['TMVA-FBDT', 'FANN-MLP'],
196  weightFiles='B2' + decayChannelTrainedOn + mcType,
197  useOnlyLocalWeightFiles=True,
198  downloadFromDatabaseIfNotFound=False,
199  workingDirectory=workingDirectory,
200  samplerFileId=str(fileNumber),
201  path=cp_val_path)
202 
203  # # Preliminarily, DNN Identifier has to be set by hand when validating
204  # # The standard name should be however
205  # This is temporary till the DNN gets retrained.
206  dnnIdentifier = "FlavorTagger_" + belleOrBelle2Flag + "_B2nunubarBGx1OptimizedForDataDNN"
207  if belleOrBelle2Flag == "Belle":
208  dnnIdentifier = "FlavorTagger_" + belleOrBelle2Flag + "_B2nunubarBGx1DNN"
209  b2.conditions.append_globaltag("analysis_tools_release-04-00")
210  DeepFlavorTagger.DeepFlavorTagger('B0:sig',
211  mode='expert',
212  working_dir='',
213  uniqueIdentifier=dnnIdentifier,
214  path=cp_val_path)
215 
216  if doVertex or mode == 'Expert':
217 
218  if doVertex:
219  if decayChannel == "JPsiKs":
220  # vx.kFit(list_name='B0:sig', conf_level=0.0, decay_string='B0:sig -> [J/psi:mumu -> ^mu+ ^mu-] K_S0',
221  # constraint='', path=cp_val_path)
222  vx.treeFit(list_name='B0:sig', conf_level=-2, path=cp_val_path)
223  vx.TagV(list_name='B0:sig', MCassociation='breco', path=cp_val_path)
224  print("TagV will be used")
225 
226  # Select variables that will be stored to ntuple
227  fs_vars = vc.pid + vc.track + vc.track_hits + vc.mc_truth
228  jpsiandk0s_vars = vc.mc_truth
229  vertex_vars = vc.vertex + vc.mc_vertex + vc.kinematics + vc.mc_kinematics
230  bvars = vc.reco_stats + \
231  vc.deltae_mbc + \
232  vc.mc_truth + \
233  vc.roe_multiplicities + \
234  vc.tag_vertex + \
235  vc.mc_tag_vertex + \
236  vertex_vars
237 
238  if decayChannel == "JPsiKs":
239  bvars = bvars + \
240  vu.create_aliases_for_selected(list_of_variables=fs_vars,
241  decay_string='B0 -> [J/psi -> ^mu+ ^mu-] [K_S0 -> ^pi+ ^pi-]') + \
242  vu.create_aliases_for_selected(list_of_variables=jpsiandk0s_vars,
243  decay_string='B0 -> [^J/psi -> mu+ mu-] [^K_S0 -> pi+ pi-]') + \
244  vu.create_aliases_for_selected(list_of_variables=vertex_vars,
245  decay_string='B0 -> [^J/psi -> ^mu+ ^mu-] [^K_S0 -> ^pi+ ^pi-]')
246  if mode == 'Expert':
247  bvars += ft.flavor_tagging + ['DNN_qrCombined', 'extraInfo(dnn_output)']
248  else:
249  vu._variablemanager.addAlias('qrMC', 'isRelatedRestOfEventB0Flavor')
250  bvars += ['qrMC']
251 
252  # Saving variables to ntuple
253  ma.variablesToNtuple(decayString='B0:sig',
254  variables=bvars,
255  filename=savingDirectory + '/' + 'B2A801-FlavorTagger' +
256  mode + str(fileNumber) + belleOrBelle2Flag + mcType + belleData + '.root',
257  treename='B0tree',
258  path=cp_val_path)
259 
260  ma.summaryOfLists(particleLists=['B0:sig'], path=cp_val_path)
261 
262 
263 if __name__ == '__main__':
264 
265  args = getCommandLineOptions()
266 
267  belleOrBelle2Flag = args.belleOrBelle2Flag
268  mode = args.mode
269  decayChannelTrainedOn = args.decayChannelTrainedOn
270  decayChannel = args.decayChannel
271  mcType = args.mcType
272  fileNumber = args.fileNumber
273  workingDirectory = args.workingDirectory
274  savingDirectory = args.savingDirectory
275  doVertex = args.doVertex
276  belleData = args.belleData
277 
278  if decayChannelTrainedOn == 'JPsiKs':
279  decayChannelTrainedOn = 'JpsiKs_mu'
280 
281  cp_val_path = b2.Path()
282 
283  if mode == "Sampler" or mode == "Expert":
284 
285  setEnvironment(belleOrBelle2Flag=belleOrBelle2Flag)
286 
287  if decayChannel == "nunubar":
288  reconstructB2nunubar()
289 
290  elif decayChannel == "JPsiKs":
291  reconstructB2JpsiKs_mu(belleOrBelle2Flag=belleOrBelle2Flag)
292 
293  mcMatchAndBuildROE(belleOrBelle2Flag=belleOrBelle2Flag)
294  applyCPVTools(mode=mode)
295  b2.process(cp_val_path)
296  print(b2.statistics)
297 
298  if mode == "Teacher":
299 
300  ft.flavorTagger(
301  particleLists=[],
302  mode='Teacher',
303  weightFiles='B2' + decayChannelTrainedOn + mcType,
304  combinerMethods=['TMVA-FBDT', 'FANN-MLP'],
305  useOnlyLocalWeightFiles=True,
306  downloadFromDatabaseIfNotFound=False,
307  uploadToDatabaseAfterTraining=True,
308  workingDirectory=workingDirectory,
309  path=cp_val_path)
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:29