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