Belle II Software release-09-00-00
ECLWaveformFit.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/* Own header. */
10#include <ecl/modules/eclWaveformFit/ECLWaveformFit.h>
11
12/* ECL headers. */
13#include <ecl/digitization/EclConfiguration.h>
14#include <ecl/digitization/shaperdsp.h>
15
16/* Basf2 headers. */
17#include <framework/core/Environment.h>
18
19/* ROOT headers. */
20#include <TMinuit.h>
21#include <TMatrixD.h>
22#include <TMatrixDSym.h>
23#include <TDecompChol.h>
24
25using namespace Belle2;
26using namespace ECL;
27
28//-----------------------------------------------------------------
29// Register the Modules
30//-----------------------------------------------------------------
31REG_MODULE(ECLWaveformFit);
32//-----------------------------------------------------------------
33// Implementation
34//-----------------------------------------------------------------
35
36extern "C" {
37
38 // Load inverse covariance matrix from the packed form.
39 // @param[in] packed_matrix Packed matrix.
40 void ecl_waveform_fit_load_inverse_covariance(const float* packed_matrix);
41
42 // Multiply vector by the stored inverse covariance matrix.
43 // @param[out] y Result vector.
44 // @param[in] x Vector.
45 void ecl_waveform_fit_multiply_inverse_covariance(double* y, const double* x);
46
47};
48
49
50//anonymous namespace for data objects used by both ECLWaveformFitModule class and fcnPhotonHadron funciton for MINUIT minimization.
51namespace {
52
53 // Number of fit points.
54 const int c_NFitPoints = 31;
55
56 // Number of fit points for vectorized data.
57 const int c_NFitPointsVector = 32;
58
59 //adc data array
60 double fitA[c_NFitPoints];
61
63 const SignalInterpolation2* g_PhotonSignal;
64
66 const SignalInterpolation2* g_HadronSignal;
67
69 double aNoise;
70
71 //Function to minimize in photon template + hadron template fit. (chi2)
72 // cppcheck-suppress constParameter ; TF1 fit functions cannot have const parameters
73 void fcnPhotonHadron(int&, double* grad, double& f, double* p, int)
74 {
75 double df[c_NFitPointsVector];
76 double da[c_NFitPointsVector];
77 const double Ag = p[1], B = p[0], T = p[2], Ah = p[3];
78 double chi2 = 0, gAg = 0, gB = 0, gT = 0, gAh = 0;
79
80 //getting photon and hadron component shapes for set of fit parameters
81 double amplitudeGamma[c_NFitPoints], derivativesGamma[c_NFitPoints];
82 double amplitudeHadron[c_NFitPoints], derivativesHadron[c_NFitPoints];
83 g_PhotonSignal->getShape(T, amplitudeGamma, derivativesGamma);
84 g_HadronSignal->getShape(T, amplitudeHadron, derivativesHadron);
85
86 //computing difference between current fit result and adc data array
87 #pragma omp simd
88 for (int i = 0; i < c_NFitPoints; ++i)
89 df[i] = fitA[i] - (Ag * amplitudeGamma[i] + Ah * amplitudeHadron[i] + B);
90
91 //computing chi2.
92 ecl_waveform_fit_multiply_inverse_covariance(da, df);
93
94 #pragma omp simd reduction(+:chi2) reduction(-:gB,gAg,gT,gAh)
95 for (int i = 0; i < c_NFitPoints; ++i) {
96 chi2 += da[i] * df[i];
97 gB -= da[i];
98 gAg -= da[i] * amplitudeGamma[i];
99 gT -= da[i] * (derivativesGamma[i] * Ag + derivativesHadron[i] * Ah);
100 gAh -= da[i] * amplitudeHadron[i];
101 }
102
103 f = chi2;
104 grad[0] = 2 * gB;
105 grad[1] = 2 * gAg;
106 grad[2] = 2 * gT;
107 grad[3] = 2 * gAh;
108 }
109
110 //Function to minimize in photon template + hadron template + background photon fit. (chi2)
111 // cppcheck-suppress constParameter ; TF1 fit functions cannot have const parameters
112 void fcnPhotonHadronBackgroundPhoton(int&, double* grad, double& f, double* p, int)
113 {
114 double df[c_NFitPointsVector];
115 double da[c_NFitPointsVector];
116 const double A2 = p[4], T2 = p[5];
117 const double Ag = p[1], B = p[0], T = p[2], Ah = p[3];
118 double chi2 = 0, gA2 = 0, gT2 = 0;
119 double gAg = 0, gB = 0, gT = 0, gAh = 0;
120
121 //getting photon and hadron component shapes for set of fit parameters
122 double amplitudeGamma[c_NFitPoints], derivativesGamma[c_NFitPoints];
123 double amplitudeGamma2[c_NFitPoints], derivativesGamma2[c_NFitPoints];
124 double amplitudeHadron[c_NFitPoints], derivativesHadron[c_NFitPoints];
125 g_PhotonSignal->getShape(T, amplitudeGamma, derivativesGamma);
126 // Background photon.
127 g_PhotonSignal->getShape(T2, amplitudeGamma2, derivativesGamma2);
128 g_HadronSignal->getShape(T, amplitudeHadron, derivativesHadron);
129
130 //computing difference between current fit result and adc data array
131 #pragma omp simd
132 for (int i = 0; i < c_NFitPoints; ++i) {
133 df[i] = fitA[i] - (Ag * amplitudeGamma[i] + Ah * amplitudeHadron[i]
134 + A2 * amplitudeGamma2[i] + B);
135 }
136
137 //computing chi2.
138 ecl_waveform_fit_multiply_inverse_covariance(da, df);
139
140 #pragma omp simd reduction(+:chi2) reduction(-:gB,gAg,gT,gAh,gA2,gT2)
141 for (int i = 0; i < c_NFitPoints; ++i) {
142 chi2 += da[i] * df[i];
143 gB -= da[i];
144 gAg -= da[i] * amplitudeGamma[i];
145 gAh -= da[i] * amplitudeHadron[i];
146 gT -= da[i] * (derivativesGamma[i] * Ag + derivativesHadron[i] * Ah);
147
148 gA2 -= da[i] * amplitudeGamma2[i];
149 gT2 -= da[i] * derivativesGamma2[i] * A2;
150 }
151 f = chi2;
152 grad[0] = 2 * gB;
153 grad[1] = 2 * gAg;
154 grad[2] = 2 * gT;
155 grad[3] = 2 * gAh;
156 grad[4] = 2 * gA2;
157 grad[5] = 2 * gT2;
158 }
159
160 // regularize autocovariance function by multipling it by the step
161 // function so elements above u0 become 0 and below are untouched.
162 void regularize(double* dst, const double* src, const int n, const double u0 = 13.0, const double u1 = 0.8)
163 {
164 for (int k = 0; k < n; k++) dst[k] = src[k] / (1 + exp((k - u0) / u1));
165 }
166
167 // transform autocovariance function of c_NFitPoints elements to the covariance matrix
168 bool makecovariance(CovariancePacked& M, const int nnoise, const double* acov)
169 {
170 TMatrixDSym E(c_NFitPoints);
171 for (int i = 0; i < c_NFitPoints; i++)
172 for (int j = 0; j < i + 1; j++)
173 if (i - j < nnoise) E(i, j) = E(j, i) = acov[i - j];
174
175 TDecompChol dc(E);
176 const bool status = dc.Invert(E);
177
178 if (status) {
179 int count = 0;
180 for (int i = 0; i < c_NFitPoints; i++)
181 for (int j = 0; j < i + 1; j++)
182 M[count++] = E(i, j);
183 M.sigma = sqrtf(acov[0]);
184 }
185 return status;
186 }
187
188}
189
191{
192 /* Set module properties. */
193 setDescription("Module to fit offline waveforms and measure hadron scintillation component light output.");
195 addParam("EnergyThreshold", m_EnergyThreshold,
196 "Energy threshold of online fit result for Fitting Waveforms (GeV).",
197 0.03);
198 addParam("Chi2Threshold25dof", m_Chi2Threshold25dof,
199 "Chi2 threshold (25 dof) to classify offline fit as good fit.",
200 57.1);
201 addParam("Chi2Threshold27dof", m_Chi2Threshold27dof,
202 "Chi2 threshold (27 dof) to classify offline fit as good fit.",
203 60.0);
204 addParam("CovarianceMatrix", m_CovarianceMatrix,
205 "Option to use crystal-dependent covariance matrices (false uses identity matrix).",
206 true);
207}
208
210{
211}
212
214{
215
216 m_TemplatesLoaded = true;
217
218 if (m_IsMCFlag == 0) {
219 //load data templates
220 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
221 for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++) {
222 for (int j = 0; j < 11; j++) {
223 Ptemp[j] = (double)m_WaveformParameters->getPhotonParameters(i + 1)[j];
224 Htemp[j] = (double)m_WaveformParameters->getHadronParameters(i + 1)[j];
225 Dtemp[j] = (double)m_WaveformParameters->getDiodeParameters(i + 1)[j];
226 }
230 }
231 } else {
232 //load mc template
233 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
234 for (int j = 0; j < 11; j++) {
235 Ptemp[j] = (double)m_WaveformParametersForMC->getPhotonParameters()[j];
236 Htemp[j] = (double)m_WaveformParametersForMC->getHadronParameters()[j];
237 Dtemp[j] = (double)m_WaveformParametersForMC->getDiodeParameters()[j];
238 }
242 }
243}
244
246{
247
249 m_TemplatesLoaded = false;
250
252 if (m_CrystalElectronics.isValid()) {
253 for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++)
254 m_ADCtoEnergy[i] = m_CrystalElectronics->getCalibVector()[i];
255 }
256 if (m_CrystalEnergy.isValid()) {
257 for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++)
258 m_ADCtoEnergy[i] *= m_CrystalEnergy->getCalibVector()[i];
259 }
260
261 /* Load covariance matrices from database. */
262 if (m_CovarianceMatrix) {
263 for (int id = 1; id <= ECLElementNumbers::c_NCrystals; id++) {
264 double buf[c_NFitPoints];
265 double reg[c_NFitPoints];
266 m_AutoCovariance->getAutoCovariance(id, buf);
267 double x0 = c_NFitPoints;
268 std::memcpy(reg, buf, c_NFitPoints * sizeof(double));
269 while (!makecovariance(m_PackedCovariance[id - 1], c_NFitPoints, reg))
270 regularize(buf, reg, c_NFitPoints, x0 -= 1, 1);
271 }
272 } else {
273 /* Default covariance matrix is identity for all crystals. */
274 double defaultCovariance[c_NFitPoints][c_NFitPoints];
275 CovariancePacked packedDefaultCovariance;
276 const double isigma = 1 / 7.5;
277 for (int i = 0; i < c_NFitPoints; ++i) {
278 for (int j = 0; j < c_NFitPoints; ++j) {
279 defaultCovariance[i][j] = (i == j) * isigma * isigma;
280 }
281 }
282 int k = 0;
283 for (int i = 0; i < c_NFitPoints; i++) {
284 for (int j = 0; j < i + 1; j++) {
285 packedDefaultCovariance.m_covMatPacked[k] = defaultCovariance[i][j];
286 k++;
287 }
288 }
289 ecl_waveform_fit_load_inverse_covariance(
290 packedDefaultCovariance.m_covMatPacked);
291 }
292
293}
294
296{
297 // ECL dataobjects
298 m_eclDSPs.registerInDataStore();
299 m_eclDigits.registerInDataStore();
300
301 //initializing fit minimizer
302 m_MinuitPhotonHadron = new TMinuit(4);
303 m_MinuitPhotonHadron->SetFCN(fcnPhotonHadron);
304 double arglist[10];
305 int ierflg = 0;
306 arglist[0] = -1;
307 m_MinuitPhotonHadron->mnexcm("SET PRIntout", arglist, 1, ierflg);
308 m_MinuitPhotonHadron->mnexcm("SET NOWarnings", arglist, 0, ierflg);
309 arglist[0] = 1;
310 m_MinuitPhotonHadron->mnexcm("SET ERR", arglist, 1, ierflg);
311 arglist[0] = 0;
312 m_MinuitPhotonHadron->mnexcm("SET STRategy", arglist, 1, ierflg);
313 arglist[0] = 1;
314 m_MinuitPhotonHadron->mnexcm("SET GRAdient", arglist, 1, ierflg);
315 arglist[0] = 1e-6;
316 m_MinuitPhotonHadron->mnexcm("SET EPSmachine", arglist, 1, ierflg);
317
318 //initializing fit minimizer photon+hadron + background photon
320 m_MinuitPhotonHadronBackgroundPhoton->SetFCN(fcnPhotonHadronBackgroundPhoton);
321 arglist[0] = -1;
322 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET PRIntout", arglist, 1, ierflg);
323 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET NOWarnings", arglist, 0, ierflg);
324 arglist[0] = 1;
325 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET ERR", arglist, 1, ierflg);
326 arglist[0] = 0;
327 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET STRategy", arglist, 1, ierflg);
328 arglist[0] = 1;
329 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET GRAdient", arglist, 1, ierflg);
330 arglist[0] = 1e-6;
331 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET EPSmachine", arglist, 1, ierflg);
332
333 //flag for callback to load templates each run
334 m_TemplatesLoaded = false;
335}
336
338{
340
341 if (!m_TemplatesLoaded) {
342 /* Load templates once per run in first event that has saved waveforms. */
343 if (m_eclDSPs.getEntries() > 0)
345 }
346
347 for (ECLDsp& aECLDsp : m_eclDSPs) {
348
349 aECLDsp.setTwoComponentTotalAmp(-1);
350 aECLDsp.setTwoComponentHadronAmp(-1);
351 aECLDsp.setTwoComponentDiodeAmp(-1);
352 aECLDsp.setTwoComponentChi2(-1);
353 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, -1);
354 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton, -1);
355 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, -1);
356 aECLDsp.setTwoComponentTime(-1);
357 aECLDsp.setTwoComponentBaseline(-1);
358 aECLDsp.setTwoComponentFitType(ECLDsp::poorChi2);
359
360 const int id = aECLDsp.getCellId() - 1;
361
362 // Filling array with ADC values.
363 for (int j = 0; j < ec.m_nsmp; j++)
364 fitA[j] = aECLDsp.getDspA()[j];
365
366 //setting relation of eclDSP to aECLDigit
367 const ECLDigit* d = nullptr;
368 for (const ECLDigit& aECLDigit : m_eclDigits) {
369 if (aECLDigit.getCellId() - 1 == id) {
370 d = &aECLDigit;
371 aECLDsp.addRelationTo(&aECLDigit);
372 break;
373 }
374 }
375 if (d == nullptr)
376 continue;
377
378 //Skipping low amplitude waveforms
379 if (d->getAmp() * m_ADCtoEnergy[id] < m_EnergyThreshold)
380 continue;
381
382 //loading template for waveform
383 if (m_IsMCFlag == 0) {
384 //data cell id dependent
385 g_PhotonSignal = &m_SignalInterpolation[id][0];
386 g_HadronSignal = &m_SignalInterpolation[id][1];
387 } else {
388 // mc uses same waveform
389 g_PhotonSignal = &m_SignalInterpolation[0][0];
390 g_HadronSignal = &m_SignalInterpolation[0][1];
391 }
392
393 //get covariance matrix for cell id
394 if (m_CovarianceMatrix) {
395 ecl_waveform_fit_load_inverse_covariance(
396 m_PackedCovariance[id].m_covMatPacked);
397 aNoise = m_PackedCovariance[id].sigma;
398 }
399
400 /* Fit with photon and hadron templates (fit type = 0). */
401 double pedestal, amplitudePhoton, signalTime, amplitudeHadron,
402 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2;
404 chi2 = -1;
405 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
406 chi2);
407 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, chi2);
408
409 /* If failed, try photon, hadron, and background photon (fit type = 1). */
410 if (chi2 >= m_Chi2Threshold27dof) {
411
413 chi2 = -1;
415 pedestal, amplitudePhoton, signalTime, amplitudeHadron,
416 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2);
417 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton,
418 chi2);
419
420 /* If failed, try diode fit (fit type = 2). */
421 if (chi2 >= m_Chi2Threshold25dof) {
422 /* Set second component to diode. */
423 g_HadronSignal = &m_SignalInterpolation[0][2];
425 chi2 = -1;
426 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
427 chi2);
428 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, chi2);
429
430 /* Indicates that all fits tried had bad chi^2. */
431 if (chi2 >= m_Chi2Threshold27dof)
432 fitType = ECLDsp::poorChi2;
433 }
434
435 }
436
437 /* Storing fit results. */
438 aECLDsp.setTwoComponentTotalAmp(amplitudePhoton + amplitudeHadron);
439 if (fitType == ECLDsp::photonDiodeCrossing) {
440 aECLDsp.setTwoComponentHadronAmp(0.0);
441 aECLDsp.setTwoComponentDiodeAmp(amplitudeHadron);
442 } else {
443 aECLDsp.setTwoComponentHadronAmp(amplitudeHadron);
444 aECLDsp.setTwoComponentDiodeAmp(0.0);
445 }
446 aECLDsp.setTwoComponentChi2(chi2);
447 aECLDsp.setTwoComponentTime(signalTime);
448 aECLDsp.setTwoComponentBaseline(pedestal);
449 aECLDsp.setTwoComponentFitType(fitType);
451 aECLDsp.setBackgroundPhotonEnergy(amplitudeBackgroundPhoton);
452 aECLDsp.setBackgroundPhotonTime(timeBackgroundPhoton);
453 }
454 }
455}
456
458{
459}
460
462{
463}
464
466 double& pedestal, double& amplitudePhoton, double& signalTime,
467 double& amplitudeHadron, double& chi2)
468{
469 //minuit parameters
470 double arglist[10] = {0};
471 int ierflg = 0;
472
473 /* Setting inital fit parameters. */
474 double dt = 0.5;
475 double amax = 0;
476 int jmax = 6;
477 for (int j = 0; j < c_NFitPoints; j++) {
478 if (amax < fitA[j]) {
479 amax = fitA[j];
480 jmax = j;
481 }
482 }
483 double sumB0 = 0;
484 int jsum = 0;
485 for (int j = 0; j < c_NFitPoints; j++) {
486 if (j < jmax - 3 || jmax + 4 < j) {
487 sumB0 += fitA[j];
488 ++jsum;
489 }
490 }
491 double B0 = sumB0 / jsum;
492 amax -= B0;
493 if (amax < 0)
494 amax = 10;
495 double T0 = dt * (4.5 - jmax);
496 double A0 = amax;
497
498 //initalize minimizer
499 m_MinuitPhotonHadron->mnparm(0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
500 m_MinuitPhotonHadron->mnparm(1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
501 m_MinuitPhotonHadron->mnparm(2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
502 m_MinuitPhotonHadron->mnparm(3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
503
504 //perform fit
505 arglist[0] = 50000;
506 arglist[1] = 1.;
507 m_MinuitPhotonHadron->mnexcm("MIGRAD", arglist, 2, ierflg);
508
509 double edm, errdef;
510 int nvpar, nparx, icstat;
511 m_MinuitPhotonHadron->mnstat(chi2, edm, errdef, nvpar, nparx, icstat);
512
513 //get fit results
514 double error;
515 m_MinuitPhotonHadron->GetParameter(0, pedestal, error);
516 m_MinuitPhotonHadron->GetParameter(1, amplitudePhoton, error);
517 m_MinuitPhotonHadron->GetParameter(2, signalTime, error);
518 m_MinuitPhotonHadron->GetParameter(3, amplitudeHadron, error);
519}
520
522 double& pedestal, double& amplitudePhoton, double& signalTime,
523 double& amplitudeHadron, double& amplitudeBackgroundPhoton,
524 double& timeBackgroundPhoton, double& chi2)
525{
526 double arglist[10] = {0};
527 int ierflg = 0;
528 double dt = 0.5;
529 double amax = 0; int jmax = 6;
530 for (int j = 0; j < c_NFitPoints; j++) {
531 if (amax < fitA[j]) {
532 amax = fitA[j];
533 jmax = j;
534 }
535 }
536
537 double amax1 = 0; int jmax1 = 6;
538 for (int j = 0; j < c_NFitPoints; j++) {
539 if (j < jmax - 3 || jmax + 4 < j) {
540 if (j == 0) {
541 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) {
542 amax1 = fitA[j];
543 jmax1 = j;
544 }
545 } else if (j == 30) {
546 if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) {
547 amax1 = fitA[j];
548 jmax1 = j;
549 }
550 } else {
551 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) {
552 amax1 = fitA[j];
553 jmax1 = j;
554 }
555 }
556 }
557 }
558
559 double sumB0 = 0;
560 int jsum = 0;
561 for (int j = 0; j < c_NFitPoints; j++) {
562 if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) {
563 sumB0 += fitA[j];
564 ++jsum;
565 }
566 }
567 double B0 = sumB0 / jsum;
568 amax -= B0;
569 amax = std::max(10.0, amax);
570 amax1 -= B0;
571 amax1 = std::max(10.0, amax1);
572 double T0 = dt * (4.5 - jmax);
573 double T01 = dt * (4.5 - jmax1);
574
575 double A0 = amax, A01 = amax1;
577 0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
579 1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
581 2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
583 3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
585 4, "A2", A01, A01 / 20, 0, 2 * A01, ierflg);
587 5, "T2", T01, 0.5, T01 - 2.5, T01 + 2.5, ierflg);
588
589 // Now ready for minimization step
590 arglist[0] = 50000;
591 arglist[1] = 1.;
592 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("MIGRAD", arglist, 2, ierflg);
593
594 double edm, errdef;
595 int nvpar, nparx, icstat;
596 m_MinuitPhotonHadronBackgroundPhoton->mnstat(chi2, edm, errdef, nvpar, nparx, icstat);
597 double error;
598 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(0, pedestal, error);
599 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(1, amplitudePhoton, error);
600 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(2, signalTime, error);
601 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(3, amplitudeHadron, error);
603 4, amplitudeBackgroundPhoton, error);
605 5, timeBackgroundPhoton, error);
606}
607
609{
610 double T0 = -0.2;
611 std::vector<double> p(s.begin() + 1, s.end());
612 p[1] = std::max(0.0029, p[1]);
613 p[4] = std::max(0.0029, p[4]);
614
615 ShaperDSP_t dsp(p, s[0]);
616 dsp.settimestride(c_dtn);
617 dsp.settimeseed(T0);
618 dd_t t[(c_nt + c_ntail)*c_ndt];
619 dsp.fillarray(sizeof(t) / sizeof(t[0]), t);
620
621 for (int i = 0; i < c_nt * c_ndt; i++) {
622 m_FunctionInterpolation[i] = t[i].first;
623 m_DerivativeInterpolation[i] = t[i].second;
624 }
625 for (int i = 0; i < c_ntail; i++) {
626 int j = c_nt * c_ndt + i;
627 int k = c_nt * c_ndt + i * c_ndt;
628 m_FunctionInterpolation[j] = t[k].first;
629 m_DerivativeInterpolation[j] = t[k].second;
630 }
631 int i1 = c_nt * c_ndt + c_ntail - 2;
632 int i2 = c_nt * c_ndt + c_ntail - 1;
635}
636
638 double t0, double* function, double* derivatives) const
639{
640 /* If before pulse start time (negative times), return 0. */
641 int k = 0;
642 while (t0 < 0) {
643 function[k] = 0;
644 derivatives[k] = 0;
645 t0 += c_dt;
646 ++k;
647 if (k >= c_NFitPoints)
648 return;
649 }
650
651 /* Function and derivative values. */
652 double function0[c_NFitPoints], function1[c_NFitPoints];
653 double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
654
655 /* Interpolate first c_nt points (short time steps). */
656 double x = t0 * c_idtn;
657 double ix = floor(x);
658 double w = x - ix;
659 int j = ix;
660 double w2 = w * w;
661 double hw2 = 0.5 * w2;
662 double tw3 = ((1. / 6) * w) * w2;
663
664 /* Number of interpolation points. */
665 int iMax = k + c_nt;
666 if (iMax > c_NFitPoints)
667 iMax = c_NFitPoints;
668
669 /* Fill interpolation points. */
670 for (int i = k; i < iMax; ++i) {
671 function0[i] = m_FunctionInterpolation[j];
672 function1[i] = m_FunctionInterpolation[j + 1];
673 derivative0[i] = m_DerivativeInterpolation[j];
674 derivative1[i] = m_DerivativeInterpolation[j + 1];
675 j = j + c_ndt;
676 }
677
678 /* Interpolation. */
679 #pragma omp simd
680 for (int i = k; i < iMax; ++i) {
681 double a[4];
682 double dfdt = (function1[i] - function0[i]) * c_idtn;
683 double fp = derivative1[i] + derivative0[i];
684 a[0] = function0[i];
685 a[1] = derivative0[i];
686 a[2] = -((fp + derivative0[i]) - 3 * dfdt);
687 a[3] = fp - 2 * dfdt;
688 double b2 = 2 * a[2];
689 double b3 = 6 * a[3];
690 function[i] = a[0] + c_dtn * (a[1] * w + b2 * hw2 + b3 * tw3);
691 derivatives[i] = a[1] + b2 * w + b3 * hw2;
692 }
693 t0 = t0 + c_dt * c_nt;
694 if (iMax == c_NFitPoints)
695 return;
696 k = iMax;
697
698 /* Interpolate next c_ntail points (long time steps). */
699 x = t0 * c_idt;
700 ix = floor(x);
701 w = x - ix;
702 w2 = w * w;
703 hw2 = 0.5 * w2;
704 tw3 = ((1. / 6) * w) * w2;
705
706 /* Number of interpolation points. */
707 iMax = k + c_ntail - 1;
708 if (iMax > c_NFitPoints)
709 iMax = c_NFitPoints;
710
711 /* Interpolation. */
712 #pragma omp simd
713 for (int i = k; i < iMax; ++i) {
714 j = c_nt * c_ndt + i - k;
715 /*
716 * The interpolation step is the same as the distance between
717 * the fit points. It is possible to load the values in the interpolation
718 * loop while keeping its vectorization.
719 */
720 double f0 = m_FunctionInterpolation[j];
721 double f1 = m_FunctionInterpolation[j + 1];
722 double fp0 = m_DerivativeInterpolation[j];
723 double fp1 = m_DerivativeInterpolation[j + 1];
724 double a[4];
725 double dfdt = (f1 - f0) * c_idt;
726 double fp = fp1 + fp0;
727 a[0] = f0;
728 a[1] = fp0;
729 a[2] = -((fp + fp0) - 3 * dfdt);
730 a[3] = fp - 2 * dfdt;
731 double b2 = 2 * a[2];
732 double b3 = 6 * a[3];
733 function[i] = a[0] + c_dt * (a[1] * w + b2 * hw2 + b3 * tw3);
734 derivatives[i] = a[1] + b2 * w + b3 * hw2;
735 }
736 if (iMax == c_NFitPoints)
737 return;
738 k = iMax;
739
740 /* Exponential tail. */
741 while (k < c_NFitPoints) {
742 function[k] = function[k - 1] * m_r0;
743 derivatives[k] = derivatives[k - 1] * m_r1;
744 ++k;
745 }
746}
R E
internal precision of FFTW codelets
Class to store ECL digitized hits (output of ECLDigi) relation to ECLHit filled in ecl/modules/eclDig...
Definition: ECLDigit.h:24
Class to store ECL ShaperDSP waveform ADC data.
Definition: ECLDsp.h:25
TwoComponentFitType
Offline two component fit type.
Definition: ECLDsp.h:29
@ photonHadronBackgroundPhoton
photon + hadron template + pile-up photon fit
Definition: ECLDsp.h:32
@ poorChi2
All offline fit attempts were greater than chi2 threshold.
Definition: ECLDsp.h:30
@ photonDiodeCrossing
photon + diode template fit
Definition: ECLDsp.h:33
@ photonHadron
photon + hadron template fit
Definition: ECLDsp.h:31
CovariancePacked m_PackedCovariance[ECLElementNumbers::c_NCrystals]
Packed covariance matrices.
virtual void initialize() override
Initialize variables.
DBObjPtr< ECLDigitWaveformParameters > m_WaveformParameters
Waveform parameters.
TMinuit * m_MinuitPhotonHadron
Minuit minimizer for fit with photon and hadron.
DBObjPtr< ECLAutoCovariance > m_AutoCovariance
Autocovariance.
virtual void event() override
event per event.
virtual void endRun() override
end run.
bool m_IsMCFlag
Flag to indicate if running over data or MC.
void fitPhotonHadronBackgroundPhoton(double &pedestal, double &amplitudePhoton, double &signalTime, double &amplitudeHadron, double &amplitudeBackgroundPhoton, double &timeBackgroundPhoton, double &chi2)
Fit with photon, hadron, and background photon.
StoreArray< ECLDsp > m_eclDSPs
StoreArray ECLDsp.
virtual void terminate() override
terminate.
SignalInterpolation2 m_SignalInterpolation[ECLElementNumbers::c_NCrystals][3]
ShaperDSP signal shapes.
StoreArray< ECLDigit > m_eclDigits
StoreArray ECLDigit.
std::vector< double > m_ADCtoEnergy
Calibration vector from ADC to energy.
void loadTemplateParameterArray()
Loads waveform templates from database.
bool m_CovarianceMatrix
Option to use crystal dependent covariance matrices.
DBObjPtr< ECLCrystalCalib > m_CrystalElectronics
Crystal electronics.
virtual void beginRun() override
begin run.
DBObjPtr< ECLCrystalCalib > m_CrystalEnergy
Crystal energy.
void fitPhotonHadron(double &pedestal, double &amplitudePhoton, double &signalTime, double &amplitudeHadron, double &chi2)
Fit with photon and hadron.
double m_EnergyThreshold
Energy threshold to fit pulse offline.
double m_Chi2Threshold25dof
chi2 threshold (25 dof) to classify offline fit as good fit.
TMinuit * m_MinuitPhotonHadronBackgroundPhoton
Minuit minimizer for fit with photon, hadron, and background photon.
DBObjPtr< ECLDigitWaveformParametersForMC > m_WaveformParametersForMC
Waveform parameters for MC.
bool m_TemplatesLoaded
Flag to indicate if waveform templates are loaded from database.
double m_Chi2Threshold27dof
chi2 threshold (27 dof) to classify offline fit as good fit.
Singleton class to hold the ECL configuration.
static EclConfiguration & get()
return this instance
static constexpr int m_nsmp
number of ADC measurements for signal fitting
Class include function that calculate electronic response from energy deposit
Definition: shaperdsp.h:26
void settimeseed(double)
set initial time
Definition: shaperdsp.cc:371
void settimestride(double)
set grid step for function calculation
Definition: shaperdsp.cc:361
void fillarray(int, double *) const
fill array for amplitude and time calculation
Definition: shaperdsp.cc:381
bool isMC() const
Do we have generated, not real data?
Definition: Environment.cc:54
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:28
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
const int c_NCrystals
Number of crystals.
Abstract base class for different kinds of events.
Struct to keep upper triangle of the covariance matrix.
float m_covMatPacked[31 *(31+1)/2]
Packed matrix.
float sigma
Sigma noise.
Interpolation of signal shape using function values and the first derivative.
double m_r0
Assuming exponential drop of the signal function far away from 0, extrapolate it to +inf.
static constexpr int c_ntail
Number of tail steps.
double m_FunctionInterpolation[c_nt *c_ndt+c_ntail]
Function values.
SignalInterpolation2()
Default constructor.
void getShape(double t0, double *function, double *derivatives) const
Returns signal shape and derivatives in 31 equidistant time points starting from t0.
static constexpr int c_nt
Signal function is sampled in c_nt time steps with c_ndt substeps and c_ntail steps.
static constexpr double c_idt
Inverted time step.
double m_DerivativeInterpolation[c_nt *c_ndt+c_ntail]
Derivative values.
static constexpr double c_idtn
Inverted time substep.
static constexpr double c_dt
Time step.
static constexpr int c_ndt
Number of substeps.
static constexpr double c_dtn
Time substep.