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 fcnPhotonHadron(
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 fcnPhotonHadronBackgroundPhoton(
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]);
193 setDescription(
"Module to fit offline waveforms and measure hadron scintillation component light output.");
196 "Energy threshold of online fit result for Fitting Waveforms (GeV).",
199 "Chi2 threshold (25 dof) to classify offline fit as good fit.",
202 "Chi2 threshold (27 dof) to classify offline fit as good fit.",
205 "Option to use crystal-dependent covariance matrices (false uses identity matrix).",
220 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
222 for (
int j = 0; j < 11; j++) {
233 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
234 for (
int j = 0; j < 11; j++) {
264 double buf[c_NFitPoints];
265 double reg[c_NFitPoints];
267 double x0 = c_NFitPoints;
268 std::memcpy(reg, buf, c_NFitPoints *
sizeof(
double));
270 regularize(buf, reg, c_NFitPoints, x0 -= 1, 1);
274 double defaultCovariance[c_NFitPoints][c_NFitPoints];
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;
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];
289 ecl_waveform_fit_load_inverse_covariance(
349 aECLDsp.setTwoComponentTotalAmp(-1);
350 aECLDsp.setTwoComponentHadronAmp(-1);
351 aECLDsp.setTwoComponentDiodeAmp(-1);
352 aECLDsp.setTwoComponentChi2(-1);
356 aECLDsp.setTwoComponentTime(-1);
357 aECLDsp.setTwoComponentBaseline(-1);
360 const int id = aECLDsp.getCellId() - 1;
363 for (
int j = 0; j < ec.
m_nsmp; j++)
364 fitA[j] = aECLDsp.getDspA()[j];
369 if (aECLDigit.getCellId() - 1 ==
id) {
371 aECLDsp.addRelationTo(&aECLDigit);
395 ecl_waveform_fit_load_inverse_covariance(
401 double pedestal, amplitudePhoton, signalTime, amplitudeHadron,
402 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2;
405 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
415 pedestal, amplitudePhoton, signalTime, amplitudeHadron,
416 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2);
426 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
438 aECLDsp.setTwoComponentTotalAmp(amplitudePhoton + amplitudeHadron);
440 aECLDsp.setTwoComponentHadronAmp(0.0);
441 aECLDsp.setTwoComponentDiodeAmp(amplitudeHadron);
443 aECLDsp.setTwoComponentHadronAmp(amplitudeHadron);
444 aECLDsp.setTwoComponentDiodeAmp(0.0);
446 aECLDsp.setTwoComponentChi2(chi2);
447 aECLDsp.setTwoComponentTime(signalTime);
448 aECLDsp.setTwoComponentBaseline(pedestal);
449 aECLDsp.setTwoComponentFitType(fitType);
451 aECLDsp.setBackgroundPhotonEnergy(amplitudeBackgroundPhoton);
452 aECLDsp.setBackgroundPhotonTime(timeBackgroundPhoton);
466 double& pedestal,
double& amplitudePhoton,
double& signalTime,
467 double& amplitudeHadron,
double& chi2)
470 double arglist[10] = {0};
477 for (
int j = 0; j < c_NFitPoints; j++) {
478 if (amax < fitA[j]) {
485 for (
int j = 0; j < c_NFitPoints; j++) {
486 if (j < jmax - 3 || jmax + 4 < j) {
491 double B0 = sumB0 / jsum;
495 double T0 = dt * (4.5 - jmax);
510 int nvpar, nparx, icstat;
522 double& pedestal,
double& amplitudePhoton,
double& signalTime,
523 double& amplitudeHadron,
double& amplitudeBackgroundPhoton,
524 double& timeBackgroundPhoton,
double& chi2)
526 double arglist[10] = {0};
529 double amax = 0;
int jmax = 6;
530 for (
int j = 0; j < c_NFitPoints; j++) {
531 if (amax < fitA[j]) {
537 double amax1 = 0;
int jmax1 = 6;
538 for (
int j = 0; j < c_NFitPoints; j++) {
539 if (j < jmax - 3 || jmax + 4 < j) {
541 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) {
545 }
else if (j == 30) {
546 if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) {
551 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) {
561 for (
int j = 0; j < c_NFitPoints; j++) {
562 if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) {
567 double B0 = sumB0 / jsum;
569 amax = std::max(10.0, amax);
571 amax1 = std::max(10.0, amax1);
572 double T0 = dt * (4.5 - jmax);
573 double T01 = dt * (4.5 - jmax1);
575 double A0 = amax, A01 = amax1;
577 0,
"B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
579 1,
"Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
581 2,
"T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
583 3,
"Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
585 4,
"A2", A01, A01 / 20, 0, 2 * A01, ierflg);
587 5,
"T2", T01, 0.5, T01 - 2.5, T01 + 2.5, ierflg);
595 int nvpar, nparx, icstat;
603 4, amplitudeBackgroundPhoton, error);
605 5, timeBackgroundPhoton, error);
611 std::vector<double> p(s.begin() + 1, s.end());
612 p[1] = std::max(0.0029, p[1]);
613 p[4] = std::max(0.0029, p[4]);
619 dsp.
fillarray(
sizeof(t) /
sizeof(t[0]), t);
625 for (
int i = 0; i <
c_ntail; i++) {
638 double t0,
double* function,
double* derivatives)
const
647 if (k >= c_NFitPoints)
652 double function0[c_NFitPoints], function1[c_NFitPoints];
653 double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
657 double ix = floor(x);
661 double hw2 = 0.5 * w2;
662 double tw3 = ((1. / 6) * w) * w2;
666 if (iMax > c_NFitPoints)
670 for (
int i = k; i < iMax; ++i) {
680 for (
int i = k; i < iMax; ++i) {
682 double dfdt = (function1[i] - function0[i]) *
c_idtn;
683 double fp = derivative1[i] + derivative0[i];
685 a[1] = derivative0[i];
686 a[2] = -((fp + derivative0[i]) - 3 * dfdt);
687 a[3] = fp - 2 * dfdt;
688 double b2 = 2 * a[2];
689 double b3 = 6 * a[3];
690 function[i] = a[0] +
c_dtn * (a[1] * w + b2 * hw2 + b3 * tw3);
691 derivatives[i] = a[1] + b2 * w + b3 * hw2;
694 if (iMax == c_NFitPoints)
704 tw3 = ((1. / 6) * w) * w2;
708 if (iMax > c_NFitPoints)
713 for (
int i = k; i < iMax; ++i) {
725 double dfdt = (f1 - f0) *
c_idt;
726 double fp = fp1 + fp0;
729 a[2] = -((fp + fp0) - 3 * dfdt);
730 a[3] = fp - 2 * dfdt;
731 double b2 = 2 * a[2];
732 double b3 = 6 * a[3];
733 function[i] = a[0] +
c_dt * (a[1] * w + b2 * hw2 + b3 * tw3);
734 derivatives[i] = a[1] + b2 * w + b3 * hw2;
736 if (iMax == c_NFitPoints)
741 while (k < c_NFitPoints) {
742 function[k] = function[k - 1] *
m_r0;
743 derivatives[k] = derivatives[k - 1] *
m_r1;
Class to store ECL digitized hits (output of ECLDigi) relation to ECLHit filled in ecl/modules/eclDig...
Class to store ECL ShaperDSP waveform ADC data.
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.
void setDescription(const std::string &description)
Sets the description of the module.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
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.
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.