Belle II Software development
asymmetriesInVariablesPlots.py
1#!/usr/bin/env python3
2
3
10
11
24
25import os
26import glob
27import math
28from matplotlib.ticker import FormatStrFormatter
29import matplotlib.pyplot as plt
30import ROOT
31from ROOT import Belle2
32import sys
33import basf2 as b2
34import flavorTagger as ft
35from inputVariablesPlots import variablesPlotParamsDict, categories
36
37import numpy as np
38import matplotlib as mpl
39mpl.use('Agg')
40mpl.rcParams.update({'font.size': 22})
41mpl.rcParams['text.usetex'] = True
42mpl.rcParams['text.latex.preamble'] = [r"\usepackage{amsmath}"]
43
44
45if len(sys.argv) != 5:
46 sys.exit("Must provide 4 arguments: [Belle or Belle2] [BGx0 or BGx1] [training] [workingDirectory]"
47 )
48
49belleOrBelle2 = sys.argv[1]
50MCtype = str(sys.argv[2])
51decayChannelTrainedOn = str(sys.argv[3]) # Decay channel of the weight files "JPsiKs" or "nunubar"
52workingDirectory = sys.argv[4]
53
54filesDirectory = workingDirectory + '/FlavorTagging/TrainedMethods'
55
56if decayChannelTrainedOn == 'JPsiKs':
57 decayChannelTrainedOn = 'JpsiKs_mu'
58
59weightFiles = 'B2' + decayChannelTrainedOn + MCtype
60
61ROOT.TH1.SetDefaultSumw2()
62
63allInputVariables = []
64
65belleOrBelle2Flag = belleOrBelle2
66
67identifiersExtraInfosDict = dict()
68identifiersExtraInfosKaonPion = []
69
70dBw = 50
71
72pBins = 50
73fBins = 100
74
75unitImp = "mm"
76
77if belleOrBelle2 == "Belle":
78 unitImp = "cm"
79
80
81# particle Label, PDG for negative, PDG for positive particle
82
83particleConditions = {'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
89if not b2.find_file('AsymmetriesInVariablesPlots', silent=True):
90 os.mkdir('./AsymmetriesInVariablesPlots')
91
92
93for (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 = f'{binWidth:8.2f}'
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
393totalNumberOfVariables = 0
394
395for category in ft.variables_fict:
396 totalNumberOfVariables += len(ft.getTrainingVariables(category))
397
398print("Total number of variables = ", totalNumberOfVariables)
399
400totalNumberOfCalculatedVariables = len(identifiersExtraInfosKaonPion)
401
402print("Calculations for Kaon-Pion Category = ", totalNumberOfCalculatedVariables)
403
404print("Variables per particle list:")
405for particleList in identifiersExtraInfosDict:
406 print(particleList)
407 print(identifiersExtraInfosDict[particleList])
408 totalNumberOfCalculatedVariables += len(identifiersExtraInfosDict[particleList])
409
410print("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.