10 #include <ecl/modules/eclWaveformFit/ECLWaveformFit.h>
13 #include <ecl/digitization/EclConfiguration.h>
14 #include <ecl/digitization/shaperdsp.h>
17 #include <framework/core/Environment.h>
22 #include <TMatrixDSym.h>
23 #include <TDecompChol.h>
40 void ecl_waveform_fit_load_inverse_covariance(
const float* packed_matrix);
45 void ecl_waveform_fit_multiply_inverse_covariance(
double* y,
const double* x);
54 const int c_NFitPoints = 31;
57 const int c_NFitPointsVector = 32;
60 double fitA[c_NFitPoints];
73 void FCN2h(
int&,
double* grad,
double& f,
double* p,
int)
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;
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);
88 for (
int i = 0; i < c_NFitPoints; ++i)
89 df[i] = fitA[i] - (Ag * amplitudeGamma[i] + Ah * amplitudeHadron[i] + B);
92 ecl_waveform_fit_multiply_inverse_covariance(da, df);
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];
98 gAg -= da[i] * amplitudeGamma[i];
99 gT -= da[i] * (derivativesGamma[i] * Ag + derivativesHadron[i] * Ah);
100 gAh -= da[i] * amplitudeHadron[i];
112 void FCN2h2(
int&,
double* grad,
double& f,
double* p,
int)
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;
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);
127 g_PhotonSignal->
getShape(T2, amplitudeGamma2, derivativesGamma2);
128 g_HadronSignal->
getShape(T, amplitudeHadron, derivativesHadron);
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);
138 ecl_waveform_fit_multiply_inverse_covariance(da, df);
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];
144 gAg -= da[i] * amplitudeGamma[i];
145 gAh -= da[i] * amplitudeHadron[i];
146 gT -= da[i] * (derivativesGamma[i] * Ag + derivativesHadron[i] * Ah);
148 gA2 -= da[i] * amplitudeGamma2[i];
149 gT2 -= da[i] * derivativesGamma2[i] * A2;
162 void regularize(
double* dst,
const double* src,
const int n,
const double u0 = 13.0,
const double u1 = 0.8)
164 for (
int k = 0; k < n; k++) dst[k] = src[k] / (1 + exp((k - u0) / u1));
168 bool makecovariance(
CovariancePacked& M,
const int nnoise,
const double* acov)
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];
176 const bool status = dc.Invert(
E);
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]);
194 setDescription(
"Module to fit offline waveforms and measure hadron scintillation component light output.");
195 setPropertyFlags(c_ParallelProcessingCertified);
196 addParam(
"EnergyThreshold", m_EnergyThreshold,
"Energy threshold of online fit result for Fitting Waveforms (GeV).", 0.03);
197 addParam(
"Chi2Threshold25dof", m_chi2Threshold25dof,
"chi2 threshold (25 dof) to classify offline fit as good fit.", 57.1);
198 addParam(
"Chi2Threshold27dof", m_chi2Threshold27dof,
"chi2 threshold (27 dof) to classify offline fit as good fit.", 60.0);
199 addParam(
"CovarianceMatrix", m_CovarianceMatrix,
200 "Option to use crystal dependent covariance matrices (false uses identity matrix).",
true);
212 m_TemplatesLoaded =
true;
214 if (m_IsMCFlag == 0) {
216 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
218 for (
int j = 0; j < 11; j++) {
219 Ptemp[j] = (double)m_WaveformParameters->getPhotonParameters(i + 1)[j];
220 Htemp[j] = (double)m_WaveformParameters->getHadronParameters(i + 1)[j];
221 Dtemp[j] = (double)m_WaveformParameters->getDiodeParameters(i + 1)[j];
229 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
230 for (
int j = 0; j < 11; j++) {
231 Ptemp[j] = (double)m_WaveformParametersForMC->getPhotonParameters()[j];
232 Htemp[j] = (double)m_WaveformParametersForMC->getHadronParameters()[j];
233 Dtemp[j] = (double)m_WaveformParametersForMC->getDiodeParameters()[j];
245 m_TemplatesLoaded =
false;
248 if (m_CrystalElectronics.isValid()) {
250 m_ADCtoEnergy[i] = m_CrystalElectronics->getCalibVector()[i];
252 if (m_CrystalEnergy.isValid()) {
254 m_ADCtoEnergy[i] *= m_CrystalEnergy->getCalibVector()[i];
258 if (m_CovarianceMatrix) {
260 double buf[c_NFitPoints];
261 double reg[c_NFitPoints];
262 m_AutoCovariance->getAutoCovariance(
id, buf);
263 double x0 = c_NFitPoints;
264 std::memcpy(reg, buf, c_NFitPoints *
sizeof(
double));
265 while (!makecovariance(m_c[
id - 1], c_NFitPoints, reg))
266 regularize(buf, reg, c_NFitPoints, x0 -= 1, 1);
270 double defaultCovariance[c_NFitPoints][c_NFitPoints];
272 const double isigma = 1 / 7.5;
273 for (
int i = 0; i < c_NFitPoints; ++i) {
274 for (
int j = 0; j < c_NFitPoints; ++j) {
275 defaultCovariance[i][j] = (i == j) * isigma * isigma;
279 for (
int i = 0; i < c_NFitPoints; i++) {
280 for (
int j = 0; j < i + 1; j++) {
281 packedDefaultCovariance.
m_covMatPacked[k] = defaultCovariance[i][j];
285 ecl_waveform_fit_load_inverse_covariance(
294 m_eclDSPs.registerInDataStore();
295 m_eclDigits.registerInDataStore();
298 m_Minit2h =
new TMinuit(4);
299 m_Minit2h->SetFCN(FCN2h);
303 m_Minit2h->mnexcm(
"SET PRIntout", arglist, 1, ierflg);
304 m_Minit2h->mnexcm(
"SET NOWarnings", arglist, 0, ierflg);
306 m_Minit2h->mnexcm(
"SET ERR", arglist, 1, ierflg);
308 m_Minit2h->mnexcm(
"SET STRategy", arglist, 1, ierflg);
310 m_Minit2h->mnexcm(
"SET GRAdient", arglist, 1, ierflg);
312 m_Minit2h->mnexcm(
"SET EPSmachine", arglist, 1, ierflg);
315 m_Minit2h2 =
new TMinuit(6);
316 m_Minit2h2->SetFCN(FCN2h2);
318 m_Minit2h2->mnexcm(
"SET PRIntout", arglist, 1, ierflg);
319 m_Minit2h2->mnexcm(
"SET NOWarnings", arglist, 0, ierflg);
321 m_Minit2h2->mnexcm(
"SET ERR", arglist, 1, ierflg);
323 m_Minit2h2->mnexcm(
"SET STRategy", arglist, 1, ierflg);
325 m_Minit2h2->mnexcm(
"SET GRAdient", arglist, 1, ierflg);
327 m_Minit2h2->mnexcm(
"SET EPSmachine", arglist, 1, ierflg);
330 m_TemplatesLoaded =
false;
337 if (!m_TemplatesLoaded) {
339 if (m_eclDSPs.getEntries() > 0) loadTemplateParameterArray();
342 for (
auto& aECLDsp : m_eclDSPs) {
344 aECLDsp.setTwoComponentTotalAmp(-1);
345 aECLDsp.setTwoComponentHadronAmp(-1);
346 aECLDsp.setTwoComponentDiodeAmp(-1);
347 aECLDsp.setTwoComponentChi2(-1);
351 aECLDsp.setTwoComponentTime(-1);
352 aECLDsp.setTwoComponentBaseline(-1);
355 const int id = aECLDsp.getCellId() - 1;
358 for (
int j = 0; j < ec.
m_nsmp; j++)
359 fitA[j] = aECLDsp.getDspA()[j];
363 for (
const auto& aECLDigit : m_eclDigits) {
364 if (aECLDigit.getCellId() - 1 ==
id) {
366 aECLDsp.addRelationTo(&aECLDigit);
370 if (d ==
nullptr)
continue;
373 if (d->getAmp() * m_ADCtoEnergy[
id] < m_EnergyThreshold)
continue;
376 if (m_IsMCFlag == 0) {
378 g_PhotonSignal = &m_si[id][0];
379 g_HadronSignal = &m_si[id][1];
382 g_PhotonSignal = &m_si[0][0];
383 g_HadronSignal = &m_si[0][1];
387 if (m_CovarianceMatrix) {
388 ecl_waveform_fit_load_inverse_covariance(m_c[
id].m_covMatPacked);
389 aNoise = m_c[id].sigma;
393 double p2_b, p2_a, p2_t, p2_a1, p2_chi2, p_extraPhotonEnergy, p_extraPhotonTime;
396 Fit2h(p2_b, p2_a, p2_t, p2_a1, p2_chi2);
400 if (p2_chi2 >= m_chi2Threshold27dof) {
404 Fit2hExtraPhoton(p2_b, p2_a, p2_t, p2_a1, p_extraPhotonEnergy, p_extraPhotonTime, p2_chi2);
408 if (p2_chi2 >= m_chi2Threshold25dof) {
409 g_HadronSignal = &m_si[0][2];
412 Fit2h(p2_b, p2_a, p2_t, p2_a1, p2_chi2);
421 aECLDsp.setTwoComponentTotalAmp(p2_a + p2_a1);
423 aECLDsp.setTwoComponentHadronAmp(0.0);
424 aECLDsp.setTwoComponentDiodeAmp(p2_a1);
426 aECLDsp.setTwoComponentHadronAmp(p2_a1);
427 aECLDsp.setTwoComponentDiodeAmp(0.0);
429 aECLDsp.setTwoComponentChi2(p2_chi2);
430 aECLDsp.setTwoComponentTime(p2_t);
431 aECLDsp.setTwoComponentBaseline(p2_b);
432 aECLDsp.setTwoComponentFitType(fitType);
434 aECLDsp.setbackgroundPhotonEnergy(p_extraPhotonEnergy);
435 aECLDsp.setbackgroundPhotonTime(p_extraPhotonTime);
461 for (
int j = 0; j < c_NFitPoints; j++)
if (amax < fitA[j]) { amax = fitA[j]; jmax = j;}
462 double sumB0 = 0;
int jsum = 0;
463 for (
int j = 0; j < c_NFitPoints; j++)
if (j < jmax - 3 || jmax + 4 < j) { sumB0 += fitA[j]; ++jsum;}
464 double B0 = sumB0 / jsum;
466 if (amax < 0) amax = 10;
467 double T0 = dt * (4.5 - jmax);
471 m_Minit2h->mnparm(0,
"B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
472 m_Minit2h->mnparm(1,
"Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
473 m_Minit2h->mnparm(2,
"T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
474 m_Minit2h->mnparm(3,
"Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
479 m_Minit2h->mnexcm(
"MIGRAD", arglist, 2, ierflg);
482 int nvpar, nparx, icstat;
483 m_Minit2h->mnstat(amin, edm, errdef, nvpar, nparx, icstat);
487 m_Minit2h->GetParameter(0, B, ep);
488 m_Minit2h->GetParameter(1, Ag, ep);
489 m_Minit2h->GetParameter(2, T, ep);
490 m_Minit2h->GetParameter(3, Ah, ep);
499 double amax = 0;
int jmax = 6;
500 for (
int j = 0; j < c_NFitPoints; j++)
if (amax < fitA[j]) { amax = fitA[j]; jmax = j;}
502 double amax1 = 0;
int jmax1 = 6;
503 for (
int j = 0; j < c_NFitPoints; j++)
504 if (j < jmax - 3 || jmax + 4 < j) {
506 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
507 }
else if (j == 30) {
508 if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
510 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
514 double sumB0 = 0;
int jsum = 0;
515 for (
int j = 0; j < c_NFitPoints; j++)
if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) { sumB0 += fitA[j]; ++jsum;}
516 double B0 = sumB0 / jsum;
517 amax -= B0; amax = std::max(10.0, amax);
518 amax1 -= B0; amax1 = std::max(10.0, amax1);
519 double T0 = dt * (4.5 - jmax);
520 double T01 = dt * (4.5 - jmax1);
522 double A0 = amax, A01 = amax1;
523 m_Minit2h2->mnparm(0,
"B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
524 m_Minit2h2->mnparm(1,
"Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
525 m_Minit2h2->mnparm(2,
"T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
526 m_Minit2h2->mnparm(3,
"Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
527 m_Minit2h2->mnparm(4,
"A2", A01, A01 / 20, 0, 2 * A01, ierflg);
528 m_Minit2h2->mnparm(5,
"T2", T01, 0.5, T01 - 2.5, T01 + 2.5, ierflg);
533 m_Minit2h2->mnexcm(
"MIGRAD", arglist, 2, ierflg);
536 int nvpar, nparx, icstat;
537 m_Minit2h2->mnstat(amin, edm, errdef, nvpar, nparx, icstat);
539 m_Minit2h2->GetParameter(0, B, ep);
540 m_Minit2h2->GetParameter(1, Ag, ep);
541 m_Minit2h2->GetParameter(2, T, ep);
542 m_Minit2h2->GetParameter(3, Ah, ep);
543 m_Minit2h2->GetParameter(4, A2, ep);
544 m_Minit2h2->GetParameter(5, T2, ep);
553 std::vector<double> p(s.begin() + 1, s.end());
554 p[1] = std::max(0.0029, p[1]);
555 p[4] = std::max(0.0029, p[4]);
560 dd_t t[(c_nt + c_ntail)*c_ndt];
561 dsp.
fillarray(
sizeof(t) /
sizeof(t[0]), t);
563 for (
int i = 0; i < c_nt * c_ndt; i++) {
564 m_FunctionInterpolation[i] = t[i].first;
565 m_DerivativeInterpolation[i] = t[i].second;
567 for (
int i = 0; i < c_ntail; i++) {
568 int j = c_nt * c_ndt + i;
569 int k = c_nt * c_ndt + i * c_ndt;
570 m_FunctionInterpolation[j] = t[k].first;
571 m_DerivativeInterpolation[j] = t[k].second;
573 int i1 = c_nt * c_ndt + c_ntail - 2;
574 int i2 = c_nt * c_ndt + c_ntail - 1;
575 m_r0 = m_FunctionInterpolation[i2] / m_FunctionInterpolation[i1];
576 m_r1 = m_DerivativeInterpolation[i2] / m_DerivativeInterpolation[i1];
580 double t0,
double*
function,
double* derivatives)
const
589 if (k >= c_NFitPoints)
594 double function0[c_NFitPoints], function1[c_NFitPoints];
595 double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
598 double x = t0 * c_idtn;
599 double ix = floor(x);
603 double hw2 = 0.5 * w2;
604 double tw3 = ((1. / 6) * w) * w2;
608 if (iMax > c_NFitPoints)
612 for (
int i = k; i < iMax; ++i) {
613 function0[i] = m_FunctionInterpolation[j];
614 function1[i] = m_FunctionInterpolation[j + 1];
615 derivative0[i] = m_DerivativeInterpolation[j];
616 derivative1[i] = m_DerivativeInterpolation[j + 1];
622 for (
int i = k; i < iMax; ++i) {
624 double dfdt = (function1[i] - function0[i]) * c_idtn;
625 double fp = derivative1[i] + derivative0[i];
627 a[1] = derivative0[i];
628 a[2] = -((fp + derivative0[i]) - 3 * dfdt);
629 a[3] = fp - 2 * dfdt;
630 double b2 = 2 * a[2];
631 double b3 = 6 * a[3];
632 function[i] = a[0] + c_dtn * (a[1] * w + b2 * hw2 + b3 * tw3);
633 derivatives[i] = a[1] + b2 * w + b3 * hw2;
635 t0 = t0 + c_dt * c_nt;
636 if (iMax == c_NFitPoints)
646 tw3 = ((1. / 6) * w) * w2;
649 iMax = k + c_ntail - 1;
650 if (iMax > c_NFitPoints)
655 for (
int i = k; i < iMax; ++i) {
656 j = c_nt * c_ndt + i - k;
662 double f0 = m_FunctionInterpolation[j];
663 double f1 = m_FunctionInterpolation[j + 1];
664 double fp0 = m_DerivativeInterpolation[j];
665 double fp1 = m_DerivativeInterpolation[j + 1];
667 double dfdt = (f1 - f0) * c_idt;
668 double fp = fp1 + fp0;
671 a[2] = -((fp + fp0) - 3 * dfdt);
672 a[3] = fp - 2 * dfdt;
673 double b2 = 2 * a[2];
674 double b3 = 6 * a[3];
675 function[i] = a[0] + c_dt * (a[1] * w + b2 * hw2 + b3 * tw3);
676 derivatives[i] = a[1] + b2 * w + b3 * hw2;
678 if (iMax == c_NFitPoints)
683 while (k < c_NFitPoints) {
684 function[k] =
function[k - 1] * m_r0;
685 derivatives[k] = derivatives[k - 1] * m_r1;
Class to store ECL digitized hits (output of ECLDigi) relation to ECLHit filled in ecl/modules/eclDig...
TwoComponentFitType
Offline two component fit type.
@ photonHadronBackgroundPhoton
photon + hadron template + pile-up photon fit
@ poorChi2
All offline fit attempts were greater than chi2 threshold.
@ photonDiodeCrossing
photon + diode template fit
@ photonHadron
photon + hadron template 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
void settimeseed(double)
set initial time
void settimestride(double)
set grid step for function calculation
void fillarray(int, double *) const
fill array for amplitude and time calculation
bool isMC() const
Do we have generated, not real data?
static Environment & Instance()
Static method to get a reference to the Environment instance.
REG_MODULE(arichBtest)
Register the Module.
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.
Interpolation of signal shape using function values and the first derivative.
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.