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(
376 aECLDsp.setTwoComponentTotalAmp(-1);
377 aECLDsp.setTwoComponentHadronAmp(-1);
378 aECLDsp.setTwoComponentDiodeAmp(-1);
379 aECLDsp.setTwoComponentChi2(-1);
383 aECLDsp.setTwoComponentTime(-1);
384 aECLDsp.setTwoComponentBaseline(-1);
387 const int id = aECLDsp.getCellId() - 1;
390 for (
int j = 0; j < ec.
m_nsmp; j++)
391 fitA[j] = aECLDsp.getDspA()[j];
396 if (aECLDigit.getCellId() - 1 ==
id) {
398 aECLDsp.addRelationTo(&aECLDigit);
422 ecl_waveform_fit_load_inverse_covariance(
428 double pedestal, amplitudePhoton, signalTime, amplitudeHadron,
429 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2;
432 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
442 pedestal, amplitudePhoton, signalTime, amplitudeHadron,
443 amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2);
453 fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
465 aECLDsp.setTwoComponentTotalAmp(amplitudePhoton + amplitudeHadron);
467 aECLDsp.setTwoComponentHadronAmp(0.0);
468 aECLDsp.setTwoComponentDiodeAmp(amplitudeHadron);
470 aECLDsp.setTwoComponentHadronAmp(amplitudeHadron);
471 aECLDsp.setTwoComponentDiodeAmp(0.0);
473 aECLDsp.setTwoComponentChi2(chi2);
474 aECLDsp.setTwoComponentTime(signalTime);
475 aECLDsp.setTwoComponentBaseline(pedestal);
476 aECLDsp.setTwoComponentFitType(fitType);
478 aECLDsp.setBackgroundPhotonEnergy(amplitudeBackgroundPhoton);
479 aECLDsp.setBackgroundPhotonTime(timeBackgroundPhoton);
493 double& pedestal,
double& amplitudePhoton,
double& signalTime,
494 double& amplitudeHadron,
double& chi2)
497 double arglist[10] = {0};
504 for (
int j = 0; j < c_NFitPoints; j++) {
505 if (amax < fitA[j]) {
512 for (
int j = 0; j < c_NFitPoints; j++) {
513 if (j < jmax - 3 || jmax + 4 < j) {
518 double B0 = sumB0 / jsum;
522 double T0 = dt * (4.5 - jmax);
537 int nvpar, nparx, icstat;
549 double& pedestal,
double& amplitudePhoton,
double& signalTime,
550 double& amplitudeHadron,
double& amplitudeBackgroundPhoton,
551 double& timeBackgroundPhoton,
double& chi2)
553 double arglist[10] = {0};
556 double amax = 0;
int jmax = 6;
557 for (
int j = 0; j < c_NFitPoints; j++) {
558 if (amax < fitA[j]) {
564 double amax1 = 0;
int jmax1 = 6;
565 for (
int j = 0; j < c_NFitPoints; j++) {
566 if (j < jmax - 3 || jmax + 4 < j) {
568 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) {
572 }
else if (j == 30) {
573 if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) {
578 if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) {
588 for (
int j = 0; j < c_NFitPoints; j++) {
589 if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) {
594 double B0 = sumB0 / jsum;
596 amax = std::max(10.0, amax);
598 amax1 = std::max(10.0, amax1);
599 double T0 = dt * (4.5 - jmax);
600 double T01 = dt * (4.5 - jmax1);
602 double A0 = amax, A01 = amax1;
604 0,
"B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
606 1,
"Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
608 2,
"T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
610 3,
"Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
612 4,
"A2", A01, A01 / 20, 0, 2 * A01, ierflg);
614 5,
"T2", T01, 0.5, T01 - 2.5, T01 + 2.5, ierflg);
622 int nvpar, nparx, icstat;
630 4, amplitudeBackgroundPhoton, error);
632 5, timeBackgroundPhoton, error);
638 std::vector<double> p(s.begin() + 1, s.end());
639 p[1] = std::max(0.0029, p[1]);
640 p[4] = std::max(0.0029, p[4]);
646 dsp.
fillarray(
sizeof(t) /
sizeof(t[0]), t);
652 for (
int i = 0; i <
c_ntail; i++) {
665 double t0,
double* function,
double* derivatives)
const
674 if (k >= c_NFitPoints)
679 double function0[c_NFitPoints], function1[c_NFitPoints];
680 double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
684 double ix = floor(x);
688 double hw2 = 0.5 * w2;
689 double tw3 = ((1. / 6) * w) * w2;
693 if (iMax > c_NFitPoints)
697 for (
int i = k; i < iMax; ++i) {
707 for (
int i = k; i < iMax; ++i) {
709 double dfdt = (function1[i] - function0[i]) *
c_idtn;
710 double fp = derivative1[i] + derivative0[i];
712 a[1] = derivative0[i];
713 a[2] = -((fp + derivative0[i]) - 3 * dfdt);
714 a[3] = fp - 2 * dfdt;
715 double b2 = 2 * a[2];
716 double b3 = 6 * a[3];
717 function[i] = a[0] +
c_dtn * (a[1] * w + b2 * hw2 + b3 * tw3);
718 derivatives[i] = a[1] + b2 * w + b3 * hw2;
721 if (iMax == c_NFitPoints)
731 tw3 = ((1. / 6) * w) * w2;
735 if (iMax > c_NFitPoints)
740 for (
int i = k; i < iMax; ++i) {
752 double dfdt = (f1 - f0) *
c_idt;
753 double fp = fp1 + fp0;
756 a[2] = -((fp + fp0) - 3 * dfdt);
757 a[3] = fp - 2 * dfdt;
758 double b2 = 2 * a[2];
759 double b3 = 6 * a[3];
760 function[i] = a[0] +
c_dt * (a[1] * w + b2 * hw2 + b3 * tw3);
761 derivatives[i] = a[1] + b2 * w + b3 * hw2;
763 if (iMax == c_NFitPoints)
768 while (k < c_NFitPoints) {
769 function[k] = function[k - 1] *
m_r0;
770 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.