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