12 #include <top/modules/TOPTimeBaseCalibrator/TOPTimeBaseCalibratorModule.h>
13 #include <top/geometry/TOPGeometryPar.h>
16 #include <framework/datastore/StoreArray.h>
19 #include <framework/logging/Logger.h>
22 #include <top/dataobjects/TOPDigit.h>
23 #include <top/dataobjects/TOPRawDigit.h>
24 #include <top/dbobjects/TOPSampleTimes.h>
30 #include <TMatrixDSym.h>
58 setDescription(
"Sample time calibrator");
62 addParam(
"moduleID", m_moduleID,
"slot ID to calibrate.");
63 addParam(
"minTimeDiff", m_minTimeDiff,
64 "lower bound on time difference [samples].", 0.0);
65 addParam(
"maxTimeDiff", m_maxTimeDiff,
66 "upper bound on time difference [samples].", 100.0);
67 addParam(
"directoryName", m_directoryName,
68 "name (with path) of the directory for the output root files.",
70 addParam(
"minHits", m_minHits,
71 "minimal required hits per channel.", (
unsigned) 1000);
72 addParam(
"numIterations", m_numIterations,
73 "number of iTBC iterations", (
unsigned) 100);
74 addParam(
"numConvIter", m_conv_iter,
75 "Max number of iTBC iterations for conversion.", (
unsigned) 50);
76 addParam(
"minChi2Change", m_dchi2_min,
77 "Minimal of chi2 change in iterations.", 0.2);
78 addParam(
"dtMin", m_dt_min,
79 "minimum Delta T of raw calpulse in iTBC", 20.0);
80 addParam(
"dtMax", m_dt_max,
81 "maximum Delta T of raw calpulse in iTBC", 24.0);
82 addParam(
"xStep", m_xstep,
83 "unit for an interation of delta(X_s)", 0.020);
84 addParam(
"devStep", m_dev_step,
85 "a step size to calculate the value of d(chisq)/dxval", 0.001);
86 addParam(
"chgStep", m_change_xstep,
87 "update m_xstep if m_dchi2dxv < m_change_step", 0.015);
88 addParam(
"newStep", m_new_xstep,
89 "a new step for delta(X_s) if m_dchi2dxv < m_change_step", 2.0 * m_xstep);
90 addParam(
"sigm2_exp", m_sigm2_exp,
91 "(sigma_0(dT))**2 for nomarlization of chisq = sum{dT^2/sigma^2}", 0.0424 * 0.0424);
93 addParam(
"method", m_method,
"method: 0 - profile histograms only, "
94 "1 - matrix inversion, 2 - iterative, "
95 "3 - matrix inversion w/ singular value decomposition.", (
unsigned) 1);
96 addParam(
"useFallingEdge", m_useFallingEdge,
97 "if true, use cal pulse falling edge instead of rising edge",
false);
101 TOPTimeBaseCalibratorModule::~TOPTimeBaseCalibratorModule()
105 void TOPTimeBaseCalibratorModule::initialize()
109 m_digits.isRequired();
112 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
113 if (!geo->isModuleIDValid(m_moduleID))
114 B2ERROR(
"Invalid module ID: " << m_moduleID);
117 if (m_directoryName.empty()) m_directoryName =
"./";
118 if (m_directoryName !=
"./") gSystem->mkdir(m_directoryName.c_str(), kTRUE);
121 m_syncTimeBase = geo->getNominalTDC().getSyncTimeBase();
124 m_goodHits = TH2F(
"goodHits",
"pulse height vs. pulse width of all good hits",
125 100, 0, 10, 100, 0, 2000);
126 m_goodHits.SetXTitle(
"pulse width (FWHM) [ns]");
127 m_goodHits.SetYTitle(
"pulse height [ADC counts]");
128 m_calPulseFirst = TH2F(
"calPulseFirst",
129 "pulse height vs. pulse width of the first calibration pulse",
130 100, 0, 10, 100, 0, 2000);
131 m_calPulseFirst.SetXTitle(
"pulse width (FWHM) [ns]");
132 m_calPulseFirst.SetYTitle(
"pulse height [ADC counts]");
133 m_calPulseSecond = TH2F(
"calPulseSecond",
134 "pulse height vs. pulse width of the second calibration pulse",
135 100, 0, 10, 100, 0, 2000);
136 m_calPulseSecond.SetXTitle(
"pulse width (FWHM) [ns]");
137 m_calPulseSecond.SetYTitle(
"pulse height [ADC counts]");
142 void TOPTimeBaseCalibratorModule::beginRun()
146 void TOPTimeBaseCalibratorModule::event()
148 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
149 double sampleWidth = geo->getNominalTDC().getSampleWidth();
151 vector<Hit> hits[c_NumChannels];
153 for (
const auto& digit : m_digits) {
154 if (digit.getModuleID() != m_moduleID)
continue;
155 if (digit.getHitQuality() != TOPDigit::c_Junk) {
156 m_goodHits.Fill(digit.getPulseWidth(), digit.getPulseHeight());
158 if (digit.getHitQuality() != TOPDigit::c_CalPulse)
continue;
159 double rawTime = digit.getRawTime();
160 double errScaleFactor = 1;
161 if (m_useFallingEdge) {
162 const auto* rawDigit = digit.getRelated<
TOPRawDigit>();
164 B2ERROR(
"No relation to TOPRawDigit - can't determine falling edge time error");
169 rawTime += rawDigit->getFWHM();
170 errScaleFactor = rawDigit->getCFDFallingTimeError(1.0) / rawDigit->getCFDLeadingTimeError(1.0);
172 double t = rawTime + digit.getFirstWindow() * c_WindowSize;
174 B2ERROR(
"Got negative sample number - digit ignored");
177 double et = digit.getTimeError() / sampleWidth * errScaleFactor;
179 B2ERROR(
"Time error is not given - digit ignored");
182 unsigned channel = digit.getChannel();
183 if (channel < c_NumChannels) {
184 hits[channel].push_back(
Hit(t, et, digit.getPulseHeight(), digit.getPulseWidth()));
188 for (
unsigned channel = 0; channel < c_NumChannels; channel++) {
189 const auto& channelHits = hits[channel];
190 if (channelHits.size() == 2) {
191 double t0 = channelHits[0].time;
192 double t1 = channelHits[1].time;
193 auto diff = fabs(t0 - t1);
194 if (diff < m_minTimeDiff)
continue;
195 if (diff > m_maxTimeDiff)
continue;
196 double sig0 = channelHits[0].timeErr;
197 double sig1 = channelHits[1].timeErr;
198 double sigma = sqrt(sig0 * sig0 + sig1 * sig1);
199 m_ntuples[channel].push_back(
TwoTimes(t0, t1, sigma));
201 m_calPulseFirst.Fill(channelHits[0].pulseWidth, channelHits[0].pulseHeight);
202 m_calPulseSecond.Fill(channelHits[1].pulseWidth, channelHits[1].pulseHeight);
204 m_calPulseSecond.Fill(channelHits[0].pulseWidth, channelHits[0].pulseHeight);
205 m_calPulseFirst.Fill(channelHits[1].pulseWidth, channelHits[1].pulseHeight);
207 }
else if (channelHits.size() > 2) {
208 B2WARNING(
"More than two cal pulses per channel found - ignored");
215 void TOPTimeBaseCalibratorModule::endRun()
219 void TOPTimeBaseCalibratorModule::terminate()
222 const auto& feMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
224 for (
unsigned bs = 0; bs < c_NumBoardstacks; bs ++) {
228 const auto* feMap = feMapper.getMap(m_moduleID, bs);
230 B2ERROR(
"No front-end map available for slot " << m_moduleID <<
", BS" << bs);
233 unsigned scrodID = feMap->getScrodID();
237 string fileName = m_directoryName +
"/tbcSlot";
238 if (m_moduleID < 10) {
239 fileName +=
"0" + to_string(m_moduleID);
241 fileName += to_string(m_moduleID);
243 fileName +=
"_" + to_string(bs) +
"-scrod" +
244 to_string(scrodID) +
".root";
245 TFile* fout = TFile::Open(fileName.c_str(),
"recreate");
247 B2ERROR(
"Can't open the output file " << fileName);
254 m_calPulseFirst.Write();
255 m_calPulseSecond.Write();
257 B2INFO(
"Fitting time base corrections for SCROD " << scrodID
258 <<
", output file: " << fileName);
262 TH1F Hchan(
"channels",
"channels with cal pulse",
263 c_NumScrodChannels, 0, c_NumScrodChannels);
264 Hchan.SetXTitle(
"channel number");
265 Hchan.SetYTitle(
"double cal pulse counts");
266 TH1F Hsuccess(
"success",
"successfuly fitted channels",
267 c_NumScrodChannels, 0, c_NumScrodChannels);
268 Hsuccess.SetXTitle(
"channel number");
269 TH1F Hchi2(
"chi2",
"normalized chi2",
270 c_NumScrodChannels, 0, c_NumScrodChannels);
271 Hchi2.SetXTitle(
"channel number");
272 Hchi2.SetYTitle(
"chi2/ndf");
273 TH1F Hndf(
"ndf",
"degrees of freedom",
274 c_NumScrodChannels, 0, c_NumScrodChannels);
275 Hndf.SetXTitle(
"channel number");
276 Hndf.SetYTitle(
"ndf");
277 TH1F HDeltaT(
"DeltaT",
"Fitted double pulse delay time",
278 c_NumScrodChannels, 0, c_NumScrodChannels);
279 HDeltaT.SetXTitle(
"channel number");
280 HDeltaT.SetYTitle(
"#Delta T [ns]");
284 for (
unsigned chan = 0; chan < c_NumScrodChannels; chan++) {
285 unsigned channel = chan + bs * c_NumScrodChannels;
286 auto& ntuple = m_ntuples[channel];
287 Hchan.SetBinContent(chan + 1, ntuple.size());
288 if (ntuple.size() > m_minHits) {
289 bool ok = calibrateChannel(ntuple, scrodID, chan, Hchi2, Hndf, HDeltaT);
290 if (ok) Hsuccess.Fill(chan);
292 B2INFO(
"... channel " << chan <<
" statistics too low ("
293 << ntuple.size() <<
" double cal pulses)");
310 bool TOPTimeBaseCalibratorModule::calibrateChannel(vector<TwoTimes>& ntuple,
311 unsigned scrodID,
unsigned chan,
312 TH1F& Hchi2, TH1F& Hndf,
318 string name =
"timeDiff_ch" + to_string(chan);
319 string forWhat =
"scrod " + to_string(scrodID) +
" channel " + to_string(chan);
320 string title =
"Cal pulse time difference vs. sample for " + forWhat;
321 TProfile prof(name.c_str(), title.c_str(), c_TimeAxisSize, 0, c_TimeAxisSize,
322 m_minTimeDiff, m_maxTimeDiff,
"S");
323 prof.SetXTitle(
"sample number");
324 prof.SetYTitle(
"time difference [samples]");
326 name =
"sampleOccup_ch" + to_string(chan);
327 title =
"Occupancy for " + forWhat;
328 TH1F hist(name.c_str(), title.c_str(), c_TimeAxisSize, 0, c_TimeAxisSize);
329 hist.SetXTitle(
"sample number");
330 hist.SetYTitle(
"entries per sample");
332 vector<double> profMeans(c_TimeAxisSize, (m_maxTimeDiff + m_minTimeDiff) / 2);
333 double sigma = (m_maxTimeDiff - m_minTimeDiff) / 6;
335 for (
int iter = 0; iter < 5; iter++) {
340 for (
auto& twoTimes : ntuple) {
341 int sample = int(twoTimes.t1) % c_TimeAxisSize;
342 double diff = twoTimes.t2 - twoTimes.t1;
343 double Ddiff = diff - profMeans[sample];
344 if (fabs(Ddiff) < 3 * sigma) {
345 prof.Fill(sample, diff);
350 twoTimes.good =
true;
352 twoTimes.good =
false;
355 for (
int i = 0; i < c_TimeAxisSize; i++) {
356 profMeans[i] = prof.GetBinContent(i + 1);
358 if (n == 0)
return false;
361 sigma = sqrt(x2 - x * x);
368 double meanTimeDifference = 0;
369 for (
auto& x : profMeans) meanTimeDifference += x;
370 meanTimeDifference /= profMeans.size();
371 meanTimeDifference -= int(meanTimeDifference / c_TimeAxisSize) * c_TimeAxisSize;
377 B2INFO(
"... channel " << chan <<
": "
378 << ntuple.size() <<
" double cal pulses)");
381 return matrixInversion(ntuple, scrodID, chan, meanTimeDifference,
382 Hchi2, Hndf, HDeltaT);
384 return iterativeTBC(ntuple, scrodID, chan, meanTimeDifference,
385 Hchi2, Hndf, HDeltaT);
387 B2ERROR(
"Singuler value decomposition not implemented yet");
390 B2ERROR(
"Unknown method " << m_method);
397 bool TOPTimeBaseCalibratorModule::matrixInversion(
const vector<TwoTimes>& ntuple,
398 unsigned scrodID,
unsigned chan,
399 double meanTimeDifference,
400 TH1F& Hchi2, TH1F& Hndf,
406 TMatrixDSym A(c_TimeAxisSize);
407 vector<double> b(c_TimeAxisSize, 0.0);
409 for (
const auto& twoTimes : ntuple) {
410 if (!twoTimes.good)
continue;
412 vector<double> m(c_TimeAxisSize, 0.0);
413 int i1 = int(twoTimes.t1);
414 m[i1 % c_TimeAxisSize] = 1.0 - (twoTimes.t1 - i1);
415 int i2 = int(twoTimes.t2);
416 m[i2 % c_TimeAxisSize] = twoTimes.t2 - i2;
417 i2 = i1 + (i2 - i1) % c_TimeAxisSize;
418 for (
int k = i1 + 1; k < i2; k++) m[k % c_TimeAxisSize] = 1;
420 double relSigma = twoTimes.sigma / meanTimeDifference;
421 double sig2 = relSigma * relSigma;
423 for (
int jj = i1; jj < i2 + 1; jj++) {
424 int j = jj % c_TimeAxisSize;
425 for (
int kk = i1; kk < i2 + 1; kk++) {
426 int k = kk % c_TimeAxisSize;
427 A(j, k) += m[j] * m[k] / sig2;
430 for (
int k = 0; k < c_TimeAxisSize; k++) b[k] += m[k] / sig2;
435 string forWhat =
"scrod " + to_string(scrodID) +
" channel " + to_string(chan);
436 saveAsHistogram(A,
"matA_ch" + to_string(chan),
"Matrix for " + forWhat);
437 saveAsHistogram(b,
"vecB_ch" + to_string(chan),
"Right side for " + forWhat);
444 B2INFO(
"... channel " << chan <<
" failed");
448 vector<double> x(c_TimeAxisSize, 0.0);
449 for (
int k = 0; k < c_TimeAxisSize; k++) {
450 for (
int j = 0; j < c_TimeAxisSize; j++) {
451 x[k] += A(k, j) * b[j];
458 int ndf = -c_TimeAxisSize;
460 for (
const auto& twoTimes : ntuple) {
461 if (!twoTimes.good)
continue;
463 vector<double> m(c_TimeAxisSize, 0.0);
464 int i1 = int(twoTimes.t1);
465 m[i1 % c_TimeAxisSize] = 1.0 - (twoTimes.t1 - i1);
466 int i2 = int(twoTimes.t2);
467 m[i2 % c_TimeAxisSize] = twoTimes.t2 - i2;
468 i2 = i1 + (i2 - i1) % c_TimeAxisSize;
469 for (
int k = i1 + 1; k < i2; k++) m[k % c_TimeAxisSize] = 1;
471 for (
int k = 0; k < c_TimeAxisSize; k++) s += m[k] * x[k];
472 double relSigma = twoTimes.sigma / meanTimeDifference;
473 double sig2 = relSigma * relSigma;
474 chi2 += s * s / sig2;
477 Hchi2.SetBinContent(chan + 1, chi2 / ndf);
478 Hndf.SetBinContent(chan + 1, ndf);
483 for (
auto xi : x) sum += xi;
488 double DeltaT = 2 * m_syncTimeBase / sum;
489 for (
auto& xi : x) xi *= DeltaT;
490 HDeltaT.SetBinContent(chan + 1, DeltaT);
493 for (
int k = 0; k < c_TimeAxisSize; k++) err.push_back(sqrt(A(k, k)) * DeltaT);
495 vector<double> sampleTimes;
496 sampleTimes.push_back(0);
497 for (
auto xi : x) sampleTimes.push_back(xi + sampleTimes.back());
501 saveAsHistogram(A,
"invA_ch" + to_string(chan),
"Inverted matrix for " + forWhat);
502 saveAsHistogram(x, err,
"dt_ch" + to_string(chan),
"Sample time bins for " + forWhat,
503 "sample number",
"#Delta t [ns]");
504 saveAsHistogram(sampleTimes,
"sampleTimes_ch" + to_string(chan),
505 "Time base corrections for " + forWhat,
"sample number",
"t [ns]");
509 string name =
"timeDiffcal_ch" + to_string(chan);
510 string title =
"Calibrated cal pulse time difference vs. sample for " + forWhat;
511 TH2F Hcor(name.c_str(), title.c_str(), c_TimeAxisSize, 0, c_TimeAxisSize,
512 100, DeltaT - 0.5, DeltaT + 0.5);
513 Hcor.SetXTitle(
"sample number");
514 Hcor.SetYTitle(
"time difference [ns]");
515 Hcor.SetStats(kTRUE);
518 timeBase.
setTimeAxis(sampleTimes, sampleTimes.back() / 2);
520 for (
const auto& twoTimes : ntuple) {
521 if (!twoTimes.good)
continue;
522 double dt = timeBase.
getDeltaTime(0, twoTimes.t2, twoTimes.t1);
523 int sample = int(twoTimes.t1) % c_TimeAxisSize;
524 Hcor.Fill(sample, dt);
528 B2INFO(
"... channel " << chan <<
" OK (chi^2/ndf = " << chi2 / ndf
529 <<
", ndf = " << ndf <<
")");
535 bool TOPTimeBaseCalibratorModule::iterativeTBC(
const std::vector<TwoTimes>& ntuple,
536 unsigned scrodID,
unsigned chan,
537 double meanTimeDifference,
538 TH1F& Hchi2, TH1F& Hndf,
541 std::vector<double> xval(c_TimeAxisSize + 1, 0.0);
542 double wx = 2 * m_syncTimeBase / c_TimeAxisSize;
543 for (
int i = 0; i < c_TimeAxisSize + 1; i++) xval[i] = i * wx;
545 B2INFO(
"TimeBaseCalibration starts for channel#" << chan);
547 double pre_chi2 = 10000000.0;
548 unsigned num_small_dev = 0;
550 for (
unsigned j = 0; j < m_numIterations; j++) {
552 Iteration(ntuple, xval);
553 double this_chi2 = Chisq(ntuple, xval);
554 if (this_chi2 < 0)
continue;
555 double deltaChi2 = pre_chi2 - this_chi2;
556 if (deltaChi2 < -m_dchi2_min)
break;
557 if (fabs(deltaChi2) < m_deltamin) num_small_dev++;
558 if (num_small_dev > m_conv_iter)
break;
559 pre_chi2 = this_chi2;
564 double chi2 = Chisq(ntuple, xval);
565 Hchi2.SetBinContent(chan + 1, chi2);
566 Hndf.SetBinContent(chan + 1, m_good);
571 for (
auto xi : xval) sum += xi;
577 double DeltaT = meanTimeDifference * (2 * m_syncTimeBase / c_TimeAxisSize);
578 HDeltaT.SetBinContent(chan + 1, DeltaT);
580 std::vector<double> timeInterval;
581 for (
int i = 0; i < c_TimeAxisSize; i++)timeInterval.push_back(xval[i + 1] - xval[i]);
584 std::vector<double> sampleTimes;
585 for (
auto xi : xval) sampleTimes.push_back(xi);
588 std::string forWhat =
"scrod " + to_string(scrodID) +
" channel " + to_string(chan);
589 saveAsHistogram(timeInterval,
"dt_ch" + to_string(chan),
"Sample time bins for " + forWhat,
590 "sample number",
"#Delta t [ns]");
591 saveAsHistogram(sampleTimes,
"sampleTimes_ch" + to_string(chan),
592 "Time base corrections for " + forWhat,
"sample number",
"t [ns]");
595 std::string name =
"timeDiffcal_ch" + to_string(chan);
596 std::string title =
"Calibrated cal pulse time difference vs. sample for " + forWhat;
597 TH2F Hcor(name.c_str(), title.c_str(), c_TimeAxisSize, 0, c_TimeAxisSize,
598 100, DeltaT - 0.5, DeltaT + 0.5);
599 Hcor.SetXTitle(
"sample number");
600 Hcor.SetYTitle(
"time difference [ns]");
601 Hcor.SetStats(kTRUE);
604 timeBase.
setTimeAxis(sampleTimes, sampleTimes.back() / 2);
606 for (
const auto& twoTimes : ntuple) {
607 if (!twoTimes.good)
continue;
608 double dt = timeBase.
getDeltaTime(0, twoTimes.t2, twoTimes.t1);
609 int sample = int(twoTimes.t1) % c_TimeAxisSize;
610 Hcor.Fill(sample, dt);
614 B2INFO(
"... channel " << chan <<
" OK (chi^2/ndf = " << chi2
615 <<
", ndf = " << m_good <<
")");
620 void TOPTimeBaseCalibratorModule::Iteration(
const std::vector<TwoTimes>& ntuple, std::vector<double>& xval)
622 for (
int i = 0; i < c_TimeAxisSize; i++) {
623 double wdth = xval[i + 1] - xval[i];
624 if (wdth < m_min_binwidth) {
625 xval[i] = xval[i] - 0.5 * fabs(wdth) - 0.5 * m_min_binwidth;
626 xval[i + 1] = xval[i + 1] + 0.5 * fabs(wdth) + 0.5 * m_min_binwidth;
628 if (wdth > m_max_binwidth) {
629 xval[i] = xval[i] - 0.5 * fabs(wdth) - 0.5 * m_max_binwidth;
630 xval[i + 1] = xval[i + 1] + 0.5 * fabs(wdth) + 0.5 * m_max_binwidth;
635 for (
int i = 0; i < c_TimeAxisSize; i++) xval[i] = xval[i] - xval[0];
637 std::vector<double> xxval(c_TimeAxisSize + 1, 0.0);
638 for (
int i = 0; i < c_TimeAxisSize + 1; i++) xxval[i] = xval[i];
640 double chi2_0 = Chisq(ntuple, xxval);
641 if (chi2_0 < 0) B2ERROR(
"iTBC chisq_0<0! xval has problem.");
643 std::vector<double> dr_chi2(c_TimeAxisSize + 1, 0.0);
644 TH1D hdrsamp_try(
"hdrsamp_try",
"dchi2/dx distribution", 100, -0.01, 0.01);
646 for (
int smp = 1; smp < c_TimeAxisSize; smp++) {
647 xxval[smp] = xval[smp] + m_dev_step;
648 double chi2_ch = Chisq(ntuple, xxval);
649 if (chi2_ch < 0)
continue;
650 dr_chi2[smp] = (chi2_ch - chi2_0) / m_dev_step;
651 hdrsamp_try.Fill(dr_chi2[smp]);
652 xxval[smp] = xval[smp];
655 for (
int smp = 1; smp < c_TimeAxisSize; smp++) {
656 double vx_it_step = dr_chi2[smp] * m_xstep;
657 xval[smp] = xval[smp] - vx_it_step;
661 m_dchi2dxv = hdrsamp_try.GetRMS();
663 if (fabs(m_dchi2dxv) < m_change_xstep) m_xstep = m_new_xstep;
666 double TOPTimeBaseCalibratorModule::Chisq(
const std::vector<TwoTimes>& ntuple,
const std::vector<double>& xxval)
673 for (
const auto& twoTimes : ntuple) {
674 if (!twoTimes.good)
continue;
676 std::vector<double> m(c_TimeAxisSize, 0.0);
678 int i1 = int(twoTimes.t1);
679 double fr = twoTimes.t1 - i1;
680 double samp0 = i1 % 256;
681 double ctdc1 = xxval[samp0] + fr * (xxval[samp0 + 1] - xxval[samp0]);
682 int i2 = int(twoTimes.t2);
683 fr = twoTimes.t2 - i2;
684 double samp1 = i2 % 256;
685 double ctdc2 = xxval[samp1] + fr * (xxval[samp1 + 1] - xxval[samp1]);
687 if (samp1 > samp0) cdt = ctdc2 - ctdc1;
688 else cdt = ctdc2 - ctdc1 + m_syncTimeBase * 2;
690 if (cdt < m_dt_max && cdt > m_dt_min) {
700 double mean = sum1 / m_good;
701 chi2 = (sum2 - m_good * mean * mean) / m_good / m_sigm2_exp;
708 void TOPTimeBaseCalibratorModule::saveAsHistogram(
const std::vector<double>& vec,
709 const std::string& name,
710 const std::string& title,
711 const std::string& xTitle,
712 const std::string& yTitle)
const
714 if (vec.empty())
return;
716 TH1F h(name.c_str(), title.c_str(), vec.size(), 0, vec.size());
717 h.SetXTitle(xTitle.c_str());
718 h.SetYTitle(yTitle.c_str());
719 if (name.find(
"Fit") != string::npos) h.SetLineColor(2);
721 for (
unsigned i = 0; i < vec.size(); i++) h.SetBinContent(i + 1, vec[i]);
727 void TOPTimeBaseCalibratorModule::saveAsHistogram(
const vector<double>& vec,
728 const vector<double>& err,
731 const string& xTitle,
732 const string& yTitle)
const
734 if (vec.empty())
return;
736 TH1F h(name.c_str(), title.c_str(), vec.size(), 0, vec.size());
737 h.SetXTitle(xTitle.c_str());
738 h.SetYTitle(yTitle.c_str());
740 for (
unsigned i = 0; i < vec.size(); i++) h.SetBinContent(i + 1, vec[i]);
741 for (
unsigned i = 0; i < err.size(); i++) h.SetBinError(i + 1, err[i]);
747 void TOPTimeBaseCalibratorModule::saveAsHistogram(
const TMatrixDSym& M,
749 const string& title)
const
751 int n = M.GetNrows();
752 TH2F h(name.c_str(), title.c_str(), n, 0, n, n, 0, n);
753 h.SetXTitle(
"columns");
756 for (
int j = 0; j < n; j++) {
757 for (
int k = 0; k < n; k++) {
758 h.SetBinContent(j + 1, n - k, M(j, k));