Belle II Software  release-06-02-00
__init__.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 """\
13 Utilities for PXD calibration and performance study
14 """
15 
16 import ROOT
17 from ROOT import Belle2
18 import pandas as pd
19 import numpy as np
20 
21 
22 # Helper functions for Belle2.VxdID
23 def get_name(self, separator="_"):
24  """
25  Get PXD module name with a specific format
26  Parameters:
27  self: Belle2.VxdID
28  separator (str): separator between different (layer/ladder/sensor) numbers.
29  Return:
30  PXD module name, e.g., 1_1_1
31  """
32  return f"{self.getLayerNumber()}{separator}{self.getLadderNumber()}{separator}{self.getSensorNumber()}"
33 
34 
35 def get_pxdid(self):
36  """
37  Get PXD module id: layer_id * 1000 + ladder_id * 10 + sensor_id
38  Parameters:
39  self: Belle2.VxdID
40  Return:
41  PXD module id, e.g., 1011
42  """
43  return self.getLayerNumber() * 1000 + self.getLadderNumber() * 10 + self.getSensorNumber()
44 
45 
46 # Helper function for TGraph
47 def graph_append(self, x, y):
48  """
49  Append a point to TGraph
50  Parameters:
51  self: ROOT.TGraph
52  x (float): x coordinate of the point
53  y (float): y coordinate of the point
54  """
55  self.SetPoint(self.GetN(), x, y)
56 
57 
58 # Extend Belle2.VxdID
59 Belle2.VxdID.get_name = get_name
60 Belle2.VxdID.get_pxdid = get_pxdid
61 # Extend ROOT classes
62 ROOT.TGraph.append = graph_append
63 
64 # Sensor id list
65 sensor_labels = [
66  "1.1.1", "1.1.2",
67  "1.2.1", "1.2.2",
68  "1.3.1", "1.3.2",
69  "1.4.1", "1.4.2",
70  "1.5.1", "1.5.2",
71  "1.6.1", "1.6.2",
72  "1.7.1", "1.7.2",
73  "1.8.1", "1.8.2",
74  "2.4.1", "2.4.2",
75  "2.5.1", "2.5.2"]
76 sensorID_list = tuple([Belle2.VxdID(label) for label in sensor_labels])
77 nsensors = len(sensorID_list)
78 
79 # Sensor matrix
80 nUCells = 250
81 nVCells = 768
82 nPixels = 192000
83 
84 # Colors and styles for ROOT
85 colors = tuple([
86  ROOT.kRed + 1, ROOT.kOrange + 1, ROOT.kYellow - 3, ROOT.kSpring + 5, ROOT.kGreen + 3,
87  ROOT.kCyan - 6, ROOT.kAzure - 5, ROOT.kAzure - 6, ROOT.kBlue + 3, ROOT.kViolet - 1])
88 
89 plot_configs = {
90  "LineWidth": 4,
91  "yTitleOffset": 0.9
92 }
93 
94 
95 def get_sensor_graphs(ytitle=""):
96  """
97  Create TGraphs and related TLegends
98  Parameters:
99  ytitle (str): Title of the y-axis
100  Return:
101  A dictionary using sensorID as key and TGraph as value. A special key "TLegends"
102  is used for the list of TLegend objects for drawing.
103  """
104  graphs = {}
105  legs = []
106  # Create TLegends
107  xlegl = [0.60, 0.57, 0.78, 0.75]
108  xlegr = [0.72, 0.65, 0.90, 0.83]
109  for i in range(4):
110  """
111  Display format (content in a TLegend is bracketed):
112  (marker1 /) (marker2 label1/label2) (marker3 /) (markter4 label3/label4)
113  """
114  legs.append(ROOT.TLegend(xlegl[i], 0.62, xlegr[i], 0.85))
115  legs[i].SetFillStyle(0)
116  legs[i].SetBorderSize(0)
117  legs[i].SetTextFont(43)
118  legs[i].SetTextSize(18)
119  # Create TGraphs and set TLegend for each sensor
120  for i, sensorID in enumerate(sensorID_list):
121  agraph = ROOT.TGraph()
122  # agraph.SetTitle(sensorID.get_name())
123  agraph.SetName(sensorID.get_name())
124  agraph.GetXaxis().SetTitle('run #')
125  agraph.GetYaxis().SetTitle(ytitle)
126  agraph.GetYaxis().SetTitleOffset(0.9)
127  agraph.SetLineColor(colors[int(i / 2)])
128  agraph.SetLineWidth(4)
129  agraph.SetMarkerColor(colors[int(i / 2)])
130  agraph.SetMarkerStyle(26 if i % 2 else 24)
131  graphs[sensorID.getID()] = agraph
132  # Set TLegend
133  i1 = 0
134  i2 = 1
135  if (i > 9):
136  i1 = 2
137  i2 = 3
138  if (i % 2):
139  legs[i1].AddEntry(agraph, sensor_labels[i - 1] + ' / ' + sensor_labels[i], 'p')
140  else:
141  legs[i2].AddEntry(agraph, ' / ', 'p')
142  graphs["TLegends"] = legs
143 
144  return graphs
145 
146 
147 def get_sensor_maps(
148  name="MaskedPixels", title="Masked Pixels", ztitle="isMasked", run=0,
149  nUCells=nUCells, nVCells=nVCells, sensorID_list=sensorID_list
150 ):
151  """
152  Create TH2F objects for saving pixel map
153  Parameters:
154  name (str): Name of a histogram
155  title (str): Title
156  ztitle (str): Label for z-axis
157  run (int): run number of the map, to be appended into the title
158  sensorID_list (list): List of sensorID objects for which histograms are created.
159  Return:
160  A dictionary using sensorID as key and TH2F as value.
161  """
162  hists = {}
163  for sensorID in sensorID_list:
164  hname = name + "_{}_run_{:d}".format(sensorID.get_name(), run)
165  htitle = title + " Sensor={:d} Run={:d}".format(sensorID.get_pxdid(), run)
166  h2 = ROOT.TH2F(hname, htitle, nUCells, 0, nUCells, nVCells, 0, nVCells)
167  h2.GetXaxis().SetTitle("uCell")
168  h2.GetYaxis().SetTitle("vCell")
169  h2.GetZaxis().SetTitle(ztitle)
170  h2.SetStats(0)
171  hists[sensorID.getID()] = h2
172  return hists
173 
174 
175 def df_calculate_eff(df, num="nTrackClusters", den="nTrackPoints", output_var="eff"):
176  """
177  Efficiency calculation with asymmetric errors for pandas DataFrame
178  Parameters:
179  df: pandas.DataFrame
180  num (str): column used as the numerator
181  den (str): column used as the denominator
182  output_var (str): column for saving efficiency
183  """
184  nums = df[num].to_numpy()
185  dens = df[den].to_numpy()
186  from root_numpy import array2hist
187  nBins = len(nums)
188  assert len(nums) == len(dens), "len(numerators) != len(denominators)"
189  h_num = ROOT.TH1I("h_num", "h_num", nBins, 0, nBins)
190  h_den = ROOT.TH1I("h_den", "h_den", nBins, 0, nBins)
191  array2hist(nums, h_num)
192  array2hist(dens, h_den)
193  h_eff = ROOT.TEfficiency(h_num, h_den)
194  df[output_var] = df[num]/df[den]
195  df[output_var+"_err_low"] = [h_eff.GetEfficiencyErrorLow(i+1) for i in range(nBins)]
196  df[output_var+"_err_up"] = [h_eff.GetEfficiencyErrorUp(i+1) for i in range(nBins)]
197 
198 
199 def getH1Sigma68(h1, fill_random=False):
200  """
201  Helper function to get sigma68 from TH1
202  Parameters:
203  h1 (ROOT.TH1): TH1 object from ROOT
204  fill_random (bool): Flag to call TH1.FillRandom
205  Return:
206  sigma68
207  """
208  qs = np.array([0., 0.])
209  probs = np.array([0.16, 0.84])
210  if fill_random:
211  h1tmp = h1.Clone()
212  h1tmp.Reset()
213  h1tmp.FillRandom(h1, int(h1.GetEffectiveEntries()))
214  h1tmp.GetQuantiles(2, qs, probs)
215  else:
216  h1.GetQuantiles(2, qs, probs)
217  return (qs[1]-qs[0])
218 
219 
220 def getH1Sigma68WithError(h1, n=300):
221  """
222  Helper function to get sigma68 and its error using TH1.FillRandom
223  Parameters:
224  h1 (ROOT.TH1): TH1 object from ROOT
225  n (int): number of randomly generated histograms for the estimation
226  Return:
227  estimatd sigma68 and its standard deviation
228  """
229  results = np.array([getH1Sigma68(h1, fill_random=True) for i in range(n)])
230  # return results.mean(), results.std()
231  return getH1Sigma68(h1), results.std()
232 
233 
234 def getSigma68(array):
235  """
236  Helper function to get sigma68 and its error using numpy.array
237  Parameters:
238  array (numpy.array): target array
239  Return:
240  estimatd sigma68
241  """
242  q1 = np.quantile(array, 0.16, axis=0)
243  q2 = np.quantile(array, 0.84, axis=0)
244  return (q2-q1) # /2*1e4 # cm to um
245 
246 
247 def getSigma68WithError(array, n=300):
248  """
249  Helper function to get sigma68 and its error using numpy.array
250  Parameters:
251  array (numpy.array): target array
252  n (int): number of bootstrap drawings
253  Return:
254  estimatd sigma68 and its standard deviation
255  """
256  bs = np.random.choice(array, (array.shape[0], n)) # bootstrap resampling
257  results = getSigma68(bs)
258  # return results.mean(), results.std()
259  return getSigma68(a), results.std()
260 
261 
262 # Extend pandas.DataFrame
263 pd.DataFrame.calculate_eff = df_calculate_eff
264 
265 # latex
266 latex_l = ROOT.TLatex() # left aligned
267 latex_l.SetTextFont(43)
268 latex_l.SetNDC()
269 latex_l.SetTextSize(24)
270 latex_ls = ROOT.TLatex() # left aligned small
271 latex_ls.SetTextFont(43)
272 latex_ls.SetNDC()
273 latex_ls.SetTextSize(19)
274 latex_r = ROOT.TLatex() # right aligned
275 latex_r.SetTextFont(43)
276 latex_r.SetNDC()
277 latex_r.SetTextSize(24)
278 latex_r.SetTextAlign(31)
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33