16 from ROOT
import Belle2
17 from ROOT
import TH1F, TH2F, TF1, TFile, TGraphErrors, TSpectrum, TCanvas, TTree, TMath
22 from array
import array
25 def fitLaserResolution(
26 mcCorrectionsFile='/group/belle2/group/detector/TOP/calibration/MCreferences/t0MC.root',
28 outputFile='laserResolutionResults.root',
32 includeBackscatter=True,
36 Function that implements the fit of the laser time distribution correcting for the propagation time in the prism.
37 The inputs to the fitter are hit time distributions per channel, in the form of TH2F.
39 Two files containing the containing the hit timing VS channels distribution must be provided:
41 * The first file is used to estimate the light propagation correction (aka MC correction),
42 the number of peaks and the separation bewteen these peaks.
43 Since the correction is the same for all the slots, the corresponding TH2F can have only 512 bins on the x-axis.
44 A default file is available, where the hit time is taken from
45 the TOPSimHits, and the laser jitter has been set to zero in the simulation.
46 * The second file contains the distribution obtained from the data do be used to estimate the resolution.
47 In this case the histrogram must have
48 (512 x 16) bins on the x-axis, to store the time distribution for each channel of the detector.
51 mcCorrectionsFile (str): File with the TH2F containing the TOPSImHits time distribution.
52 Used to calculate the MC corrections
53 dataFile (str): File with the TH2F containing the TOPDigit time distribution on which the resolutions
55 outputFile (str): rootFile containing the outupt trees and plots
56 pdfType (str): PDF used in the data fit: cb for a CrystalBall, gaus for a Gaussian or
57 gausExpo for an exponentially modified Gaussian
58 maxPeaks (int): maximum number of peaks that can be used in the data fit. Note that the
59 actual value is decided channel-by-channel
60 according to the MC simulation, this parameter is only a maximum cap.
61 In the current implementation only 1 or 2 peaks are supported, therefore maxPeaks can only go up to 2
62 saveFits (bool): set to True to save the histrogram and the fit for eavey single channel
63 includeBackscatter (bool): set to True to add an extra peak in the fit to account for the
65 useMCPeaks (bool): ste to True to fix the light path time difference from the MC. Set to False
66 to let this parameter floating in the fit
71 if maxPeaks > 2
or maxPeaks < 1:
72 B2FATAL(
'Usupported value for the maximum number for peaks (maxPeaks = ' +
73 str(maxPeaks) +
'). Please set maxPeak o either 1 or 2.')
74 if pdfType
is not 'cb' and pdfType
is not 'gaus' and pdfType
is not 'gausExpo':
78 ". The possible options are cb for the Crystal Ball,"
79 "gaus for the Gaussian and gausExpo for exponentially modified Gaussian")
86 mcPeaks = [[-1.
for second
in range(2)]
for first
in range(512)]
89 tFileMC = TFile(mcCorrectionsFile)
90 histoMC = tFileMC.Get(
'LaserTimingVSChannelOneSlot')
93 for kCh
in range(512):
95 timeProjectionMC = histoMC.ProjectionY(
'projectionMC', kCh + 1, kCh + 1)
96 timeProjectionMC.GetXaxis().SetRangeUser(0., 1.)
98 spectrum = TSpectrum()
101 numPeaks = spectrum.Search(timeProjectionMC, 1.,
'nobackground', 0.1)
104 peaksX_ = spectrum.GetPositionX()
105 peaksY_ = spectrum.GetPositionY()
106 peaksX = [peaksX_[i]
for i
in range(numPeaks)]
107 peaksY = [peaksY_[j]
for j
in range(numPeaks)]
111 for iMax
in range(numPeaks):
113 maxPosition = int(peaksY.index(max(peaksY)))
114 peaksY[maxPosition] = -1.
115 mcPeaks[kCh][iMax] = peaksX[maxPosition]
122 tFileData = TFile(dataFile)
123 histoData = tFileData.Get(
'LaserTimingVSChannel')
126 tFileOut = TFile(outputFile,
"RECREATE")
127 outTree = TTree(
"tree",
"tree")
130 slotID = array(
'i', [0])
132 hwChannel = array(
'i', [0])
134 nPeaks = array(
'i', [0])
136 ndf = array(
'f', [0])
138 chi2 = array(
'f', [0.])
140 sigma = array(
'f', [0.])
142 errSigma = array(
'f', [0.])
144 peakTime = array(
'f', [0.])
146 errPeakTime = array(
'f', [0.])
149 extraTime = array(
'f', [0.])
151 errExtraTime = array(
'f', [0.])
154 sigmaExtra = array(
'f', [0.])
156 errSigmaExtra = array(
'f', [0.])
159 alpha = array(
'f', [0.])
161 errAlpha = array(
'f', [0.])
165 errN = array(
'f', [0.])
167 lam = array(
'f', [0.])
169 errLam = array(
'f', [0.])
171 norm1 = array(
'f', [0.])
173 errNorm1 = array(
'f', [0.])
175 norm2 = array(
'f', [0.])
177 errNorm2 = array(
'f', [0.])
180 normExtra = array(
'f', [0.])
182 errNormExtra = array(
'f', [0.])
185 deltaMC = array(
'f', [0.])
187 correctedTime = array(
'f', [0.])
189 latePeak = array(
'f', [0.])
191 earlyPeak = array(
'f', [0.])
194 outTree.Branch(
'slotID', slotID,
'slotID/I')
195 outTree.Branch(
'hwChannel', hwChannel,
'hwChannel/I')
196 outTree.Branch(
'ndf', ndf,
'ndf/F')
197 outTree.Branch(
'chi2', chi2,
'chi2/F')
198 outTree.Branch(
'nPeaks', nPeaks,
'nPeaks/I')
199 outTree.Branch(
'sigma', sigma,
'sigma/F')
200 outTree.Branch(
'errSigma', errSigma,
'errSigma/F')
201 outTree.Branch(
'peakTime', peakTime,
'peakTime/F')
202 outTree.Branch(
'errPeakTime', errPeakTime,
'errPeakTime/F')
203 outTree.Branch(
'extraTime', extraTime,
'extraTime/F')
204 outTree.Branch(
'errExtraTime', errExtraTime,
'errExtraTime/F')
205 outTree.Branch(
'alpha', alpha,
'alpha/F')
206 outTree.Branch(
'errAlpha', errAlpha,
'errAlpha/F')
207 outTree.Branch(
'n', n,
'n/F')
208 outTree.Branch(
'errN', errN,
'errN/F')
209 outTree.Branch(
'lam', lam,
'lam/F')
210 outTree.Branch(
'errLam', errLam,
'errLam/F')
211 outTree.Branch(
'norm1', norm1,
'norm1/F')
212 outTree.Branch(
'errNorm1', errNorm1,
'errNorm1/F')
213 outTree.Branch(
'norm2', norm2,
'norm2/F')
214 outTree.Branch(
'errNorm2', errNorm2,
'errNorm2/F')
215 outTree.Branch(
'normExtra', normExtra,
'normExtra/F')
216 outTree.Branch(
'errNormExtra', errNormExtra,
'errNormExtra/F')
217 outTree.Branch(
'sigmaExtra', sigmaExtra,
'sigmaExtra/F')
218 outTree.Branch(
'errSigmaExtra', errSigmaExtra,
'errSigmaExtra/F')
219 outTree.Branch(
'deltaMC', deltaMC,
'deltaMC/F')
220 outTree.Branch(
'correctedTime', correctedTime,
'correctedTime/F')
221 outTree.Branch(
'latePeak', latePeak,
'latePeak/F')
222 outTree.Branch(
'earlyPeak', earlyPeak,
'earlyPeak/F')
226 for iSlot
in range(0, 16):
227 print(
'Fitting slot ' + str(iSlot))
228 for k
in range(0, 512):
229 timeProjection = histoData.ProjectionY(
'projection_' + str(iSlot + 1) +
'_' +
230 str(k), k + iSlot * 512 + 1, k + iSlot * 512 + 1)
231 maximum = timeProjection.GetXaxis().GetBinCenter(timeProjection.GetMaximumBin())
232 if timeProjection.Integral() < 10:
234 timeProjection.GetXaxis().SetRangeUser(maximum - 1., maximum + 2.)
236 slotID[0] = iSlot + 1
240 if(mcPeaks[k][1] > 0):
245 if mcPeaks[k][1] > mcPeaks[k][0]:
246 earlyPeak[0] = mcPeaks[k][0]
247 latePeak[0] = mcPeaks[k][1]
249 earlyPeak[0] = mcPeaks[k][1]
250 latePeak[0] = mcPeaks[k][0]
251 deltaMC[0] = earlyPeak[0] - latePeak[0]
256 latePeak[0] = mcPeaks[k][0]
263 "[0]*ROOT:: Math: : crystalball_function(x, [2], [3], [4], [5]) + "
264 "[1]*[0]*ROOT::Math::crystalball_function(x, [2], [3], [4], [5]+[6]) + "
265 "[7]*[0]*ROOT:: Math::crystalball_function(x, [2], [3], [9]*[4], [5]+[8]) ",
271 cb.SetParameter(0, 10.)
272 cb.SetParameter(2, -1.)
273 cb.SetParLimits(2, -30., -0.01)
274 cb.SetParameter(3, 3.)
275 cb.SetParLimits(3, 0.01, 6.)
276 cb.SetParameter(4, 0.05)
277 cb.SetParLimits(4, 0.03, 0.200)
278 cb.SetParameter(5, maximum)
279 cb.SetParLimits(5, maximum - 0.1, maximum + 0.1)
281 cb.SetParameter(7, 0.01)
282 cb.SetParLimits(7, 0., .1)
283 cb.SetParameter(8, 1.)
284 cb.SetParLimits(8, 0.2, 2.)
285 cb.SetParameter(9, 1.5)
286 cb.SetParLimits(9, 1.1, 3.)
287 if not includeBackscatter:
288 cb.FixParameter(7, 0.)
289 cb.FixParameter(8, 1.)
290 cb.FixParameter(9, 1.5)
292 if(mcPeaks[k][1] > 0
and not useSinglePDF):
293 cb.SetParameter(1, 0.3)
294 cb.SetParLimits(1, 0., 100.)
296 cb.FixParameter(6, deltaMC[0])
298 cb.SetParameter(6, deltaMC[0])
299 cb.SetParLimits(6, deltaMC[0] - 0.2, -0.001)
301 cb.FixParameter(1, 0.)
302 cb.FixParameter(6, 0.)
305 timeProjection.Fit(
'cb',
'RQS')
306 timeProjection.Fit(
'cb',
'RQS')
307 result = timeProjection.Fit(
'cb',
'RQS')
310 chi2[0] = result.Chi2()
311 ndf[0] = result.Ndf()
312 alpha[0] = cb.GetParameter(2)
313 errAlpha[0] = cb.GetParError(2)
314 n[0] = cb.GetParameter(3)
315 errN[0] = cb.GetParError(3)
318 peakTime[0] = cb.GetParameter(5)
319 errPeakTime[0] = cb.GetParError(5)
320 sigma[0] = cb.GetParameter(4)
321 errSigma[0] = cb.GetParError(4)
322 norm1[0] = cb.GetParameter(0)
323 errNorm1[0] = cb.GetParError(0)
324 norm2[0] = cb.GetParameter(1)
325 errNorm2[0] = cb.GetParError(1)
326 normExtra[0] = cb.GetParameter(7)
327 errNormExtra[0] = cb.GetParError(7)
328 extraTime[0] = cb.GetParameter(8)
329 errExtraTime[0] = cb.GetParError(8)
330 sigmaExtra[0] = cb.GetParameter(9)
331 errSigmaExtra[0] = cb.GetParError(9)
334 if pdfType ==
'gausExpo':
338 "[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*[2] + [4]*[3]*[3]- 2.*x)))*"
339 "ROOT::Math::erfc(([2] + [4]*[3]*[3] - x)/(TMath::Sqrt(2.)*[3])) + "
340 "[1]*[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*([2]+[5])+[4]*[3]*[3]-2.*x)))*"
341 "ROOT::Math::erfc((([2]+[5]) + [4]*[3]*[3] - x)/(TMath::Sqrt(2.)*[3])) +"
342 "[6]*[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*([2]+[7])+[4]*[8]*[3]*[8]*[3]-2.*x)))*"
343 "ROOT::Math::erfc((([2]+[7]) + [4]*[8]*[3]*[8]*[3] - x)/(TMath::Sqrt(2.)*[8]*[3]))",
350 gausExpo.SetParameter(0, 1000.)
351 gausExpo.SetParameter(2, maximum)
352 gausExpo.SetParLimits(2, maximum - 0.1, maximum + 0.1)
353 gausExpo.SetParameter(3, 0.05)
354 gausExpo.SetParLimits(3, 0.03, 0.200)
355 gausExpo.SetParameter(4, 1.2)
357 gausExpo.SetParameter(6, 0.01)
358 gausExpo.SetParLimits(6, 0., 0.1)
359 gausExpo.SetParameter(7, 1.)
360 gausExpo.SetParLimits(7, 0.2, 2.)
361 gausExpo.SetParameter(8, 1.5)
362 gausExpo.SetParLimits(8, 1.1, 3.)
363 if not includeBackscatter:
364 gausExpo.FixParameter(6, 0.)
365 gausExpo.FixParameter(7, 1.)
366 gausExpo.FixParameter(8, 1.5)
368 if(mcPeaks[k][1] > 0
and not useSinglePDF):
369 gausExpo.SetParameter(1, 0.3)
370 gausExpo.SetParLimits(1, 0., 100.)
372 gausExpo.FixParameter(5, deltaMC[0])
374 gausExpo.SetParameter(5, deltaMC[0])
375 gausExpo.SetParLimits(5, deltaMC[0] - 0.2, -0.001)
377 gausExpo.FixParameter(1, 0.)
378 gausExpo.FixParameter(5, 0.)
381 gausExpo.SetNpx(1000)
382 timeProjection.Fit(
'gausExpo',
'RQS')
383 timeProjection.Fit(
'gausExpo',
'RQS')
384 result = timeProjection.Fit(
'gausExpo',
'RQS')
387 chi2[0] = result.Chi2()
388 ndf[0] = result.Ndf()
393 lam[0] = gausExpo.GetParameter(4)
394 errLam[0] = gausExpo.GetParError(4)
395 peakTime[0] = gausExpo.GetParameter(2)
396 errPeakTime[0] = gausExpo.GetParError(2)
397 sigma[0] = gausExpo.GetParameter(3)
398 errSigma[0] = gausExpo.GetParError(3)
399 norm1[0] = gausExpo.GetParameter(0)
400 errNorm1[0] = gausExpo.GetParError(0)
401 norm2[0] = gausExpo.GetParameter(1)
402 errNorm2[0] = gausExpo.GetParError(1)
403 normExtra[0] = gausExpo.GetParameter(6)
404 errNormExtra[0] = gausExpo.GetParError(6)
405 extraTime[0] = gausExpo.GetParameter(7)
406 errExtraTime[0] = gausExpo.GetParError(7)
407 sigmaExtra[0] = gausExpo.GetParameter(8)
408 errSigmaExtra[0] = gausExpo.GetParError(8)
411 if pdfType ==
'gaus':
414 "[0]*TMath::Gaus([2], [3], kTRUE)) + "
415 "[0]*[1]*TMath::Gaus([2]+[4], [3], kTRUE)) +"
416 "[0]*[5]*TMath::Gaus([2]+[6], [3]*[7], kTRUE))",
422 gaussian.SetParameter(0, 10.)
423 gaussian.SetParameter(2, maximum)
424 gaussian.SetParLimits(2, maximum - 0.1, maximum + 0.1)
425 gaussian.SetParameter(3, 0.05)
426 gaussian.SetParLimits(3, 0.03, 0.200)
428 gaussian.SetParameter(5, 0.01)
429 gaussian.SetParLimits(5, 0., .1)
430 gaussian.SetParameter(6, 1.)
431 gaussian.SetParLimits(6, 0.2, 2.)
432 gaussian.SetParameter(7, 1.5)
433 gaussian.SetParLimits(7, 1.1, 3.)
434 if not includeBackscatter:
435 gaussian.FixParameter(5, 0.)
436 gaussian.FixParameter(6, 1.)
437 gaussian.FixParameter(7, 1.5)
439 if(mcPeaks[k][1] > 0
and not useSinglePDF):
440 gaussian.SetParameter(1, 0.3)
441 gaussian.SetParLimits(1, 0., 100.)
443 gaussian.FixParameter(4, deltaMC[0])
445 gaussian.SetParameter(4, deltaMC[0])
446 gaussian.SetParLimits(4, deltaMC[0] - 0.2, -0.001)
448 gaussian.FixParameter(1, 0.)
449 gaussian.FixParameter(4, 0.)
451 gaussian.SetNpx(1000)
452 timeProjection.Fit(
'gaussian',
'RQS')
453 timeProjection.Fit(
'gaussian',
'RQS')
454 result = timeProjection.Fit(
'gaussian',
'RQS')
457 chi2[0] = result.Chi2()
458 ndf[0] = result.Ndf()
465 peakTime[0] = gaussian.GetParameter(2)
466 errPeakTime[0] = gaussian.GetParError(2)
467 sigma[0] = gaussian.GetParameter(3)
468 errSigma[0] = gaussian.GetParError(3)
469 norm1[0] = gaussian.GetParameter(0)
470 errNorm1[0] = gaussian.GetParError(0)
471 norm2[0] = gaussian.GetParameter(1)
472 errNorm2[0] = gaussian.GetParError(1)
473 normExtra[0] = gaussian.GetParameter(5)
474 errNormExtra[0] = gaussian.GetParError(5)
475 extraTime[0] = gaussian.GetParameter(6)
476 errExtraTime[0] = gaussian.GetParError(6)
477 sigmaExtra[0] = gaussian.GetParameter(7)
478 errSigmaExtra[0] = gaussian.GetParError(7)
481 correctedTime[0] = peakTime[0] - mcPeaks[k][0]
486 timeProjection.Write()
492 def plotLaserResolution(fitResultsFile='laserResolutionResults.root'):
494 Function that creates some standard plots from the tree containg the flaset fit results
498 tFileData = TFile(fitResultsFile)
499 treeData = tFileData.Get(
'tree')
500 histoData = tFileData.Get(
'LaserTimingVSChannel')
503 h_test = TH1F(
"h_test",
"a test histogram to determine the histogram boundaries", 1000, 0., 100.)
504 treeData.Draw(
"correctedTime>>h_test")
505 meanCorrTime = h_test.GetMean()
508 h_localT0Resolution = [TH1F(
"h_localT0Resolution_slot" + str(iSlot + 1),
509 "Laser peak position after the MC correction in slot " + str(iSlot + 1),
512 meanCorrTime + 2.)
for iSlot
in range(16)]
514 h_singleChannelResolution = TH1F(
"h_singleChannelResolution",
"Resolution of the laser peak.", 40, 0., 0.4)
517 h_singleChannelResolutionVSChannel = TH1F(
518 "singleChannelResolutionVSChannel",
519 "Resolution of the laser peak VS channel number",
525 h_localT0ResolutionVSChannel = TH1F(
526 "localT0ResolutionVSChannel",
527 "Resolution of the laser peak VS channel number",
533 h_latePeakVSChannel = TH1F(
"latePeakVSChannel",
"Late Peak position", 512 * 16, 0, 512 * 16)
535 h_earlyPeakVSChannel = TH1F(
"earlyPeakVSChannel",
"Early Peak position", 512 * 16, 0, 512 * 16)
537 for entry
in treeData:
538 globalChannel = entry.hwChannel + entry.slotID * 512
540 h_localT0Resolution[entry.slotID - 1].Fill(entry.correctedTime)
541 h_singleChannelResolution.Fill(entry.sigma)
543 h_singleChannelResolutionVSChannel.SetBinContent(globalChannel + 1, entry.sigma)
544 h_singleChannelResolutionVSChannel.SetBinError(globalChannel + 1, entry.errSigma)
546 h_localT0ResolutionVSChannel.SetBinContent(globalChannel + 1, entry.correctedTime)
547 h_localT0ResolutionVSChannel.SetBinError(globalChannel + 1, entry.errPeakTime)
549 h_latePeakVSChannel.SetBinContent(globalChannel + 1, entry.latePeak)
550 if entry.earlyPeak > 0:
551 h_earlyPeakVSChannel.SetBinContent(globalChannel + 1, entry.earlyPeak)
554 for iSlot
in range(16):
555 laserTime = histoData.GetBinContent(iSlot * 512 + 1)
556 mcTime = h_latePeakVSChannel.GetBinContent(iSlot * 512 + 1)
557 timeShift = laserTime - mcTime
558 for iBin
in range(512):
559 lateTime = h_latePeakVSChannel.GetBinContent(iBin + iSlot * 512 + 1) + timeShift
560 earlyTime = h_earlyPeakVSChannel.GetBinContent(iBin + iSlot * 512 + 1) + timeShift
561 h_latePeakVSChannel.SetBinContent(iBin + iSlot * 512 + 1, lateTime)
562 h_earlyPeakVSChannel.SetBinContent(iBin + iSlot * 512 + 1, earlyTime)
565 tFileOut = TFile(
'plots.root',
"RECREATE")
568 h_latePeakVSChannel.Write()
569 h_earlyPeakVSChannel.Write()
570 h_singleChannelResolution.Write()
571 h_singleChannelResolutionVSChannel.Write()
572 h_localT0ResolutionVSChannel.Write()
575 h_localT0Resolution[i].Write()