Belle II Software development
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 function 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 multiplying 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.isRequired();
299 m_eclDigits.isRequired();
300 // While we set a relation from ECLDsps to ECLDigits here, the relation
301 // is already register in previous modules: let's require it here
302 m_eclDSPs.registerRelationTo(m_eclDigits);
303
304 //initializing fit minimizer
305 m_MinuitPhotonHadron = new TMinuit(4);
306 m_MinuitPhotonHadron->SetFCN(fcnPhotonHadron);
307 double arglist[10];
308 int ierflg = 0;
309 arglist[0] = -1;
310 m_MinuitPhotonHadron->mnexcm("SET PRIntout", arglist, 1, ierflg);
311 m_MinuitPhotonHadron->mnexcm("SET NOWarnings", arglist, 0, ierflg);
312 arglist[0] = 1;
313 m_MinuitPhotonHadron->mnexcm("SET ERR", arglist, 1, ierflg);
314 arglist[0] = 0;
315 m_MinuitPhotonHadron->mnexcm("SET STRategy", arglist, 1, ierflg);
316 arglist[0] = 1;
317 m_MinuitPhotonHadron->mnexcm("SET GRAdient", arglist, 1, ierflg);
318 arglist[0] = 1e-6;
319 m_MinuitPhotonHadron->mnexcm("SET EPSmachine", arglist, 1, ierflg);
320
321 //initializing fit minimizer photon+hadron + background photon
323 m_MinuitPhotonHadronBackgroundPhoton->SetFCN(fcnPhotonHadronBackgroundPhoton);
324 arglist[0] = -1;
325 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET PRIntout", arglist, 1, ierflg);
326 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET NOWarnings", arglist, 0, ierflg);
327 arglist[0] = 1;
328 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET ERR", arglist, 1, ierflg);
329 arglist[0] = 0;
330 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET STRategy", arglist, 1, ierflg);
331 arglist[0] = 1;
332 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET GRAdient", arglist, 1, ierflg);
333 arglist[0] = 1e-6;
334 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET EPSmachine", arglist, 1, ierflg);
335
336 //flag for callback to load templates each run
337 m_TemplatesLoaded = false;
338}
339
341{
343
344 if (!m_TemplatesLoaded) {
345 /* Load templates once per run in first event that has saved waveforms. */
346 if (m_eclDSPs.getEntries() > 0)
348 }
349
350 for (ECLDsp& aECLDsp : m_eclDSPs) {
351
352 aECLDsp.setTwoComponentTotalAmp(-1);
353 aECLDsp.setTwoComponentHadronAmp(-1);
354 aECLDsp.setTwoComponentDiodeAmp(-1);
355 aECLDsp.setTwoComponentChi2(-1);
356 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, -1);
357 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton, -1);
358 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, -1);
359 aECLDsp.setTwoComponentTime(-1);
360 aECLDsp.setTwoComponentBaseline(-1);
361 aECLDsp.setTwoComponentFitType(ECLDsp::poorChi2);
362
363 const int id = aECLDsp.getCellId() - 1;
364
365 // Filling array with ADC values.
366 for (int j = 0; j < ec.m_nsmp; j++)
367 fitA[j] = aECLDsp.getDspA()[j];
368
369 //setting relation of eclDSP to aECLDigit
370 const ECLDigit* d = nullptr;
371 for (const ECLDigit& aECLDigit : m_eclDigits) {
372 if (aECLDigit.getCellId() - 1 == id) {
373 d = &aECLDigit;
374 aECLDsp.addRelationTo(&aECLDigit);
375 break;
376 }
377 }
378 if (d == nullptr)
379 continue;
380
381 //Skipping low amplitude waveforms
382 if (d->getAmp() * m_ADCtoEnergy[id] < m_EnergyThreshold)
383 continue;
384
385 //loading template for waveform
386 if (m_IsMCFlag == 0) {
387 //data cell id dependent
388 g_PhotonSignal = &m_SignalInterpolation[id][0];
389 g_HadronSignal = &m_SignalInterpolation[id][1];
390 } else {
391 // mc uses same waveform
392 g_PhotonSignal = &m_SignalInterpolation[0][0];
393 g_HadronSignal = &m_SignalInterpolation[0][1];
394 }
395
396 //get covariance matrix for cell id
397 if (m_CovarianceMatrix) {
398 ecl_waveform_fit_load_inverse_covariance(
399 m_PackedCovariance[id].m_covMatPacked);
400 aNoise = m_PackedCovariance[id].sigma;
401 }
402
403 /* Fit with photon and hadron templates (fit type = 0). */
404 double pedestal, amplitudePhoton, signalTime, amplitudeHadron,
405 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2;
407 chi2 = -1;
408 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
409 chi2);
410 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, chi2);
411
412 /* If failed, try photon, hadron, and background photon (fit type = 1). */
413 if (chi2 >= m_Chi2Threshold27dof) {
414
416 chi2 = -1;
418 pedestal, amplitudePhoton, signalTime, amplitudeHadron,
419 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2);
420 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton,
421 chi2);
422
423 /* If failed, try diode fit (fit type = 2). */
424 if (chi2 >= m_Chi2Threshold25dof) {
425 /* Set second component to diode. */
426 g_HadronSignal = &m_SignalInterpolation[0][2];
428 chi2 = -1;
429 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
430 chi2);
431 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, chi2);
432
433 /* Indicates that all fits tried had bad chi^2. */
434 if (chi2 >= m_Chi2Threshold27dof)
435 fitType = ECLDsp::poorChi2;
436 }
437
438 }
439
440 /* Storing fit results. */
441 aECLDsp.setTwoComponentTotalAmp(amplitudePhoton + amplitudeHadron);
442 if (fitType == ECLDsp::photonDiodeCrossing) {
443 aECLDsp.setTwoComponentHadronAmp(0.0);
444 aECLDsp.setTwoComponentDiodeAmp(amplitudeHadron);
445 } else {
446 aECLDsp.setTwoComponentHadronAmp(amplitudeHadron);
447 aECLDsp.setTwoComponentDiodeAmp(0.0);
448 }
449 aECLDsp.setTwoComponentChi2(chi2);
450 aECLDsp.setTwoComponentTime(signalTime);
451 aECLDsp.setTwoComponentBaseline(pedestal);
452 aECLDsp.setTwoComponentFitType(fitType);
454 aECLDsp.setBackgroundPhotonEnergy(amplitudeBackgroundPhoton);
455 aECLDsp.setBackgroundPhotonTime(timeBackgroundPhoton);
456 }
457 }
458}
459
461{
462}
463
465{
466}
467
469 double& pedestal, double& amplitudePhoton, double& signalTime,
470 double& amplitudeHadron, double& chi2)
471{
472 //minuit parameters
473 double arglist[10] = {0};
474 int ierflg = 0;
475
476 /* Setting initial fit parameters. */
477 double dt = 0.5;
478 double amax = 0;
479 int jmax = 6;
480 for (int j = 0; j < c_NFitPoints; j++) {
481 if (amax < fitA[j]) {
482 amax = fitA[j];
483 jmax = j;
484 }
485 }
486 double sumB0 = 0;
487 int jsum = 0;
488 for (int j = 0; j < c_NFitPoints; j++) {
489 if (j < jmax - 3 || jmax + 4 < j) {
490 sumB0 += fitA[j];
491 ++jsum;
492 }
493 }
494 double B0 = sumB0 / jsum;
495 amax -= B0;
496 if (amax < 0)
497 amax = 10;
498 double T0 = dt * (4.5 - jmax);
499 double A0 = amax;
500
501 //initialize minimizer
502 m_MinuitPhotonHadron->mnparm(0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
503 m_MinuitPhotonHadron->mnparm(1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
504 m_MinuitPhotonHadron->mnparm(2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
505 m_MinuitPhotonHadron->mnparm(3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
506
507 //perform fit
508 arglist[0] = 50000;
509 arglist[1] = 1.;
510 m_MinuitPhotonHadron->mnexcm("MIGRAD", arglist, 2, ierflg);
511
512 double edm, errdef;
513 int nvpar, nparx, icstat;
514 m_MinuitPhotonHadron->mnstat(chi2, edm, errdef, nvpar, nparx, icstat);
515
516 //get fit results
517 double error;
518 m_MinuitPhotonHadron->GetParameter(0, pedestal, error);
519 m_MinuitPhotonHadron->GetParameter(1, amplitudePhoton, error);
520 m_MinuitPhotonHadron->GetParameter(2, signalTime, error);
521 m_MinuitPhotonHadron->GetParameter(3, amplitudeHadron, error);
522}
523
525 double& pedestal, double& amplitudePhoton, double& signalTime,
526 double& amplitudeHadron, double& amplitudeBackgroundPhoton,
527 double& timeBackgroundPhoton, double& chi2)
528{
529 double arglist[10] = {0};
530 int ierflg = 0;
531 double dt = 0.5;
532 double amax = 0; int jmax = 6;
533 for (int j = 0; j < c_NFitPoints; j++) {
534 if (amax < fitA[j]) {
535 amax = fitA[j];
536 jmax = j;
537 }
538 }
539
540 double amax1 = 0; int jmax1 = 6;
541 for (int j = 0; j < c_NFitPoints; j++) {
542 if (j < jmax - 3 || jmax + 4 < j) {
543 if (j == 0) {
544 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) {
545 amax1 = fitA[j];
546 jmax1 = j;
547 }
548 } else if (j == 30) {
549 if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) {
550 amax1 = fitA[j];
551 jmax1 = j;
552 }
553 } else {
554 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) {
555 amax1 = fitA[j];
556 jmax1 = j;
557 }
558 }
559 }
560 }
561
562 double sumB0 = 0;
563 int jsum = 0;
564 for (int j = 0; j < c_NFitPoints; j++) {
565 if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) {
566 sumB0 += fitA[j];
567 ++jsum;
568 }
569 }
570 double B0 = sumB0 / jsum;
571 amax -= B0;
572 amax = std::max(10.0, amax);
573 amax1 -= B0;
574 amax1 = std::max(10.0, amax1);
575 double T0 = dt * (4.5 - jmax);
576 double T01 = dt * (4.5 - jmax1);
577
578 double A0 = amax, A01 = amax1;
580 0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
582 1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
584 2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
586 3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
588 4, "A2", A01, A01 / 20, 0, 2 * A01, ierflg);
590 5, "T2", T01, 0.5, T01 - 2.5, T01 + 2.5, ierflg);
591
592 // Now ready for minimization step
593 arglist[0] = 50000;
594 arglist[1] = 1.;
595 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("MIGRAD", arglist, 2, ierflg);
596
597 double edm, errdef;
598 int nvpar, nparx, icstat;
599 m_MinuitPhotonHadronBackgroundPhoton->mnstat(chi2, edm, errdef, nvpar, nparx, icstat);
600 double error;
601 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(0, pedestal, error);
602 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(1, amplitudePhoton, error);
603 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(2, signalTime, error);
604 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(3, amplitudeHadron, error);
606 4, amplitudeBackgroundPhoton, error);
608 5, timeBackgroundPhoton, error);
609}
610
612{
613 double T0 = -0.2;
614 std::vector<double> p(s.begin() + 1, s.end());
615 p[1] = std::max(0.0029, p[1]);
616 p[4] = std::max(0.0029, p[4]);
617
618 ShaperDSP_t dsp(p, s[0]);
619 dsp.settimestride(c_dtn);
620 dsp.settimeseed(T0);
621 dd_t t[(c_nt + c_ntail)*c_ndt];
622 dsp.fillarray(sizeof(t) / sizeof(t[0]), t);
623
624 for (int i = 0; i < c_nt * c_ndt; i++) {
625 m_FunctionInterpolation[i] = t[i].first;
626 m_DerivativeInterpolation[i] = t[i].second;
627 }
628 for (int i = 0; i < c_ntail; i++) {
629 int j = c_nt * c_ndt + i;
630 int k = c_nt * c_ndt + i * c_ndt;
631 m_FunctionInterpolation[j] = t[k].first;
632 m_DerivativeInterpolation[j] = t[k].second;
633 }
634 int i1 = c_nt * c_ndt + c_ntail - 2;
635 int i2 = c_nt * c_ndt + c_ntail - 1;
638}
639
641 double t0, double* function, double* derivatives) const
642{
643 /* If before pulse start time (negative times), return 0. */
644 int k = 0;
645 while (t0 < 0) {
646 function[k] = 0;
647 derivatives[k] = 0;
648 t0 += c_dt;
649 ++k;
650 if (k >= c_NFitPoints)
651 return;
652 }
653
654 /* Function and derivative values. */
655 double function0[c_NFitPoints], function1[c_NFitPoints];
656 double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
657
658 /* Interpolate first c_nt points (short time steps). */
659 double x = t0 * c_idtn;
660 double ix = floor(x);
661 double w = x - ix;
662 int j = ix;
663 double w2 = w * w;
664 double hw2 = 0.5 * w2;
665 double tw3 = ((1. / 6) * w) * w2;
666
667 /* Number of interpolation points. */
668 int iMax = k + c_nt;
669 if (iMax > c_NFitPoints)
670 iMax = c_NFitPoints;
671
672 /* Fill interpolation points. */
673 for (int i = k; i < iMax; ++i) {
674 function0[i] = m_FunctionInterpolation[j];
675 function1[i] = m_FunctionInterpolation[j + 1];
676 derivative0[i] = m_DerivativeInterpolation[j];
677 derivative1[i] = m_DerivativeInterpolation[j + 1];
678 j = j + c_ndt;
679 }
680
681 /* Interpolation. */
682 #pragma omp simd
683 for (int i = k; i < iMax; ++i) {
684 double a[4];
685 double dfdt = (function1[i] - function0[i]) * c_idtn;
686 double fp = derivative1[i] + derivative0[i];
687 a[0] = function0[i];
688 a[1] = derivative0[i];
689 a[2] = -((fp + derivative0[i]) - 3 * dfdt);
690 a[3] = fp - 2 * dfdt;
691 double b2 = 2 * a[2];
692 double b3 = 6 * a[3];
693 function[i] = a[0] + c_dtn * (a[1] * w + b2 * hw2 + b3 * tw3);
694 derivatives[i] = a[1] + b2 * w + b3 * hw2;
695 }
696 t0 = t0 + c_dt * c_nt;
697 if (iMax == c_NFitPoints)
698 return;
699 k = iMax;
700
701 /* Interpolate next c_ntail points (long time steps). */
702 x = t0 * c_idt;
703 ix = floor(x);
704 w = x - ix;
705 w2 = w * w;
706 hw2 = 0.5 * w2;
707 tw3 = ((1. / 6) * w) * w2;
708
709 /* Number of interpolation points. */
710 iMax = k + c_ntail - 1;
711 if (iMax > c_NFitPoints)
712 iMax = c_NFitPoints;
713
714 /* Interpolation. */
715 #pragma omp simd
716 for (int i = k; i < iMax; ++i) {
717 j = c_nt * c_ndt + i - k;
718 /*
719 * The interpolation step is the same as the distance between
720 * the fit points. It is possible to load the values in the interpolation
721 * loop while keeping its vectorization.
722 */
723 double f0 = m_FunctionInterpolation[j];
724 double f1 = m_FunctionInterpolation[j + 1];
725 double fp0 = m_DerivativeInterpolation[j];
726 double fp1 = m_DerivativeInterpolation[j + 1];
727 double a[4];
728 double dfdt = (f1 - f0) * c_idt;
729 double fp = fp1 + fp0;
730 a[0] = f0;
731 a[1] = fp0;
732 a[2] = -((fp + fp0) - 3 * dfdt);
733 a[3] = fp - 2 * dfdt;
734 double b2 = 2 * a[2];
735 double b3 = 6 * a[3];
736 function[i] = a[0] + c_dt * (a[1] * w + b2 * hw2 + b3 * tw3);
737 derivatives[i] = a[1] + b2 * w + b3 * hw2;
738 }
739 if (iMax == c_NFitPoints)
740 return;
741 k = iMax;
742
743 /* Exponential tail. */
744 while (k < c_NFitPoints) {
745 function[k] = function[k - 1] * m_r0;
746 derivatives[k] = derivatives[k - 1] * m_r1;
747 ++k;
748 }
749}
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.