Belle II Software  release-06-02-00
13_trackingEfficiency_createPlots.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 
18 
19 """
20 <header>
21  <input>trackingEfficiency_pt_0.05GeV.root,
22  trackingEfficiency_pt_0.10GeV.root,trackingEfficiency_pt_0.25GeV.root,
23  trackingEfficiency_pt_0.40GeV.root,trackingEfficiency_pt_0.60GeV.root,
24  trackingEfficiency_pt_1.00GeV.root,trackingEfficiency_pt_1.50GeV.root,
25  trackingEfficiency_pt_2.00GeV.root,trackingEfficiency_pt_3.00GeV.root,
26  trackingEfficiency_pt_4.00GeV.root</input>
27  <output>TrackingValidation.root</output>
28  <contact>software-tracking@belle2.org</contact>
29  <description>Create momentum resolution, impact parameter resolution and efficiency plots.</description>
30 </header>
31 """
32 
33 
34 import ROOT
35 
36 ROOT.PyConfig.IgnoreCommandLineOptions = True # noqa
37 from ROOT import TFile, TChain, TH1F, \
38  gStyle, TNamed, TProfile
39 import sys
40 import math
41 import numpy as np
42 from optparse import OptionParser
43 from tracking.validation.tracking_efficiency_helpers import get_generated_pt_values
44 
45 DELTA_PT = 0.0001
46 
47 PT_VALUES = get_generated_pt_values()
48 # PT_VALUES = [0.05, 0.1, 0.15, 0.25, 0.5, 1.0, 2.0, 3.0]
49 
50 # contact person information
51 # is added to the plot descriptions
52 CONTACT_PERSON = {'Name': 'tracking software mailing list',
53  'Email': 'software-tracking@belle2.org'}
54 
55 
56 def make_expert_plot(hist):
57  hist.GetListOfFunctions().Add(TNamed('MetaOptions', 'expert'))
58 
59 
60 def main():
61  """Function which is executed"""
62 
63  print('Tracking validation plots.')
64 
65  option_parser = OptionParser()
66  option_parser.add_option('-i', '--input-file', dest='input_file',
67  default='../trackingEfficiency_pt_*.root',
68  help='Root file with StandardTrackingPerformance output.'
69  )
70  option_parser.add_option('-o', '--output-file', dest='output_file',
71  default='TrackingValidation.root',
72  help='Root file with all histograms.')
73 
74  options = option_parser.parse_args()[0]
75 
76  gStyle.SetOptStat(0)
77 
78  # load data tree
79  tree_name = 'data'
80  data_tree = TChain(tree_name) # input_root_file.Get(tree_name)
81  data_tree.Add(options.input_file)
82 
83  number_entries = 0
84  try:
85  number_entries = data_tree.GetEntries()
86  except AttributeError:
87  print('Could not load tree with name %s.' % tree_name)
88 
89  if number_entries == 0:
90  print('Data tree \'%s\'is empty or does not exist. Exit.' % tree_name)
91  sys.exit(0)
92 
93  # output root file
94  output_file_name = options.output_file
95  output_root_file = TFile(output_file_name, 'recreate')
96 
97  # create efficiency in bins of pt plot
98  calculate_efficiency_in_pt(data_tree)
99 
100  pt_of_interest = [0.05, 0.25, 1.]
101  # pt_of_interest = PT_VALUES
102 
103  for pt_value in pt_of_interest:
104  # create plots of efficiency in bins of cos Theta for different pt
105  generate_cos_theta_plot(data_tree, pt_value)
106 
107  # create momentum resolution plot
108  create_momentum_resolution_plot(data_tree)
109 
110  draw_impact_parameter(data_tree)
111 
112  draw_pvalue(data_tree)
113 
114  draw_hit_counts(data_tree, pt_of_interest)
115 
116  draw_residua(data_tree, 'x', 'x_gen', pt_of_interest=pt_of_interest)
117  draw_residua(data_tree, 'y', 'y_gen', pt_of_interest=pt_of_interest)
118  draw_residua(data_tree, 'z', 'z_gen', pt_of_interest=pt_of_interest)
119 
120  draw_residua(
121  data_tree,
122  'pt',
123  'pt_gen',
124  bins=200,
125  ledge=-0.1,
126  uedge=0.1,
127  normalize=1,
128  pt_of_interest=pt_of_interest,
129  )
130 
131  # write additional plots in sub dir
132  sub_dir = 'additionalPlots'
133  output_root_file.mkdir(sub_dir)
134  output_root_file.cd(sub_dir)
135 
136  for pt_value in PT_VALUES:
137  # create plots of efficiency in bins of cos Theta for different pt
138  generate_cos_theta_plot(data_tree, pt_value)
139 
140  draw_residua(data_tree, 'x', 'x_gen')
141  draw_residua(data_tree, 'y', 'y_gen')
142  draw_residua(data_tree, 'z', 'z_gen')
143 
144  draw_residua(
145  data_tree,
146  'pt',
147  'pt_gen',
148  bins=200,
149  ledge=-0.1,
150  uedge=0.1,
151  normalize=1,
152  )
153 
154  # close output file
155  output_root_file.Write()
156  output_root_file.Close()
157 
158 
159 def draw_hit_counts(data_tree, pt_values):
160  """
161  Draw the hit count distribution.
162  """
163 
164  pt_lower = -0.025
165  pt_upper = 4.025
166  # 50 MeV wide bins. + 0.5 serves for correct rounding.
167  number_bins = int((pt_upper - pt_lower) / 0.05 + 0.5)
168 
169  hists = {}
170  for det in ['PXD', 'SVD', 'CDC']:
171  hists[det] = TProfile('hHitCounts%s' % det,
172  'Hit count profile for the %s;pT;nHits' % det,
173  number_bins, pt_lower, pt_upper)
174 
175  description = 'Distribution of Hit Counts in %s (Contact: %s).' \
176  % (det, CONTACT_PERSON['Email'])
177  check = ''
178 
179  hists[det].GetListOfFunctions().Add(TNamed('Description', description))
180  hists[det].GetListOfFunctions().Add(TNamed('Check', check))
181  make_expert_plot(hists[det])
182 
183  hNweights = TH1F('hNweights', 'number of weights stored', 201, 0, 201)
184  hWeightsProfile = TProfile('hWeightsProfile', 'profile of weights', 201,
185  0, 201)
186  hWeightsProfile.SetMinimum(0)
187  hWeightsProfile.SetMaximum(1.1)
188  hWeights = TH1F('hWeights', 'DAF weights', 50, 0, 1)
189 
190  for track in data_tree:
191  if not track.pValue == -999:
192  hists['PXD'].Fill(track.pt_gen, track.nPXDhits)
193  hists['SVD'].Fill(track.pt_gen, track.nSVDhits)
194  hists['CDC'].Fill(track.pt_gen, track.nCDChits)
195  hNweights.Fill(track.nWeights)
196  for i in range(track.nWeights):
197  hWeights.Fill(track.weights[i])
198  hWeightsProfile.Fill(i, track.weights[i])
199 
200  for key in hists:
201  hists[key].Write()
202  # hNweights.Write()
203  # hWeights.Write()
204  make_expert_plot(hWeightsProfile)
205  hWeightsProfile.Write()
206 
207 
208 def draw_pvalue(data_tree):
209  """
210  Create a histogram of the pValue of the track fits
211  """
212 
213  number_entries = data_tree.GetEntries()
214  # Normalize number of bins to number of events to keep plots comparable.
215  numBins = math.trunc(number_entries / 200)
216  hist_pvalue = TH1F('hpValue', 'p-Value Distribution', numBins, 0., 1.)
217  # Make axis range independent of first bin contents for more pleasant look
218  hist_pvalue.SetMinimum(0)
219  # hist_pvalue.SetMaximum(number_entries / 50.)
220 
221  for entry in range(number_entries):
222  data_tree.GetEntry(entry)
223 
224  try:
225  pvalue = data_tree.GetLeaf('pValue').GetValue()
226  except ReferenceError:
227  print('The variable "pValue" doesn\'t exist in the tree "%s".\nLeave this function without plotting the variable.'
228  % data_tree.GetName())
229  return
230 
231  if pvalue is -999:
232  continue
233  else:
234  hist_pvalue.Fill(pvalue)
235 
236  hist_pvalue.SetTitle('Distribution of pValue')
237  hist_pvalue.SetXTitle('pValue')
238  hist_pvalue.SetYTitle('number of entries')
239 
240  description = 'Distribution of pValues of the tracks (Contact: %s).' \
241  % CONTACT_PERSON['Email']
242  check = 'Should be a flat distribution.'
243 
244  hist_pvalue.GetListOfFunctions().Add(TNamed('Description', description))
245  hist_pvalue.GetListOfFunctions().Add(TNamed('Check', check))
246  make_expert_plot(hist_pvalue)
247 
248  hist_pvalue.Write()
249 
250 
251 def calculate_efficiency_in_pt(data_tree):
252  """Calculate single track reconstruction efficiency in bins of pt"""
253 
254  pt_lower = -0.025
255  pt_upper = 4.025
256  # 50 MeV wide bins. + 0.5 serves for correct rounding.
257  number_bins = int((pt_upper - pt_lower) / 0.05 + 0.5)
258 
259  hist_pt_gen = TH1F('hPtGen', 'hPtGen', number_bins, pt_lower, pt_upper)
260  hist_pt_rec = TH1F('hPtRec', 'hPtRec', number_bins, pt_lower, pt_upper)
261 
262  # draw data in defined histos
263  data_tree.Draw('pt_gen>>hPtGen', '', 'goff')
264  data_tree.Draw('pt_gen>>hPtRec', 'pt != -999', 'goff')
265 
266  # final hist
267  efficiency_hist = TH1F('hEfficiency', 'hEfficiency', number_bins,
268  pt_lower, pt_upper)
269  efficiency_hist.SetMinimum(0)
270  efficiency_hist.SetMaximum(1.05)
271 
272  description = ('Events with 10 muon tracks with fixed transverse '
273  'momentum are generated using the ParticleGun(500 '
274  'events for each pt value). The events are reconstructed '
275  'with VXDTF + CDC Track Finder + VXDCDCMerger.'
276  'plot shows the single track reconstruction efficiency '
277  'over the transverse momentum.')
278 
279  check = 'The efficiency should be stable for higher pt values.'
280  efficiency_hist.GetListOfFunctions().Add(TNamed('Description',
281  description))
282  efficiency_hist.GetListOfFunctions().Add(TNamed('Check', check))
283  efficiency_hist.GetListOfFunctions().Add(TNamed('Contact',
284  CONTACT_PERSON['Email']))
285 
286  # loop over bins and calculate efficiency and error of efficiency
287  for ibin in range(1, number_bins + 1):
288  number_generated = hist_pt_gen.GetBinContent(ibin)
289  efficiency = 0
290  error = 0
291 
292  if number_generated > 0:
293  number_reconstructed = hist_pt_rec.GetBinContent(ibin)
294  efficiency = number_reconstructed / number_generated
295  error = math.sqrt(number_reconstructed * (number_generated - number_reconstructed) / pow(number_generated, 3))
296  # set according bin to the efficiency value and add errorbar
297  efficiency_hist.SetBinContent(ibin, efficiency)
298  efficiency_hist.SetBinError(ibin, error)
299 
300  efficiency_hist.SetTitle('Tracking efficiency in bins of transverse momentum pt.'
301  )
302  efficiency_hist.SetXTitle('pt in GeV')
303  efficiency_hist.SetYTitle('efficiency')
304 
305  # write hist to the output file
306  efficiency_hist.Write()
307 
308 
309 def generate_cos_theta_plot(data_tree, pt_value):
310  """Creates a efficiency histo in bins of cos theta"""
311 
312  number_bins = 100
313  cos_lower = -1
314  cos_upper = 1
315 
316  hist_cos_gen = TH1F('hCosGen', 'hCosGen', number_bins, cos_lower,
317  cos_upper)
318  hist_cos_rec = TH1F('hCosRec', 'hCosRec', number_bins, cos_lower,
319  cos_upper)
320 
321  data_tree.Draw('cosTheta_gen>>hCosGen',
322  'pt_gen>(%.2f - %f) &&pt_gen<(%.2f + %f)' % (pt_value,
323  DELTA_PT, pt_value, DELTA_PT), 'goff')
324  data_tree.Draw('cosTheta_gen>>hCosRec',
325  'pt_gen>(%.2f - %f) &&pt_gen<(%.2f + %f) && pt != -999'
326  % (pt_value, DELTA_PT, pt_value, DELTA_PT), 'goff')
327 
328  description = ('Events with 10 muon tracks with fixed transverse '
329  'momentum are generated using the ParticleGun(500 '
330  'events for each pt value). The events are reconstructed '
331  'with VXDTF + CDCTF + MCTrackCandCombiner. The plot '
332  'shows the single track reconstruction efficiency in '
333  'bins of the polar angle for the fixed transverse '
334  'momentum pt = %.2f GeV.')
335  check = 'Stable efficiency over the hole range of the polar angle.'
336 
337  efficiency_hist = TH1F('hEfficiencyPt%.2fGeV' % pt_value,
338  'hEfficiencyPt%.2fGeV' % pt_value, number_bins,
339  cos_lower, cos_upper)
340  efficiency_hist.GetListOfFunctions().Add(TNamed('Description',
341  description))
342  efficiency_hist.GetListOfFunctions().Add(TNamed('Check', check))
343  efficiency_hist.GetListOfFunctions().Add(TNamed('Contact',
344  CONTACT_PERSON['Email']))
345 
346  for ibin in range(1, number_bins + 1):
347  efficiency = 0
348  error = 0
349  number_generated = hist_cos_gen.GetBinContent(ibin)
350 
351  if number_generated > 0:
352  number_reconstructed = hist_cos_rec.GetBinContent(ibin)
353  efficiency = number_reconstructed / number_generated
354  error = math.sqrt(number_reconstructed * (number_generated - number_reconstructed) / pow(number_generated, 3))
355 
356  efficiency_hist.SetBinContent(ibin, efficiency)
357  efficiency_hist.SetBinError(ibin, error)
358 
359  efficiency_hist.SetTitle('Tracks with pt = %.2f GeV' % pt_value)
360  efficiency_hist.SetXTitle('cos #Theta')
361  efficiency_hist.SetYTitle('efficiency')
362  make_expert_plot(efficiency_hist)
363  efficiency_hist.Write()
364 
365 
366 def create_momentum_resolution_plot(data_tree):
367  """Create momentum resolution plot"""
368 
369  pt_lower = -0.025
370  pt_upper = 4.025
371  # 50 MeV wide bins. + 0.5 serves for correct rounding.
372  number_bins = int((pt_upper - pt_lower) / 0.05 + 0.5)
373 
374  sigma_pt_values = calculate_momentum_resolution2(data_tree)
375 
376  hist_resolution = TH1F('hPtResolution', 'hPtResolution', number_bins,
377  pt_lower, pt_upper)
378 
379  fit_pt_values = []
380  fit_pt_res_values = []
381  fit_pt_res_errors = []
382 
383  for (pt_value, sigma_pt_value) in sigma_pt_values.items():
384  ibin = hist_resolution.FindBin(pt_value)
385  bin_center = hist_resolution.GetBinCenter(ibin)
386 
387  sigma_pt_over_pt = 0
388  if sigma_pt_value[0] != -999:
389  sigma_pt_over_pt = sigma_pt_value[0] / pt_value
390  sigma_pt_error_over_pt = sigma_pt_value[1] / pt_value
391 
392  fit_pt_res_values.append(sigma_pt_over_pt)
393  fit_pt_res_errors.append(sigma_pt_error_over_pt)
394  fit_pt_values.append(bin_center)
395 
396  hist_resolution.SetBinContent(ibin, sigma_pt_over_pt)
397  hist_resolution.SetBinError(ibin, sigma_pt_error_over_pt)
398 
399  hist_resolution.SetTitle('Transverse Momentum resolution')
400  hist_resolution.SetXTitle('pt in GeV/c')
401  hist_resolution.SetYTitle('#sigma_{pt}/pt')
402 
403  description = ('Events with 10 muon tracks with fixed transverse '
404  'momentum are generated using the ParticleGun(200 '
405  'events for each pt value). The events are reconstructed '
406  'with VXDTF + CDCTF + MCTrackCandCombiner. The plot '
407  'shows the relative momentum resolution of the '
408  'transverse momentum over transverse momentum.')
409 
410  check = ''
411  hist_resolution.GetListOfFunctions().Add(TNamed('Description',
412  description))
413  hist_resolution.GetListOfFunctions().Add(TNamed('Check', check))
414  hist_resolution.GetListOfFunctions().Add(TNamed('Contact',
415  CONTACT_PERSON['Email']))
416  hist_resolution.GetListOfFunctions().Add(TNamed('MetaOptions', 'logy'))
417  hist_resolution.Write()
418 
419  # fit_parameters = fit_resolution(fit_pt_values, fit_pt_res_values, 1, fit_pt_res_errors)
420 
421 
422 def get_scaled_rms_90(values, scale_factor=0.79):
423  """
424  Calculate the RMS90
425 
426  param values: list of numbers
427  return scaled RMS90 of the distribution in values
428  """
429 
430  (vMin, vMax) = (np.nanpercentile(values, 5), np.nanpercentile(values, 95))
431  final_list = np.array(values)[np.logical_and(values > vMin, values < vMax)]
432 
433  rms_90 = np.sqrt(np.mean(np.square(final_list))) / scale_factor
434 
435  rms_error = rms_90 / (scale_factor * np.sqrt(2 * len(final_list)))
436 
437  return (rms_90, rms_error)
438 
439 
440 def value_in_list(test_value, value_list):
441  """
442  Function checks, if a given value is in the list values
443  """
444 
445  for value in value_list:
446  if value - DELTA_PT < test_value < value + DELTA_PT:
447  return (True, value)
448 
449  return (False, -999)
450 
451 
452 def calculate_momentum_resolution2(data_tree):
453  """
454  Calculate momentum resolution
455  """
456 
457  delta_pt_dict = {}
458 
459  for key in PT_VALUES:
460  delta_pt_dict[key] = []
461 
462  for entry_index in range(data_tree.GetEntries()):
463  # load entry
464  data_tree.GetEntry(entry_index)
465 
466  pt_gen = data_tree.GetLeaf('pt_gen').GetValue()
467 
468  test_object = value_in_list(pt_gen, PT_VALUES)
469 
470  if test_object[0]:
471  pt = data_tree.GetLeaf('pt').GetValue()
472  if pt != -999:
473  try:
474  delta_pt_dict[test_object[1]].append(pt - pt_gen)
475  except KeyError:
476  print('pt = %0.2f is not generated and not used as key. Abort!'
477  % test_object[1])
478  sys.exit(1)
479  pt_resolutions = {}
480 
481  print('********************************')
482  print('Momentum resolution:')
483  for key in sorted(delta_pt_dict):
484  (rms90, rms_error) = get_scaled_rms_90(delta_pt_dict[key])
485  pt_resolutions[key] = [rms90, rms_error]
486  print('pt = %0.2f: sigma/pt = %0.4f' % (key, rms90 / key))
487 
488  return pt_resolutions
489 
490 
491 def fit_resolution(
492  x_value_list,
493  y_value_list,
494  degree,
495  y_value_errors=None,
496 ):
497  """
498  Fit a polynomial to data
499 
500  @param x_value_list list of x values
501 
502  @param y_value_list list of y values
503 
504  @param degree degree of the fitting polynomial
505 
506  @param y_value_errors list of corresponding errors on y x_values
507  """
508 
509  try:
510  import scipy.optimize
511  except ImportError:
512  print('Module scipy.optimize is not installed. Fit cannot be done.')
513  return []
514 
515  # weights = None
516  # if y_value_errors is not None:
517  # weights = [1 / x ** 2 for x in y_value_errors]
518  #
519  # parameters = np.polyfit(x_value_list, y_value_list, degree, w=weights,
520  # cov=True)
521 
522  x_value_list = np.array(x_value_list)
523  y_value_list = np.array(y_value_list)
524  y_value_errors = np.array(y_value_errors)
525 
526  (par_opt, par_cov) = \
527  scipy.optimize.curve_fit(fit_function_sigma_pt_over_pt, x_value_list,
528  y_value_list, [0.002, 0.003],
529  sigma=y_value_errors)
530 
531  print(par_opt, par_cov)
532 
533  return par_opt
534 
535 
536 def draw_impact_parameter(data_tree):
537  """
538  Create a histogram with the impact parameter resolution
539 
540  @param data_tree ROOT tree with the input data
541  """
542 
543  print('********************************')
544  print('Impact parameter:')
545 
546  impact_param_d = {}
547  impact_param_z = {}
548  for key in PT_VALUES:
549  impact_param_d[key] = []
550  impact_param_z[key] = []
551 
552  try:
553  number_of_entries = data_tree.GetEntries()
554  except AttributeError:
555  print('ERROR: data_tree in function "draw_impact_parameter" is no TTree.')
556  sys.exit(2)
557 
558  for index_entry in range(number_of_entries):
559  data_tree.GetEntry(index_entry)
560 
561  pt_gen = data_tree.GetLeaf('pt_gen').GetValue()
562 
563  test_object = value_in_list(pt_gen, PT_VALUES)
564  if test_object[0] is True:
565  poca_x = data_tree.GetLeaf('x').GetValue()
566 
567  if poca_x == -999:
568  continue
569 
570  poca_y = data_tree.GetLeaf('y').GetValue()
571  poca_z = data_tree.GetLeaf('z').GetValue()
572 
573  z_gen = data_tree.GetLeaf('z_gen').GetValue()
574 
575  px = data_tree.GetLeaf('px').GetValue()
576  py = data_tree.GetLeaf('py').GetValue()
577 
578  d0 = d0_sign([poca_x, poca_y], [px, py]) * np.hypot(poca_x, poca_y)
579 
580  impact_param_d[test_object[1]].append(d0)
581  impact_param_z[test_object[1]].append(poca_z - z_gen)
582  # estimate sign of d0
583 
584  d0_resolutions = {}
585  z_resolutions = {}
586  for key in sorted(impact_param_d):
587  (d0_resolution, d0_error) = get_scaled_rms_90(impact_param_d[key])
588  d0_resolutions[key] = [d0_resolution, d0_error]
589  (z_resolution, z_error) = get_scaled_rms_90(impact_param_z[key])
590  z_resolutions[key] = [z_resolution, z_error]
591  print('pt = %0.2f: sigma_d0 = %0.4f, sigma_z = %0.4f' % (key,
592  d0_resolution, z_resolution))
593 
594  number_bins = 62
595  lower_edge = -0.025
596  upper_edge = 4.025
597 
598  hist_impact_parameter_d0 = TH1F('hd0resolution', 'hd0resolution',
599  number_bins, lower_edge, upper_edge)
600  hist_impact_parameter_d0.SetTitle('d0 resolution')
601  hist_impact_parameter_d0.SetXTitle('pt in GeV/c')
602  hist_impact_parameter_d0.SetYTitle('#sigma_{d0} [cm]')
603  hist_impact_parameter_d0.GetListOfFunctions().Add(TNamed('MetaOptions', 'logy'))
604  hist_impact_parameter_d0.GetListOfFunctions().Add(TNamed('Contact',
605  CONTACT_PERSON['Email']))
606 
607  hist_impact_parameter_z = TH1F('hzresolution', 'hzresolution',
608  number_bins, lower_edge, upper_edge)
609  hist_impact_parameter_z.SetTitle('z resolution')
610  hist_impact_parameter_z.SetXTitle('pt in GeV/c')
611  hist_impact_parameter_z.SetYTitle('#sigma_{z} [cm]')
612  hist_impact_parameter_z.GetListOfFunctions().Add(TNamed('MetaOptions', 'logy'))
613  hist_impact_parameter_z.GetListOfFunctions().Add(TNamed('Contact',
614  CONTACT_PERSON['Email']))
615 
616  for pt in PT_VALUES:
617  ibin = hist_impact_parameter_d0.FindBin(pt)
618  if d0_resolutions[pt][0] > 0 and d0_resolutions[pt][1] > 0:
619  hist_impact_parameter_d0.SetBinContent(ibin, d0_resolutions[pt][0])
620  hist_impact_parameter_d0.SetBinError(ibin, d0_resolutions[pt][1])
621  if z_resolutions[pt][0] > 0 and z_resolutions[pt][1] > 0:
622  hist_impact_parameter_z.SetBinContent(ibin, z_resolutions[pt][0])
623  hist_impact_parameter_z.SetBinError(ibin, z_resolutions[pt][1])
624 
625  hist_impact_parameter_d0.Write()
626  hist_impact_parameter_z.Write()
627 
628 
629 def scale_histogram(hist):
630  """
631  Scales a TH1F using the TH1::Scale function
632  """
633 
634  if isinstance(hist, TH1F):
635  if hist.GetEntries() > 0:
636  hist.Scale(1 / hist.GetEntries())
637  else:
638  print('Cannot scale. No entries in histogram ' + hist.GetName())
639  else:
640  print('Not a TH1F. Not able to scale.')
641 
642 
643 def d0_sign(vector_d, momentum):
644  """
645  Estimate the sign of the impact parameter d0_sign
646 
647  @return -1 or +1
648  """
649 
650  if len(vector_d) != 2 or len(momentum) != 2:
651  print('Need x and y values of d and p_d.')
652  sys.exit(1)
653 
654  phi_momentum = np.arctan2(momentum[1], momentum[0])
655  phi_d = np.arctan2(vector_d[1], vector_d[0])
656 
657  diff = phi_momentum - phi_d
658  # Catch corner cases. For clarity, don't return early.
659  if diff > np.pi:
660  diff = diff - 2 * np.pi
661  elif diff < -np.pi:
662  diff = 2 * np.pi + diff
663 
664  return np.sign(diff)
665 
666 
667 def draw_residua(
668  data_tree,
669  variable_name,
670  gen_variable_name,
671  bins=100,
672  ledge=-0.01,
673  uedge=0.01,
674  normalize=0,
675  pt_of_interest=None,
676 ):
677  """
678  Write histogram of difference of variable_name (reconstructed) and
679  gen_variable_name (generated) in gDirectory
680  """
681 
682  if pt_of_interest is None:
683  used_pts = PT_VALUES
684  else:
685  used_pts = [pt for pt in pt_of_interest if pt in PT_VALUES]
686 
687  number_entries = data_tree.GetEntries()
688 
689  histograms = {}
690  for pt_value in used_pts:
691  histograms[pt_value] = TH1F('h%sResiduum_%0.2fGeV' % (variable_name,
692  pt_value), 'h%sResiduum_%0.2fGeV'
693  % (variable_name, pt_value), bins, ledge,
694  uedge)
695 
696  for index in range(number_entries):
697  data_tree.GetEntry(index)
698 
699  variable_reconstructed = data_tree.GetLeaf(variable_name).GetValue()
700  if variable_reconstructed != -999:
701  variable_generated = \
702  data_tree.GetLeaf(gen_variable_name).GetValue()
703  pt_gen = round(data_tree.GetLeaf('pt_gen').GetValue(), 2)
704  if pt_gen in used_pts:
705  if normalize:
706  histograms[pt_gen].Fill((variable_reconstructed - variable_generated) / variable_generated)
707  else:
708  histograms[pt_gen].Fill(variable_reconstructed - variable_generated)
709 
710  for (pt, hist) in histograms.items():
711  scale_histogram(hist)
712  if normalize:
713  hist.SetXTitle('(%s - %s) / %s' % (variable_name,
714  gen_variable_name, gen_variable_name))
715  else:
716  hist.SetXTitle('(%s - %s)' % (variable_name, gen_variable_name))
717  hist.GetListOfFunctions().Add(TNamed('Contact', CONTACT_PERSON['Email'
718  ]))
719  make_expert_plot(hist)
720  hist.Write()
721 
722 
723 def tf1_fit_function(x, par):
724  return fit_function_sigma_pt_over_pt(x, par[0], par[1])
725 
726 
727 def fit_function_sigma_pt_over_pt(x, a, b):
728  return np.sqrt((a * x) ** 2 + b * b)
729 
730 
731 if __name__ == '__main__':
732  main()
int main(int argc, char **argv)
Run all tests.
Definition: test_main.cc:75