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