10 #include <ecl/modules/eclWaveformFit/ECLWaveformFit.h>
11 #include <ecl/dbobjects/ECLCrystalCalib.h>
12 #include <ecl/digitization/EclConfiguration.h>
13 #include <ecl/digitization/shaperdsp.h>
14 #include <ecl/dbobjects/ECLDigitWaveformParameters.h>
15 #include <ecl/dbobjects/ECLDigitWaveformParametersForMC.h>
16 #include <ecl/dbobjects/ECLAutoCovariance.h>
19 #include <framework/core/Environment.h>
20 #include <framework/database/DBObjPtr.h>
25 #include <TMatrixDSym.h>
26 #include <TDecompChol.h>
45 std::vector<double> fitA(31);
53 std::vector< std::vector<double> > currentCovMat;
57 void FCN2h(
int&,
double* grad,
double& f,
double* p,
int)
60 std::vector<double> df(N);
61 std::vector<double> da(N);
62 const double Ag = p[1], B = p[0], T = p[2], Ah = p[3];
63 double chi2 = 0, gAg = 0, gB = 0, gT = 0, gAh = 0;
71 for (
int i = 0; i < N; ++i) df[i] = fitA[i] - (Ag * ADg[i].f0 + Ah * ADh[i].f0 + B);
74 for (
int i = 0; i < N; ++i) da[i] = std::inner_product(currentCovMat[i].begin(), currentCovMat[i].end(), df.begin(), 0.0);
76 for (
int i = 0; i < N; ++i) {
77 chi2 += da[i] * df[i];
79 gAg -= da[i] * ADg[i].
f0;
80 gT -= da[i] * (ADg[i].
f1 * Ag + ADh[i].
f1 * Ah);
81 gAh -= da[i] * ADh[i].
f0;
92 void FCN2h2(
int&,
double* grad,
double& f,
double* p,
int)
95 std::vector<double> df(N);
96 std::vector<double> da(N);
97 const double A2 = p[4], T2 = p[5];
98 const double Ag = p[1], B = p[0], T = p[2], Ah = p[3];
99 double chi2 = 0, gA2 = 0, gT2 = 0;
100 double gAg = 0, gB = 0, gT = 0, gAh = 0;
109 for (
int i = 0; i < N; ++i) df[i] = fitA[i] - (Ag * ADg[i].f0 + Ah * ADh[i].f0 + A2 * AD2[i].f0 + B);
112 for (
int i = 0; i < N; ++i) da[i] = std::inner_product(currentCovMat[i].begin(), currentCovMat[i].end(), df.begin(), 0.0);
114 for (
int i = 0; i < N; ++i) {
115 chi2 += da[i] * df[i];
117 gAg -= da[i] * ADg[i].
f0;
118 gAh -= da[i] * ADh[i].
f0;
119 gT -= da[i] * (ADg[i].
f1 * Ag + ADh[i].
f1 * Ah);;
121 gA2 -= da[i] * AD2[i].
f0;
122 gT2 -= da[i] * AD2[i].
f1 * A2;
135 void regularize(
double* dst,
const double* src,
const int n,
const double u0 = 13.0,
const double u1 = 0.8)
137 for (
int k = 0; k < n; k++) dst[k] = src[k] / (1 + exp((k - u0) / u1));
141 bool makecovariance(
CovariancePacked& M,
const int nnoise,
const double* acov)
145 for (
int i = 0; i < ns; i++)
146 for (
int j = 0; j < i + 1; j++)
147 if (i - j < nnoise) E(i, j) = E(j, i) = acov[i - j];
150 const bool status = dc.Invert(E);
154 for (
int i = 0; i < ns; i++)
155 for (
int j = 0; j < i + 1; j++)
156 M[count++] = E(i, j);
157 M.
sigma = sqrtf(acov[0]);
168 currentCovMat.clear();
169 currentCovMat.resize(ns);
170 for (
int i = 0; i < ns; i++) {
171 currentCovMat[i].resize(ns);
172 for (
int j = 0; j < i + 1; j++) {
173 currentCovMat[i][j] = currentCovMat[j][i] = matrixPacked[count++];
176 aNoise = matrixPacked.
sigma;
185 setDescription(
"Module to fit offline waveforms and measure hadron scintillation component light output.");
186 setPropertyFlags(c_ParallelProcessingCertified);
187 addParam(
"EnergyThreshold", m_EnergyThreshold,
"Energy threshold of online fit result for Fitting Waveforms (GeV).", 0.03);
188 addParam(
"Chi2Threshold25dof", m_chi2Threshold25dof,
"chi2 threshold (25 dof) to classify offline fit as good fit.", 57.1);
189 addParam(
"Chi2Threshold27dof", m_chi2Threshold27dof,
"chi2 threshold (27 dof) to classify offline fit as good fit.", 60.0);
190 addParam(
"CovarianceMatrix", m_CovarianceMatrix,
191 "Option to use crystal dependent covariance matrices (false uses identity matrix).",
true);
203 m_TemplatesLoaded =
true;
205 if (m_IsMCFlag == 0) {
208 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
209 for (
int i = 0; i < 8736; i++) {
210 for (
int j = 0; j < 11; j++) {
211 Ptemp[j] = (double)WavePars->getPhotonParameters(i + 1)[j];
212 Htemp[j] = (double)WavePars->getHadronParameters(i + 1)[j];
213 Dtemp[j] = (double)WavePars->getDiodeParameters(i + 1)[j];
222 std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
223 for (
int j = 0; j < 11; j++) {
224 Ptemp[j] = (double)WaveParsMC->getPhotonParameters()[j];
225 Htemp[j] = (double)WaveParsMC->getHadronParameters()[j];
226 Dtemp[j] = (double)WaveParsMC->getDiodeParameters()[j];
238 m_TemplatesLoaded =
false;
241 m_ADCtoEnergy.resize(8736);
242 if (Ael)
for (
int i = 0; i < 8736; i++) m_ADCtoEnergy[i] = Ael->getCalibVector()[i];
243 if (Aen)
for (
int i = 0; i < 8736; i++) m_ADCtoEnergy[i] *= Aen->getCalibVector()[i];
246 if (m_CovarianceMatrix) {
248 for (
int id = 1;
id <= 8736;
id++) {
249 constexpr
int N = 31;
250 std::vector<double> buf(N);
251 std::vector<double> reg(N);
252 cov->getAutoCovariance(
id, buf.data());
255 while (!makecovariance(m_c[
id - 1], N, reg.data()))
256 regularize(buf.data(), reg.data(), N, x0 -= 1, 1);
260 const double isigma = 1 / 7.5;
261 currentCovMat.clear();
262 currentCovMat.resize(31);
263 for (
int i = 0; i < 31; ++i) {
264 currentCovMat[i].resize(31);
265 for (
int j = 0; j < 31; ++j) {
266 currentCovMat[i][j] = (i == j) * isigma * isigma;
276 m_eclDSPs.registerInDataStore();
277 m_eclDigits.registerInDataStore();
280 m_Minit2h =
new TMinuit(4);
281 m_Minit2h->SetFCN(FCN2h);
285 m_Minit2h->mnexcm(
"SET PRIntout", arglist, 1, ierflg);
286 m_Minit2h->mnexcm(
"SET NOWarnings", arglist, 0, ierflg);
288 m_Minit2h->mnexcm(
"SET ERR", arglist, 1, ierflg);
290 m_Minit2h->mnexcm(
"SET STRategy", arglist, 1, ierflg);
292 m_Minit2h->mnexcm(
"SET GRAdient", arglist, 1, ierflg);
294 m_Minit2h->mnexcm(
"SET EPSmachine", arglist, 1, ierflg);
297 m_Minit2h2 =
new TMinuit(6);
298 m_Minit2h2->SetFCN(FCN2h2);
300 m_Minit2h2->mnexcm(
"SET PRIntout", arglist, 1, ierflg);
301 m_Minit2h2->mnexcm(
"SET NOWarnings", arglist, 0, ierflg);
303 m_Minit2h2->mnexcm(
"SET ERR", arglist, 1, ierflg);
305 m_Minit2h2->mnexcm(
"SET STRategy", arglist, 1, ierflg);
307 m_Minit2h2->mnexcm(
"SET GRAdient", arglist, 1, ierflg);
309 m_Minit2h2->mnexcm(
"SET EPSmachine", arglist, 1, ierflg);
312 m_TemplatesLoaded =
false;
319 if (!m_TemplatesLoaded) {
321 if (m_eclDSPs.getEntries() > 0) loadTemplateParameterArray();
324 for (
auto& aECLDsp : m_eclDSPs) {
326 aECLDsp.setTwoComponentTotalAmp(-1);
327 aECLDsp.setTwoComponentHadronAmp(-1);
328 aECLDsp.setTwoComponentDiodeAmp(-1);
329 aECLDsp.setTwoComponentChi2(-1);
333 aECLDsp.setTwoComponentTime(-1);
334 aECLDsp.setTwoComponentBaseline(-1);
337 const int id = aECLDsp.getCellId() - 1;
340 for (
int j = 0; j < ec.
m_nsmp; j++) fitA[j] = aECLDsp.getDspA()[j];
344 for (
const auto& aECLDigit : m_eclDigits) {
345 if (aECLDigit.getCellId() - 1 ==
id) {
347 aECLDsp.addRelationTo(&aECLDigit);
351 if (d ==
nullptr)
continue;
354 if (d->getAmp() * m_ADCtoEnergy[
id] < m_EnergyThreshold)
continue;
357 if (m_IsMCFlag == 0) {
360 g_sih = &m_si[id][1];
368 if (m_CovarianceMatrix) unpackcovariance(m_c[
id]);
371 double p2_b, p2_a, p2_t, p2_a1, p2_chi2, p_extraPhotonEnergy, p_extraPhotonTime;
374 Fit2h(p2_b, p2_a, p2_t, p2_a1, p2_chi2);
378 if (p2_chi2 >= m_chi2Threshold27dof) {
382 Fit2hExtraPhoton(p2_b, p2_a, p2_t, p2_a1, p_extraPhotonEnergy, p_extraPhotonTime, p2_chi2);
386 if (p2_chi2 >= m_chi2Threshold25dof) {
390 Fit2h(p2_b, p2_a, p2_t, p2_a1, p2_chi2);
399 aECLDsp.setTwoComponentTotalAmp(p2_a + p2_a1);
401 aECLDsp.setTwoComponentHadronAmp(0.0);
402 aECLDsp.setTwoComponentDiodeAmp(p2_a1);
404 aECLDsp.setTwoComponentHadronAmp(p2_a1);
405 aECLDsp.setTwoComponentDiodeAmp(0.0);
407 aECLDsp.setTwoComponentChi2(p2_chi2);
408 aECLDsp.setTwoComponentTime(p2_t);
409 aECLDsp.setTwoComponentBaseline(p2_b);
410 aECLDsp.setTwoComponentFitType(fitType);
412 aECLDsp.setbackgroundPhotonEnergy(p_extraPhotonEnergy);
413 aECLDsp.setbackgroundPhotonTime(p_extraPhotonTime);
439 for (
int j = 0; j < 31; j++)
if (amax < fitA[j]) { amax = fitA[j]; jmax = j;}
440 double sumB0 = 0;
int jsum = 0;
441 for (
int j = 0; j < 31; j++)
if (j < jmax - 3 || jmax + 4 < j) { sumB0 += fitA[j]; ++jsum;}
442 double B0 = sumB0 / jsum;
444 if (amax < 0) amax = 10;
445 double T0 = dt * (4.5 - jmax);
449 m_Minit2h->mnparm(0,
"B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
450 m_Minit2h->mnparm(1,
"Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
451 m_Minit2h->mnparm(2,
"T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
452 m_Minit2h->mnparm(3,
"Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
457 m_Minit2h->mnexcm(
"MIGRAD", arglist, 2, ierflg);
460 int nvpar, nparx, icstat;
461 m_Minit2h->mnstat(amin, edm, errdef, nvpar, nparx, icstat);
465 m_Minit2h->GetParameter(0, B, ep);
466 m_Minit2h->GetParameter(1, Ag, ep);
467 m_Minit2h->GetParameter(2, T, ep);
468 m_Minit2h->GetParameter(3, Ah, ep);
477 double amax = 0;
int jmax = 6;
478 for (
int j = 0; j < 31; j++)
if (amax < fitA[j]) { amax = fitA[j]; jmax = j;}
480 double amax1 = 0;
int jmax1 = 6;
481 for (
int j = 0; j < 31; j++)
482 if (j < jmax - 3 || jmax + 4 < j) {
483 if (j == 0 && amax1 < fitA[j] && fitA[j + 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
484 else if (j == 30 && amax1 < fitA[j] && fitA[j - 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
485 else if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
488 double sumB0 = 0;
int jsum = 0;
489 for (
int j = 0; j < 31; j++)
if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) { sumB0 += fitA[j]; ++jsum;}
490 double B0 = sumB0 / jsum;
491 amax -= B0; amax = std::max(10.0, amax);
492 amax1 -= B0; amax1 = std::max(10.0, amax1);
493 double T0 = dt * (4.5 - jmax);
494 double T01 = dt * (4.5 - jmax1);
496 double A0 = amax, A01 = amax1;
497 m_Minit2h2->mnparm(0,
"B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
498 m_Minit2h2->mnparm(1,
"Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
499 m_Minit2h2->mnparm(2,
"T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
500 m_Minit2h2->mnparm(3,
"Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
501 m_Minit2h2->mnparm(4,
"A2", A01, A01 / 20, 0, 2 * A01, ierflg);
502 m_Minit2h2->mnparm(5,
"T2", T01 , 0.5 , T01 - 2.5, T01 + 2.5, ierflg);
507 m_Minit2h2->mnexcm(
"MIGRAD", arglist, 2, ierflg);
510 int nvpar, nparx, icstat;
511 m_Minit2h2->mnstat(amin, edm, errdef, nvpar, nparx, icstat);
513 m_Minit2h2->GetParameter(0, B, ep);
514 m_Minit2h2->GetParameter(1, Ag, ep);
515 m_Minit2h2->GetParameter(2, T, ep);
516 m_Minit2h2->GetParameter(3, Ah, ep);
517 m_Minit2h2->GetParameter(4, A2, ep);
518 m_Minit2h2->GetParameter(5, T2, ep);
527 std::vector<double> p(s.begin() + 1, s.end());
528 p[1] = std::max(0.0029, p[1]);
529 p[4] = std::max(0.0029, p[4]);
534 dd_t t[(c_nt + c_ntail)*c_ndt];
535 dsp.
fillarray(
sizeof(t) /
sizeof(t[0]), t);
537 for (
int i = 0; i < c_nt * c_ndt; i++) m_F[i] = t[i];
538 for (
int i = 0; i < c_ntail; i++) m_F[c_nt * c_ndt + i] = t[c_nt * c_ndt + i * c_ndt];
539 const auto& Fm = *(std::end(m_F) - 2), &F0 = *(std::end(m_F) - 1);
540 m_r0 = F0.first / Fm.first;
541 m_r1 = F0.second / Fm.second;
550 const int iend0 = c_nt * c_ndt, iend1 = c_nt * c_ndt + c_ntail;
556 if (++A >= Aend)
return;
561 double x = t0 * c_idtn, ix = floor(x), w = x - ix;
563 double w2 = w * w, hw2 = 0.5 * w2, tw3 = ((1. / 6) * w) * w2;
564 auto I = [
this, &w, &hw2, &tw3](
int j,
double idt,
double dt) {
566 f0 = m_F[j].first, f1 = m_F[j + 1].first,
567 fp0 = m_F[j].second, fp1 = m_F[j + 1].second,
568 dfdt = (f1 - f0) * idt, fp = fp1 + fp0;
572 a[2] = -((fp + fp0) - 3 * dfdt);
573 a[3] = ((fp) - 2 * dfdt);
575 double b2 = 2 * a[2], b3 = 6 * a[3];
577 y.f0 = a[0] + dt * (a[1] * w + b2 * hw2 + b3 * tw3);
578 y.f1 = a[1] + b2 * w + b3 * hw2;
579 y.f2 = (b2 + b3 * w) * idt;
586 *A = I(i, c_idtn, c_dtn);
587 if (++A >= Aend)
return;
592 x = t0 * c_idt; ix = floor(x); w = x - ix;
594 i = (j - c_nt) + iend0;
595 w2 = w * w, hw2 = 0.5 * w2, tw3 = ((1. / 6) * w) * w2;
599 while (i < iend1 - 1) {
600 *A = I(i++, c_idt, c_dt);
601 if (++A >= Aend)
return;
Class for accessing objects in the database.
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.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.
Struct to keep upper triangle of the covariance matrix.
Interpolate signal shape using function values and the first derivative.
void getshape(double, val_der_t *) const
returns signal shape(+derivatives) in 31 equidistant time points starting from T0
SignalInterpolation2()
Default constructor.
Struct to return signal function information f0 is the function value f1 is the first derivative f2 i...
double f1
see struct description
double f0
see struct description