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