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