Belle II Software  release-06-02-00
TOPLocalCalFitter.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <top/calibration/TOPLocalCalFitter.h>
10 
11 #include "TH2F.h"
12 #include "TFile.h"
13 #include "TMath.h"
14 #include "TF1.h"
15 #include "TROOT.h"
16 #include "TTree.h"
17 #include "math.h"
18 #include <limits>
19 #include <framework/logging/Logger.h>
20 #include <top/dbobjects/TOPCalChannelT0.h>
21 
22 
23 //using namespace std;
24 using namespace Belle2;
25 using namespace TOP;
26 
27 double crystalball_function(double x, double alpha, double n, double sigma, double mean)
28 {
29  // evaluate the crystal ball function
30  if (sigma < 0.) return 0.;
31  double z = (x - mean) / sigma;
32  if (alpha < 0) z = -z;
33  double abs_alpha = std::abs(alpha);
34  if (z > - abs_alpha)
35  return std::exp(- 0.5 * z * z);
36  else {
37  double nDivAlpha = n / abs_alpha;
38  double AA = std::exp(-0.5 * abs_alpha * abs_alpha);
39  double B = nDivAlpha - abs_alpha;
40  double arg = nDivAlpha / (B - z);
41  return AA * std::pow(arg, n);
42  }
43 }
44 
45 double crystalball_pdf(double x, double alpha, double n, double sigma, double mean)
46 {
47  // evaluation of the PDF ( is defined only for n >1)
48  if (sigma < 0.) return 0.;
49  if (n <= 1) return std::numeric_limits<double>::quiet_NaN(); // pdf is not normalized for n <=1
50  double abs_alpha = std::abs(alpha);
51  double C = n / abs_alpha * 1. / (n - 1.) * std::exp(-alpha * alpha / 2.);
52  double D = std::sqrt(M_PI / 2.) * (1. + erf(abs_alpha / std::sqrt(2.)));
53  double N = 1. / (sigma * (C + D));
54  return N * crystalball_function(x, alpha, n, sigma, mean);
55 }
56 
57 
58 
59 // Two gaussians to model the TTS of the MCP-PMTs.
60 double TTSPDF(double x, double time, double deltaT, double sigma1, double sigma2, double f1)
61 {
62  return f1 * TMath::Gaus(x, time, sigma1, kTRUE) + (1 - f1) * TMath::Gaus(x, time + deltaT, sigma2, kTRUE) ;
63 }
64 
65 
66 // Full PDF to fit the laser, made of:
67 // 2 TTSPDF
68 // 1 crystal ball PDF for the extra peak at +1 ns we don't understand
69 // 1 gaussian to help modelling the tail
70 double laserPDF(double* x, double* p)
71 {
72  double time = p[0];
73  double sigma = p[1];
74  double fraction = p[2];
75  double deltaTLaser = p[3];
76  double sigmaRatio = p[4];
77  double deltaTTS = p[5];
78  double f1 = p[6];
79  double norm = p[7];
80 
81  double deltaTExtra = p[8];
82  double sigmaExtra = p[9];
83  double normExtra = p[10];
84 
85  double deltaTBkg = p[11];
86  double sigmaBkg = p[12];
87  double bkg = p[13];
88 
89  double alpha = p[14];
90  double n = p[15];
91 
92  double mainPeak = fraction * TTSPDF(x[0], time, deltaTTS, sigma, TMath::Sqrt(sigma * sigma + sigmaRatio * sigmaRatio), f1);
93  double secondaryPeak = (1. - fraction) * TTSPDF(x[0], time + deltaTLaser, deltaTTS, sigma,
94  TMath::Sqrt(sigma * sigma + sigmaRatio * sigmaRatio), f1);
95  double extraPeak = crystalball_pdf(x[0], alpha, n, sigmaExtra, time + deltaTExtra);
96  double background = TMath::Gaus(x[0], time + deltaTBkg + deltaTTS, sigmaBkg, kTRUE);
97 
98  return norm * (mainPeak + secondaryPeak) + normExtra * extraPeak + bkg * background;
99 }
100 
101 
103 {
105  "Perform the fit of the laser and pulser runs"
106  );
107 
108 }
109 
110 
111 
113 {
114  m_inputTTS = TFile::Open(m_TTSData.c_str());
115  m_inputConstraints = TFile::Open(m_fitConstraints.c_str());
116 
117  B2INFO("Getting the TTS parameters from " << m_TTSData);
118  m_inputTTS->cd();
119  m_inputTTS->GetObject("tree", m_treeTTS);
120  m_treeTTS->SetBranchAddress("mean2", &m_mean2);
121  m_treeTTS->SetBranchAddress("sigma1", &m_sigma1);
122  m_treeTTS->SetBranchAddress("sigma2", &m_sigma2);
123  m_treeTTS->SetBranchAddress("fraction1", &m_f1);
124  m_treeTTS->SetBranchAddress("fraction2", &m_f2);
125  m_treeTTS->SetBranchAddress("pixelRow", &m_pixelRow);
126  m_treeTTS->SetBranchAddress("pixelCol", &m_pixelCol);
127 
128  if (m_fitterMode == "MC")
129  std::cout << "Running in MC mode, not constraints will be set" << std::endl;
130  else {
131  B2INFO("Getting the laser fit parameters from " << m_fitConstraints);
132  m_inputConstraints->cd();
133  m_inputConstraints->GetObject("fitTree", m_treeConstraints);
134  m_treeConstraints->SetBranchAddress("peakTime", &m_peakTimeConstraints);
135  m_treeConstraints->SetBranchAddress("deltaT", &m_deltaTConstraints);
136  m_treeConstraints->SetBranchAddress("fraction", &m_fractionConstraints);
137  if (m_fitterMode == "monitoring") {
138  m_treeConstraints->SetBranchAddress("timeExtra", &m_timeExtraConstraints);
139  m_treeConstraints->SetBranchAddress("sigmaExtra", &m_sigmaExtraConstraints);
140  m_treeConstraints->SetBranchAddress("alphaExtra", &m_alphaExtraConstraints);
141  m_treeConstraints->SetBranchAddress("nExtra", &m_nExtraConstraints);
142  m_treeConstraints->SetBranchAddress("timeBackground", &m_timeBackgroundConstraints);
143  m_treeConstraints->SetBranchAddress("sigmaBackground", &m_sigmaBackgroundConstraints);
144  }
145  }
146  return;
147 }
148 
149 
151 {
152  m_histFile = new TFile(m_output.c_str(), "recreate");
153  m_histFile->cd();
154  m_fitTree = new TTree("fitTree", "fitTree");
155  m_fitTree->Branch<short>("channel", &m_channel);
156  m_fitTree->Branch<short>("slot", &m_slot);
157  m_fitTree->Branch<short>("row", &m_row);
158  m_fitTree->Branch<short>("col", &m_col);
159  m_fitTree->Branch<float>("peakTime", &m_peakTime);
160  m_fitTree->Branch<float>("peakTimeErr", &m_peakTimeErr);
161  m_fitTree->Branch<float>("deltaT", &m_deltaT);
162  m_fitTree->Branch<float>("deltaTErr", &m_deltaTErr);
163  m_fitTree->Branch<float>("sigma", &m_sigma);
164  m_fitTree->Branch<float>("sigmaErr", &m_sigmaErr);
165  m_fitTree->Branch<float>("fraction", &m_fraction);
166  m_fitTree->Branch<float>("fractionErr", &m_fractionErr);
167  m_fitTree->Branch<float>("yieldLaser", &m_yieldLaser);
168  m_fitTree->Branch<float>("yieldLaserErr", &m_yieldLaserErr);
169  m_fitTree->Branch<float>("timeExtra", &m_timeExtra);
170  m_fitTree->Branch<float>("sigmaExtra", &m_sigmaExtra);
171  m_fitTree->Branch<float>("nExtra", &m_nExtra);
172  m_fitTree->Branch<float>("alphaExtra", &m_alphaExtra);
173  m_fitTree->Branch<float>("yieldLaserExtra", &m_yieldLaserExtra);
174  m_fitTree->Branch<float>("timeBackground", &m_timeBackground);
175  m_fitTree->Branch<float>("sigmaBackground", &m_sigmaBackground);
176  m_fitTree->Branch<float>("yieldLaserBackground", &m_yieldLaserBackground);
177 
178  m_fitTree->Branch<float>("fractionMC", &m_fractionMC);
179  m_fitTree->Branch<float>("deltaTMC", &m_deltaTMC);
180  m_fitTree->Branch<float>("peakTimeMC", &m_peakTimeMC);
181  m_fitTree->Branch<float>("firstPulserTime", &m_firstPulserTime);
182  m_fitTree->Branch<float>("firstPulserSigma", &m_firstPulserSigma);
183  m_fitTree->Branch<float>("secondPulserTime", &m_secondPulserTime);
184  m_fitTree->Branch<float>("secondPulserSigma", &m_secondPulserSigma);
185  m_fitTree->Branch<short>("fitStatus", &m_fitStatus);
186 
187  m_fitTree->Branch<float>("chi2", &m_chi2);
188  m_fitTree->Branch<float>("rms", &m_rms);
189 
190 
192  m_timewalkTree = new TTree("timewalkTree", "timewalkTree");
193 
194  m_timewalkTree->Branch<float>("binLowerEdge", &m_binLowerEdge);
195  m_timewalkTree->Branch<float>("binUpperEdge", &m_binUpperEdge);
196  m_timewalkTree->Branch<short>("channel", &m_channel);
197  m_timewalkTree->Branch<short>("slot", &m_slot);
198  m_timewalkTree->Branch<short>("row", &m_row);
199  m_timewalkTree->Branch<short>("col", &m_col);
200  m_timewalkTree->Branch<float>("histoIntegral", &m_histoIntegral);
201  m_timewalkTree->Branch<float>("peakTime", &m_peakTime);
202  m_timewalkTree->Branch<float>("peakTimeErr", &m_peakTimeErr);
203  m_timewalkTree->Branch<float>("deltaT", &m_deltaT);
204  m_timewalkTree->Branch<float>("deltaTErr", &m_deltaTErr);
205  m_timewalkTree->Branch<float>("sigma", &m_sigma);
206  m_timewalkTree->Branch<float>("sigmaErr", &m_sigmaErr);
207  m_timewalkTree->Branch<float>("fraction", &m_fraction);
208  m_timewalkTree->Branch<float>("fractionErr", &m_fractionErr);
209  m_timewalkTree->Branch<float>("yieldLaser", &m_yieldLaser);
210  m_timewalkTree->Branch<float>("yieldLaserErr", &m_yieldLaserErr);
211  m_timewalkTree->Branch<float>("timeExtra", &m_timeExtra);
212  m_timewalkTree->Branch<float>("sigmaExtra", &m_sigmaExtra);
213  m_timewalkTree->Branch<float>("nExtra", &m_nExtra);
214  m_timewalkTree->Branch<float>("alphaExtra", &m_alphaExtra);
215  m_timewalkTree->Branch<float>("yieldLaserExtra", &m_yieldLaserExtra);
216  m_timewalkTree->Branch<float>("timeBackground", &m_timeBackground);
217  m_timewalkTree->Branch<float>("sigmaBackground", &m_sigmaBackground);
218  m_timewalkTree->Branch<float>("yieldLaserBackground", &m_yieldLaserBackground);
219 
220  m_timewalkTree->Branch<float>("fractionMC", &m_fractionMC);
221  m_timewalkTree->Branch<float>("deltaTMC", &m_deltaTMC);
222  m_timewalkTree->Branch<float>("peakTimeMC", &m_peakTimeMC);
223  m_timewalkTree->Branch<float>("firstPulserTime", &m_firstPulserTime);
224  m_timewalkTree->Branch<float>("firstPulserSigma", &m_firstPulserSigma);
225  m_timewalkTree->Branch<float>("secondPulserTime", &m_secondPulserTime);
226  m_timewalkTree->Branch<float>("secondPulserSigma", &m_secondPulserSigma);
227  m_timewalkTree->Branch<short>("fitStatus", &m_fitStatus);
228 
229  m_timewalkTree->Branch<float>("chi2", &m_chi2);
230  m_timewalkTree->Branch<float>("rms", &m_rms);
231 
232  }
233 
234  return;
235 }
236 
237 
238 
239 
240 void TOPLocalCalFitter::fitChannel(short iSlot, short iChannel, TH1* h_profile)
241 {
242 
243  // loads the TTS infos and the fit constraint for the given channel and slot
244  if (m_fitterMode == "monitoring")
245  m_treeConstraints->GetEntry(iChannel + 512 * iSlot);
246  else if (m_fitterMode == "calibration") // The MC-based constraint file has only slot 1 at the moment
247  m_treeConstraints->GetEntry(iChannel);
248 
249  m_treeTTS->GetEntry(iChannel + 512 * iSlot);
250  // finds the maximum of the hit timing histogram and adjust the histogram range around it (3 ns window)
251  double maxpos = h_profile->GetBinCenter(h_profile->GetMaximumBin());
252  h_profile->GetXaxis()->SetRangeUser(maxpos - 1, maxpos + 2.);
253 
254  // gets the histogram integral to give a starting value to the fitter
255  double integral = h_profile->Integral();
256 
257  // creates the fit function
258  TF1 laser = TF1("laser", laserPDF, maxpos - 1, maxpos + 2., 16);
259 
260  // par[0] = peakTime
261  laser.SetParameter(0, maxpos);
262  laser.SetParLimits(0, maxpos - 0.06, maxpos + 0.06);
263 
264  // par[1] = sigma
265  laser.SetParameter(1, 0.1);
266  laser.SetParLimits(1, 0.05, 0.25);
267  if (m_fitterMode == "MC") {
268  laser.SetParameter(1, 0.02);
269  laser.SetParLimits(1, 0., 0.04);
270  }
271  // par[2] = fraction of the main peak respect to the total
272  laser.SetParameter(2, m_fractionConstraints);
273  laser.SetParLimits(2, 0.5, 1.);
274 
275  // par[3]= time difference between the main and secondary path. fixed to the MC value
276  laser.FixParameter(3, m_deltaTConstraints);
277 
278  // This is an hack: in some channels the MC sees one peak only, while in the data there are clearly
279  // two well distinguished peaks. This will disappear if we'll ever get a better laser simulation.
280  if (m_deltaTConstraints > -0.001) {
281  laser.SetParameter(3, -0.3);
282  laser.SetParLimits(3, -0.4, -0.2);
283  }
284 
285  // par[4] is the quadratic difference of the sigmas of the two TTS gaussians (tail - core)
286  laser.FixParameter(4, TMath::Sqrt(m_sigma2 * m_sigma2 - m_sigma1 * m_sigma1));
287  // par[5] is the position of the second TTS gaussian w/ respect to the first one
288  laser.FixParameter(5, m_mean2);
289  // par[6] is the relative contribution of the second TTS gaussian
290  laser.FixParameter(6, m_f1);
291  if (m_fitterMode == "MC")
292  laser.FixParameter(6, 0);
293 
294  // par[7] is the PDF normalization, = integral*bin width
295  laser.SetParameter(7, integral * 0.005);
296  laser.SetParLimits(7, 0.2 * integral * 0.005, 2.*integral * 0.005);
297 
298  // par[8-10] are the relative position, the sigma and the integral of the extra peak
299  laser.SetParameter(8, 1.);
300  laser.SetParLimits(8, 0.3, 2.);
301  laser.SetParameter(9, 0.2);
302  laser.SetParLimits(9, 0.08, 1.);
303  laser.SetParameter(10, 0.1 * integral * 0.005);
304  laser.SetParLimits(10, 0., 0.2 * integral * 0.005);
305  // par[14-15] are the tail parameters of the crystal ball function used to describe the extra peak
306  laser.SetParameter(14, -2.);
307  laser.SetParameter(15, 2.);
308  laser.SetParLimits(15, 1.01, 20.);
309 
310  // par[11-13] are relative position, sigma and integral of the broad gaussian added to better describe the tail at high times
311  laser.SetParameter(11, 1.);
312  laser.SetParLimits(11, 0.1, 5.);
313  laser.SetParameter(12, 0.8);
314  laser.SetParLimits(12, 0., 5.);
315  laser.SetParameter(13, 0.01 * integral * 0.005);
316  laser.SetParLimits(13, 0., 0.2 * integral * 0.005);
317 
318  // if it's a monitoring fit, fix a buch more parameters.
319  if (m_fitterMode == "monitoring") {
320  laser.FixParameter(2, m_fractionConstraints);
321  laser.FixParameter(3, m_deltaTConstraints);
322  laser.FixParameter(8, m_timeExtraConstraints);
323  laser.FixParameter(9, m_sigmaExtraConstraints);
324  laser.FixParameter(14, m_alphaExtraConstraints);
325  laser.FixParameter(15, m_nExtraConstraints);
326  laser.FixParameter(11, m_timeBackgroundConstraints);
327  laser.FixParameter(12, m_sigmaBackgroundConstraints);
328  }
329 
330 
331  // if it's a MC fit, fix a buch more parameters.
332  if (m_fitterMode == "MC") {
333  laser.SetParameter(2, 0.8);
334  laser.SetParLimits(2, 0., 1.);
335  laser.SetParameter(3, -0.1);
336  laser.SetParLimits(3, -0.4, -0.);
337  // The following are just random reasonable number, only to pin-point the tail components to some value and remove them form the fit
338  laser.FixParameter(8, 0);
339  laser.FixParameter(9, 0.1);
340  laser.FixParameter(14, -2.);
341  laser.FixParameter(15, 2);
342  laser.FixParameter(11, 1.);
343  laser.FixParameter(12, 0.1);
344  laser.FixParameter(13, 0.);
345  laser.FixParameter(10, 0.);
346  }
347 
348 
349 
350  // make the plot of the fit function nice setting 2000 sampling points
351  laser.SetNpx(2000);
352 
353 
354  // do the fit!
355  h_profile->Fit("laser", "R L Q");
356 
357 
358  // Add by hand the different fit components to the histogram, mostly for debugging/presentation purposes
359  TF1* peak1 = new TF1("peak1", laserPDF, maxpos - 1, maxpos + 2., 16);
360  TF1* peak2 = new TF1("peak2", laserPDF, maxpos - 1, maxpos + 2., 16);
361  TF1* extra = new TF1("extra", laserPDF, maxpos - 1, maxpos + 2., 16);
362  TF1* background = new TF1("background", laserPDF, maxpos - 1, maxpos + 2., 16);
363  for (int iPar = 0; iPar < 16; iPar++) {
364  peak1->FixParameter(iPar, laser.GetParameter(iPar));
365  peak2->FixParameter(iPar, laser.GetParameter(iPar));
366  extra->FixParameter(iPar, laser.GetParameter(iPar));
367  background->FixParameter(iPar, laser.GetParameter(iPar));
368  }
369  peak1->FixParameter(2, 0.);
370  peak1->FixParameter(7, (1 - laser.GetParameter(2))*laser.GetParameter(7));
371  peak1->FixParameter(10, 0.);
372  peak1->FixParameter(13, 0.);
373 
374  peak2->FixParameter(2, 1.);
375  peak2->FixParameter(7, laser.GetParameter(2)*laser.GetParameter(7));
376  peak2->FixParameter(10, 0.);
377  peak2->FixParameter(13, 0.);
378 
379  extra->FixParameter(7, 0.);
380  extra->FixParameter(13, 0.);
381 
382  background->FixParameter(7, 0.);
383  background->FixParameter(10, 0.);
384 
385  h_profile->GetListOfFunctions()->Add(peak1);
386  h_profile->GetListOfFunctions()->Add(peak2);
387  h_profile->GetListOfFunctions()->Add(extra);
388  h_profile->GetListOfFunctions()->Add(background);
389 
390 
391  // save the results in the variables linked to the tree branches
392  m_channel = iChannel;
393  m_row = m_pixelRow;
394  m_col = m_pixelCol;
395  m_slot = iSlot + 1;
396  m_peakTime = laser.GetParameter(0);
397  m_peakTimeErr = laser.GetParError(0);
398  m_deltaT = laser.GetParameter(3);
399  m_deltaTErr = laser.GetParError(3);
400  m_sigma = laser.GetParameter(1);
401  m_sigmaErr = laser.GetParError(1);
402  m_fraction = laser.GetParameter(2);
403  m_fractionErr = laser.GetParError(2);
404  m_yieldLaser = laser.GetParameter(7) / 0.005;
405  m_yieldLaserErr = laser.GetParError(7) / 0.005;
406  m_timeExtra = laser.GetParameter(8);
407  m_sigmaExtra = laser.GetParameter(9);
408  m_yieldLaserExtra = laser.GetParameter(10) / 0.005;
409  m_alphaExtra = laser.GetParameter(14);
410  m_nExtra = laser.GetParameter(15);
411  m_timeBackground = laser.GetParameter(11);
412  m_sigmaBackground = laser.GetParameter(12);
413  m_yieldLaserBackground = laser.GetParameter(13) / 0.005;
414  m_chi2 = laser.GetChisquare() / laser.GetNDF();
415 
416  // copy some MC information to the output tree
420 
421  return;
422 }
423 
424 
425 void TOPLocalCalFitter::fitPulser(TH1* h_profileFirstPulser, TH1* h_profileSecondPulser)
426 {
427  float maxpos = h_profileFirstPulser->GetBinCenter(h_profileFirstPulser->GetMaximumBin());
428  h_profileFirstPulser->GetXaxis()->SetRangeUser(maxpos - 1, maxpos + 1.);
429  if (h_profileFirstPulser->Integral() > 1000) {
430  TF1 pulser1 = TF1("pulser1", "[0]*TMath::Gaus(x, [1], [2], kTRUE)", maxpos - 1, maxpos + 1.);
431  pulser1.SetParameter(0, 1.);
432  pulser1.SetParameter(1, maxpos);
433  pulser1.SetParameter(2, 0.05);
434  h_profileFirstPulser->Fit("pulser1", "R Q");
435  m_firstPulserTime = pulser1.GetParameter(1);
436  m_firstPulserSigma = pulser1.GetParameter(2);
437  h_profileFirstPulser->Write();
438  } else {
439  m_firstPulserTime = -999;
440  m_firstPulserSigma = -999;
441  }
442 
443  maxpos = h_profileSecondPulser->GetBinCenter(h_profileSecondPulser->GetMaximumBin());
444  h_profileSecondPulser->GetXaxis()->SetRangeUser(maxpos - 1, maxpos + 1.);
445  if (h_profileSecondPulser->Integral() > 1000) {
446  TF1 pulser2 = TF1("pulser2", "[0]*TMath::Gaus(x, [1], [2], kTRUE)", maxpos - 1, maxpos + 1.);
447  pulser2.SetParameter(0, 1.);
448  pulser2.SetParameter(1, maxpos);
449  pulser2.SetParameter(2, 0.05);
450  h_profileSecondPulser->Fit("pulser2", "R Q");
451  m_secondPulserTime = pulser2.GetParameter(1);
452  m_secondPulserSigma = pulser2.GetParameter(2);
453  h_profileSecondPulser->Write();
454  } else {
455  m_secondPulserTime = -999;
456  m_secondPulserSigma = -999;
457  }
458  return;
459 }
460 
461 
462 
464 {
465  if (m_chi2 < 4 && m_sigma < 0.2 && m_yieldLaser > 1000) {
466  m_fitStatus = 0;
467  } else {
468  m_fitStatus = 1;
469  }
470  return;
471 }
472 
473 
475 {
476  int nEntries = m_fitTree->GetEntries();
477  if (nEntries != 8192) {
478  B2ERROR("fitTree does not contain an entry wit a fit result for each channel. Found " << nEntries <<
479  " instead of 8192. Perhaps you tried to run the commonT0 calculation before finishing the fitting?");
480  return;
481  }
482 
483  // Create and fill the TOPCalChannelT0 object.
484  // This part is mostly copy-pasted from the DB importer used up to Jan 2020
485  auto* channelT0 = new TOPCalChannelT0();
486  short nCal[16] = {0};
487  for (int i = 0; i < nEntries; i++) {
488  m_fitTree->GetEntry(i);
489  channelT0->setT0(m_slot, m_channel, m_peakTime - m_peakTimeMC, m_peakTimeErr);
490  if (m_fitStatus == 0) {
491  nCal[m_slot - 1]++;
492  } else {
493  channelT0->setUnusable(m_slot, m_channel);
494  }
495  }
496 
497  // Normalize the constants
498  channelT0->suppressAverage();
499 
500  // create the localDB
501  saveCalibration(channelT0);
502 
503  short nCalTot = 0;
504  B2INFO("Summary: ");
505  for (int iSlot = 1; iSlot < 17; iSlot++) {
506  B2INFO("--> Number of calibrated channels on Slot " << iSlot << " : " << nCal[iSlot - 1] << "/512");
507  B2INFO("--> Cal on ch 1, 256 and 511: " << channelT0->getT0(iSlot, 0) << ", " << channelT0->getT0(iSlot,
508  257) << ", " << channelT0->getT0(iSlot, 511));
509  nCalTot += nCal[iSlot - 1];
510  }
511 
512  B2RESULT("Channel T0 calibration constants imported to database, calibrated channels: " << nCalTot << "/ 8192");
513 
514 
515  // Loop again on the output tree to save the constants there too, adding two more branches.
516  TBranch* channelT0Branch = m_fitTree->Branch<float>("channelT0", &m_channelT0);
517  TBranch* channelT0ErrBranch = m_fitTree->Branch<float>("channelT0Err", &m_channelT0Err);
518 
519  for (int i = 0; i < nEntries; i++) {
520  m_fitTree->GetEntry(i);
521  m_channelT0 = channelT0->getT0(m_slot, m_channel);
522  m_channelT0Err = channelT0->getT0Error(m_slot, m_channel);
523  channelT0Branch->Fill();
524  channelT0ErrBranch->Fill();
525  }
526  return ;
527 
528 }
529 
530 
531 
533 {
534  gROOT->SetBatch();
535 
536  loadMCInfoTrees();
537 
538 
540 
541  // Loads the tree with the hits
542  auto hitTree = getObjectPtr<TTree>("hitTree");
543  TH2F* h_hitTime = new TH2F("h_hitTime", " ", 512 * 16, 0., 512 * 16, 22000, -70, 40.); // 5 ps bins
544 
545  float amplitude, hitTime;
546  short channel, slot;
547  bool refTimeValid;
548  hitTree->SetBranchAddress("amplitude", &amplitude);
549  hitTree->SetBranchAddress("hitTime", &hitTime);
550  hitTree->SetBranchAddress("channel", &channel);
551  hitTree->SetBranchAddress("slot", &slot);
552  hitTree->SetBranchAddress("refTimeValid", &refTimeValid);
553 
554  // An attempt to speed things up looping over the tree only once.
555  std::vector<TH2F*> h_hitTimeLaserHistos = {};
556  for (int iLowerEdge = 0; iLowerEdge < (int)m_binEdges.size() - 1; iLowerEdge++) {
557  TH2F* h_hitTimeLaser = new TH2F(("h_hitTimeLaser_" + std::to_string(iLowerEdge + 1)).c_str(), " ", 512 * 16, 0., 512 * 16, 14000,
558  -70, 0.); // 5 ps bins
559  h_hitTimeLaserHistos.push_back(h_hitTimeLaser);
560  }
561 
562  for (unsigned int i = 0; i < hitTree->GetEntries(); i++) {
563  auto onepc = (unsigned int)(hitTree->GetEntries() / 100);
564  if (i % onepc == 0)
565  std::cout << "processing hit " << i << " of " << hitTree->GetEntries() << " (" << i / (onepc * 10) << " %)" << std::endl;
566  hitTree->GetEntry(i);
567  auto it = std::lower_bound(m_binEdges.cbegin(), m_binEdges.cend(), amplitude);
568  int iLowerEdge = std::distance(m_binEdges.cbegin(), it) - 1;
569 
570  if (iLowerEdge >= 0 && iLowerEdge < static_cast<int>(m_binEdges.size()) - 1 && refTimeValid)
571  h_hitTimeLaserHistos[iLowerEdge]->Fill(channel + (slot - 1) * 512, hitTime);
572  if (amplitude > 80. && refTimeValid)
573  h_hitTime->Fill(channel + (slot - 1) * 512, hitTime);
574  }
575 
576  m_histFile->cd();
577  h_hitTime->Write();
578 
579  for (short iSlot = 0; iSlot < 16; iSlot++) {
580  std::cout << "fitting slot " << iSlot + 1 << std::endl;
581  for (short iChannel = 0; iChannel < 512; iChannel++) {
582  TH1D* h_profile = h_hitTime->ProjectionY(("profile_" + std::to_string(iSlot + 1) + "_" + std::to_string(iChannel)).c_str(),
583  iSlot * 512 + iChannel + 1, iSlot * 512 + iChannel + 1);
584  if (m_fitterMode == "MC")
585  h_profile->GetXaxis()->SetRangeUser(-10, -10);
586  else
587  h_profile->GetXaxis()->SetRangeUser(-65,
588  -5); // if you will even change it, make sure not to include the h_hitTime overflow bins in this range
589  fitChannel(iSlot, iChannel, h_profile);
590 
592 
593  // Now let's fit the pulser
594  TH1D* h_profileFirstPulser = h_hitTime->ProjectionY(("profileFirstPulser_" + std::to_string(iSlot + 1) + "_" + std::to_string(
595  iChannel)).c_str(), iSlot * 512 + iChannel + 1, iSlot * 512 + iChannel + 1);
596  TH1D* h_profileSecondPulser = h_hitTime->ProjectionY(("profileSecondPulser_" + std::to_string(iSlot + 1) + "_" + std::to_string(
597  iChannel)).c_str(), iSlot * 512 + iChannel + 1, iSlot * 512 + iChannel + 1);
598  h_profileFirstPulser->GetXaxis()->SetRangeUser(-10, 10);
599  h_profileSecondPulser->GetXaxis()->SetRangeUser(10, 40);
600 
601  fitPulser(h_profileFirstPulser, h_profileSecondPulser);
602 
603  m_fitTree->Fill();
604 
605  h_profile->Write();
606  h_profileFirstPulser->Write();
607  h_profileSecondPulser->Write();
608  }
609 
610  h_hitTime->Write();
611  }
612 
614 
615  m_fitTree->Write();
616 
617 
619  std::cout << "Fitting in bins" << std::endl;
620  for (int iLowerEdge = 0; iLowerEdge < (int)m_binEdges.size() - 1; iLowerEdge++) {
621  m_binLowerEdge = m_binEdges[iLowerEdge];
622  m_binUpperEdge = m_binEdges[iLowerEdge + 1];
623  std::cout << "Fitting the amplitude interval (" << m_binLowerEdge << ", " << m_binUpperEdge << " )" << std::endl;
624 
625  for (short iSlot = 0; iSlot < 16; iSlot++) {
626  std::cout << " Fitting slot " << iSlot + 1 << std::endl;
627  for (short iChannel = 0; iChannel < 512; iChannel++) {
628  TH1D* h_profile = h_hitTimeLaserHistos[iLowerEdge]->ProjectionY(("profile_" + std::to_string(iSlot + 1) + "_" + std::to_string(
629  iChannel) + "_" + std::to_string(iLowerEdge)).c_str(),
630  iSlot * 512 + iChannel + 1, iSlot * 512 + iChannel + 1);
631  if (m_fitterMode == "MC")
632  h_profile->GetXaxis()->SetRangeUser(-10, -10);
633  else
634  h_profile->GetXaxis()->SetRangeUser(-65,
635  -5); // if you will even change it, make sure not to include the h_hitTime overflow bins in this range
636  fitChannel(iSlot, iChannel, h_profile);
637  m_histoIntegral = h_profile->Integral();
639 
640  m_timewalkTree->Fill();
641  h_profile->Write();
642  }
643  }
644  }
645 
646  m_timewalkTree->Write();
647  }
648 
649  m_histFile->Close();
650 
651  return c_OK;
652 }
Base class for calibration algorithms.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
void setDescription(const std::string &description)
Set algorithm description (in constructor)
EResult
The result of calibration.
@ c_OK
Finished successfuly =0 in Python.
Channel T0 calibration constants for all 512 channels of 16 modules.
short m_fitStatus
Fit quality flag, propagated to the constants.
float m_yieldLaserErr
Statistical error on yield.
float m_binLowerEdge
Lower edge of the amplitude bin in which this fit is performed.
void fitChannel(short, short, TH1 *)
Fits the laser light on one channel.
float m_nExtraConstraints
parameter n of the tail of the extra peak
float m_chi2
Reduced chi2 of the fit.
float m_timeExtraConstraints
Position of the guassian used to describe the extra peak on the timing distribution tail.
float m_f1
Fraction of the first gaussian on the TTS parametrization.
float m_fraction
Fraction of events in the secondary peak.
float m_sigmaExtra
Gaussian sigma of the extra peak in the timing tail
float m_secondPulserSigma
Time resolution from the fit of the first electronic pulse, from a Gaussian fit.
float m_yieldLaserBackground
Integral of the background gaussian.
float m_sigma
Gaussian time resolution, fitted.
float m_peakTimeMC
Time of the main peak in teh MC simulation, i.e.
std::string m_output
Name of the output file.
float m_timeBackground
Position of the gaussian used to describe the background, w/ respect to peakTime.
void loadMCInfoTrees()
loads the TTS parameters and the MC truth info
float m_deltaTMC
Time difference between the main peak and the secondary peak in the MC simulation.
float m_peakTimeErr
Statistical error on peakTime.
short m_channel
Channel number (0-511)
float m_channelT0Err
Statistical error on channelT0.
std::string m_TTSData
File with the Fit constraints and MC info.
std::vector< float > m_binEdges
Amplitude bins.
float m_sigmaBackground
Sigma of the gaussian used to describe the background.
float m_peakTime
Fitted time of the main (i.e.
float m_fractionErr
Statistical error on fraction.
bool m_isFitInAmplitudeBins
Enables the fit in amplitude bins.
void calculateChennelT0()
Calculates the commonT0 calibration after the fits have been done.
float m_alphaExtra
alpha parameter of the tail of the extra peak.
float m_rms
RMS of the histogram used for the fit.
float m_mean2
Position of the second gaussian of the TTS parametrization with respect to the first one.
std::string m_fitConstraints
File with the TTS parametrization.
TTree * m_timewalkTree
Output of the fitter.
float m_yieldLaser
Total number of laser hits from the fitting function integral.
TFile * m_inputTTS
File containing m_treeTTS.
float m_nExtra
parameter n of the tail of the extra peak
float m_alphaExtraConstraints
alpha parameter of the tail of the extra peak.
float m_channelT0
Raw, channelT0 calibration, defined as peakTime-peakTimeMC.
float m_sigmaErr
Statistical error on sigma.
std::string m_fitterMode
Fit mode.
float m_binUpperEdge
Upper edge of the amplitude bin in which this fit is performed.
TFile * m_histFile
Output of the fitter.
TTree * m_treeConstraints
Input to the fitter.
float m_sigmaExtraConstraints
Width of the guassian used to describe the extra peak on the timing distribution tail.
float m_firstPulserSigma
Time resolution from the fit of the first electronic pulse, from a Gaussian fit.
float m_deltaT
Time difference between the main peak and the secondary peak.
TTree * m_fitTree
Output of the fitter.
float m_f2
Fraction of the second gaussian on the TTS parametrization.
void determineFitStatus()
determines if the constant obtained by the fit are good or not
float m_secondPulserTime
Average time of the second electronic pulse respect to the reference pulse, from a gaussian fit.
float m_peakTimeConstraints
Time of the main laser peak in the MC simulation (aka MC correction)
float m_sigma1
Width of the first gaussian on the TTS parametrization.
float m_fractionMC
Fraction of events in the secondary peak form the MC simulation.
float m_sigmaBackgroundConstraints
Sigma of the gaussian used to describe the background.
virtual EResult calibrate() override
Runs the algorithm on events.
TTree * m_treeTTS
Input to the fitter.
void setupOutputTreeAndFile()
prepares the output tree
float m_timeBackgroundConstraints
Position of the gaussian used to describe the background, w/ respect to peakTime.
TFile * m_inputConstraints
File containing m_treeConstraints.
float m_deltaTErr
Statistical error on deltaT.
float m_firstPulserTime
Average time of the first electronic pulse respect to the reference pulse, from a Gaussian fit.
float m_histoIntegral
Integral of the fitted histogram.
float m_yieldLaserExtra
Integral of the extra peak.
float m_sigma2
Width of the second gaussian on the TTS parametrization.
void fitPulser(TH1 *, TH1 *)
Fits the two pulsers.
float m_timeExtra
Position of the extra peak seen in the timing tail, w/ respect to peakTime.
float m_fractionConstraints
Fraction of the main peak.
float m_deltaTConstraints
Distance between the main and the secondary laser peak.
Abstract base class for different kinds of events.