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, double u0, double u1, double u2)
163 {
164 for (int k = 1; k < n; k++) dst[k] = u2 * 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 addParam("RegParam1", m_u1, "u1 parameter for regularization function).", 1.0);
208}
209
211{
212}
213
215{
216
217 m_TemplatesLoaded = true;
218
219 if (m_IsMCFlag == 0) {
220 //load data templates
221 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
222 for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++) {
223 for (int j = 0; j < 11; j++) {
224 Ptemp[j] = (double)m_WaveformParameters->getPhotonParameters(i + 1)[j];
225 Htemp[j] = (double)m_WaveformParameters->getHadronParameters(i + 1)[j];
226 Dtemp[j] = (double)m_WaveformParameters->getDiodeParameters(i + 1)[j];
227 }
231 }
232 } else {
233 //load mc template
234 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
235 for (int j = 0; j < 11; j++) {
236 Ptemp[j] = (double)m_WaveformParametersForMC->getPhotonParameters()[j];
237 Htemp[j] = (double)m_WaveformParametersForMC->getHadronParameters()[j];
238 Dtemp[j] = (double)m_WaveformParametersForMC->getDiodeParameters()[j];
239 }
243 }
244}
245
247{
248
250 m_TemplatesLoaded = false;
251
253 if (m_CrystalElectronics.isValid()) {
254 for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++)
255 m_ADCtoEnergy[i] = m_CrystalElectronics->getCalibVector()[i];
256 }
257 if (m_CrystalEnergy.isValid()) {
258 for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++)
259 m_ADCtoEnergy[i] *= m_CrystalEnergy->getCalibVector()[i];
260 }
261
262 /* Load covariance matrices from database. */
263 if (m_CovarianceMatrix) {
264 for (int id = 1; id <= ECLElementNumbers::c_NCrystals; id++) {
265 double buf[c_NFitPoints];
266 double reg[c_NFitPoints];
267 m_AutoCovariance->getAutoCovariance(id, buf);
268 double x0 = c_NFitPoints;
269 std::memcpy(reg, buf, c_NFitPoints * sizeof(double));
270 bool invertSuccess = makecovariance(m_PackedCovariance[id - 1], c_NFitPoints, reg);
271 double param_u2 = 1.0;
272 int idToLoad = id;
273 while (invertSuccess == false) {
274
275 /* as x0-=1 iterates off-diagonal are suppressed. */
276 regularize(buf, reg, c_NFitPoints, x0 -= 1, m_u1, param_u2);
277 invertSuccess = makecovariance(m_PackedCovariance[id - 1], c_NFitPoints, reg);
278
279 /* set off-diagonals to zero for final attempt*/
280 if (x0 == 1) param_u2 = 0.0;
281
282 /* Indicates problem with matrix as identity should be invertible*/
283 if (x0 == 0) {
284 B2WARNING("Could not invert matrix for id " << id);
285 B2WARNING("Loading neighbour matrix for id " << id);
286 if (idToLoad > 1) {
287 m_AutoCovariance->getAutoCovariance(idToLoad = -1, buf);
288 } else {
289 m_AutoCovariance->getAutoCovariance(idToLoad += 1, buf);
290 }
291 std::memcpy(reg, buf, c_NFitPoints * sizeof(double));
292 }
293
294 }
295 }
296 } else {
297 /* Default covariance matrix is identity for all crystals. */
298 double defaultCovariance[c_NFitPoints][c_NFitPoints];
299 CovariancePacked packedDefaultCovariance;
300 const double isigma = 1 / 7.5;
301 for (int i = 0; i < c_NFitPoints; ++i) {
302 for (int j = 0; j < c_NFitPoints; ++j) {
303 defaultCovariance[i][j] = (i == j) * isigma * isigma;
304 }
305 }
306 int k = 0;
307 for (int i = 0; i < c_NFitPoints; i++) {
308 for (int j = 0; j < i + 1; j++) {
309 packedDefaultCovariance.m_covMatPacked[k] = defaultCovariance[i][j];
310 k++;
311 }
312 }
313 ecl_waveform_fit_load_inverse_covariance(
314 packedDefaultCovariance.m_covMatPacked);
315 }
316
317}
318
320{
321 // ECL dataobjects
322 m_eclDSPs.isRequired();
323 m_eclDigits.isRequired();
324 // While we set a relation from ECLDsps to ECLDigits here, the relation
325 // is already register in previous modules: let's require it here
326 m_eclDSPs.registerRelationTo(m_eclDigits);
327
328 //initializing fit minimizer
329 m_MinuitPhotonHadron = new TMinuit(4);
330 m_MinuitPhotonHadron->SetFCN(fcnPhotonHadron);
331 double arglist[10];
332 int ierflg = 0;
333 arglist[0] = -1;
334 m_MinuitPhotonHadron->mnexcm("SET PRIntout", arglist, 1, ierflg);
335 m_MinuitPhotonHadron->mnexcm("SET NOWarnings", arglist, 0, ierflg);
336 arglist[0] = 1;
337 m_MinuitPhotonHadron->mnexcm("SET ERR", arglist, 1, ierflg);
338 arglist[0] = 0;
339 m_MinuitPhotonHadron->mnexcm("SET STRategy", arglist, 1, ierflg);
340 arglist[0] = 1;
341 m_MinuitPhotonHadron->mnexcm("SET GRAdient", arglist, 1, ierflg);
342 arglist[0] = 1e-6;
343 m_MinuitPhotonHadron->mnexcm("SET EPSmachine", arglist, 1, ierflg);
344
345 //initializing fit minimizer photon+hadron + background photon
347 m_MinuitPhotonHadronBackgroundPhoton->SetFCN(fcnPhotonHadronBackgroundPhoton);
348 arglist[0] = -1;
349 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET PRIntout", arglist, 1, ierflg);
350 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET NOWarnings", arglist, 0, ierflg);
351 arglist[0] = 1;
352 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET ERR", arglist, 1, ierflg);
353 arglist[0] = 0;
354 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET STRategy", arglist, 1, ierflg);
355 arglist[0] = 1;
356 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET GRAdient", arglist, 1, ierflg);
357 arglist[0] = 1e-6;
358 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET EPSmachine", arglist, 1, ierflg);
359
360 //flag for callback to load templates each run
361 m_TemplatesLoaded = false;
362}
363
365{
367
368 if (!m_TemplatesLoaded) {
369 /* Load templates once per run in first event that has saved waveforms. */
370 if (m_eclDSPs.getEntries() > 0)
372 }
373
374 for (ECLDsp& aECLDsp : m_eclDSPs) {
375
376 aECLDsp.setTwoComponentTotalAmp(-1);
377 aECLDsp.setTwoComponentHadronAmp(-1);
378 aECLDsp.setTwoComponentDiodeAmp(-1);
379 aECLDsp.setTwoComponentChi2(-1);
380 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, -1);
381 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton, -1);
382 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, -1);
383 aECLDsp.setTwoComponentTime(-1);
384 aECLDsp.setTwoComponentBaseline(-1);
385 aECLDsp.setTwoComponentFitType(ECLDsp::poorChi2);
386
387 const int id = aECLDsp.getCellId() - 1;
388
389 // Filling array with ADC values.
390 for (int j = 0; j < ec.m_nsmp; j++)
391 fitA[j] = aECLDsp.getDspA()[j];
392
393 //setting relation of eclDSP to aECLDigit
394 const ECLDigit* d = nullptr;
395 for (const ECLDigit& aECLDigit : m_eclDigits) {
396 if (aECLDigit.getCellId() - 1 == id) {
397 d = &aECLDigit;
398 aECLDsp.addRelationTo(&aECLDigit);
399 break;
400 }
401 }
402 if (d == nullptr)
403 continue;
404
405 //Skipping low amplitude waveforms
406 if (d->getAmp() * m_ADCtoEnergy[id] < m_EnergyThreshold)
407 continue;
408
409 //loading template for waveform
410 if (m_IsMCFlag == 0) {
411 //data cell id dependent
412 g_PhotonSignal = &m_SignalInterpolation[id][0];
413 g_HadronSignal = &m_SignalInterpolation[id][1];
414 } else {
415 // mc uses same waveform
416 g_PhotonSignal = &m_SignalInterpolation[0][0];
417 g_HadronSignal = &m_SignalInterpolation[0][1];
418 }
419
420 //get covariance matrix for cell id
421 if (m_CovarianceMatrix) {
422 ecl_waveform_fit_load_inverse_covariance(
423 m_PackedCovariance[id].m_covMatPacked);
424 aNoise = m_PackedCovariance[id].sigma;
425 }
426
427 /* Fit with photon and hadron templates (fit type = 0). */
428 double pedestal, amplitudePhoton, signalTime, amplitudeHadron,
429 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2;
431 chi2 = -1;
432 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
433 chi2);
434 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, chi2);
435
436 /* If failed, try photon, hadron, and background photon (fit type = 1). */
437 if (chi2 >= m_Chi2Threshold27dof) {
438
440 chi2 = -1;
442 pedestal, amplitudePhoton, signalTime, amplitudeHadron,
443 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2);
444 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton,
445 chi2);
446
447 /* If failed, try diode fit (fit type = 2). */
448 if (chi2 >= m_Chi2Threshold25dof) {
449 /* Set second component to diode. */
450 g_HadronSignal = &m_SignalInterpolation[0][2];
452 chi2 = -1;
453 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
454 chi2);
455 aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, chi2);
456
457 /* Indicates that all fits tried had bad chi^2. */
458 if (chi2 >= m_Chi2Threshold27dof)
459 fitType = ECLDsp::poorChi2;
460 }
461
462 }
463
464 /* Storing fit results. */
465 aECLDsp.setTwoComponentTotalAmp(amplitudePhoton + amplitudeHadron);
466 if (fitType == ECLDsp::photonDiodeCrossing) {
467 aECLDsp.setTwoComponentHadronAmp(0.0);
468 aECLDsp.setTwoComponentDiodeAmp(amplitudeHadron);
469 } else {
470 aECLDsp.setTwoComponentHadronAmp(amplitudeHadron);
471 aECLDsp.setTwoComponentDiodeAmp(0.0);
472 }
473 aECLDsp.setTwoComponentChi2(chi2);
474 aECLDsp.setTwoComponentTime(signalTime);
475 aECLDsp.setTwoComponentBaseline(pedestal);
476 aECLDsp.setTwoComponentFitType(fitType);
478 aECLDsp.setBackgroundPhotonEnergy(amplitudeBackgroundPhoton);
479 aECLDsp.setBackgroundPhotonTime(timeBackgroundPhoton);
480 }
481 }
482}
483
485{
486}
487
489{
490}
491
493 double& pedestal, double& amplitudePhoton, double& signalTime,
494 double& amplitudeHadron, double& chi2)
495{
496 //minuit parameters
497 double arglist[10] = {0};
498 int ierflg = 0;
499
500 /* Setting initial fit parameters. */
501 double dt = 0.5;
502 double amax = 0;
503 int jmax = 6;
504 for (int j = 0; j < c_NFitPoints; j++) {
505 if (amax < fitA[j]) {
506 amax = fitA[j];
507 jmax = j;
508 }
509 }
510 double sumB0 = 0;
511 int jsum = 0;
512 for (int j = 0; j < c_NFitPoints; j++) {
513 if (j < jmax - 3 || jmax + 4 < j) {
514 sumB0 += fitA[j];
515 ++jsum;
516 }
517 }
518 double B0 = sumB0 / jsum;
519 amax -= B0;
520 if (amax < 0)
521 amax = 10;
522 double T0 = dt * (4.5 - jmax);
523 double A0 = amax;
524
525 //initialize minimizer
526 m_MinuitPhotonHadron->mnparm(0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
527 m_MinuitPhotonHadron->mnparm(1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
528 m_MinuitPhotonHadron->mnparm(2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
529 m_MinuitPhotonHadron->mnparm(3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
530
531 //perform fit
532 arglist[0] = 50000;
533 arglist[1] = 1.;
534 m_MinuitPhotonHadron->mnexcm("MIGRAD", arglist, 2, ierflg);
535
536 double edm, errdef;
537 int nvpar, nparx, icstat;
538 m_MinuitPhotonHadron->mnstat(chi2, edm, errdef, nvpar, nparx, icstat);
539
540 //get fit results
541 double error;
542 m_MinuitPhotonHadron->GetParameter(0, pedestal, error);
543 m_MinuitPhotonHadron->GetParameter(1, amplitudePhoton, error);
544 m_MinuitPhotonHadron->GetParameter(2, signalTime, error);
545 m_MinuitPhotonHadron->GetParameter(3, amplitudeHadron, error);
546}
547
549 double& pedestal, double& amplitudePhoton, double& signalTime,
550 double& amplitudeHadron, double& amplitudeBackgroundPhoton,
551 double& timeBackgroundPhoton, double& chi2)
552{
553 double arglist[10] = {0};
554 int ierflg = 0;
555 double dt = 0.5;
556 double amax = 0; int jmax = 6;
557 for (int j = 0; j < c_NFitPoints; j++) {
558 if (amax < fitA[j]) {
559 amax = fitA[j];
560 jmax = j;
561 }
562 }
563
564 double amax1 = 0; int jmax1 = 6;
565 for (int j = 0; j < c_NFitPoints; j++) {
566 if (j < jmax - 3 || jmax + 4 < j) {
567 if (j == 0) {
568 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) {
569 amax1 = fitA[j];
570 jmax1 = j;
571 }
572 } else if (j == 30) {
573 if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) {
574 amax1 = fitA[j];
575 jmax1 = j;
576 }
577 } else {
578 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) {
579 amax1 = fitA[j];
580 jmax1 = j;
581 }
582 }
583 }
584 }
585
586 double sumB0 = 0;
587 int jsum = 0;
588 for (int j = 0; j < c_NFitPoints; j++) {
589 if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) {
590 sumB0 += fitA[j];
591 ++jsum;
592 }
593 }
594 double B0 = sumB0 / jsum;
595 amax -= B0;
596 amax = std::max(10.0, amax);
597 amax1 -= B0;
598 amax1 = std::max(10.0, amax1);
599 double T0 = dt * (4.5 - jmax);
600 double T01 = dt * (4.5 - jmax1);
601
602 double A0 = amax, A01 = amax1;
604 0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
606 1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
608 2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
610 3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
612 4, "A2", A01, A01 / 20, 0, 2 * A01, ierflg);
614 5, "T2", T01, 0.5, T01 - 2.5, T01 + 2.5, ierflg);
615
616 // Now ready for minimization step
617 arglist[0] = 50000;
618 arglist[1] = 1.;
619 m_MinuitPhotonHadronBackgroundPhoton->mnexcm("MIGRAD", arglist, 2, ierflg);
620
621 double edm, errdef;
622 int nvpar, nparx, icstat;
623 m_MinuitPhotonHadronBackgroundPhoton->mnstat(chi2, edm, errdef, nvpar, nparx, icstat);
624 double error;
625 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(0, pedestal, error);
626 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(1, amplitudePhoton, error);
627 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(2, signalTime, error);
628 m_MinuitPhotonHadronBackgroundPhoton->GetParameter(3, amplitudeHadron, error);
630 4, amplitudeBackgroundPhoton, error);
632 5, timeBackgroundPhoton, error);
633}
634
636{
637 double T0 = -0.2;
638 std::vector<double> p(s.begin() + 1, s.end());
639 p[1] = std::max(0.0029, p[1]);
640 p[4] = std::max(0.0029, p[4]);
641
642 ShaperDSP_t dsp(p, s[0]);
643 dsp.settimestride(c_dtn);
644 dsp.settimeseed(T0);
645 dd_t t[(c_nt + c_ntail)*c_ndt];
646 dsp.fillarray(sizeof(t) / sizeof(t[0]), t);
647
648 for (int i = 0; i < c_nt * c_ndt; i++) {
649 m_FunctionInterpolation[i] = t[i].first;
650 m_DerivativeInterpolation[i] = t[i].second;
651 }
652 for (int i = 0; i < c_ntail; i++) {
653 int j = c_nt * c_ndt + i;
654 int k = c_nt * c_ndt + i * c_ndt;
655 m_FunctionInterpolation[j] = t[k].first;
656 m_DerivativeInterpolation[j] = t[k].second;
657 }
658 int i1 = c_nt * c_ndt + c_ntail - 2;
659 int i2 = c_nt * c_ndt + c_ntail - 1;
662}
663
665 double t0, double* function, double* derivatives) const
666{
667 /* If before pulse start time (negative times), return 0. */
668 int k = 0;
669 while (t0 < 0) {
670 function[k] = 0;
671 derivatives[k] = 0;
672 t0 += c_dt;
673 ++k;
674 if (k >= c_NFitPoints)
675 return;
676 }
677
678 /* Function and derivative values. */
679 double function0[c_NFitPoints], function1[c_NFitPoints];
680 double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
681
682 /* Interpolate first c_nt points (short time steps). */
683 double x = t0 * c_idtn;
684 double ix = floor(x);
685 double w = x - ix;
686 int j = ix;
687 double w2 = w * w;
688 double hw2 = 0.5 * w2;
689 double tw3 = ((1. / 6) * w) * w2;
690
691 /* Number of interpolation points. */
692 int iMax = k + c_nt;
693 if (iMax > c_NFitPoints)
694 iMax = c_NFitPoints;
695
696 /* Fill interpolation points. */
697 for (int i = k; i < iMax; ++i) {
698 function0[i] = m_FunctionInterpolation[j];
699 function1[i] = m_FunctionInterpolation[j + 1];
700 derivative0[i] = m_DerivativeInterpolation[j];
701 derivative1[i] = m_DerivativeInterpolation[j + 1];
702 j = j + c_ndt;
703 }
704
705 /* Interpolation. */
706 #pragma omp simd
707 for (int i = k; i < iMax; ++i) {
708 double a[4];
709 double dfdt = (function1[i] - function0[i]) * c_idtn;
710 double fp = derivative1[i] + derivative0[i];
711 a[0] = function0[i];
712 a[1] = derivative0[i];
713 a[2] = -((fp + derivative0[i]) - 3 * dfdt);
714 a[3] = fp - 2 * dfdt;
715 double b2 = 2 * a[2];
716 double b3 = 6 * a[3];
717 function[i] = a[0] + c_dtn * (a[1] * w + b2 * hw2 + b3 * tw3);
718 derivatives[i] = a[1] + b2 * w + b3 * hw2;
719 }
720 t0 = t0 + c_dt * c_nt;
721 if (iMax == c_NFitPoints)
722 return;
723 k = iMax;
724
725 /* Interpolate next c_ntail points (long time steps). */
726 x = t0 * c_idt;
727 ix = floor(x);
728 w = x - ix;
729 w2 = w * w;
730 hw2 = 0.5 * w2;
731 tw3 = ((1. / 6) * w) * w2;
732
733 /* Number of interpolation points. */
734 iMax = k + c_ntail - 1;
735 if (iMax > c_NFitPoints)
736 iMax = c_NFitPoints;
737
738 /* Interpolation. */
739 #pragma omp simd
740 for (int i = k; i < iMax; ++i) {
741 j = c_nt * c_ndt + i - k;
742 /*
743 * The interpolation step is the same as the distance between
744 * the fit points. It is possible to load the values in the interpolation
745 * loop while keeping its vectorization.
746 */
747 double f0 = m_FunctionInterpolation[j];
748 double f1 = m_FunctionInterpolation[j + 1];
749 double fp0 = m_DerivativeInterpolation[j];
750 double fp1 = m_DerivativeInterpolation[j + 1];
751 double a[4];
752 double dfdt = (f1 - f0) * c_idt;
753 double fp = fp1 + fp0;
754 a[0] = f0;
755 a[1] = fp0;
756 a[2] = -((fp + fp0) - 3 * dfdt);
757 a[3] = fp - 2 * dfdt;
758 double b2 = 2 * a[2];
759 double b3 = 6 * a[3];
760 function[i] = a[0] + c_dt * (a[1] * w + b2 * hw2 + b3 * tw3);
761 derivatives[i] = a[1] + b2 * w + b3 * hw2;
762 }
763 if (iMax == c_NFitPoints)
764 return;
765 k = iMax;
766
767 /* Exponential tail. */
768 while (k < c_NFitPoints) {
769 function[k] = function[k - 1] * m_r0;
770 derivatives[k] = derivatives[k - 1] * m_r1;
771 ++k;
772 }
773}
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.
double m_u1
u1 parameter for regularization function.
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:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:649
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.