Belle II Software  release-08-00-10
ECLWaveformFit.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 /* Own header. */
10 #include <ecl/modules/eclWaveformFit/ECLWaveformFit.h>
11 
12 /* ECL headers. */
13 #include <ecl/digitization/EclConfiguration.h>
14 #include <ecl/digitization/shaperdsp.h>
15 
16 /* Basf2 headers. */
17 #include <framework/core/Environment.h>
18 
19 /* ROOT headers. */
20 #include <TMinuit.h>
21 #include <TMatrixD.h>
22 #include <TMatrixDSym.h>
23 #include <TDecompChol.h>
24 
25 /* C++ headers. */
26 #include <numeric>
27 
28 using namespace Belle2;
29 using namespace ECL;
30 
31 //-----------------------------------------------------------------
32 // Register the Modules
33 //-----------------------------------------------------------------
34 REG_MODULE(ECLWaveformFit);
35 //-----------------------------------------------------------------
36 // Implementation
37 //-----------------------------------------------------------------
38 
39 extern "C" {
40 
41  // Load inverse covariance matrix from the packed form.
42  // @param[in] packed_matrix Packed matrix.
43  void ecl_waveform_fit_load_inverse_covariance(const float* packed_matrix);
44 
45  // Multiply vector by the stored inverse covariance matrix.
46  // @param[out] y Result vector.
47  // @param[in] x Vector.
48  void ecl_waveform_fit_multiply_inverse_covariance(double* y, const double* x);
49 
50 };
51 
52 
53 //anonymous namespace for data objects used by both ECLWaveformFitModule class and FCN2h funciton for MINUIT minimization.
54 namespace {
55 
56  // Number of fit points.
57  const int c_NFitPoints = 31;
58 
59  // Number of fit points for vectorized data.
60  const int c_NFitPointsVector = 32;
61 
62  //adc data array
63  double fitA[c_NFitPoints];
64 
66  const SignalInterpolation2* g_PhotonSignal;
67 
69  const SignalInterpolation2* g_HadronSignal;
70 
72  double aNoise;
73 
74  //Function to minimize in photon template + hadron template fit. (chi2)
75  // cppcheck-suppress constParameter ; TF1 fit functions cannot have const parameters
76  void FCN2h(int&, double* grad, double& f, double* p, int)
77  {
78  double df[c_NFitPointsVector];
79  double da[c_NFitPointsVector];
80  const double Ag = p[1], B = p[0], T = p[2], Ah = p[3];
81  double chi2 = 0, gAg = 0, gB = 0, gT = 0, gAh = 0;
82 
83  //getting photon and hadron component shapes for set of fit parameters
84  double amplitudeGamma[c_NFitPoints], derivativesGamma[c_NFitPoints];
85  double amplitudeHadron[c_NFitPoints], derivativesHadron[c_NFitPoints];
86  g_PhotonSignal->getShape(T, amplitudeGamma, derivativesGamma);
87  g_HadronSignal->getShape(T, amplitudeHadron, derivativesHadron);
88 
89  //computing difference between current fit result and adc data array
90  #pragma omp simd
91  for (int i = 0; i < c_NFitPoints; ++i)
92  df[i] = fitA[i] - (Ag * amplitudeGamma[i] + Ah * amplitudeHadron[i] + B);
93 
94  //computing chi2.
95  ecl_waveform_fit_multiply_inverse_covariance(da, df);
96 
97  #pragma omp simd reduction(+:chi2) reduction(-:gB,gAg,gT,gAh)
98  for (int i = 0; i < c_NFitPoints; ++i) {
99  chi2 += da[i] * df[i];
100  gB -= da[i];
101  gAg -= da[i] * amplitudeGamma[i];
102  gT -= da[i] * (derivativesGamma[i] * Ag + derivativesHadron[i] * Ah);
103  gAh -= da[i] * amplitudeHadron[i];
104  }
105 
106  f = chi2;
107  grad[0] = 2 * gB;
108  grad[1] = 2 * gAg;
109  grad[2] = 2 * gT;
110  grad[3] = 2 * gAh;
111  }
112 
113  //Function to minimize in photon template + hadron template + background photon fit. (chi2)
114  // cppcheck-suppress constParameter ; TF1 fit functions cannot have const parameters
115  void FCN2h2(int&, double* grad, double& f, double* p, int)
116  {
117  double df[c_NFitPointsVector];
118  double da[c_NFitPointsVector];
119  const double A2 = p[4], T2 = p[5];
120  const double Ag = p[1], B = p[0], T = p[2], Ah = p[3];
121  double chi2 = 0, gA2 = 0, gT2 = 0;
122  double gAg = 0, gB = 0, gT = 0, gAh = 0;
123 
124  //getting photon and hadron component shapes for set of fit parameters
125  double amplitudeGamma[c_NFitPoints], derivativesGamma[c_NFitPoints];
126  double amplitudeGamma2[c_NFitPoints], derivativesGamma2[c_NFitPoints];
127  double amplitudeHadron[c_NFitPoints], derivativesHadron[c_NFitPoints];
128  g_PhotonSignal->getShape(T, amplitudeGamma, derivativesGamma);
129  // Background photon.
130  g_PhotonSignal->getShape(T2, amplitudeGamma2, derivativesGamma2);
131  g_HadronSignal->getShape(T, amplitudeHadron, derivativesHadron);
132 
133  //computing difference between current fit result and adc data array
134  #pragma omp simd
135  for (int i = 0; i < c_NFitPoints; ++i) {
136  df[i] = fitA[i] - (Ag * amplitudeGamma[i] + Ah * amplitudeHadron[i]
137  + A2 * amplitudeGamma2[i] + B);
138  }
139 
140  //computing chi2.
141  ecl_waveform_fit_multiply_inverse_covariance(da, df);
142 
143  #pragma omp simd reduction(+:chi2) reduction(-:gB,gAg,gT,gAh,gA2,gT2)
144  for (int i = 0; i < c_NFitPoints; ++i) {
145  chi2 += da[i] * df[i];
146  gB -= da[i];
147  gAg -= da[i] * amplitudeGamma[i];
148  gAh -= da[i] * amplitudeHadron[i];
149  gT -= da[i] * (derivativesGamma[i] * Ag + derivativesHadron[i] * Ah);
150 
151  gA2 -= da[i] * amplitudeGamma2[i];
152  gT2 -= da[i] * derivativesGamma2[i] * A2;
153  }
154  f = chi2;
155  grad[0] = 2 * gB;
156  grad[1] = 2 * gAg;
157  grad[2] = 2 * gT;
158  grad[3] = 2 * gAh;
159  grad[4] = 2 * gA2;
160  grad[5] = 2 * gT2;
161  }
162 
163  // regularize autocovariance function by multipling it by the step
164  // function so elements above u0 become 0 and below are untouched.
165  void regularize(double* dst, const double* src, const int n, const double u0 = 13.0, const double u1 = 0.8)
166  {
167  for (int k = 0; k < n; k++) dst[k] = src[k] / (1 + exp((k - u0) / u1));
168  }
169 
170  // transform autocovariance function of c_NFitPoints elements to the covariance matrix
171  bool makecovariance(CovariancePacked& M, const int nnoise, const double* acov)
172  {
173  TMatrixDSym E(c_NFitPoints);
174  for (int i = 0; i < c_NFitPoints; i++)
175  for (int j = 0; j < i + 1; j++)
176  if (i - j < nnoise) E(i, j) = E(j, i) = acov[i - j];
177 
178  TDecompChol dc(E);
179  const bool status = dc.Invert(E);
180 
181  if (status) {
182  int count = 0;
183  for (int i = 0; i < c_NFitPoints; i++)
184  for (int j = 0; j < i + 1; j++)
185  M[count++] = E(i, j);
186  M.sigma = sqrtf(acov[0]);
187  }
188  return status;
189  }
190 
191 }
192 
193 // constructor
195 {
196  // Set module properties
197  setDescription("Module to fit offline waveforms and measure hadron scintillation component light output.");
198  setPropertyFlags(c_ParallelProcessingCertified);
199  addParam("EnergyThreshold", m_EnergyThreshold, "Energy threshold of online fit result for Fitting Waveforms (GeV).", 0.03);
200  addParam("Chi2Threshold25dof", m_chi2Threshold25dof, "chi2 threshold (25 dof) to classify offline fit as good fit.", 57.1);
201  addParam("Chi2Threshold27dof", m_chi2Threshold27dof, "chi2 threshold (27 dof) to classify offline fit as good fit.", 60.0);
202  addParam("CovarianceMatrix", m_CovarianceMatrix,
203  "Option to use crystal dependent covariance matrices (false uses identity matrix).", true);
204 }
205 
206 // destructor
208 {
209 }
210 
211 //callback for loading templates from database
213 {
214 
215  m_TemplatesLoaded = true;
216 
217  if (m_IsMCFlag == 0) {
218  //load data templates
219  std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
220  for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++) {
221  for (int j = 0; j < 11; j++) {
222  Ptemp[j] = (double)m_WaveformParameters->getPhotonParameters(i + 1)[j];
223  Htemp[j] = (double)m_WaveformParameters->getHadronParameters(i + 1)[j];
224  Dtemp[j] = (double)m_WaveformParameters->getDiodeParameters(i + 1)[j];
225  }
226  new (&m_si[i][0]) SignalInterpolation2(Ptemp);
227  new (&m_si[i][1]) SignalInterpolation2(Htemp);
228  new (&m_si[i][2]) SignalInterpolation2(Dtemp);
229  }
230  } else {
231  //load mc template
232  std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
233  for (int j = 0; j < 11; j++) {
234  Ptemp[j] = (double)m_WaveformParametersForMC->getPhotonParameters()[j];
235  Htemp[j] = (double)m_WaveformParametersForMC->getHadronParameters()[j];
236  Dtemp[j] = (double)m_WaveformParametersForMC->getDiodeParameters()[j];
237  }
238  new (&m_si[0][0]) SignalInterpolation2(Ptemp);
239  new (&m_si[0][1]) SignalInterpolation2(Htemp);
240  new (&m_si[0][2]) SignalInterpolation2(Dtemp);
241  }
242 }
243 
245 {
246 
247  m_IsMCFlag = Environment::Instance().isMC();
248  m_TemplatesLoaded = false;
249 
250  m_ADCtoEnergy.resize(ECLElementNumbers::c_NCrystals);
251  if (m_CrystalElectronics.isValid()) {
252  for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++)
253  m_ADCtoEnergy[i] = m_CrystalElectronics->getCalibVector()[i];
254  }
255  if (m_CrystalEnergy.isValid()) {
256  for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++)
257  m_ADCtoEnergy[i] *= m_CrystalEnergy->getCalibVector()[i];
258  }
259 
260  //Load covariance matricies from database;
261  if (m_CovarianceMatrix) {
262  for (int id = 1; id <= ECLElementNumbers::c_NCrystals; id++) {
263  double buf[c_NFitPoints];
264  double reg[c_NFitPoints];
265  m_AutoCovariance->getAutoCovariance(id, buf);
266  double x0 = c_NFitPoints;
267  std::memcpy(reg, buf, c_NFitPoints * sizeof(double));
268  while (!makecovariance(m_c[id - 1], c_NFitPoints, reg))
269  regularize(buf, reg, c_NFitPoints, x0 -= 1, 1);
270  }
271  } else {
272  // Default covariance matrix is identity for all crystals.
273  double defaultCovariance[c_NFitPoints][c_NFitPoints];
274  CovariancePacked packedDefaultCovariance;
275  const double isigma = 1 / 7.5;
276  for (int i = 0; i < c_NFitPoints; ++i) {
277  for (int j = 0; j < c_NFitPoints; ++j) {
278  defaultCovariance[i][j] = (i == j) * isigma * isigma;
279  }
280  }
281  int k = 0;
282  for (int i = 0; i < c_NFitPoints; i++) {
283  for (int j = 0; j < i + 1; j++) {
284  packedDefaultCovariance.m_covMatPacked[k] = defaultCovariance[i][j];
285  k++;
286  }
287  }
288  ecl_waveform_fit_load_inverse_covariance(
289  packedDefaultCovariance.m_covMatPacked);
290  }
291 
292 }
293 
295 {
296  // ECL dataobjects
297  m_eclDSPs.registerInDataStore();
298  m_eclDigits.registerInDataStore();
299 
300  //initializing fit minimizer
301  m_Minit2h = new TMinuit(4);
302  m_Minit2h->SetFCN(FCN2h);
303  double arglist[10];
304  int ierflg = 0;
305  arglist[0] = -1;
306  m_Minit2h->mnexcm("SET PRIntout", arglist, 1, ierflg);
307  m_Minit2h->mnexcm("SET NOWarnings", arglist, 0, ierflg);
308  arglist[0] = 1;
309  m_Minit2h->mnexcm("SET ERR", arglist, 1, ierflg);
310  arglist[0] = 0;
311  m_Minit2h->mnexcm("SET STRategy", arglist, 1, ierflg);
312  arglist[0] = 1;
313  m_Minit2h->mnexcm("SET GRAdient", arglist, 1, ierflg);
314  arglist[0] = 1e-6;
315  m_Minit2h->mnexcm("SET EPSmachine", arglist, 1, ierflg);
316 
317  //initializing fit minimizer photon+hadron + background photon
318  m_Minit2h2 = new TMinuit(6);
319  m_Minit2h2->SetFCN(FCN2h2);
320  arglist[0] = -1;
321  m_Minit2h2->mnexcm("SET PRIntout", arglist, 1, ierflg);
322  m_Minit2h2->mnexcm("SET NOWarnings", arglist, 0, ierflg);
323  arglist[0] = 1;
324  m_Minit2h2->mnexcm("SET ERR", arglist, 1, ierflg);
325  arglist[0] = 0;
326  m_Minit2h2->mnexcm("SET STRategy", arglist, 1, ierflg);
327  arglist[0] = 1;
328  m_Minit2h2->mnexcm("SET GRAdient", arglist, 1, ierflg);
329  arglist[0] = 1e-6;
330  m_Minit2h2->mnexcm("SET EPSmachine", arglist, 1, ierflg);
331 
332  //flag for callback to load templates each run
333  m_TemplatesLoaded = false;
334 }
335 
337 {
339 
340  if (!m_TemplatesLoaded) {
341  //load templates once per run in first event that has saved waveforms.
342  if (m_eclDSPs.getEntries() > 0) loadTemplateParameterArray();
343  }
344 
345  for (auto& aECLDsp : m_eclDSPs) {
346 
347  aECLDsp.setTwoComponentTotalAmp(-1);
348  aECLDsp.setTwoComponentHadronAmp(-1);
349  aECLDsp.setTwoComponentDiodeAmp(-1);
350  aECLDsp.setTwoComponentChi2(-1);
351  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, -1);
352  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton, -1);
353  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, -1);
354  aECLDsp.setTwoComponentTime(-1);
355  aECLDsp.setTwoComponentBaseline(-1);
356  aECLDsp.setTwoComponentFitType(ECLDsp::poorChi2);
357 
358  const int id = aECLDsp.getCellId() - 1;
359 
360  // Filling array with ADC values.
361  for (int j = 0; j < ec.m_nsmp; j++)
362  fitA[j] = aECLDsp.getDspA()[j];
363 
364  //setting relation of eclDSP to aECLDigit
365  const ECLDigit* d = nullptr;
366  for (const auto& aECLDigit : m_eclDigits) {
367  if (aECLDigit.getCellId() - 1 == id) {
368  d = &aECLDigit;
369  aECLDsp.addRelationTo(&aECLDigit);
370  break;
371  }
372  }
373  if (d == nullptr) continue;
374 
375  //Skipping low amplitude waveforms
376  if (d->getAmp() * m_ADCtoEnergy[id] < m_EnergyThreshold) continue;
377 
378  //loading template for waveform
379  if (m_IsMCFlag == 0) {
380  //data cell id dependent
381  g_PhotonSignal = &m_si[id][0];
382  g_HadronSignal = &m_si[id][1];
383  } else {
384  // mc uses same waveform
385  g_PhotonSignal = &m_si[0][0];
386  g_HadronSignal = &m_si[0][1];
387  }
388 
389  //get covariance matrix for cell id
390  if (m_CovarianceMatrix) {
391  ecl_waveform_fit_load_inverse_covariance(m_c[id].m_covMatPacked);
392  aNoise = m_c[id].sigma;
393  }
394 
395  //Calling optimized fit photon template + hadron template (fit type = 0)
396  double p2_b, p2_a, p2_t, p2_a1, p2_chi2, p_extraPhotonEnergy, p_extraPhotonTime;
398  p2_chi2 = -1;
399  Fit2h(p2_b, p2_a, p2_t, p2_a1, p2_chi2);
400  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, p2_chi2);
401 
402  //if hadron fit failed try hadron + background photon (fit type = 1)
403  if (p2_chi2 >= m_chi2Threshold27dof) {
404 
406  p2_chi2 = -1;
407  Fit2hExtraPhoton(p2_b, p2_a, p2_t, p2_a1, p_extraPhotonEnergy, p_extraPhotonTime, p2_chi2);
408  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton, p2_chi2);
409 
410  //hadron + background photon fit failed try diode fit (fit type = 2)
411  if (p2_chi2 >= m_chi2Threshold25dof) {
412  g_HadronSignal = &m_si[0][2];//set second component to diode
413  fitType = ECLDsp::photonDiodeCrossing;
414  p2_chi2 = -1;
415  Fit2h(p2_b, p2_a, p2_t, p2_a1, p2_chi2);
416  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, p2_chi2);
417 
418  if (p2_chi2 >= m_chi2Threshold27dof) fitType = ECLDsp::poorChi2; //indicates all fits tried had bad chi2
419  }
420 
421  }
422 
423  //storing fit results
424  aECLDsp.setTwoComponentTotalAmp(p2_a + p2_a1);
425  if (fitType == ECLDsp::photonDiodeCrossing) {
426  aECLDsp.setTwoComponentHadronAmp(0.0);
427  aECLDsp.setTwoComponentDiodeAmp(p2_a1);
428  } else {
429  aECLDsp.setTwoComponentHadronAmp(p2_a1);
430  aECLDsp.setTwoComponentDiodeAmp(0.0);
431  }
432  aECLDsp.setTwoComponentChi2(p2_chi2);
433  aECLDsp.setTwoComponentTime(p2_t);
434  aECLDsp.setTwoComponentBaseline(p2_b);
435  aECLDsp.setTwoComponentFitType(fitType);
436  if (fitType == ECLDsp::photonHadronBackgroundPhoton) {
437  aECLDsp.setbackgroundPhotonEnergy(p_extraPhotonEnergy);
438  aECLDsp.setbackgroundPhotonTime(p_extraPhotonTime);
439  }
440  }
441 }
442 
443 // end run
445 {
446 }
447 
448 // terminate
450 {
451 }
452 
453 //Two component fit. Fits photon+hadron component hypothesis
454 void ECLWaveformFitModule::Fit2h(double& B, double& Ag, double& T, double& Ah, double& amin)
455 {
456  //minuit parameters
457  double arglist[10];
458  int ierflg = 0;
459 
460  // setting inital fit parameters
461  double dt = 0.5;
462  double amax = 0;
463  int jmax = 6;
464  for (int j = 0; j < c_NFitPoints; j++) if (amax < fitA[j]) { amax = fitA[j]; jmax = j;}
465  double sumB0 = 0; int jsum = 0;
466  for (int j = 0; j < c_NFitPoints; j++) if (j < jmax - 3 || jmax + 4 < j) { sumB0 += fitA[j]; ++jsum;}
467  double B0 = sumB0 / jsum;
468  amax -= B0;
469  if (amax < 0) amax = 10;
470  double T0 = dt * (4.5 - jmax);
471  double A0 = amax;
472 
473  //initalize minimizer
474  m_Minit2h->mnparm(0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
475  m_Minit2h->mnparm(1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
476  m_Minit2h->mnparm(2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
477  m_Minit2h->mnparm(3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
478 
479  //perform fit
480  arglist[0] = 50000;
481  arglist[1] = 1.;
482  m_Minit2h->mnexcm("MIGRAD", arglist, 2, ierflg);
483 
484  double edm, errdef;
485  int nvpar, nparx, icstat;
486  m_Minit2h->mnstat(amin, edm, errdef, nvpar, nparx, icstat);
487 
488  //get fit results
489  double ep;
490  m_Minit2h->GetParameter(0, B, ep);
491  m_Minit2h->GetParameter(1, Ag, ep);
492  m_Minit2h->GetParameter(2, T, ep);
493  m_Minit2h->GetParameter(3, Ah, ep);
494 }
495 
496 //Two component fit background ith extra photon. Fits photon+hadron component + extra photon hypothesis
497 void ECLWaveformFitModule::Fit2hExtraPhoton(double& B, double& Ag, double& T, double& Ah, double& A2, double& T2, double& amin)
498 {
499  double arglist[10];
500  int ierflg = 0;
501  double dt = 0.5;
502  double amax = 0; int jmax = 6;
503  for (int j = 0; j < c_NFitPoints; j++) if (amax < fitA[j]) { amax = fitA[j]; jmax = j;}
504 
505  double amax1 = 0; int jmax1 = 6;
506  for (int j = 0; j < c_NFitPoints; j++)
507  if (j < jmax - 3 || jmax + 4 < j) {
508  if (j == 0) {
509  if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
510  } else if (j == 30) {
511  if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
512  } else {
513  if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) { amax1 = fitA[j]; jmax1 = j;}
514  }
515  }
516 
517  double sumB0 = 0; int jsum = 0;
518  for (int j = 0; j < c_NFitPoints; j++) if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) { sumB0 += fitA[j]; ++jsum;}
519  double B0 = sumB0 / jsum;
520  amax -= B0; amax = std::max(10.0, amax);
521  amax1 -= B0; amax1 = std::max(10.0, amax1);
522  double T0 = dt * (4.5 - jmax);
523  double T01 = dt * (4.5 - jmax1);
524 
525  double A0 = amax, A01 = amax1;
526  m_Minit2h2->mnparm(0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
527  m_Minit2h2->mnparm(1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
528  m_Minit2h2->mnparm(2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
529  m_Minit2h2->mnparm(3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
530  m_Minit2h2->mnparm(4, "A2", A01, A01 / 20, 0, 2 * A01, ierflg);
531  m_Minit2h2->mnparm(5, "T2", T01, 0.5, T01 - 2.5, T01 + 2.5, ierflg);
532 
533  // Now ready for minimization step
534  arglist[0] = 50000;
535  arglist[1] = 1.;
536  m_Minit2h2->mnexcm("MIGRAD", arglist, 2, ierflg);
537 
538  double edm, errdef;
539  int nvpar, nparx, icstat;
540  m_Minit2h2->mnstat(amin, edm, errdef, nvpar, nparx, icstat);
541  double ep;
542  m_Minit2h2->GetParameter(0, B, ep);
543  m_Minit2h2->GetParameter(1, Ag, ep);
544  m_Minit2h2->GetParameter(2, T, ep);
545  m_Minit2h2->GetParameter(3, Ah, ep);
546  m_Minit2h2->GetParameter(4, A2, ep);
547  m_Minit2h2->GetParameter(5, T2, ep);
548 }
549 
550 
551 
552 //Signal interpolation code used for fast evaluation of shaperDSP templates
553 SignalInterpolation2::SignalInterpolation2(const std::vector<double>& s)
554 {
555  double T0 = -0.2;
556  std::vector<double> p(s.begin() + 1, s.end());
557  p[1] = std::max(0.0029, p[1]);
558  p[4] = std::max(0.0029, p[4]);
559 
560  ShaperDSP_t dsp(p, s[0]);
561  dsp.settimestride(c_dtn);
562  dsp.settimeseed(T0);
563  dd_t t[(c_nt + c_ntail)*c_ndt];
564  dsp.fillarray(sizeof(t) / sizeof(t[0]), t);
565 
566  for (int i = 0; i < c_nt * c_ndt; i++) {
567  m_FunctionInterpolation[i] = t[i].first;
568  m_DerivativeInterpolation[i] = t[i].second;
569  }
570  for (int i = 0; i < c_ntail; i++) {
571  int j = c_nt * c_ndt + i;
572  int k = c_nt * c_ndt + i * c_ndt;
573  m_FunctionInterpolation[j] = t[k].first;
574  m_DerivativeInterpolation[j] = t[k].second;
575  }
576  int i1 = c_nt * c_ndt + c_ntail - 2;
577  int i2 = c_nt * c_ndt + c_ntail - 1;
578  m_r0 = m_FunctionInterpolation[i2] / m_FunctionInterpolation[i1];
579  m_r1 = m_DerivativeInterpolation[i2] / m_DerivativeInterpolation[i1];
580 }
581 
583  double t0, double* function, double* derivatives) const
584 {
585  /* If before pulse start time (negative times), return 0. */
586  int k = 0;
587  while (t0 < 0) {
588  function[k] = 0;
589  derivatives[k] = 0;
590  t0 += c_dt;
591  ++k;
592  if (k >= c_NFitPoints)
593  return;
594  }
595 
596  /* Function and derivative values. */
597  double function0[c_NFitPoints], function1[c_NFitPoints];
598  double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
599 
600  /* Interpolate first c_nt points (short time steps). */
601  double x = t0 * c_idtn;
602  double ix = floor(x);
603  double w = x - ix;
604  int j = ix;
605  double w2 = w * w;
606  double hw2 = 0.5 * w2;
607  double tw3 = ((1. / 6) * w) * w2;
608 
609  /* Number of interpolation points. */
610  int iMax = k + c_nt;
611  if (iMax > c_NFitPoints)
612  iMax = c_NFitPoints;
613 
614  /* Fill interpolation points. */
615  for (int i = k; i < iMax; ++i) {
616  function0[i] = m_FunctionInterpolation[j];
617  function1[i] = m_FunctionInterpolation[j + 1];
618  derivative0[i] = m_DerivativeInterpolation[j];
619  derivative1[i] = m_DerivativeInterpolation[j + 1];
620  j = j + c_ndt;
621  }
622 
623  /* Interpolation. */
624  #pragma omp simd
625  for (int i = k; i < iMax; ++i) {
626  double a[4];
627  double dfdt = (function1[i] - function0[i]) * c_idtn;
628  double fp = derivative1[i] + derivative0[i];
629  a[0] = function0[i];
630  a[1] = derivative0[i];
631  a[2] = -((fp + derivative0[i]) - 3 * dfdt);
632  a[3] = fp - 2 * dfdt;
633  double b2 = 2 * a[2];
634  double b3 = 6 * a[3];
635  function[i] = a[0] + c_dtn * (a[1] * w + b2 * hw2 + b3 * tw3);
636  derivatives[i] = a[1] + b2 * w + b3 * hw2;
637  }
638  t0 = t0 + c_dt * c_nt;
639  if (iMax == c_NFitPoints)
640  return;
641  k = iMax;
642 
643  /* Interpolate next c_ntail points (long time steps). */
644  x = t0 * c_idt;
645  ix = floor(x);
646  w = x - ix;
647  w2 = w * w;
648  hw2 = 0.5 * w2;
649  tw3 = ((1. / 6) * w) * w2;
650 
651  /* Number of interpolation points. */
652  iMax = k + c_ntail - 1;
653  if (iMax > c_NFitPoints)
654  iMax = c_NFitPoints;
655 
656  /* Interpolation. */
657  #pragma omp simd
658  for (int i = k; i < iMax; ++i) {
659  j = c_nt * c_ndt + i - k;
660  /*
661  * The interpolation step is the same as the distance between
662  * the fit points. It is possible to load the values in the interpolation
663  * loop while keeping its vectorization.
664  */
665  double f0 = m_FunctionInterpolation[j];
666  double f1 = m_FunctionInterpolation[j + 1];
667  double fp0 = m_DerivativeInterpolation[j];
668  double fp1 = m_DerivativeInterpolation[j + 1];
669  double a[4];
670  double dfdt = (f1 - f0) * c_idt;
671  double fp = fp1 + fp0;
672  a[0] = f0;
673  a[1] = fp0;
674  a[2] = -((fp + fp0) - 3 * dfdt);
675  a[3] = fp - 2 * dfdt;
676  double b2 = 2 * a[2];
677  double b3 = 6 * a[3];
678  function[i] = a[0] + c_dt * (a[1] * w + b2 * hw2 + b3 * tw3);
679  derivatives[i] = a[1] + b2 * w + b3 * hw2;
680  }
681  if (iMax == c_NFitPoints)
682  return;
683  k = iMax;
684 
685  /* Exponential tail. */
686  while (k < c_NFitPoints) {
687  function[k] = function[k - 1] * m_r0;
688  derivatives[k] = derivatives[k - 1] * m_r1;
689  ++k;
690  }
691 }
R E
internal precision of FFTW codelets
Class to store ECL digitized hits (output of ECLDigi) relation to ECLHit filled in ecl/modules/eclDig...
Definition: ECLDigit.h:24
TwoComponentFitType
Offline two component fit type.
Definition: ECLDsp.h:29
@ photonHadronBackgroundPhoton
photon + hadron template + pile-up photon fit
Definition: ECLDsp.h:32
@ poorChi2
All offline fit attempts were greater than chi2 threshold.
Definition: ECLDsp.h:30
@ photonDiodeCrossing
photon + diode template fit
Definition: ECLDsp.h:33
@ photonHadron
photon + hadron template fit
Definition: ECLDsp.h:31
void Fit2hExtraPhoton(double &b, double &a0, double &t0, double &a1, double &A2, double &T2, double &chi2)
Optimized fit using hadron component model plus out-of-time background photon.
virtual void initialize() override
Initialize variables.
virtual void event() override
event per event.
virtual void endRun() override
end run.
virtual void terminate() override
terminate.
void loadTemplateParameterArray()
Loads waveform templates from database.
void Fit2h(double &b, double &a0, double &t0, double &a1, double &chi2)
Optimized fit using hadron component model.
virtual void beginRun() override
begin run.
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
Definition: shaperdsp.h:26
void settimeseed(double)
set initial time
Definition: shaperdsp.cc:371
void settimestride(double)
set grid step for function calculation
Definition: shaperdsp.cc:361
void fillarray(int, double *) const
fill array for amplitude and time calculation
Definition: shaperdsp.cc:381
bool isMC() const
Do we have generated, not real data?
Definition: Environment.cc:54
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:28
REG_MODULE(arichBtest)
Register the Module.
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.
float sigma
Sigma noise.
Interpolation of signal shape using function values and the first derivative.
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.