19 from ROOT
import TF1, TFile, TH1F, TSpectrum, TTree
20 from array
import array
23 def fitLaserResolution(
24 mcCorrectionsFile='/group/belle2/group/detector/TOP/calibration/MCreferences/t0MC.root',
26 outputFile='laserResolutionResults.root',
30 includeBackscatter=True,
34 Function that implements the fit of the laser time distribution correcting for the propagation time in the prism.
35 The inputs to the fitter are hit time distributions per channel, in the form of TH2F.
37 Two files containing the containing the hit timing VS channels distribution must be provided:
39 * The first file is used to estimate the light propagation correction (aka MC correction),
40 the number of peaks and the separation bewteen these peaks.
41 Since the correction is the same for all the slots, the corresponding TH2F can have only 512 bins on the x-axis.
42 A default file is available, where the hit time is taken from
43 the TOPSimHits, and the laser jitter has been set to zero in the simulation.
44 * The second file contains the distribution obtained from the data do be used to estimate the resolution.
45 In this case the histrogram must have
46 (512 x 16) bins on the x-axis, to store the time distribution for each channel of the detector.
49 mcCorrectionsFile (str): File with the TH2F containing the TOPSImHits time distribution.
50 Used to calculate the MC corrections
51 dataFile (str): File with the TH2F containing the TOPDigit time distribution on which the resolutions
53 outputFile (str): rootFile containing the outupt trees and plots
54 pdfType (str): PDF used in the data fit: cb for a CrystalBall, gaus for a Gaussian or
55 gausExpo for an exponentially modified Gaussian
56 maxPeaks (int): maximum number of peaks that can be used in the data fit. Note that the
57 actual value is decided channel-by-channel
58 according to the MC simulation, this parameter is only a maximum cap.
59 In the current implementation only 1 or 2 peaks are supported, therefore maxPeaks can only go up to 2
60 saveFits (bool): set to True to save the histrogram and the fit for eavey single channel
61 includeBackscatter (bool): set to True to add an extra peak in the fit to account for the
63 useMCPeaks (bool): ste to True to fix the light path time difference from the MC. Set to False
64 to let this parameter floating in the fit
69 if maxPeaks > 2
or maxPeaks < 1:
70 b2.B2FATAL(
'Usupported value for the maximum number for peaks (maxPeaks = ' +
71 str(maxPeaks) +
'). Please set maxPeak o either 1 or 2.')
72 if pdfType !=
'cb' and pdfType !=
'gaus' and pdfType !=
'gausExpo':
76 ". The possible options are cb for the Crystal Ball,"
77 "gaus for the Gaussian and gausExpo for exponentially modified Gaussian")
84 mcPeaks = [[-1.
for second
in range(2)]
for first
in range(512)]
87 tFileMC = TFile(mcCorrectionsFile)
88 histoMC = tFileMC.Get(
'LaserTimingVSChannelOneSlot')
91 for kCh
in range(512):
93 timeProjectionMC = histoMC.ProjectionY(
'projectionMC', kCh + 1, kCh + 1)
94 timeProjectionMC.GetXaxis().SetRangeUser(0., 1.)
96 spectrum = TSpectrum()
99 numPeaks = spectrum.Search(timeProjectionMC, 1.,
'nobackground', 0.1)
102 peaksX_ = spectrum.GetPositionX()
103 peaksY_ = spectrum.GetPositionY()
104 peaksX = [peaksX_[i]
for i
in range(numPeaks)]
105 peaksY = [peaksY_[j]
for j
in range(numPeaks)]
109 for iMax
in range(numPeaks):
111 maxPosition = int(peaksY.index(max(peaksY)))
112 peaksY[maxPosition] = -1.
113 mcPeaks[kCh][iMax] = peaksX[maxPosition]
120 tFileData = TFile(dataFile)
121 histoData = tFileData.Get(
'LaserTimingVSChannel')
125 outTree = TTree(
"tree",
"tree")
128 slotID = array(
'i', [0])
130 hwChannel = array(
'i', [0])
132 nPeaks = array(
'i', [0])
134 ndf = array(
'f', [0])
136 chi2 = array(
'f', [0.])
138 sigma = array(
'f', [0.])
140 errSigma = array(
'f', [0.])
142 peakTime = array(
'f', [0.])
144 errPeakTime = array(
'f', [0.])
147 extraTime = array(
'f', [0.])
149 errExtraTime = array(
'f', [0.])
152 sigmaExtra = array(
'f', [0.])
154 errSigmaExtra = array(
'f', [0.])
157 alpha = array(
'f', [0.])
159 errAlpha = array(
'f', [0.])
163 errN = array(
'f', [0.])
165 lam = array(
'f', [0.])
167 errLam = array(
'f', [0.])
169 norm1 = array(
'f', [0.])
171 errNorm1 = array(
'f', [0.])
173 norm2 = array(
'f', [0.])
175 errNorm2 = array(
'f', [0.])
178 normExtra = array(
'f', [0.])
180 errNormExtra = array(
'f', [0.])
183 deltaMC = array(
'f', [0.])
185 correctedTime = array(
'f', [0.])
187 latePeak = array(
'f', [0.])
189 earlyPeak = array(
'f', [0.])
192 outTree.Branch(
'slotID', slotID,
'slotID/I')
193 outTree.Branch(
'hwChannel', hwChannel,
'hwChannel/I')
194 outTree.Branch(
'ndf', ndf,
'ndf/F')
195 outTree.Branch(
'chi2', chi2,
'chi2/F')
196 outTree.Branch(
'nPeaks', nPeaks,
'nPeaks/I')
197 outTree.Branch(
'sigma', sigma,
'sigma/F')
198 outTree.Branch(
'errSigma', errSigma,
'errSigma/F')
199 outTree.Branch(
'peakTime', peakTime,
'peakTime/F')
200 outTree.Branch(
'errPeakTime', errPeakTime,
'errPeakTime/F')
201 outTree.Branch(
'extraTime', extraTime,
'extraTime/F')
202 outTree.Branch(
'errExtraTime', errExtraTime,
'errExtraTime/F')
203 outTree.Branch(
'alpha', alpha,
'alpha/F')
204 outTree.Branch(
'errAlpha', errAlpha,
'errAlpha/F')
205 outTree.Branch(
'n', n,
'n/F')
206 outTree.Branch(
'errN', errN,
'errN/F')
207 outTree.Branch(
'lam', lam,
'lam/F')
208 outTree.Branch(
'errLam', errLam,
'errLam/F')
209 outTree.Branch(
'norm1', norm1,
'norm1/F')
210 outTree.Branch(
'errNorm1', errNorm1,
'errNorm1/F')
211 outTree.Branch(
'norm2', norm2,
'norm2/F')
212 outTree.Branch(
'errNorm2', errNorm2,
'errNorm2/F')
213 outTree.Branch(
'normExtra', normExtra,
'normExtra/F')
214 outTree.Branch(
'errNormExtra', errNormExtra,
'errNormExtra/F')
215 outTree.Branch(
'sigmaExtra', sigmaExtra,
'sigmaExtra/F')
216 outTree.Branch(
'errSigmaExtra', errSigmaExtra,
'errSigmaExtra/F')
217 outTree.Branch(
'deltaMC', deltaMC,
'deltaMC/F')
218 outTree.Branch(
'correctedTime', correctedTime,
'correctedTime/F')
219 outTree.Branch(
'latePeak', latePeak,
'latePeak/F')
220 outTree.Branch(
'earlyPeak', earlyPeak,
'earlyPeak/F')
224 for iSlot
in range(0, 16):
225 print(
'Fitting slot ' + str(iSlot))
226 for k
in range(0, 512):
227 timeProjection = histoData.ProjectionY(
'projection_' + str(iSlot + 1) +
'_' +
228 str(k), k + iSlot * 512 + 1, k + iSlot * 512 + 1)
229 maximum = timeProjection.GetXaxis().GetBinCenter(timeProjection.GetMaximumBin())
230 if timeProjection.Integral() < 10:
232 timeProjection.GetXaxis().SetRangeUser(maximum - 1., maximum + 2.)
234 slotID[0] = iSlot + 1
238 if(mcPeaks[k][1] > 0):
243 if mcPeaks[k][1] > mcPeaks[k][0]:
244 earlyPeak[0] = mcPeaks[k][0]
245 latePeak[0] = mcPeaks[k][1]
247 earlyPeak[0] = mcPeaks[k][1]
248 latePeak[0] = mcPeaks[k][0]
249 deltaMC[0] = earlyPeak[0] - latePeak[0]
254 latePeak[0] = mcPeaks[k][0]
261 "[0]*ROOT:: Math: : crystalball_function(x, [2], [3], [4], [5]) + "
262 "[1]*[0]*ROOT::Math::crystalball_function(x, [2], [3], [4], [5]+[6]) + "
263 "[7]*[0]*ROOT:: Math::crystalball_function(x, [2], [3], [9]*[4], [5]+[8]) ",
269 cb.SetParameter(0, 10.)
270 cb.SetParameter(2, -1.)
271 cb.SetParLimits(2, -30., -0.01)
272 cb.SetParameter(3, 3.)
273 cb.SetParLimits(3, 0.01, 6.)
274 cb.SetParameter(4, 0.05)
275 cb.SetParLimits(4, 0.03, 0.200)
276 cb.SetParameter(5, maximum)
277 cb.SetParLimits(5, maximum - 0.1, maximum + 0.1)
279 cb.SetParameter(7, 0.01)
280 cb.SetParLimits(7, 0., .1)
281 cb.SetParameter(8, 1.)
282 cb.SetParLimits(8, 0.2, 2.)
283 cb.SetParameter(9, 1.5)
284 cb.SetParLimits(9, 1.1, 3.)
285 if not includeBackscatter:
286 cb.FixParameter(7, 0.)
287 cb.FixParameter(8, 1.)
288 cb.FixParameter(9, 1.5)
290 if(mcPeaks[k][1] > 0
and not useSinglePDF):
291 cb.SetParameter(1, 0.3)
292 cb.SetParLimits(1, 0., 100.)
294 cb.FixParameter(6, deltaMC[0])
296 cb.SetParameter(6, deltaMC[0])
297 cb.SetParLimits(6, deltaMC[0] - 0.2, -0.001)
299 cb.FixParameter(1, 0.)
300 cb.FixParameter(6, 0.)
303 timeProjection.Fit(
'cb',
'RQS')
304 timeProjection.Fit(
'cb',
'RQS')
305 result = timeProjection.Fit(
'cb',
'RQS')
308 chi2[0] = result.Chi2()
309 ndf[0] = result.Ndf()
310 alpha[0] = cb.GetParameter(2)
311 errAlpha[0] = cb.GetParError(2)
312 n[0] = cb.GetParameter(3)
313 errN[0] = cb.GetParError(3)
316 peakTime[0] = cb.GetParameter(5)
317 errPeakTime[0] = cb.GetParError(5)
318 sigma[0] = cb.GetParameter(4)
319 errSigma[0] = cb.GetParError(4)
320 norm1[0] = cb.GetParameter(0)
321 errNorm1[0] = cb.GetParError(0)
322 norm2[0] = cb.GetParameter(1)
323 errNorm2[0] = cb.GetParError(1)
324 normExtra[0] = cb.GetParameter(7)
325 errNormExtra[0] = cb.GetParError(7)
326 extraTime[0] = cb.GetParameter(8)
327 errExtraTime[0] = cb.GetParError(8)
328 sigmaExtra[0] = cb.GetParameter(9)
329 errSigmaExtra[0] = cb.GetParError(9)
332 if pdfType ==
'gausExpo':
336 "[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*[2] + [4]*[3]*[3]- 2.*x)))*"
337 "ROOT::Math::erfc(([2] + [4]*[3]*[3] - x)/(TMath::Sqrt(2.)*[3])) + "
338 "[1]*[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*([2]+[5])+[4]*[3]*[3]-2.*x)))*"
339 "ROOT::Math::erfc((([2]+[5]) + [4]*[3]*[3] - x)/(TMath::Sqrt(2.)*[3])) +"
340 "[6]*[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*([2]+[7])+[4]*[8]*[3]*[8]*[3]-2.*x)))*"
341 "ROOT::Math::erfc((([2]+[7]) + [4]*[8]*[3]*[8]*[3] - x)/(TMath::Sqrt(2.)*[8]*[3]))",
348 gausExpo.SetParameter(0, 1000.)
349 gausExpo.SetParameter(2, maximum)
350 gausExpo.SetParLimits(2, maximum - 0.1, maximum + 0.1)
351 gausExpo.SetParameter(3, 0.05)
352 gausExpo.SetParLimits(3, 0.03, 0.200)
353 gausExpo.SetParameter(4, 1.2)
355 gausExpo.SetParameter(6, 0.01)
356 gausExpo.SetParLimits(6, 0., 0.1)
357 gausExpo.SetParameter(7, 1.)
358 gausExpo.SetParLimits(7, 0.2, 2.)
359 gausExpo.SetParameter(8, 1.5)
360 gausExpo.SetParLimits(8, 1.1, 3.)
361 if not includeBackscatter:
362 gausExpo.FixParameter(6, 0.)
363 gausExpo.FixParameter(7, 1.)
364 gausExpo.FixParameter(8, 1.5)
366 if(mcPeaks[k][1] > 0
and not useSinglePDF):
367 gausExpo.SetParameter(1, 0.3)
368 gausExpo.SetParLimits(1, 0., 100.)
370 gausExpo.FixParameter(5, deltaMC[0])
372 gausExpo.SetParameter(5, deltaMC[0])
373 gausExpo.SetParLimits(5, deltaMC[0] - 0.2, -0.001)
375 gausExpo.FixParameter(1, 0.)
376 gausExpo.FixParameter(5, 0.)
379 gausExpo.SetNpx(1000)
380 timeProjection.Fit(
'gausExpo',
'RQS')
381 timeProjection.Fit(
'gausExpo',
'RQS')
382 result = timeProjection.Fit(
'gausExpo',
'RQS')
385 chi2[0] = result.Chi2()
386 ndf[0] = result.Ndf()
391 lam[0] = gausExpo.GetParameter(4)
392 errLam[0] = gausExpo.GetParError(4)
393 peakTime[0] = gausExpo.GetParameter(2)
394 errPeakTime[0] = gausExpo.GetParError(2)
395 sigma[0] = gausExpo.GetParameter(3)
396 errSigma[0] = gausExpo.GetParError(3)
397 norm1[0] = gausExpo.GetParameter(0)
398 errNorm1[0] = gausExpo.GetParError(0)
399 norm2[0] = gausExpo.GetParameter(1)
400 errNorm2[0] = gausExpo.GetParError(1)
401 normExtra[0] = gausExpo.GetParameter(6)
402 errNormExtra[0] = gausExpo.GetParError(6)
403 extraTime[0] = gausExpo.GetParameter(7)
404 errExtraTime[0] = gausExpo.GetParError(7)
405 sigmaExtra[0] = gausExpo.GetParameter(8)
406 errSigmaExtra[0] = gausExpo.GetParError(8)
409 if pdfType ==
'gaus':
412 "[0]*TMath::Gaus([2], [3], kTRUE)) + "
413 "[0]*[1]*TMath::Gaus([2]+[4], [3], kTRUE)) +"
414 "[0]*[5]*TMath::Gaus([2]+[6], [3]*[7], kTRUE))",
420 gaussian.SetParameter(0, 10.)
421 gaussian.SetParameter(2, maximum)
422 gaussian.SetParLimits(2, maximum - 0.1, maximum + 0.1)
423 gaussian.SetParameter(3, 0.05)
424 gaussian.SetParLimits(3, 0.03, 0.200)
426 gaussian.SetParameter(5, 0.01)
427 gaussian.SetParLimits(5, 0., .1)
428 gaussian.SetParameter(6, 1.)
429 gaussian.SetParLimits(6, 0.2, 2.)
430 gaussian.SetParameter(7, 1.5)
431 gaussian.SetParLimits(7, 1.1, 3.)
432 if not includeBackscatter:
433 gaussian.FixParameter(5, 0.)
434 gaussian.FixParameter(6, 1.)
435 gaussian.FixParameter(7, 1.5)
437 if(mcPeaks[k][1] > 0
and not useSinglePDF):
438 gaussian.SetParameter(1, 0.3)
439 gaussian.SetParLimits(1, 0., 100.)
441 gaussian.FixParameter(4, deltaMC[0])
443 gaussian.SetParameter(4, deltaMC[0])
444 gaussian.SetParLimits(4, deltaMC[0] - 0.2, -0.001)
446 gaussian.FixParameter(1, 0.)
447 gaussian.FixParameter(4, 0.)
449 gaussian.SetNpx(1000)
450 timeProjection.Fit(
'gaussian',
'RQS')
451 timeProjection.Fit(
'gaussian',
'RQS')
452 result = timeProjection.Fit(
'gaussian',
'RQS')
455 chi2[0] = result.Chi2()
456 ndf[0] = result.Ndf()
463 peakTime[0] = gaussian.GetParameter(2)
464 errPeakTime[0] = gaussian.GetParError(2)
465 sigma[0] = gaussian.GetParameter(3)
466 errSigma[0] = gaussian.GetParError(3)
467 norm1[0] = gaussian.GetParameter(0)
468 errNorm1[0] = gaussian.GetParError(0)
469 norm2[0] = gaussian.GetParameter(1)
470 errNorm2[0] = gaussian.GetParError(1)
471 normExtra[0] = gaussian.GetParameter(5)
472 errNormExtra[0] = gaussian.GetParError(5)
473 extraTime[0] = gaussian.GetParameter(6)
474 errExtraTime[0] = gaussian.GetParError(6)
475 sigmaExtra[0] = gaussian.GetParameter(7)
476 errSigmaExtra[0] = gaussian.GetParError(7)
479 correctedTime[0] = peakTime[0] - mcPeaks[k][0]
484 timeProjection.Write()
490 def plotLaserResolution(fitResultsFile='laserResolutionResults.root'):
492 Function that creates some standard plots from the tree containg the flaset fit results
496 tFileData = TFile(fitResultsFile)
497 treeData = tFileData.Get(
'tree')
498 histoData = tFileData.Get(
'LaserTimingVSChannel')
501 h_test = TH1F(
"h_test",
"a test histogram to determine the histogram boundaries", 1000, 0., 100.)
502 treeData.Draw(
"correctedTime>>h_test")
503 meanCorrTime = h_test.GetMean()
506 h_localT0Resolution = [TH1F(
"h_localT0Resolution_slot" + str(iSlot + 1),
507 "Laser peak position after the MC correction in slot " + str(iSlot + 1),
510 meanCorrTime + 2.)
for iSlot
in range(16)]
512 h_singleChannelResolution = TH1F(
"h_singleChannelResolution",
"Resolution of the laser peak.", 40, 0., 0.4)
515 h_singleChannelResolutionVSChannel = TH1F(
516 "singleChannelResolutionVSChannel",
517 "Resolution of the laser peak VS channel number",
523 h_localT0ResolutionVSChannel = TH1F(
524 "localT0ResolutionVSChannel",
525 "Resolution of the laser peak VS channel number",
531 h_latePeakVSChannel = TH1F(
"latePeakVSChannel",
"Late Peak position", 512 * 16, 0, 512 * 16)
533 h_earlyPeakVSChannel = TH1F(
"earlyPeakVSChannel",
"Early Peak position", 512 * 16, 0, 512 * 16)
535 for entry
in treeData:
536 globalChannel = entry.hwChannel + entry.slotID * 512
538 h_localT0Resolution[entry.slotID - 1].Fill(entry.correctedTime)
539 h_singleChannelResolution.Fill(entry.sigma)
541 h_singleChannelResolutionVSChannel.SetBinContent(globalChannel + 1, entry.sigma)
542 h_singleChannelResolutionVSChannel.SetBinError(globalChannel + 1, entry.errSigma)
544 h_localT0ResolutionVSChannel.SetBinContent(globalChannel + 1, entry.correctedTime)
545 h_localT0ResolutionVSChannel.SetBinError(globalChannel + 1, entry.errPeakTime)
547 h_latePeakVSChannel.SetBinContent(globalChannel + 1, entry.latePeak)
548 if entry.earlyPeak > 0:
549 h_earlyPeakVSChannel.SetBinContent(globalChannel + 1, entry.earlyPeak)
552 for iSlot
in range(16):
553 laserTime = histoData.GetBinContent(iSlot * 512 + 1)
554 mcTime = h_latePeakVSChannel.GetBinContent(iSlot * 512 + 1)
555 timeShift = laserTime - mcTime
556 for iBin
in range(512):
557 lateTime = h_latePeakVSChannel.GetBinContent(iBin + iSlot * 512 + 1) + timeShift
558 earlyTime = h_earlyPeakVSChannel.GetBinContent(iBin + iSlot * 512 + 1) + timeShift
559 h_latePeakVSChannel.SetBinContent(iBin + iSlot * 512 + 1, lateTime)
560 h_earlyPeakVSChannel.SetBinContent(iBin + iSlot * 512 + 1, earlyTime)
563 tFileOut = TFile(
'plots.root',
"RECREATE")
566 h_latePeakVSChannel.Write()
567 h_earlyPeakVSChannel.Write()
568 h_singleChannelResolution.Write()
569 h_singleChannelResolutionVSChannel.Write()
570 h_localT0ResolutionVSChannel.Write()
573 h_localT0Resolution[i].Write()