Belle II Software  release-06-01-15
test6_CPVFlavorTaggerEfficiency.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 """
13 <header>
14  <input>CPVToolsOutput.root</input>
15  <output>test6_CPVFlavorTaggerEfficiency.root</output>
16  <contact>Yo Sato; yosato@post.kek.jp</contact>
17  <description>This file calculates the effective efficiency of the category based flavor tagger considering the two
18  standard combiners and the individual categories. Validation plots are also produced. </description>
19 </header>
20 """
21 
22 
23 import flavorTagger as ft
24 import ROOT
25 from array import array
26 
27 ROOT.gROOT.SetBatch(True)
28 
29 workingFiles = ["../CPVToolsOutput.root"]
30 treeName = str("B0tree")
31 
32 
33 workingDirectory = '.'
34 
35 #
36 # *******************************************
37 # DETERMINATION OF TOTAL EFFECTIVE EFFICIENCY
38 # *******************************************
39 #
40 
41 r_subsample = array('d', [
42  0.0,
43  0.1,
44  0.25,
45  0.5,
46  0.625,
47  0.75,
48  0.875,
49  1.0])
50 r_size = len(r_subsample)
51 average_eff = 0
52 
53 # working directory
54 # needs the B0_B0bar_final.root-file
55 # treeName = 'B0tree'
56 
57 
58 # All possible Categories
59 categories = [
60  'Electron',
61  'IntermediateElectron',
62  'Muon',
63  'IntermediateMuon',
64  'KinLepton',
65  'IntermediateKinLepton',
66  'Kaon',
67  'KaonPion',
68  'SlowPion',
69  'FSC',
70  'MaximumPstar',
71  'FastHadron',
72  'Lambda']
73 
74 
75 methods = []
76 
77 
78 class Quiet:
79  """Context handler class to quiet errors in a 'with' statement"""
80 
81  def __init__(self, level=ROOT.kInfo + 1):
82  """Class constructor"""
83 
84  self.levellevel = level
85 
86  def __enter__(self):
87  """Enter the context"""
88 
89  self.oldleveloldlevel = ROOT.gErrorIgnoreLevel
90  ROOT.gErrorIgnoreLevel = self.levellevel
91 
92  def __exit__(self, type, value, traceback):
93  """Exit the context"""
94  ROOT.gErrorIgnoreLevel = self.oldleveloldlevel
95 
96 
97 tree = ROOT.TChain(treeName)
98 
99 mcstatus = array('d', [-511.5, 0.0, 511.5])
100 ROOT.TH1.SetDefaultSumw2()
101 
102 for iFile in workingFiles:
103  tree.AddFile(iFile)
104 
105 totalBranches = []
106 for branch in tree.GetListOfBranches():
107  totalBranches.append(branch.GetName())
108 
109 if 'FBDT_qrCombined' in totalBranches:
110  methods.append("FBDT")
111 
112 if 'FANN_qrCombined' in totalBranches:
113  methods.append("FANN")
114 
115 usedCategories = []
116 for cat in categories:
117  catBranch = 'qp' + cat
118  if catBranch in totalBranches:
119  usedCategories.append(cat)
120 
121 if len(usedCategories) > 1:
122  ft.WhichCategories(usedCategories)
123 
124 categoriesNtupleList = str()
125 for (particleList, category, combinerVariable) in ft.eventLevelParticleLists:
126  categoriesNtupleList = categoriesNtupleList + "Eff_%s:" % category
127 
128 
129 # Output Validation file
130 outputFile = ROOT.TFile("test6_CPVFlavorTaggerEfficiency.root", "RECREATE")
131 
132 # Values to be watched
133 outputNtuple = ROOT.TNtuple(
134  "FT_Efficiencies",
135  "Effective efficiencies of the flavor tagger combiners as well as of the individual tagging categories.",
136  "Eff_FBDT:DeltaEff_FBDT:Eff_FANN:DeltaEff_FANN:" + categoriesNtupleList)
137 
138 outputNtuple.SetAlias('Description', "These are the effective efficiencies of the flavor tagger combiners as well as of " +
139  "the individual tagging efficiencies.")
140 outputNtuple.SetAlias(
141  'Check',
142  "These values should not change drastically. Since the nightly reconstruction validation runs" +
143  "on the same input file (which changes only from release to release), the values between builds should be the same.")
144 outputNtuple.SetAlias('Contact', "yosato@post.kek.jp")
145 
146 efficienciesForNtuple = []
147 
148 YmaxForQrPlot = 0
149 
150 for method in methods:
151  # histogram contains the average r in each of 6 bins -> calculation see below
152  histo_avr_r = ROOT.TH1F('Average_r', 'Average r in each of 6 bins (B0 and B0bar)', 6,
153  r_subsample)
154  histo_avr_rB0 = ROOT.TH1F('Average_rB0', 'Average r in each of 6 bins (B0)', 6,
155  r_subsample)
156  histo_avr_rB0bar = ROOT.TH1F('Average_rB0bar', 'Average r in each of 6 bins (B0bar)', 6,
157  r_subsample)
158  # histogram with number of entries in for each bin
159  histo_entries_per_bin = ROOT.TH1F(
160  'entries_per_bin',
161  'Events binned in r_subsample according to their r-value for B0 and B0bar prob',
162  6,
163  r_subsample)
164  histo_entries_per_binB0 = ROOT.TH1F('entries_per_binB0', 'Events binned in r_subsample according '
165  'to their r-value for B0 prob', 6, r_subsample)
166  histo_entries_per_binB0bar = ROOT.TH1F('entries_per_binB0bar',
167  'Events binned in r_subsample according to their r-value '
168  'for B0bar prob', 6, r_subsample)
169  # histogram network output (not qr and not r) for true B0 (signal) - not necessary
170  histo_Cnet_output_B0 = ROOT.TH1F('Comb_Net_Output_B0', 'Combiner network output [not equal to r] '
171  'for true B0 (binning 100)', 100, 0.0, 1.0)
172  # histogram network output (not qr and not r) for true B0bar (background) - not necessary
173  histo_Cnet_output_B0bar = ROOT.TH1F('Comb_Net_Output_B0bar', 'Combiner network output [not equal to r] '
174  'for true B0bar (binning 100)', 100, 0.0, 1.0)
175  # histogram containing the belle paper plot (qr-tagger output for true B0)
176  histo_belleplotB0 = ROOT.TH1F('qr_' + method + '_B0',
177  'BellePlot for true B0 (binning 50)', 50,
178  -1.0, 1.0)
179  # histogram containing the belle paper plot (qr-tagger output for true B0bar)
180  histo_belleplotB0bar = ROOT.TH1F('qr_' + method + '_B0Bar',
181  'BellePlot for true B0Bar (binning 50)',
182  50, -1.0, 1.0)
183 
184  # histogram containing the qr plot (qr-tagger output)
185  histo_belleplotBoth = ROOT.TH1F('qr_' + method + '_B0Both',
186  'qr-tagger output (binning 50)',
187  50, -1.0, 1.0)
188  # calibration plot for B0. If we get a linaer line our MC is fine, than the assumption r ~ 1- 2w is reasonable
189  # expectation is, that for B0 calibration plot: qr=0 half B0 and half B0bar, qr = 1 only B0 and qr = -1
190  # no B0. Inverse for B0bar calibration plot
191  histo_calib_B0 = ROOT.TH1F('Calibration_' + method + '_B0', 'CalibrationPlot for true B0', 100, -1.0, 1.0)
192  # calibration plot for B0bar calibration plot
193  histo_calib_B0bar = ROOT.TH1F('Calibration_' + method + '_B0Bar',
194  'CalibrationPlot for true B0Bar', 100, -1.0,
195  1.0)
196  # belle plot with true B0 and B0bars
197  hallo12 = ROOT.TH1F('BellePlot_NoCut', 'BellePlot_NoCut (binning 100)',
198  100, -1.0, 1.0)
199 
200 
201  diag = ROOT.TF1('diag', 'pol1', -1, 1)
202 
203 
204  # histograms for the efficiency calculation in wrong way
205  histo_m0 = ROOT.TH1F('BellePlot_B0_m0',
206  'BellePlot_m for true B0 (binning 50)', 50, -1.0, 1.0)
207  histo_m1 = ROOT.TH1F('BellePlot_B0_m1',
208  'BellePlot_m for true B0 (binning 50)', 50, -1.0, 1.0)
209  histo_m2 = ROOT.TH1F('BellePlot_B0_m2',
210  'BellePlot_m for true B0Bar (binning 50)', 50, -1.0,
211  1.0)
212 
213  # filling the histograms
214 
215  tree.Draw(method + '_qrCombined>>qr_' + method + '_B0', 'qrMC == 1')
216  tree.Draw(method + '_qrCombined>>qr_' + method + '_B0Bar', 'qrMC == -1')
217  tree.Draw(method + '_qrCombined>>BellePlot_NoCut', 'abs(qrMC) == 1')
218  tree.Draw(method + '_qrCombined>>qr_' + method + '_B0Both', 'abs(qrMC) == 1')
219 
220  tree.Draw(method + '_qrCombined>>Calibration_' + method + '_B0', 'qrMC == 1')
221  tree.Draw(method + '_qrCombined>>Calibration_' + method + '_B0Bar', 'qrMC == -1')
222 
223  # filling histograms wrong efficiency calculation
224  tree.Draw(method + '_qrCombined>>BellePlot_B0_m0',
225  'qrMC == 1 && ' + method + '_qrCombined>0')
226  tree.Draw(method + '_qrCombined>>BellePlot_B0_m1',
227  'qrMC == 1 && ' + method + '_qrCombined<0')
228  tree.Draw(method + '_qrCombined>>BellePlot_B0_m2',
229  'qrMC == -1 && ' + method + '_qrCombined>0 ')
230 
231  # filling with abs(qr) in one of 6 bins with its weight
232  # separate calculation for B0 and B0bar
233 
234  tree.Project('Average_r', 'abs(' + method + '_qrCombined)',
235  'abs(' + method + '_qrCombined)')
236  tree.Project('Average_rB0', 'abs(' + method + '_qrCombined)', 'abs(' + method + '_qrCombined)*(qrMC==1)')
237  tree.Project('Average_rB0bar', 'abs(' + method + '_qrCombined)', 'abs(' + method + '_qrCombined)*(qrMC==-1)')
238 
239  # filling with abs(qr) in one of 6 bins
240  tree.Project('entries_per_bin', 'abs(' + method + '_qrCombined)', 'abs(qrMC) == 1')
241  tree.Project('entries_per_binB0', 'abs(' + method + '_qrCombined)', 'qrMC == 1')
242  tree.Project('entries_per_binB0bar', 'abs(' + method + '_qrCombined)', 'qrMC == -1')
243 
244  # producing the average r histograms
245  histo_avr_r.Divide(histo_entries_per_bin)
246  histo_avr_rB0.Divide(histo_entries_per_binB0)
247  histo_avr_rB0bar.Divide(histo_entries_per_binB0bar)
248 
249  # producing the calibration plots
250  # Errors ok
251  histo_calib_B0.Divide(hallo12)
252  histo_calib_B0bar.Divide(hallo12)
253 
254  # Fit for calibration plot
255  print(' ')
256  print('****************** CALIBRATION CHECK FOR COMBINER USING ' + method + ' ***************************************')
257  print(' ')
258  print('Fit polynomial of first order to the calibration plot. Expected value ~0.5')
259  print(' ')
260  histo_calib_B0.Fit(diag, 'TEST')
261  print(' ')
262  print('****************** MEASURED EFFECTIVE EFFICIENCY FOR COMBINER USING ' + method + ' ***************************')
263  print('* *')
264  # get total number of entries
265  total_entries = histo_entries_per_bin.GetEntries()
266  total_entries_B0 = histo_entries_per_binB0.GetEntries()
267  total_entries_B0bar = histo_entries_per_binB0bar.GetEntries()
268  tot_eff_effB0 = 0
269  tot_eff_effB0bar = 0
270  event_fractionB0 = array('f', [0] * r_size)
271  event_fractionB0bar = array('f', [0] * r_size)
272  event_fractionTotal = array('f', [0] * r_size)
273  event_fractionDiff = array('f', [0] * r_size)
274  rvalueB0 = array('f', [0] * r_size)
275  rvalueB0bar = array('f', [0] * r_size)
276  rvalueB0Average = array('f', [0] * r_size)
277  wvalue = array('f', [0] * r_size)
278  wvalueB0 = array('f', [0] * r_size)
279  wvalueB0bar = array('f', [0] * r_size)
280  wvalueDiff = array('f', [0] * r_size)
281  entries = array('f', [0] * r_size)
282  entriesB0 = array('f', [0] * r_size)
283  entriesB0bar = array('f', [0] * r_size)
284  iEffEfficiency = array('f', [0] * r_size)
285  iDeltaEffEfficiency = array('f', [0] * r_size)
286  # intervallEff = array('f', [0] * r_size)
287  performance = []
288  for i in range(1, r_size):
289  # get the average r-value
290  rvalueB0[i] = histo_avr_rB0.GetBinContent(i)
291  rvalueB0bar[i] = histo_avr_rB0bar.GetBinContent(i)
292  rvalueB0Average[i] = (rvalueB0[i] + rvalueB0bar[i]) / 2
293  # calculate the wrong tag fraction (only true if MC data good)
294  wvalue[i] = (1 - rvalueB0Average[i]) / 2
295  wvalueB0[i] = (1 - rvalueB0[i]) / 2
296  wvalueB0bar[i] = (1 - rvalueB0bar[i]) / 2
297  wvalueDiff[i] = wvalueB0[i] - wvalueB0bar[i]
298  entries[i] = histo_entries_per_bin.GetBinContent(i)
299  entriesB0[i] = histo_entries_per_binB0.GetBinContent(i)
300  entriesB0bar[i] = histo_entries_per_binB0bar.GetBinContent(i)
301  # fraction of events/all events
302  event_fractionTotal[i] = (entriesB0[i] + entriesB0bar[i]) / total_entries
303  event_fractionDiff[i] = (entriesB0[i] - entriesB0bar[i]) / total_entries
304  event_fractionB0[i] = entriesB0[i] / total_entries_B0
305  event_fractionB0bar[i] = entriesB0bar[i] / total_entries_B0bar
306  iEffEfficiency[i] = (event_fractionB0[i] * rvalueB0[i] * rvalueB0[i] +
307  event_fractionB0bar[i] * rvalueB0bar[i] * rvalueB0bar[i]) / 2
308  iDeltaEffEfficiency[i] = event_fractionB0[i] * rvalueB0[i] * \
309  rvalueB0[i] - event_fractionB0bar[i] * rvalueB0bar[i] * rvalueB0bar[i]
310  # finally calculating the total effective efficiency
311  tot_eff_effB0 = tot_eff_effB0 + event_fractionB0[i] * rvalueB0[i] * rvalueB0[i]
312  tot_eff_effB0bar = tot_eff_effB0bar + event_fractionB0bar[i] * rvalueB0bar[i] * rvalueB0bar[i]
313 
314  average_eff = (tot_eff_effB0 + tot_eff_effB0bar) / 2
315  diff_eff = tot_eff_effB0 - tot_eff_effB0bar
316  print('* ------------------------------------------------------------------------------------------------ *')
317  print('* *')
318  print('* __________________________________________________________________________________________ *')
319  print('* | | *')
320  print('* | TOTAL NUMBER OF TAGGED EVENTS = ' +
321  '{:<24}'.format("%.0f" % total_entries) + '{:>36}'.format('| *'))
322  print('* | | *')
323  print('* | TOTAL AVERAGE EFFECTIVE EFFICIENCY (q=+-1)= ' + '{:.2f}'.format(average_eff * 100) +
324  ' % | *')
325  print('* | | *')
326  print('* | B0-TAGGER TOTAL EFFECTIVE EFFICIENCIES: ' +
327  '{:.2f}'.format(tot_eff_effB0 * 100) + ' % (q=+1) ' +
328  '{:.2f}'.format(tot_eff_effB0bar * 100) + ' % (q=-1) EffDiff=' +
329  '{:^5.2f}'.format(diff_eff * 100) + ' % | *')
330  print('* | | *')
331  print('* | FLAVOR PERCENTAGE (MC): ' +
332  '{:.2f}'.format(total_entries_B0 / total_entries * 100) + ' % (q=+1) ' +
333  '{:.2f}'.format(total_entries_B0bar / total_entries * 100) + ' % (q=-1) Diff=' +
334  '{:^5.2f}'.format((total_entries_B0 - total_entries_B0bar) / total_entries * 100) + ' % | *')
335  print('* |__________________________________________________________________________________________| *')
336  print('* *')
337  print('****************************************************************************************************')
338  print('* *')
339 
340  efficienciesForNtuple.append(float(average_eff * 100))
341  efficienciesForNtuple.append(float(diff_eff * 100))
342 
343  maxB0 = histo_belleplotB0.GetBinContent(histo_belleplotB0.GetMaximumBin())
344  maxB0bar = histo_belleplotB0bar.GetBinContent(histo_belleplotB0bar.GetMaximumBin())
345  maxB0Both = histo_belleplotBoth.GetBinContent(histo_belleplotBoth.GetMaximumBin())
346 
347  Ymax = max(maxB0, maxB0bar, maxB0Both)
348  Ymax = Ymax + Ymax / 12
349 
350  if YmaxForQrPlot < Ymax:
351  YmaxForQrPlot = Ymax
352 
353  # produce a pdf
354  ROOT.gStyle.SetOptStat(0)
355  with Quiet(ROOT.kError):
356  Canvas1 = ROOT.TCanvas('Bla', 'Final Output', 1200, 800)
357  Canvas1.cd() # activate
358  Canvas1.SetLeftMargin(0.13)
359  Canvas1.SetRightMargin(0.04)
360  Canvas1.SetTopMargin(0.03)
361  Canvas1.SetBottomMargin(0.14)
362  histo_belleplotB0.SetFillColorAlpha(ROOT.kBlue, 0.2)
363  histo_belleplotB0.SetFillStyle(1001)
364  histo_belleplotB0.GetXaxis().SetLabelSize(0.04)
365  histo_belleplotB0.GetYaxis().SetLabelSize(0.04)
366  histo_belleplotB0.GetYaxis().SetTitleOffset(0.9)
367  histo_belleplotB0.GetXaxis().SetTitleSize(0.06)
368  histo_belleplotB0.GetYaxis().SetTitleSize(0.06)
369  histo_belleplotB0.GetYaxis().SetLimits(0, YmaxForQrPlot)
370  histo_belleplotB0.SetLineColor(ROOT.kBlue)
371  histo_belleplotB0bar.SetFillColorAlpha(ROOT.kRed, 1.0)
372  histo_belleplotB0bar.SetFillStyle(3005)
373  histo_belleplotB0bar.SetLineColor(ROOT.kRed)
374  # SetLabelSize etc SetTitle
375 
376  histo_belleplotB0.SetTitle('; #it{qr}_{' + method + '} ; Events (Total = ' + '{:<1}'.format("%.0f" % total_entries) + ')'
377  )
378  histo_belleplotB0.SetMinimum(0)
379  histo_belleplotB0.SetMaximum(YmaxForQrPlot)
380  histo_belleplotB0.Draw('hist')
381  histo_belleplotB0bar.Draw('hist same')
382 
383  leg = ROOT.TLegend(0.2, 0.7, 0.9, 0.95)
384  leg.AddEntry(
385  histo_belleplotB0,
386  'true B^{0} ' +
387  ' #varepsilon_{eff}(B^{0}) = ' +
388  '{:.2f}'.format(
389  tot_eff_effB0 *
390  100) +
391  '% #frac{n_{B^{0}}}{n} = ' +
392  '{:.2f}'.format(
393  total_entries_B0 /
394  total_entries *
395  100) +
396  '%')
397  leg.AddEntry(
398  histo_belleplotB0bar,
399  'true #bar{B}^{0} ' +
400  ' #varepsilon_{eff}(#bar{B}^{0}) = ' +
401  '{:.2f}'.format(
402  tot_eff_effB0bar *
403  100) +
404  '% #frac{n_{#bar{B}^{0}}}{n} = ' +
405  '{:.2f}'.format(
406  total_entries_B0bar /
407  total_entries *
408  100) +
409  '%')
410  leg.AddEntry("", "Avrg. #bf{ #varepsilon_{eff} = " + '{:.2f}'.format(average_eff * 100) +
411  '%} #Delta#varepsilon_{eff} = ' + '{:^5.2f}'.format(diff_eff * 100) + '%')
412  leg.SetTextSize(0.045)
413  leg.Draw()
414 
415  Canvas1.Update()
416 
417  with Quiet(ROOT.kError):
418  Canvas1.SaveAs(workingDirectory + '/' + 'test6_CPVFTqr' + method + '_both.pdf')
419 
420  # Validation Plot 1
421  histo_belleplotBoth.GetXaxis().SetLabelSize(0.04)
422  histo_belleplotBoth.GetYaxis().SetLabelSize(0.04)
423  histo_belleplotBoth.GetYaxis().SetTitleOffset(0.7)
424  histo_belleplotBoth.GetXaxis().SetTitleOffset(0.7)
425  histo_belleplotBoth.GetXaxis().SetTitleSize(0.06)
426  histo_belleplotBoth.GetYaxis().SetTitleSize(0.06)
427 
428  histo_belleplotBoth.GetListOfFunctions().Add(ROOT.TNamed('MetaOptions', 'nostats'))
429  histo_belleplotBoth.GetListOfFunctions().Add(ROOT.TNamed('Description', 'Output of the flavor tagger combiner ' + method))
430  histo_belleplotBoth.GetListOfFunctions().Add(
431  ROOT.TNamed(
432  'Check',
433  'Shape should not change drastically. E.g. Warning if the peak at 0 increases or if the peaks at +-1 decrease.'))
434  histo_belleplotBoth.GetListOfFunctions().Add(ROOT.TNamed('Contact', 'yosato@post.kek.jp'))
435 
436  histo_belleplotBoth.SetTitle(
437  'Flavor tagger output for combiner ' +
438  method +
439  '; #it{qr}_{' +
440  method +
441  '} ; Events (Total = ' +
442  '{:<1}'.format(
443  "%.0f" %
444  total_entries) +
445  ')')
446  histo_belleplotBoth.SetMinimum(0)
447  histo_belleplotBoth.SetMaximum(YmaxForQrPlot)
448  histo_belleplotBoth.SetStats(False)
449  histo_belleplotBoth.Write()
450 
451  # Validation Plot 2
452  histo_belleplotB0.GetYaxis().SetTitleOffset(0.7)
453  histo_belleplotB0.GetXaxis().SetTitleOffset(0.7)
454  histo_belleplotB0.SetLineColor(ROOT.kBlue + 2)
455  histo_belleplotB0.SetTitle(
456  'Flavor tagger output for combiner ' +
457  method +
458  ' for true B^{0}s; #it{qr}_{' +
459  method +
460  '} ; Events (Total = ' +
461  '{:<1}'.format(
462  "%.0f" %
463  histo_belleplotB0.GetEntries()) +
464  ')')
465  histo_belleplotB0.SetStats(False)
466 
467  histo_belleplotB0.GetListOfFunctions().Add(ROOT.TNamed('MetaOptions', 'nostats'))
468  histo_belleplotB0.GetListOfFunctions().Add(
469  ROOT.TNamed('Description', 'Output of the flavor tagger combiner ' + method + ' for true B0s'))
470  histo_belleplotB0.GetListOfFunctions().Add(
471  ROOT.TNamed(
472  'Check',
473  'Shape should not change drastically. E.g. Warning if the peak at 0 increases or if the peak at +1 decreases.'))
474  histo_belleplotB0.GetListOfFunctions().Add(ROOT.TNamed('Contact', 'yosato@post.kek.jp'))
475  histo_belleplotB0.Write()
476 
477  # Validation Plot 3
478  histo_belleplotB0bar.GetXaxis().SetLabelSize(0.04)
479  histo_belleplotB0bar.GetYaxis().SetLabelSize(0.04)
480  histo_belleplotB0bar.GetYaxis().SetTitleOffset(0.7)
481  histo_belleplotB0bar.GetXaxis().SetTitleOffset(0.7)
482  histo_belleplotB0bar.GetXaxis().SetTitleSize(0.06)
483  histo_belleplotB0bar.GetYaxis().SetTitleSize(0.06)
484  histo_belleplotB0bar.SetLineColor(ROOT.kBlue + 2)
485  histo_belleplotB0bar.SetTitle(
486  'Flavor tagger output for combiner ' +
487  method +
488  ' for true #bar{B}^{0}s; #it{qr}_{' +
489  method +
490  '} ; Events (Total = ' +
491  '{:<1}'.format(
492  "%.0f" %
493  histo_belleplotB0bar.GetEntries()) +
494  ')')
495  histo_belleplotB0bar.SetMinimum(0)
496  histo_belleplotB0bar.SetMaximum(YmaxForQrPlot)
497  histo_belleplotB0bar.SetStats(False)
498 
499  histo_belleplotB0bar.GetListOfFunctions().Add(ROOT.TNamed('MetaOptions', 'nostats'))
500  histo_belleplotB0bar.GetListOfFunctions().Add(
501  ROOT.TNamed(
502  'Description',
503  'Output of the flavor tagger combiner ' +
504  method +
505  ' for true B0bars'))
506  histo_belleplotB0bar.GetListOfFunctions().Add(ROOT.TNamed(
507  'Check', 'Shape should not change drastically. E.g. Warning if the peak at 0 increases or if the peak at -1 decreases.'))
508  histo_belleplotB0bar.GetListOfFunctions().Add(ROOT.TNamed('Contact', 'yosato@post.kek.jp'))
509  histo_belleplotB0bar.Write()
510 
511  # IPython.embed()
512 
513  # produce the nice calibration plot
514  with Quiet(ROOT.kError):
515  Canvas2 = ROOT.TCanvas('Bla2', 'Calibration plot for true B0', 1200, 800)
516  Canvas2.cd() # activate
517  Canvas2.SetLeftMargin(0.13)
518  Canvas2.SetRightMargin(0.04)
519  Canvas2.SetTopMargin(0.03)
520  Canvas2.SetBottomMargin(0.14)
521  histo_calib_B0.GetXaxis().SetLabelSize(0.04)
522  histo_calib_B0.GetYaxis().SetLabelSize(0.04)
523  histo_calib_B0.GetYaxis().SetTitleOffset(0.9)
524  histo_calib_B0.GetXaxis().SetTitleSize(0.06)
525  histo_calib_B0.GetYaxis().SetTitleSize(0.06)
526  histo_calib_B0.SetFillColorAlpha(ROOT.kBlue, 0.2)
527  histo_calib_B0.SetFillStyle(1001)
528  histo_calib_B0.GetYaxis().SetTitleOffset(0.9)
529  histo_calib_B0.SetLineColor(ROOT.kBlue)
530 
531  histo_calib_B0.SetTitle('; #it{qr}_{' + method + '} ; Calibration '
532  )
533  histo_calib_B0.Draw('hist')
534  diag.Draw('SAME')
535 
536  leg2 = ROOT.TLegend(0.2, 0.75, 0.63, 0.93)
537  leg2.SetHeader(" y = #it{m}#it{x} + #it{c}", "")
538  leg2.GetListOfPrimitives().First().SetTextAlign(22)
539  leg2.AddEntry(
540  diag,
541  "#it{m} = " +
542  '{:.2f}'.format(
543  diag.GetParameter("p1")) +
544  " #it{c} = " +
545  '{:.2f}'.format(
546  diag.GetParameter("p0")))
547  leg2.SetTextSize(0.05)
548  leg2.Draw()
549 
550  Canvas2.Update()
551  with Quiet(ROOT.kError):
552  Canvas2.SaveAs(workingDirectory + '/' + 'test6_CPVFTCalibration_' + method + '_B0.pdf')
553 
554  # Validation Plot 4
555 
556  histo_calib_B0.GetYaxis().SetTitleOffset(0.7)
557  histo_calib_B0.GetXaxis().SetTitleOffset(0.7)
558  histo_calib_B0.SetLineColor(ROOT.kBlue + 2)
559  histo_calib_B0.SetTitle('Calibration plot for the flavor tagger combiner ' +
560  method + ' ; #it{qr}_{' + method + '} ; Calibration')
561  histo_calib_B0.SetMinimum(-0.2)
562  histo_calib_B0.SetMaximum(+1.2)
563  histo_calib_B0.SetStats(False)
564 
565  histo_calib_B0.GetListOfFunctions().Add(ROOT.TNamed('MetaOptions', 'nostats'))
566  histo_calib_B0.GetListOfFunctions().Add(
567  ROOT.TNamed(
568  'Description',
569  'Calibration plot for the flavor tagger combiner ' +
570  method +
571  ' for true B0s'))
572  histo_calib_B0.GetListOfFunctions().Add(
573  ROOT.TNamed('Check', 'Shape should not change drastically. E.g. warning if the shape stops being linear.'))
574  histo_calib_B0.GetListOfFunctions().Add(ROOT.TNamed('Contact', 'yosato@post.kek.jp'))
575  histo_calib_B0.Write()
576 
577  histo_belleplotBoth.Delete()
578  histo_avr_r.Delete()
579  histo_avr_rB0.Delete()
580  histo_avr_rB0bar.Delete()
581  histo_entries_per_bin.Delete()
582  histo_entries_per_binB0.Delete()
583  histo_entries_per_binB0bar.Delete()
584  histo_Cnet_output_B0.Delete()
585  histo_Cnet_output_B0bar.Delete()
586  histo_belleplotB0.Delete()
587  histo_belleplotB0bar.Delete()
588  histo_calib_B0.Delete()
589  histo_calib_B0bar.Delete()
590  hallo12.Delete()
591  histo_m0.Delete()
592  histo_m1.Delete()
593  histo_m2.Delete()
594  Canvas1.Clear()
595  Canvas2.Clear()
596 
597 
598 # **********************************************
599 # DETERMINATION OF INDIVIDUAL EFFECTIVE EFFICIENCY
600 # **********************************************
601 
602 print('************************* MEASURED EFFECTIVE EFFICIENCY FOR INDIVIDUAL CATEGORIES *********************************')
603 print('* *')
604 # input: Classifier input from event-level. Output of event-level is recalculated for input on combiner-level.
605 # but is re-evaluated under combiner target. Signal is B0, background is B0Bar.
606 
607 for (particleList, category, combinerVariable) in ft.eventLevelParticleLists:
608  # histogram of input variable (only signal) - not yet a probability! It's a classifier plot!
609  hist_signal = ROOT.TH1F('Signal_' + category, 'Input Signal (B0)' +
610  category + ' (binning 50)', 50, -1.0, 1.0)
611  # histogram of input variable (only background) - not yet a probability! It's a classifier plot!
612  hist_background = ROOT.TH1F('Background_' + category, 'Input Background (B0bar)' +
613  category + ' (binning 50)', 50, -1.0, 1.0)
614  hist_both = ROOT.TH1F('qp_' + category, 'Input Background (B0bar)' +
615  category + ' (binning 50)', 100, -1, 1)
616 
617  # per definition that input is not comparable to the network output, this has to be transformed.
618  # probability output from 0 to 1 (corresponds to net output probability) -> calculation below
619  hist_probB0 = ROOT.TH1F('ProbabilityB0_' + category,
620  'Transformed to probability (B0) (' + category + ')',
621  50, 0.0, 1.0)
622  hist_probB0bar = ROOT.TH1F('ProbabilityB0bar_' + category,
623  'Transformed to probability (B0bar) (' + category + ')',
624  50, 0.0, 1.0)
625  # qp output from -1 to 1 -> transformation below
626  hist_qpB0 = ROOT.TH1F('QRB0_' + category, 'Transformed to qp (B0)(' +
627  category + ')', 50, -1.0, 1.0)
628  hist_qpB0bar = ROOT.TH1F('QRB0bar_' + category, 'Transformed to qp (B0bar) (' +
629  category + ')', 50, -1.0, 1.0)
630  # histogram for abs(qp), i.e. this histogram contains the r-values -> transformation below
631  # also used to get the number of entries, sorted into 6 bins
632  hist_absqpB0 = ROOT.TH1F('AbsQRB0_' + category, 'Abs(qp)(B0) (' + category + ')', 6, r_subsample)
633  hist_absqpB0bar = ROOT.TH1F('AbsQRB0bar_' + category, 'Abs(qp) (B0bar) (' + category + ')', 6, r_subsample)
634  # histogram contains at the end the average r values -> calculation below
635  # sorted into 6 bins
636  hist_aver_rB0 = ROOT.TH1F('AverageRB0_' + category, 'A good one (B0)' +
637  category, 6, r_subsample)
638  hist_aver_rB0bar = ROOT.TH1F('AverageRB0bar_' + category, 'A good one (B0bar)' +
639  category, 6, r_subsample)
640  # ****** TEST OF CALIBRATION ******
641  # for calibration plot we want to have
642  hist_all = ROOT.TH1F('All_' + category, 'Input Signal (B0) and Background (B0Bar)' +
643  category + ' (binning 50)', 50, 0.0, 1.0)
644  tree.Draw('qp' + category + '>>All_' + category, 'qrMC!=0')
645  hist_calib_B0 = ROOT.TH1F('Calib_B0_' + category, 'Calibration Plot for true B0' +
646  category + ' (binning 50)', 50, 0.0, 1.0)
647  tree.Draw('qp' + category + '>>Calib_B0_' + category, 'qrMC == 1.0')
648  hist_calib_B0.Divide(hist_all)
649 
650  # fill signal
651  tree.Draw('qp' + category + '>>Signal_' + category, 'qrMC == 1.0')
652  # fill background
653  tree.Draw('qp' + category + '>>Background_' + category, 'qrMC == -1.0'
654  )
655  # fill both
656  tree.Draw('qp' + category + '>>qp_' + category, 'abs(qrMC) == 1.0'
657  )
658 
659  # ***** TEST OF CALIBRATION ******
660 
661  # initialize some arrays
662  purityB0 = array('d', [0] * 51)
663  dilutionB02 = array('d', [0] * 51)
664  purityB0bar = array('d', [0] * 51)
665  dilutionB0bar2 = array('d', [0] * 51)
666  signal = array('d', [0] * 51)
667  back = array('d', [0] * 51)
668  weight = array('d', [0] * 51)
669 
670  for i in range(1, 51):
671  # doing the transformation to probabilities
672  signal[i] = hist_signal.GetBinContent(i)
673  back[i] = hist_background.GetBinContent(i)
674 
675  weight[i] = signal[i] + back[i]
676 
677  # avoid dividing by zero
678  if signal[i] + back[i] == 0:
679  purityB0[i] = 0
680  dilutionB02[i] = 0
681  purityB0bar[i] = 0
682  dilutionB0bar2[i] = 0
683  else:
684  purityB0[i] = signal[i] / (signal[i] + back[i])
685  dilutionB02[i] = -1 + 2 * signal[i] / (signal[i] + back[i])
686 
687  purityB0bar[i] = back[i] / (signal[i] + back[i])
688  dilutionB0bar2[i] = -1 + 2 * back[i] / (signal[i] + back[i])
689 
690  # filling histogram with probability from 0 to 1
691  hist_probB0.Fill(purityB0[i], signal[i])
692  hist_probB0bar.Fill(purityB0bar[i], back[i])
693 
694  # filling histogram with qp from -1 to 1
695  hist_qpB0.Fill(dilutionB02[i], signal[i])
696  hist_qpB0bar.Fill(dilutionB0bar2[i], back[i])
697 
698  # filling histogram with abs(qp), i.e. this histogram contains the r-values (not qp)
699  hist_absqpB0.Fill(abs(dilutionB02[i]), signal[i])
700  hist_absqpB0bar.Fill(abs(dilutionB0bar2[i]), back[i])
701  # filling histogram with abs(qp) special weighted - needed for average r calculation
702  hist_aver_rB0.Fill(abs(dilutionB02[i]), abs(dilutionB02[i]) * signal[i])
703  hist_aver_rB0bar.Fill(abs(dilutionB0bar2[i]), abs(dilutionB0bar2[i]) * back[i])
704 
705  # hist_aver_rB0bar contains now the average r-value
706  hist_aver_rB0.Divide(hist_absqpB0)
707  hist_aver_rB0bar.Divide(hist_absqpB0bar)
708  # now calculating the efficiency
709 
710  # calculating number of events
711  tot_entriesB0 = 0
712  tot_entriesB0bar = 0
713  for i in range(1, r_size):
714  tot_entriesB0 = tot_entriesB0 + hist_absqpB0.GetBinContent(i)
715  tot_entriesB0bar = tot_entriesB0bar + hist_absqpB0bar.GetBinContent(i)
716  # initializing some arrays
717  tot_eff_effB0 = 0
718  tot_eff_effB0bar = 0
719  event_fractionB0 = array('f', [0] * r_size)
720  event_fractionB0bar = array('f', [0] * r_size)
721  rvalueB0 = array('f', [0] * r_size)
722  rvalueB0bar = array('f', [0] * r_size)
723  # wvalue = array('f', [0] * r_size)
724  entriesB0 = array('f', [0] * r_size)
725  entriesB0bar = array('f', [0] * r_size)
726 
727  for i in range(1, r_size):
728  rvalueB0[i] = hist_aver_rB0.GetBinContent(i)
729  rvalueB0bar[i] = hist_aver_rB0bar.GetBinContent(i)
730  # wvalue[i] = (1 - rvalueB0[i]) / 2
731  entriesB0[i] = hist_absqpB0.GetBinContent(i)
732  entriesB0bar[i] = hist_absqpB0bar.GetBinContent(i)
733  event_fractionB0[i] = entriesB0[i] / tot_entriesB0
734  event_fractionB0bar[i] = entriesB0bar[i] / tot_entriesB0bar
735  # print '* Bin ' + str(i) + ' r-value: ' + str(rvalueB0[i]), 'entriesB0: ' +
736  # str(event_fractionB0[i] * 100) + ' % (' + str(entriesB0[i]) + '/' +
737  # str(tot_entriesB0) + ')'
738  tot_eff_effB0 = tot_eff_effB0 + event_fractionB0[i] * rvalueB0[i] \
739  * rvalueB0[i]
740  tot_eff_effB0bar = tot_eff_effB0bar + event_fractionB0bar[i] * rvalueB0bar[i] \
741  * rvalueB0bar[i]
742  effDiff = tot_eff_effB0 - tot_eff_effB0bar
743  effAverage = (tot_eff_effB0 + tot_eff_effB0bar) / 2
744 
745  print(
746  '{:<25}'.format("* " +
747  category) +
748  ' B0-Eff=' +
749  '{: 8.2f}'.format(
750  tot_eff_effB0 *
751  100) +
752  ' %' +
753  ' B0bar-Eff=' +
754  '{: 8.2f}'.format(
755  tot_eff_effB0bar *
756  100) +
757  ' %' +
758  ' EffAverage=' +
759  '{: 8.2f}'.format(effAverage * 100) + ' %' +
760  ' EffDiff=' +
761  '{: 8.2f}'.format(effDiff * 100) + ' % *')
762 
763  # ****** produce the input plots from combiner level ******
764 
765  efficienciesForNtuple.append(float(effAverage * 100))
766 
767  maxSignal = hist_signal.GetBinContent(hist_signal.GetMaximumBin())
768  maxBackground = hist_background.GetBinContent(hist_background.GetMaximumBin())
769 
770  Ymax = max(maxSignal, maxBackground)
771  Ymax = Ymax + Ymax / 12
772 
773  ROOT.gStyle.SetOptStat(0)
774  with Quiet(ROOT.kError):
775  Canvas = ROOT.TCanvas('Bla', 'TITEL BLA', 1200, 800)
776  Canvas.cd() # activate
777  Canvas.SetLogy()
778  Canvas.SetLeftMargin(0.13)
779  Canvas.SetRightMargin(0.04)
780  Canvas.SetTopMargin(0.03)
781  Canvas.SetBottomMargin(0.14)
782  hist_signal.SetFillColorAlpha(ROOT.kBlue, 0.2)
783  hist_signal.SetFillStyle(1001)
784  hist_signal.SetTitleSize(0.1)
785  hist_signal.GetXaxis().SetLabelSize(0.04)
786  hist_signal.GetYaxis().SetLabelSize(0.04)
787  hist_signal.GetXaxis().SetTitleSize(0.06)
788  hist_signal.GetYaxis().SetTitleSize(0.06)
789  hist_signal.GetXaxis().SetLabelSize(0.04)
790  hist_signal.GetYaxis().SetLabelSize(0.04)
791  hist_signal.GetXaxis().SetTitleSize(0.05)
792  hist_signal.GetYaxis().SetTitleSize(0.05)
793  hist_signal.GetXaxis().SetTitleOffset(0.95)
794  hist_signal.GetYaxis().SetTitleOffset(1.1)
795  hist_signal.GetXaxis().SetTitleOffset(1.15)
796  hist_signal.GetYaxis().SetLimits(0, Ymax)
797  hist_signal.SetLineColor(ROOT.kBlue)
798  hist_background.SetFillColorAlpha(ROOT.kRed, 1.0)
799  hist_background.SetFillStyle(3005)
800  hist_background.GetYaxis().SetLimits(0, Ymax)
801  hist_background.SetLineColor(ROOT.kRed)
802 
803  catName = category
804  if category == 'MaximumPstar':
805  catName = 'MaximumP*'
806 
807  hist_signal.SetTitle('; (#it{qp})^{' + catName + '} ; Events')
808  # hist_signal.SetMinimum(0)
809  hist_signal.SetMaximum(Ymax)
810  # hist_background.SetMinimum(0)
811  hist_background.SetMaximum(Ymax)
812 
813  hist_signal.Draw('hist')
814  hist_background.Draw('hist same')
815 
816  l0 = ROOT.TLegend(0.13, 0.65, 0.33, 0.97)
817  l0.SetFillColorAlpha(ROOT.kWhite, 0)
818  l0.AddEntry(hist_signal, ' #varepsilon_{eff}(B^{0}) = ' + '{:.2f}'.format(tot_eff_effB0 * 100) + "%")
819  l0.AddEntry(hist_background, ' #varepsilon_{eff}(#bar{B}^{0}) = ' + '{:.2f}'.format(tot_eff_effB0bar * 100) + "%")
820  l0.AddEntry("", "#bf{#varepsilon_{eff} = " + '{:.2f}'.format(effAverage * 100) + '%}')
821  l0.AddEntry("", '#Delta#varepsilon_{eff} = ' + '{:^5.2f}'.format(effDiff * 100) + '%')
822  l0.SetBorderSize(0)
823  l0.SetTextSize(0.045)
824  l0.Draw()
825 
826  l1 = ROOT.TLegend(0.85, 0.7, 0.96, 0.97)
827  l1.SetFillColorAlpha(ROOT.kWhite, 0.35)
828  l1.AddEntry(hist_signal, 'B^{0}_{MC}')
829  l1.AddEntry(hist_background, '#bar{B}^{0}_{MC}')
830  l1.SetTextSize(0.045)
831  l1.Draw()
832 
833  Canvas.Update()
834  with Quiet(ROOT.kError):
835  Canvas.SaveAs(workingDirectory + '/' + 'test6_CPVFTqp_' + category + '_both.pdf')
836 
837  # Validation Plot 4
838  hist_both.GetXaxis().SetLabelSize(0.04)
839  hist_both.GetYaxis().SetLabelSize(0.04)
840  hist_both.GetYaxis().SetTitleOffset(0.7)
841  hist_both.GetXaxis().SetTitleOffset(0.7)
842  hist_both.GetXaxis().SetTitleSize(0.06)
843  hist_both.GetYaxis().SetTitleSize(0.06)
844 
845  hist_both.GetListOfFunctions().Add(ROOT.TNamed('MetaOptions', 'nostats, logy'))
846  hist_both.GetListOfFunctions().Add(ROOT.TNamed('Description', 'Output of the flavor tagger category ' + catName))
847  hist_both.GetListOfFunctions().Add(
848  ROOT.TNamed('Check', 'Shape should not change drastically. E.g. Warning if there is only a peak at 0.'))
849  hist_both.GetListOfFunctions().Add(ROOT.TNamed('Contact', 'yosato@post.kek.jp'))
850 
851  hist_both.SetTitle(
852  'Flavor tagger output of the category ' +
853  catName +
854  '; #it{qp}_{' +
855  catName +
856  '} ; Events (Total = ' +
857  '{:<1}'.format(
858  "%.0f" %
859  hist_both.GetEntries()) +
860  ')')
861  # hist_both.SetStats(False)
862  hist_both.Write()
863 
864  Canvas.Clear()
865 
866 outputNtuple.Fill(array('f', efficienciesForNtuple))
867 outputNtuple.Write()
868 outputFile.Close()
869 
870 print('* *')
871 print('*******************************************************************************************************************')
oldlevel
the previously set level to be ignored