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(
352 aECLDsp.setTwoComponentTotalAmp(-1);
353 aECLDsp.setTwoComponentHadronAmp(-1);
354 aECLDsp.setTwoComponentDiodeAmp(-1);
355 aECLDsp.setTwoComponentChi2(-1);
359 aECLDsp.setTwoComponentTime(-1);
360 aECLDsp.setTwoComponentBaseline(-1);
363 const int id = aECLDsp.getCellId() - 1;
366 for (
int j = 0; j < ec.
m_nsmp; j++)
367 fitA[j] = aECLDsp.getDspA()[j];
372 if (aECLDigit.getCellId() - 1 ==
id) {
374 aECLDsp.addRelationTo(&aECLDigit);
398 ecl_waveform_fit_load_inverse_covariance(
404 double pedestal, amplitudePhoton, signalTime, amplitudeHadron,
405 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2;
408 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
418 pedestal, amplitudePhoton, signalTime, amplitudeHadron,
419 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2);
429 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
441 aECLDsp.setTwoComponentTotalAmp(amplitudePhoton + amplitudeHadron);
443 aECLDsp.setTwoComponentHadronAmp(0.0);
444 aECLDsp.setTwoComponentDiodeAmp(amplitudeHadron);
446 aECLDsp.setTwoComponentHadronAmp(amplitudeHadron);
447 aECLDsp.setTwoComponentDiodeAmp(0.0);
449 aECLDsp.setTwoComponentChi2(chi2);
450 aECLDsp.setTwoComponentTime(signalTime);
451 aECLDsp.setTwoComponentBaseline(pedestal);
452 aECLDsp.setTwoComponentFitType(fitType);
454 aECLDsp.setBackgroundPhotonEnergy(amplitudeBackgroundPhoton);
455 aECLDsp.setBackgroundPhotonTime(timeBackgroundPhoton);
469 double& pedestal,
double& amplitudePhoton,
double& signalTime,
470 double& amplitudeHadron,
double& chi2)
473 double arglist[10] = {0};
480 for (
int j = 0; j < c_NFitPoints; j++) {
481 if (amax < fitA[j]) {
488 for (
int j = 0; j < c_NFitPoints; j++) {
489 if (j < jmax - 3 || jmax + 4 < j) {
494 double B0 = sumB0 / jsum;
498 double T0 = dt * (4.5 - jmax);
513 int nvpar, nparx, icstat;
525 double& pedestal,
double& amplitudePhoton,
double& signalTime,
526 double& amplitudeHadron,
double& amplitudeBackgroundPhoton,
527 double& timeBackgroundPhoton,
double& chi2)
529 double arglist[10] = {0};
532 double amax = 0;
int jmax = 6;
533 for (
int j = 0; j < c_NFitPoints; j++) {
534 if (amax < fitA[j]) {
540 double amax1 = 0;
int jmax1 = 6;
541 for (
int j = 0; j < c_NFitPoints; j++) {
542 if (j < jmax - 3 || jmax + 4 < j) {
544 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) {
548 }
else if (j == 30) {
549 if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) {
554 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) {
564 for (
int j = 0; j < c_NFitPoints; j++) {
565 if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) {
570 double B0 = sumB0 / jsum;
572 amax = std::max(10.0, amax);
574 amax1 = std::max(10.0, amax1);
575 double T0 = dt * (4.5 - jmax);
576 double T01 = dt * (4.5 - jmax1);
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);
598 int nvpar, nparx, icstat;
606 4, amplitudeBackgroundPhoton, error);
608 5, timeBackgroundPhoton, error);
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]);
622 dsp.
fillarray(
sizeof(t) /
sizeof(t[0]), t);
628 for (
int i = 0; i <
c_ntail; i++) {
641 double t0,
double* function,
double* derivatives)
const
650 if (k >= c_NFitPoints)
655 double function0[c_NFitPoints], function1[c_NFitPoints];
656 double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
660 double ix = floor(x);
664 double hw2 = 0.5 * w2;
665 double tw3 = ((1. / 6) * w) * w2;
669 if (iMax > c_NFitPoints)
673 for (
int i = k; i < iMax; ++i) {
683 for (
int i = k; i < iMax; ++i) {
685 double dfdt = (function1[i] - function0[i]) *
c_idtn;
686 double fp = derivative1[i] + derivative0[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;
697 if (iMax == c_NFitPoints)
707 tw3 = ((1. / 6) * w) * w2;
711 if (iMax > c_NFitPoints)
716 for (
int i = k; i < iMax; ++i) {
728 double dfdt = (f1 - f0) *
c_idt;
729 double fp = fp1 + 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;
739 if (iMax == c_NFitPoints)
744 while (k < c_NFitPoints) {
745 function[k] = function[k - 1] *
m_r0;
746 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.