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