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,
double u0,
double u1,
double u2)
164 for (
int k = 1; k < n; k++) dst[k] = u2 * 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).",
207 addParam(
"RegParam1",
m_u1,
"u1 parameter for regularization function).", 1.0);
221 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
223 for (
int j = 0; j < 11; j++) {
234 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
235 for (
int j = 0; j < 11; j++) {
265 double buf[c_NFitPoints];
266 double reg[c_NFitPoints];
268 double x0 = c_NFitPoints;
269 std::memcpy(reg, buf, c_NFitPoints *
sizeof(
double));
271 double param_u2 = 1.0;
273 while (invertSuccess ==
false) {
276 regularize(buf, reg, c_NFitPoints, x0 -= 1,
m_u1, param_u2);
280 if (x0 == 1) param_u2 = 0.0;
284 B2WARNING(
"Could not invert matrix for id " <<
id);
285 B2WARNING(
"Loading neighbour matrix for id " <<
id);
291 std::memcpy(reg, buf, c_NFitPoints *
sizeof(
double));
298 double defaultCovariance[c_NFitPoints][c_NFitPoints];
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;
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];
313 ecl_waveform_fit_load_inverse_covariance(
373 aECLDsp.setTwoComponentTotalAmp(-1);
374 aECLDsp.setTwoComponentHadronAmp(-1);
375 aECLDsp.setTwoComponentDiodeAmp(-1);
376 aECLDsp.setTwoComponentChi2(-1);
380 aECLDsp.setTwoComponentTime(-1);
381 aECLDsp.setTwoComponentBaseline(-1);
384 const int id = aECLDsp.getCellId() - 1;
387 for (
int j = 0; j < ec.
m_nsmp; j++)
388 fitA[j] = aECLDsp.getDspA()[j];
393 if (aECLDigit.getCellId() - 1 ==
id) {
395 aECLDsp.addRelationTo(&aECLDigit);
419 ecl_waveform_fit_load_inverse_covariance(
425 double pedestal, amplitudePhoton, signalTime, amplitudeHadron,
426 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2;
429 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
439 pedestal, amplitudePhoton, signalTime, amplitudeHadron,
440 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2);
450 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
462 aECLDsp.setTwoComponentTotalAmp(amplitudePhoton + amplitudeHadron);
464 aECLDsp.setTwoComponentHadronAmp(0.0);
465 aECLDsp.setTwoComponentDiodeAmp(amplitudeHadron);
467 aECLDsp.setTwoComponentHadronAmp(amplitudeHadron);
468 aECLDsp.setTwoComponentDiodeAmp(0.0);
470 aECLDsp.setTwoComponentChi2(chi2);
471 aECLDsp.setTwoComponentTime(signalTime);
472 aECLDsp.setTwoComponentBaseline(pedestal);
473 aECLDsp.setTwoComponentFitType(fitType);
475 aECLDsp.setBackgroundPhotonEnergy(amplitudeBackgroundPhoton);
476 aECLDsp.setBackgroundPhotonTime(timeBackgroundPhoton);
490 double& pedestal,
double& amplitudePhoton,
double& signalTime,
491 double& amplitudeHadron,
double& chi2)
494 double arglist[10] = {0};
501 for (
int j = 0; j < c_NFitPoints; j++) {
502 if (amax < fitA[j]) {
509 for (
int j = 0; j < c_NFitPoints; j++) {
510 if (j < jmax - 3 || jmax + 4 < j) {
515 double B0 = sumB0 / jsum;
519 double T0 = dt * (4.5 - jmax);
534 int nvpar, nparx, icstat;
546 double& pedestal,
double& amplitudePhoton,
double& signalTime,
547 double& amplitudeHadron,
double& amplitudeBackgroundPhoton,
548 double& timeBackgroundPhoton,
double& chi2)
550 double arglist[10] = {0};
553 double amax = 0;
int jmax = 6;
554 for (
int j = 0; j < c_NFitPoints; j++) {
555 if (amax < fitA[j]) {
561 double amax1 = 0;
int jmax1 = 6;
562 for (
int j = 0; j < c_NFitPoints; j++) {
563 if (j < jmax - 3 || jmax + 4 < j) {
565 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) {
569 }
else if (j == 30) {
570 if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) {
575 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) {
585 for (
int j = 0; j < c_NFitPoints; j++) {
586 if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) {
591 double B0 = sumB0 / jsum;
593 amax = std::max(10.0, amax);
595 amax1 = std::max(10.0, amax1);
596 double T0 = dt * (4.5 - jmax);
597 double T01 = dt * (4.5 - jmax1);
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);
619 int nvpar, nparx, icstat;
627 4, amplitudeBackgroundPhoton, error);
629 5, timeBackgroundPhoton, error);
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]);
643 dsp.
fillarray(
sizeof(t) /
sizeof(t[0]), t);
649 for (
int i = 0; i <
c_ntail; i++) {
662 double t0,
double* function,
double* derivatives)
const
671 if (k >= c_NFitPoints)
676 double function0[c_NFitPoints], function1[c_NFitPoints];
677 double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
681 double ix = floor(x);
685 double hw2 = 0.5 * w2;
686 double tw3 = ((1. / 6) * w) * w2;
690 if (iMax > c_NFitPoints)
694 for (
int i = k; i < iMax; ++i) {
704 for (
int i = k; i < iMax; ++i) {
706 double dfdt = (function1[i] - function0[i]) *
c_idtn;
707 double fp = derivative1[i] + derivative0[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;
718 if (iMax == c_NFitPoints)
728 tw3 = ((1. / 6) * w) * w2;
732 if (iMax > c_NFitPoints)
737 for (
int i = k; i < iMax; ++i) {
749 double dfdt = (f1 - f0) *
c_idt;
750 double fp = fp1 + 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;
760 if (iMax == c_NFitPoints)
765 while (k < c_NFitPoints) {
766 function[k] = function[k - 1] *
m_r0;
767 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.