Belle II Software  release-08-01-10
asymmetriesInVariablesPlots.py
1 #!/usr/bin/env python3
2 
3 
10 
11 
24 
25 import os
26 import glob
27 import math
28 from matplotlib.ticker import FormatStrFormatter
29 import matplotlib.pyplot as plt
30 import ROOT
31 from ROOT import Belle2
32 import sys
33 import basf2 as b2
34 import flavorTagger as ft
35 from inputVariablesPlots import variablesPlotParamsDict, categories
36 
37 import numpy as np
38 import matplotlib as mpl
39 mpl.use('Agg')
40 mpl.rcParams.update({'font.size': 22})
41 mpl.rcParams['text.usetex'] = True
42 mpl.rcParams['text.latex.preamble'] = [r"\usepackage{amsmath}"]
43 
44 
45 if len(sys.argv) != 5:
46  sys.exit("Must provide 4 arguments: [Belle or Belle2] [BGx0 or BGx1] [training] [workingDirectory]"
47  )
48 
49 belleOrBelle2 = sys.argv[1]
50 MCtype = str(sys.argv[2])
51 decayChannelTrainedOn = str(sys.argv[3]) # Decay channel of the weight files "JPsiKs" or "nunubar"
52 workingDirectory = sys.argv[4]
53 
54 filesDirectory = workingDirectory + '/FlavorTagging/TrainedMethods'
55 
56 if decayChannelTrainedOn == 'JPsiKs':
57  decayChannelTrainedOn = 'JpsiKs_mu'
58 
59 weightFiles = 'B2' + decayChannelTrainedOn + MCtype
60 
61 ROOT.TH1.SetDefaultSumw2()
62 
63 allInputVariables = []
64 
65 belleOrBelle2Flag = belleOrBelle2
66 
67 identifiersExtraInfosDict = dict()
68 identifiersExtraInfosKaonPion = []
69 
70 dBw = 50
71 
72 pBins = 50
73 fBins = 100
74 
75 unitImp = "mm"
76 
77 if belleOrBelle2 == "Belle":
78  unitImp = "cm"
79 
80 
81 # particle Label, PDG for negative, PDG for positive particle
82 
83 particleConditions = {'e+:inRoe': ['e', " mcPDG > 0 ", " mcPDG < 0 "], 'mu+:inRoe': [r'\mu', " mcPDG > 0 ", " mcPDG < 0 "],
84  'lepton+:inRoe': ['l', " mcPDG > 0 ", " mcPDG < 0 "],
85  'K+:inRoe': ['K', " mcPDG < 0 ", " mcPDG > 0 "], 'pi+:inRoe': [r'\pi', " mcPDG < 0 ", " mcPDG > 0 "],
86  'h+:inRoe': ['h', " mcPDG < 0 ", " mcPDG > 0 "], 'Lambda0:inRoe': [r'\Lambda', " mcPDG < 0 ", " mcPDG > 0 "]}
87 
88 
89 if not b2.find_file('AsymmetriesInVariablesPlots', silent=True):
90  os.mkdir('./AsymmetriesInVariablesPlots')
91 
92 
93 for (particleList, category, _) in ft.getEventLevelParticleLists(categories):
94 
95  # if category != "KinLepton":
96  # continue
97 
98  if not b2.find_file('AsymmetriesInVariablesPlots/' + category, silent=True):
99  os.mkdir('./AsymmetriesInVariablesPlots/' + category)
100 
101  if particleList not in identifiersExtraInfosDict and category != 'KaonPion':
102  identifiersExtraInfosDict[particleList] = []
103 
104  methodPrefixEventLevel = "FlavorTagger_" + belleOrBelle2Flag + "_" + weightFiles + 'EventLevel' + category + 'FBDT'
105  treeName = methodPrefixEventLevel + "_tree"
106  targetVariable = 'isRightCategory(' + category + ')'
107 
108  tree = ROOT.TChain(treeName)
109 
110  workingFiles = glob.glob(filesDirectory + '/' + methodPrefixEventLevel + 'sampled*.root')
111  # workingFiles = glob.glob(filesDirectory + '/' + methodPrefixEventLevel + 'sampled1?.root')
112 
113  for iFile in workingFiles:
114  tree.AddFile(iFile)
115 
116  categoryInputVariables = []
117  trulyUsedInputVariables = []
118  for iVariable in tree.GetListOfBranches():
119 
120  managerVariableName = str(Belle2.MakeROOTCompatible.invertMakeROOTCompatible(iVariable.GetName()))
121 
122  if managerVariableName in ft.getTrainingVariables(category) or managerVariableName == 'distance' or\
123  managerVariableName == 'z0' or managerVariableName == 'ImpactXY' or\
124  managerVariableName == 'y' or managerVariableName == 'OBoost':
125  if managerVariableName in categoryInputVariables:
126  continue
127 
128  categoryInputVariables.append(managerVariableName)
129  if managerVariableName in ft.getTrainingVariables(category):
130  allInputVariables.append((category, managerVariableName))
131  trulyUsedInputVariables.append((category, managerVariableName))
132 
133  if managerVariableName not in identifiersExtraInfosDict[particleList] and category != 'KaonPion':
134  identifiersExtraInfosDict[particleList].append(managerVariableName)
135 
136  elif category == 'KaonPion' and managerVariableName not in identifiersExtraInfosKaonPion:
137  identifiersExtraInfosKaonPion.append(managerVariableName)
138 
139  print("The number of variables used in " + category + " is = ", len(trulyUsedInputVariables))
140 
141  if category != 'KaonPion' and category != 'FSC' and category != 'MaximumPstar' and\
142  category != 'FastHadron' and category != 'Lambda':
143  categoryInputVariables.append('BtagToWBosonVariables(recoilMass)')
144 
145  for inputVariable in categoryInputVariables:
146 
147  # if not (inputVariable == 'z0' or inputVariable == 'ImpactXY' or inputVariable == 'y' or inputVariable == 'OBoost'):
148  # continue
149 
150  print(inputVariable)
151 
152  nBins = variablesPlotParamsDict[inputVariable][1]
153  limXmin = variablesPlotParamsDict[inputVariable][2]
154  limXmax = variablesPlotParamsDict[inputVariable][3]
155 
156  if belleOrBelle2 == "Belle2":
157  if inputVariable == 'distance':
158  limXmax = 1.0
159 
160  if inputVariable == 'ImpactXY':
161  limXmax = 0.3
162 
163  if category == "SlowPion":
164  if inputVariable == 'p' or inputVariable == 'useCMSFrame(p)' or\
165  inputVariable == 'pt' or inputVariable == 'useCMSFrame(pt)':
166  nBins = 150
167  limXmax = 1.5
168 
169  if inputVariable == 'distance':
170  nBins = 80
171  limXmax = 2.4
172 
173  if inputVariable == 'ImpactXY':
174  nBins = 80
175  limXmax = 0.8
176 
177  if category == "Lambda":
178  if inputVariable == 'distance':
179  # nBins = 25
180  limXmax = 10
181 
182  if inputVariable == 'chiProb':
183  nBins = 25
184 
185  additionalCond = ''
186 
187  if category == "FastHadron":
188  particleList = 'h+:inRoe'
189 
190  if category == "KinLepton" or category == "IntermediateKinLepton":
191  particleList = 'lepton+:inRoe'
192 
193  negativeHistogram = ROOT.TH1F("negative" + category + str(Belle2.MakeROOTCompatible.makeROOTCompatible(inputVariable)), "",
194  nBins,
195  limXmin,
196  limXmax)
197  positiveHistogram = ROOT.TH1F("positive" + category + str(Belle2.MakeROOTCompatible.makeROOTCompatible(inputVariable)), "",
198  nBins,
199  limXmin,
200  limXmax)
201 
202  factorMultiplication = ''
203 
204  if belleOrBelle2 == "Belle2" and ((category != "Lambda" and inputVariable == 'distance') or inputVariable ==
205  'z0' or inputVariable == 'ImpactXY' or inputVariable == 'y' or inputVariable == 'OBoost'):
206  factorMultiplication = "*10 "
207 
208  tree.Draw(variablesPlotParamsDict[inputVariable][0] +
209  factorMultiplication +
210  ">> negative" +
211  category +
212  str(Belle2.MakeROOTCompatible.makeROOTCompatible(inputVariable)), additionalCond +
213  "abs(" +
215  ") > 0 && " +
216  particleConditions[particleList][1])
217 
218  tree.Draw(variablesPlotParamsDict[inputVariable][0] +
219  factorMultiplication +
220  ">> positive" +
221  category +
222  str(Belle2.MakeROOTCompatible.makeROOTCompatible(inputVariable)), additionalCond +
223  "abs(" +
225  ") > 0 && " +
226  particleConditions[particleList][2])
227 
228  negativeScalingFactor = negativeHistogram.Integral()
229  positiveScalingFactor = positiveHistogram.Integral()
230 
231  if negativeScalingFactor == 0:
232  negativeScalingFactor = 1
233 
234  if positiveScalingFactor == 0:
235  positiveScalingFactor = 1
236 
237  negativeHistogram.Scale(1 / negativeScalingFactor)
238  positiveHistogram.Scale(1 / positiveScalingFactor)
239 
240  negativeArray = np.zeros((negativeHistogram.GetNbinsX(), 2))
241  positiveArray = np.zeros((positiveHistogram.GetNbinsX(), 2))
242 
243  asymmetryArray = np.zeros((positiveHistogram.GetNbinsX(), 2))
244  asymmetryArrayUncertainties = np.zeros((positiveHistogram.GetNbinsX(), 2))
245 
246  for i in range(0, negativeHistogram.GetNbinsX()):
247  negativeArray[i] = np.array([negativeHistogram.GetBinCenter(i + 1), negativeHistogram.GetBinContent(i + 1)])
248  positiveArray[i] = np.array([positiveHistogram.GetBinCenter(i + 1), positiveHistogram.GetBinContent(i + 1)])
249 
250  numerator = float(positiveArray[i][1] - negativeArray[i][1])
251  denominator = float(positiveArray[i][1] + negativeArray[i][1])
252 
253  if denominator == 0:
254  asymmetryArray[i] = np.array([negativeHistogram.GetBinCenter(i + 1), 0])
255  asymmetryArrayUncertainties[i] = np.array([negativeHistogram.GetBinCenter(i + 1), 0])
256  else:
257  asymmetryArray[i] = np.array([negativeHistogram.GetBinCenter(i + 1), float(numerator / denominator)])
258 
259  uncertainty = 2 * math.sqrt((negativeArray[i][1] * negativeHistogram.GetBinError(i + 1))**2 + (
260  positiveArray[i][1] * positiveHistogram.GetBinError(i + 1))**2) / (negativeArray[i][1] + positiveArray[i][1])**2
261 
262  asymmetryArrayUncertainties[i] = np.array([negativeHistogram.GetBinCenter(i + 1), uncertainty])
263 
264  fig1 = plt.figure(1, figsize=(11, 11))
265 
266  # if inputVariable == 'Kid_dEdx' or inputVariable == 'muid_dEdx':
267  # ax1 = plt.axes([0.18, 0.17, 0.75, 0.8])
268  # if inputVariable == 'pi_vs_edEdxid':
269  # ax1 = plt.axes([0.18, 0.187, 0.75, 0.805])
270  # else:
271  ax1 = plt.axes([0.19, 0.37, 0.76, 0.60])
272 
273  # print(negativeArray.shape, negativeHistogram.GetNbinsX(), )
274  # print(negativeArray)
275  ax1.hist(
276  negativeArray[:, 0], weights=negativeArray[:, 1], bins=negativeHistogram.GetNbinsX(),
277  histtype='step', edgecolor='b', linewidth=4.5, linestyle='dashed',
278  label=r'$' + particleConditions[particleList][0] + '^{-} $')
279 
280  ax1.hist(positiveArray[:, 0], weights=positiveArray[:, 1], bins=positiveHistogram.GetNbinsX(),
281  histtype='step', edgecolor='r', linewidth=4, alpha=0.7,
282  label=r'$' + particleConditions[particleList][0] + '^{+} $') # hatch='.',
283 
284  p1, = ax1.plot([], label=r'$' + particleConditions[particleList][0] + '^{-} $',
285  linewidth=5.5, linestyle='dashed', c='b')
286  p2, = ax1.plot([], label=r'$' + particleConditions[particleList][0] +
287  '^{+} $', linewidth=5, linestyle='solid', alpha=0.9, c='r')
288 
289  binWidth = negativeHistogram.GetBinWidth(2)
290 
291  if inputVariable == 'lambdaZError': # or inputVariable == 'ImpactXY' or\
292  # (category != "Lambda" and inputVariable == 'distance'):
293  binWidth = binWidth * 10
294 
295  if inputVariable == 'M':
296  binWidth = binWidth * 1000
297 
298  if category == "Lambda" and inputVariable == 'distance':
299  variablesPlotParamsDict[inputVariable][5] = r"{\rm cm}\, "
300 
301  binWidth = '{:8.2f}'.format(binWidth)
302 
303  legendLocation = 1
304  ax1.set_ylabel(r'${\rm Fraction\hspace{0.25em} of\hspace{0.25em} Events}\, /\, (\, ' + binWidth + r'\, ' +
305  variablesPlotParamsDict[inputVariable][5] + r')$', fontsize=35)
306  if inputVariable == 'extraInfo(isRightCategory(Kaon))' or\
307  inputVariable == 'HighestProbInCat(pi+:inRoe, isRightCategory(SlowPion))':
308  legendLocation = 3
309  ax1.set_yscale('log', nonposy='clip')
310  else:
311  ax1.yaxis.set_major_formatter(FormatStrFormatter(r'$%.2f$'))
312 
313  # ax1.set_ylim(0, 1.4)
314  ax1.set_xlim(limXmin, limXmax)
315 
316  locs, labels = plt.xticks()
317  empty_string_labels = [''] * len(labels)
318  plt.locator_params(axis='x', nbins=len(labels))
319  ax1.set_xticklabels(empty_string_labels)
320  ax1.tick_params(axis='y', labelsize=37)
321 
322  if inputVariable.find('ARICH') != -1 or inputVariable.find('TOP') != -1 or \
323  inputVariable == 'cosTPTO' or inputVariable.find('KLM') != -1 or\
324  inputVariable == 'cosTheta' or inputVariable == 'FSCVariables(cosTPTOFast)' or\
325  inputVariable == 'KaonPionVariables(cosKaonPion)':
326  legendLocation = 2
327 
328  elif inputVariable == 'FSCVariables(SlowFastHaveOpositeCharges)' or \
329  inputVariable == 'KaonPionVariables(HaveOpositeCharges)' or inputVariable == "eid_ECL" or \
330  inputVariable.find('ID') != -1 or inputVariable.find('dEdx') != -1:
331  legendLocation = 9
332 
333  if inputVariable == 'muid_dEdx':
334  if category != 'KinLepton':
335  legendLocation = 8
336 
337  ax1.legend([p1, p2], [r'$' +
338  particleConditions[particleList][0] +
339  '^{-} $', r'$' +
340  particleConditions[particleList][0] +
341  '^{+} $'], prop={'size': 50}, loc=legendLocation, numpoints=1, handlelength=1)
342  ax1.grid(True)
343 
344  ax2 = plt.axes([0.19, 0.15, 0.76, 0.2])
345 
346  # print(asymmetryArrayUncertainties)
347 
348  ax2.errorbar(asymmetryArray[:, 0], asymmetryArray[:, 1], xerr=float(negativeHistogram.GetBinWidth(2) / 2),
349  yerr=asymmetryArrayUncertainties[:, 1], elinewidth=2, mew=2, ecolor='k',
350  fmt='o', mfc='k', mec='k', markersize=6, label=r'${\rm Data}$')
351 
352  ax2.set_ylabel(r'$\frac{f^{+}\; -\;\, f^{-}}{f^{+}\; +\;\, f^{-}}$', fontsize=50, labelpad=20)
353  ax2.yaxis.labelpad = 8
354 
355  plt.yticks([-0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75],
356  [r'', r'$-0.5$', r'', r'$0.0$', r'', r'$0.5$', r''], rotation=0, size=25)
357  ax2.set_ylim(-0.75, 0.75)
358  ax2.xaxis.grid(True) # linestyle='--'
359  plt.axhline(y=0.5, linewidth=2, color='tab:gray', linestyle='-')
360  plt.axhline(y=0.25, linewidth=2, color='tab:gray', linestyle='-')
361  plt.axhline(y=0, linewidth=2, color='tab:gray', linestyle='-')
362  plt.axhline(y=-0.25, linewidth=2, color='tab:gray', linestyle='-')
363  plt.axhline(y=-0.5, linewidth=2, color='tab:gray', linestyle='-')
364 
365  xLabel = variablesPlotParamsDict[inputVariable][4]
366  if category == "FSC":
367  if inputVariable == 'cosTPTO':
368  xLabel = r'$\vert\cos{\theta^*_{\rm T, Slow}}\vert$'
369  if inputVariable == 'useCMSFrame(p)':
370  xLabel = r'$p^*_{\rm Slow}\ [{\rm GeV}/c]$'
371  if category == 'Lambda':
372  if inputVariable == 'useCMSFrame(p)':
373  xLabel = r'$p^*_{\Lambda}\ [{\rm GeV}/c]$'
374  if inputVariable == 'p':
375  xLabel = r'$p_{\Lambda}\ [{\rm GeV}/c]$'
376 
377  if inputVariable == 'pi_vs_edEdxid':
378  ax2.xaxis.labelpad = 5
379  else:
380  ax2.xaxis.labelpad = 15
381  plt.locator_params(axis='x', nbins=len(labels))
382 
383  ax2.set_xlim(limXmin, limXmax)
384  ax2.tick_params(axis='x', labelsize=40)
385  ax2.set_xlabel(xLabel, fontsize=50)
386  plt.savefig('./AsymmetriesInVariablesPlots/' + category + '/' + category +
387  "_" + str(Belle2.MakeROOTCompatible.makeROOTCompatible(inputVariable)) + '.pdf')
388  fig1.clear()
389 
390  negativeHistogram.Delete()
391  positiveHistogram.Delete()
392 
393 totalNumberOfVariables = 0
394 
395 for category in ft.variables_fict:
396  totalNumberOfVariables += len(ft.getTrainingVariables(category))
397 
398 print("Total number of variables = ", totalNumberOfVariables)
399 
400 totalNumberOfCalculatedVariables = len(identifiersExtraInfosKaonPion)
401 
402 print("Calculations for Kaon-Pion Category = ", totalNumberOfCalculatedVariables)
403 
404 print("Variables per particle list:")
405 for particleList in identifiersExtraInfosDict:
406  print(particleList)
407  print(identifiersExtraInfosDict[particleList])
408  totalNumberOfCalculatedVariables += len(identifiersExtraInfosDict[particleList])
409 
410 print("Total number of calculated variables = ", totalNumberOfCalculatedVariables)
static std::string makeROOTCompatible(std::string str)
Remove special characters that ROOT dislikes in branch names, e.g.
static std::string invertMakeROOTCompatible(std::string str)
Invert makeROOTCompatible operation.