18from ROOT
import TF1, TFile, TH1F, TSpectrum, TTree
19from array
import array
22def fitLaserResolution(
23 mcCorrectionsFile='/group/belle2/group/detector/TOP/calibration/MCreferences/t0MC.root',
25 outputFile='laserResolutionResults.root',
29 includeBackscatter=True,
33 Function that implements the fit of the laser time distribution correcting for the propagation time
in the prism.
34 The inputs to the fitter are hit time distributions per channel,
in the form of TH2F.
36 Two files containing the containing the hit timing VS channels distribution must be provided:
38 * The first file
is used to estimate the light propagation correction (aka MC correction),
39 the number of peaks
and the separation bewteen these peaks.
40 Since the correction
is the same
for all the slots, the corresponding TH2F can have only 512 bins on the x-axis.
41 A default file
is available, where the hit time
is taken
from
42 the TOPSimHits,
and the laser jitter has been set to zero
in the simulation.
43 * The second file contains the distribution obtained
from the data do be used to estimate the resolution.
44 In this case the histrogram must have
45 (512 x 16) bins on the x-axis, to store the time distribution
for each channel of the detector.
48 mcCorrectionsFile (str): File
with the TH2F containing the TOPSImHits time distribution.
49 Used to calculate the MC corrections
50 dataFile (str): File
with the TH2F containing the TOPDigit time distribution on which the resolutions
52 outputFile (str): rootFile containing the outupt trees
and plots
53 pdfType (str): PDF used
in the data fit: cb
for a CrystalBall, gaus
for a Gaussian
or
54 gausExpo
for an exponentially modified Gaussian
55 maxPeaks (int): maximum number of peaks that can be used
in the data fit. Note that the
56 actual value
is decided channel-by-channel
57 according to the MC simulation, this parameter
is only a maximum cap.
58 In the current implementation only 1
or 2 peaks are supported, therefore maxPeaks can only go up to 2
59 saveFits (bool): set to
True to save the histrogram
and the fit
for eavey single channel
60 includeBackscatter (bool): set to
True to add an extra peak
in the fit to account
for the
62 useMCPeaks (bool): ste to
True to fix the light path time difference
from the MC. Set to
False
63 to let this parameter floating
in the fit
68 if maxPeaks > 2
or maxPeaks < 1:
69 b2.B2FATAL(
'Usupported value for the maximum number for peaks (maxPeaks = ' +
70 str(maxPeaks) +
'). Please set maxPeak o either 1 or 2.')
71 if pdfType !=
'cb' and pdfType !=
'gaus' and pdfType !=
'gausExpo':
75 ". The possible options are cb for the Crystal Ball,"
76 "gaus for the Gaussian and gausExpo for exponentially modified Gaussian")
83 mcPeaks = [[-1.
for second
in range(2)]
for first
in range(512)]
86 tFileMC = TFile(mcCorrectionsFile)
87 histoMC = tFileMC.Get(
'LaserTimingVSChannelOneSlot')
90 for kCh
in range(512):
92 timeProjectionMC = histoMC.ProjectionY(
'projectionMC', kCh + 1, kCh + 1)
93 timeProjectionMC.GetXaxis().SetRangeUser(0., 1.)
95 spectrum = TSpectrum()
98 numPeaks = spectrum.Search(timeProjectionMC, 1.,
'nobackground', 0.1)
101 peaksX_ = spectrum.GetPositionX()
102 peaksY_ = spectrum.GetPositionY()
103 peaksX = [peaksX_[i]
for i
in range(numPeaks)]
104 peaksY = [peaksY_[j]
for j
in range(numPeaks)]
108 for iMax
in range(numPeaks):
110 maxPosition = int(peaksY.index(max(peaksY)))
111 peaksY[maxPosition] = -1.
112 mcPeaks[kCh][iMax] = peaksX[maxPosition]
119 tFileData = TFile(dataFile)
120 histoData = tFileData.Get(
'LaserTimingVSChannel')
124 outTree = TTree(
"tree",
"tree")
127 slotID = array(
'i', [0])
129 hwChannel = array(
'i', [0])
131 nPeaks = array(
'i', [0])
133 ndf = array(
'f', [0])
135 chi2 = array(
'f', [0.])
137 sigma = array(
'f', [0.])
139 errSigma = array(
'f', [0.])
141 peakTime = array(
'f', [0.])
143 errPeakTime = array(
'f', [0.])
146 extraTime = array(
'f', [0.])
148 errExtraTime = array(
'f', [0.])
151 sigmaExtra = array(
'f', [0.])
153 errSigmaExtra = array(
'f', [0.])
156 alpha = array(
'f', [0.])
158 errAlpha = array(
'f', [0.])
162 errN = array(
'f', [0.])
164 lam = array(
'f', [0.])
166 errLam = array(
'f', [0.])
168 norm1 = array(
'f', [0.])
170 errNorm1 = array(
'f', [0.])
172 norm2 = array(
'f', [0.])
174 errNorm2 = array(
'f', [0.])
177 normExtra = array(
'f', [0.])
179 errNormExtra = array(
'f', [0.])
182 deltaMC = array(
'f', [0.])
184 correctedTime = array(
'f', [0.])
186 latePeak = array(
'f', [0.])
188 earlyPeak = array(
'f', [0.])
191 outTree.Branch(
'slotID', slotID,
'slotID/I')
192 outTree.Branch(
'hwChannel', hwChannel,
'hwChannel/I')
193 outTree.Branch(
'ndf', ndf,
'ndf/F')
194 outTree.Branch(
'chi2', chi2,
'chi2/F')
195 outTree.Branch(
'nPeaks', nPeaks,
'nPeaks/I')
196 outTree.Branch(
'sigma', sigma,
'sigma/F')
197 outTree.Branch(
'errSigma', errSigma,
'errSigma/F')
198 outTree.Branch(
'peakTime', peakTime,
'peakTime/F')
199 outTree.Branch(
'errPeakTime', errPeakTime,
'errPeakTime/F')
200 outTree.Branch(
'extraTime', extraTime,
'extraTime/F')
201 outTree.Branch(
'errExtraTime', errExtraTime,
'errExtraTime/F')
202 outTree.Branch(
'alpha', alpha,
'alpha/F')
203 outTree.Branch(
'errAlpha', errAlpha,
'errAlpha/F')
204 outTree.Branch(
'n', n,
'n/F')
205 outTree.Branch(
'errN', errN,
'errN/F')
206 outTree.Branch(
'lam', lam,
'lam/F')
207 outTree.Branch(
'errLam', errLam,
'errLam/F')
208 outTree.Branch(
'norm1', norm1,
'norm1/F')
209 outTree.Branch(
'errNorm1', errNorm1,
'errNorm1/F')
210 outTree.Branch(
'norm2', norm2,
'norm2/F')
211 outTree.Branch(
'errNorm2', errNorm2,
'errNorm2/F')
212 outTree.Branch(
'normExtra', normExtra,
'normExtra/F')
213 outTree.Branch(
'errNormExtra', errNormExtra,
'errNormExtra/F')
214 outTree.Branch(
'sigmaExtra', sigmaExtra,
'sigmaExtra/F')
215 outTree.Branch(
'errSigmaExtra', errSigmaExtra,
'errSigmaExtra/F')
216 outTree.Branch(
'deltaMC', deltaMC,
'deltaMC/F')
217 outTree.Branch(
'correctedTime', correctedTime,
'correctedTime/F')
218 outTree.Branch(
'latePeak', latePeak,
'latePeak/F')
219 outTree.Branch(
'earlyPeak', earlyPeak,
'earlyPeak/F')
223 for iSlot
in range(0, 16):
224 print(
'Fitting slot ' + str(iSlot))
225 for k
in range(0, 512):
226 timeProjection = histoData.ProjectionY(
'projection_' + str(iSlot + 1) +
'_' +
227 str(k), k + iSlot * 512 + 1, k + iSlot * 512 + 1)
228 maximum = timeProjection.GetXaxis().GetBinCenter(timeProjection.GetMaximumBin())
229 if timeProjection.Integral() < 10:
231 timeProjection.GetXaxis().SetRangeUser(maximum - 1., maximum + 2.)
233 slotID[0] = iSlot + 1
237 if(mcPeaks[k][1] > 0):
242 if mcPeaks[k][1] > mcPeaks[k][0]:
243 earlyPeak[0] = mcPeaks[k][0]
244 latePeak[0] = mcPeaks[k][1]
246 earlyPeak[0] = mcPeaks[k][1]
247 latePeak[0] = mcPeaks[k][0]
248 deltaMC[0] = earlyPeak[0] - latePeak[0]
253 latePeak[0] = mcPeaks[k][0]
260 "[0]*ROOT:: Math: : crystalball_function(x, [2], [3], [4], [5]) + "
261 "[1]*[0]*ROOT::Math::crystalball_function(x, [2], [3], [4], [5]+[6]) + "
262 "[7]*[0]*ROOT:: Math::crystalball_function(x, [2], [3], [9]*[4], [5]+[8]) ",
268 cb.SetParameter(0, 10.)
269 cb.SetParameter(2, -1.)
270 cb.SetParLimits(2, -30., -0.01)
271 cb.SetParameter(3, 3.)
272 cb.SetParLimits(3, 0.01, 6.)
273 cb.SetParameter(4, 0.05)
274 cb.SetParLimits(4, 0.03, 0.200)
275 cb.SetParameter(5, maximum)
276 cb.SetParLimits(5, maximum - 0.1, maximum + 0.1)
278 cb.SetParameter(7, 0.01)
279 cb.SetParLimits(7, 0., .1)
280 cb.SetParameter(8, 1.)
281 cb.SetParLimits(8, 0.2, 2.)
282 cb.SetParameter(9, 1.5)
283 cb.SetParLimits(9, 1.1, 3.)
284 if not includeBackscatter:
285 cb.FixParameter(7, 0.)
286 cb.FixParameter(8, 1.)
287 cb.FixParameter(9, 1.5)
289 if(mcPeaks[k][1] > 0
and not useSinglePDF):
290 cb.SetParameter(1, 0.3)
291 cb.SetParLimits(1, 0., 100.)
293 cb.FixParameter(6, deltaMC[0])
295 cb.SetParameter(6, deltaMC[0])
296 cb.SetParLimits(6, deltaMC[0] - 0.2, -0.001)
298 cb.FixParameter(1, 0.)
299 cb.FixParameter(6, 0.)
302 timeProjection.Fit(
'cb',
'RQS')
303 timeProjection.Fit(
'cb',
'RQS')
304 result = timeProjection.Fit(
'cb',
'RQS')
307 chi2[0] = result.Chi2()
308 ndf[0] = result.Ndf()
309 alpha[0] = cb.GetParameter(2)
310 errAlpha[0] = cb.GetParError(2)
311 n[0] = cb.GetParameter(3)
312 errN[0] = cb.GetParError(3)
315 peakTime[0] = cb.GetParameter(5)
316 errPeakTime[0] = cb.GetParError(5)
317 sigma[0] = cb.GetParameter(4)
318 errSigma[0] = cb.GetParError(4)
319 norm1[0] = cb.GetParameter(0)
320 errNorm1[0] = cb.GetParError(0)
321 norm2[0] = cb.GetParameter(1)
322 errNorm2[0] = cb.GetParError(1)
323 normExtra[0] = cb.GetParameter(7)
324 errNormExtra[0] = cb.GetParError(7)
325 extraTime[0] = cb.GetParameter(8)
326 errExtraTime[0] = cb.GetParError(8)
327 sigmaExtra[0] = cb.GetParameter(9)
328 errSigmaExtra[0] = cb.GetParError(9)
331 if pdfType ==
'gausExpo':
335 "[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*[2] + [4]*[3]*[3]- 2.*x)))*"
336 "ROOT::Math::erfc(([2] + [4]*[3]*[3] - x)/(TMath::Sqrt(2.)*[3])) + "
337 "[1]*[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*([2]+[5])+[4]*[3]*[3]-2.*x)))*"
338 "ROOT::Math::erfc((([2]+[5]) + [4]*[3]*[3] - x)/(TMath::Sqrt(2.)*[3])) +"
339 "[6]*[0]*(([4]/2.)*TMath::Exp(([4]/2.)*(2*([2]+[7])+[4]*[8]*[3]*[8]*[3]-2.*x)))*"
340 "ROOT::Math::erfc((([2]+[7]) + [4]*[8]*[3]*[8]*[3] - x)/(TMath::Sqrt(2.)*[8]*[3]))",
347 gausExpo.SetParameter(0, 1000.)
348 gausExpo.SetParameter(2, maximum)
349 gausExpo.SetParLimits(2, maximum - 0.1, maximum + 0.1)
350 gausExpo.SetParameter(3, 0.05)
351 gausExpo.SetParLimits(3, 0.03, 0.200)
352 gausExpo.SetParameter(4, 1.2)
354 gausExpo.SetParameter(6, 0.01)
355 gausExpo.SetParLimits(6, 0., 0.1)
356 gausExpo.SetParameter(7, 1.)
357 gausExpo.SetParLimits(7, 0.2, 2.)
358 gausExpo.SetParameter(8, 1.5)
359 gausExpo.SetParLimits(8, 1.1, 3.)
360 if not includeBackscatter:
361 gausExpo.FixParameter(6, 0.)
362 gausExpo.FixParameter(7, 1.)
363 gausExpo.FixParameter(8, 1.5)
365 if(mcPeaks[k][1] > 0
and not useSinglePDF):
366 gausExpo.SetParameter(1, 0.3)
367 gausExpo.SetParLimits(1, 0., 100.)
369 gausExpo.FixParameter(5, deltaMC[0])
371 gausExpo.SetParameter(5, deltaMC[0])
372 gausExpo.SetParLimits(5, deltaMC[0] - 0.2, -0.001)
374 gausExpo.FixParameter(1, 0.)
375 gausExpo.FixParameter(5, 0.)
378 gausExpo.SetNpx(1000)
379 timeProjection.Fit(
'gausExpo',
'RQS')
380 timeProjection.Fit(
'gausExpo',
'RQS')
381 result = timeProjection.Fit(
'gausExpo',
'RQS')
384 chi2[0] = result.Chi2()
385 ndf[0] = result.Ndf()
390 lam[0] = gausExpo.GetParameter(4)
391 errLam[0] = gausExpo.GetParError(4)
392 peakTime[0] = gausExpo.GetParameter(2)
393 errPeakTime[0] = gausExpo.GetParError(2)
394 sigma[0] = gausExpo.GetParameter(3)
395 errSigma[0] = gausExpo.GetParError(3)
396 norm1[0] = gausExpo.GetParameter(0)
397 errNorm1[0] = gausExpo.GetParError(0)
398 norm2[0] = gausExpo.GetParameter(1)
399 errNorm2[0] = gausExpo.GetParError(1)
400 normExtra[0] = gausExpo.GetParameter(6)
401 errNormExtra[0] = gausExpo.GetParError(6)
402 extraTime[0] = gausExpo.GetParameter(7)
403 errExtraTime[0] = gausExpo.GetParError(7)
404 sigmaExtra[0] = gausExpo.GetParameter(8)
405 errSigmaExtra[0] = gausExpo.GetParError(8)
408 if pdfType ==
'gaus':
411 "[0]*TMath::Gaus([2], [3], kTRUE)) + "
412 "[0]*[1]*TMath::Gaus([2]+[4], [3], kTRUE)) +"
413 "[0]*[5]*TMath::Gaus([2]+[6], [3]*[7], kTRUE))",
419 gaussian.SetParameter(0, 10.)
420 gaussian.SetParameter(2, maximum)
421 gaussian.SetParLimits(2, maximum - 0.1, maximum + 0.1)
422 gaussian.SetParameter(3, 0.05)
423 gaussian.SetParLimits(3, 0.03, 0.200)
425 gaussian.SetParameter(5, 0.01)
426 gaussian.SetParLimits(5, 0., .1)
427 gaussian.SetParameter(6, 1.)
428 gaussian.SetParLimits(6, 0.2, 2.)
429 gaussian.SetParameter(7, 1.5)
430 gaussian.SetParLimits(7, 1.1, 3.)
431 if not includeBackscatter:
432 gaussian.FixParameter(5, 0.)
433 gaussian.FixParameter(6, 1.)
434 gaussian.FixParameter(7, 1.5)
436 if(mcPeaks[k][1] > 0
and not useSinglePDF):
437 gaussian.SetParameter(1, 0.3)
438 gaussian.SetParLimits(1, 0., 100.)
440 gaussian.FixParameter(4, deltaMC[0])
442 gaussian.SetParameter(4, deltaMC[0])
443 gaussian.SetParLimits(4, deltaMC[0] - 0.2, -0.001)
445 gaussian.FixParameter(1, 0.)
446 gaussian.FixParameter(4, 0.)
448 gaussian.SetNpx(1000)
449 timeProjection.Fit(
'gaussian',
'RQS')
450 timeProjection.Fit(
'gaussian',
'RQS')
451 result = timeProjection.Fit(
'gaussian',
'RQS')
454 chi2[0] = result.Chi2()
455 ndf[0] = result.Ndf()
462 peakTime[0] = gaussian.GetParameter(2)
463 errPeakTime[0] = gaussian.GetParError(2)
464 sigma[0] = gaussian.GetParameter(3)
465 errSigma[0] = gaussian.GetParError(3)
466 norm1[0] = gaussian.GetParameter(0)
467 errNorm1[0] = gaussian.GetParError(0)
468 norm2[0] = gaussian.GetParameter(1)
469 errNorm2[0] = gaussian.GetParError(1)
470 normExtra[0] = gaussian.GetParameter(5)
471 errNormExtra[0] = gaussian.GetParError(5)
472 extraTime[0] = gaussian.GetParameter(6)
473 errExtraTime[0] = gaussian.GetParError(6)
474 sigmaExtra[0] = gaussian.GetParameter(7)
475 errSigmaExtra[0] = gaussian.GetParError(7)
478 correctedTime[0] = peakTime[0] - mcPeaks[k][0]
483 timeProjection.Write()
489def plotLaserResolution(fitResultsFile='laserResolutionResults.root'):
491 Function that creates some standard plots from the tree containg the flaset fit results
495 tFileData = TFile(fitResultsFile)
496 treeData = tFileData.Get(
'tree')
497 histoData = tFileData.Get(
'LaserTimingVSChannel')
500 h_test = TH1F(
"h_test",
"a test histogram to determine the histogram boundaries", 1000, 0., 100.)
501 treeData.Draw(
"correctedTime>>h_test")
502 meanCorrTime = h_test.GetMean()
505 h_localT0Resolution = [TH1F(
"h_localT0Resolution_slot" + str(iSlot + 1),
506 "Laser peak position after the MC correction in slot " + str(iSlot + 1),
509 meanCorrTime + 2.)
for iSlot
in range(16)]
511 h_singleChannelResolution = TH1F(
"h_singleChannelResolution",
"Resolution of the laser peak.", 40, 0., 0.4)
514 h_singleChannelResolutionVSChannel = TH1F(
515 "singleChannelResolutionVSChannel",
516 "Resolution of the laser peak VS channel number",
522 h_localT0ResolutionVSChannel = TH1F(
523 "localT0ResolutionVSChannel",
524 "Resolution of the laser peak VS channel number",
530 h_latePeakVSChannel = TH1F(
"latePeakVSChannel",
"Late Peak position", 512 * 16, 0, 512 * 16)
532 h_earlyPeakVSChannel = TH1F(
"earlyPeakVSChannel",
"Early Peak position", 512 * 16, 0, 512 * 16)
534 for entry
in treeData:
535 globalChannel = entry.hwChannel + entry.slotID * 512
537 h_localT0Resolution[entry.slotID - 1].Fill(entry.correctedTime)
538 h_singleChannelResolution.Fill(entry.sigma)
540 h_singleChannelResolutionVSChannel.SetBinContent(globalChannel + 1, entry.sigma)
541 h_singleChannelResolutionVSChannel.SetBinError(globalChannel + 1, entry.errSigma)
543 h_localT0ResolutionVSChannel.SetBinContent(globalChannel + 1, entry.correctedTime)
544 h_localT0ResolutionVSChannel.SetBinError(globalChannel + 1, entry.errPeakTime)
546 h_latePeakVSChannel.SetBinContent(globalChannel + 1, entry.latePeak)
547 if entry.earlyPeak > 0:
548 h_earlyPeakVSChannel.SetBinContent(globalChannel + 1, entry.earlyPeak)
551 for iSlot
in range(16):
552 laserTime = histoData.GetBinContent(iSlot * 512 + 1)
553 mcTime = h_latePeakVSChannel.GetBinContent(iSlot * 512 + 1)
554 timeShift = laserTime - mcTime
555 for iBin
in range(512):
556 lateTime = h_latePeakVSChannel.GetBinContent(iBin + iSlot * 512 + 1) + timeShift
557 earlyTime = h_earlyPeakVSChannel.GetBinContent(iBin + iSlot * 512 + 1) + timeShift
558 h_latePeakVSChannel.SetBinContent(iBin + iSlot * 512 + 1, lateTime)
559 h_earlyPeakVSChannel.SetBinContent(iBin + iSlot * 512 + 1, earlyTime)
562 tFileOut = TFile(
'plots.root',
"RECREATE")
565 h_latePeakVSChannel.Write()
566 h_earlyPeakVSChannel.Write()
567 h_singleChannelResolution.Write()
568 h_singleChannelResolutionVSChannel.Write()
569 h_localT0ResolutionVSChannel.Write()
572 h_localT0Resolution[i].Write()