12Utilities for PXD calibration and performance study
16from ROOT
import Belle2
22def get_name(self, separator="_"):
24 Get PXD module name with a specific format
27 separator (str): separator between different (layer/ladder/sensor) numbers.
29 PXD module name, e.g., 1_1_1
31 return f
"{self.getLayerNumber()}{separator}{self.getLadderNumber()}{separator}{self.getSensorNumber()}"
36 Get PXD module id: layer_id * 1000 + ladder_id * 10 + sensor_id
40 PXD module id, e.g., 1011
42 return self.getLayerNumber() * 1000 + self.getLadderNumber() * 10 + self.getSensorNumber()
46def graph_append(self, x, y):
48 Append a point to TGraph
51 x (float): x coordinate of the point
52 y (float): y coordinate of the point
54 self.SetPoint(self.GetN(), x, y)
58Belle2.VxdID.get_name = get_name
59Belle2.VxdID.get_pxdid = get_pxdid
61ROOT.TGraph.append = graph_append
75sensorID_list = tuple([
Belle2.VxdID(label)
for label
in sensor_labels])
76nsensors = len(sensorID_list)
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])
94def get_sensor_graphs(ytitle=""):
96 Create TGraphs and related TLegends
98 ytitle (str): Title of the y-axis
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.
106 xlegl = [0.60, 0.57, 0.78, 0.75]
107 xlegr = [0.72, 0.65, 0.90, 0.83]
110 Display format (content in a TLegend
is bracketed):
111 (marker1 /) (marker2 label1/label2) (marker3 /) (markter4 label3/label4)
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)
119 for i, sensorID
in enumerate(sensorID_list):
120 agraph = ROOT.TGraph()
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
138 legs[i1].AddEntry(agraph, sensor_labels[i - 1] +
' / ' + sensor_labels[i],
'p')
140 legs[i2].AddEntry(agraph,
' / ',
'p')
141 graphs[
"TLegends"] = legs
147 name="MaskedPixels", title="Masked Pixels", ztitle="isMasked", run=0,
148 nUCells=nUCells, nVCells=nVCells, sensorID_list=sensorID_list
151 Create TH2F objects for saving pixel map
153 name (str): Name of a histogram
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.
159 A dictionary using sensorID
as key
and TH2F
as value.
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)
170 hists[sensorID.getID()] = h2
174def df_calculate_eff(df, num="nTrackClusters", den="nTrackPoints", output_var="eff"):
176 Efficiency calculation with asymmetric errors
for 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
183 nums = df[num].to_numpy()
184 dens = df[den].to_numpy()
185 from hist_utils
import array2hist
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)]
198def getH1Sigma68(h1, fill_random=False):
200 Helper function to get sigma68 from TH1
202 h1 (ROOT.TH1): TH1 object
from ROOT
203 fill_random (bool): Flag to call TH1.FillRandom
207 qs = np.array([0., 0.])
208 probs = np.array([0.16, 0.84])
212 h1tmp.FillRandom(h1, int(h1.GetEffectiveEntries()))
213 h1tmp.GetQuantiles(2, qs, probs)
215 h1.GetQuantiles(2, qs, probs)
219def getH1Sigma68WithError(h1, n=300):
221 Helper function to get sigma68 and its error using TH1.FillRandom
223 h1 (ROOT.TH1): TH1 object
from ROOT
224 n (int): number of randomly generated histograms
for the estimation
226 estimatd sigma68
and its standard deviation
228 results = np.array([getH1Sigma68(h1, fill_random=True)
for i
in range(n)])
230 return getH1Sigma68(h1), results.std()
233def getSigma68(array):
235 Helper function to get sigma68 and its error using numpy.array
237 array (numpy.array): target array
241 q1 = np.quantile(array, 0.16, axis=0)
242 q2 = np.quantile(array, 0.84, axis=0)
246def getSigma68WithError(array, n=300):
248 Helper function to get sigma68 and its error using numpy.array
250 array (numpy.array): target array
251 n (int): number of bootstrap drawings
253 estimatd sigma68
and its standard deviation
255 bs = np.random.choice(array, (array.shape[0], n))
256 results = getSigma68(bs)
258 return getSigma68(array), results.std()
262pd.DataFrame.calculate_eff = df_calculate_eff
265latex_l = ROOT.TLatex()
266latex_l.SetTextFont(43)
268latex_l.SetTextSize(24)
269latex_ls = ROOT.TLatex()
270latex_ls.SetTextFont(43)
272latex_ls.SetTextSize(19)
273latex_r = ROOT.TLatex()
274latex_r.SetTextFont(43)
276latex_r.SetTextSize(24)
277latex_r.SetTextAlign(31)
Class to uniquely identify a any structure of the PXD and SVD.