Belle II Software  release-08-02-06
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 fcnPhotonHadron function 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 fcnPhotonHadron(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 fcnPhotonHadronBackgroundPhoton(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 multiplying 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, double u0, double u1, double u2)
163  {
164  for (int k = 1; k < n; k++) dst[k] = u2 * 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 
191 {
192  /* Set module properties. */
193  setDescription("Module to fit offline waveforms and measure hadron scintillation component light output.");
194  setPropertyFlags(c_ParallelProcessingCertified);
195  addParam("EnergyThreshold", m_EnergyThreshold,
196  "Energy threshold of online fit result for Fitting Waveforms (GeV).",
197  0.03);
198  addParam("Chi2Threshold25dof", m_Chi2Threshold25dof,
199  "Chi2 threshold (25 dof) to classify offline fit as good fit.",
200  57.1);
201  addParam("Chi2Threshold27dof", m_Chi2Threshold27dof,
202  "Chi2 threshold (27 dof) to classify offline fit as good fit.",
203  60.0);
204  addParam("CovarianceMatrix", m_CovarianceMatrix,
205  "Option to use crystal-dependent covariance matrices (false uses identity matrix).",
206  true);
207  addParam("RegParam1", m_u1, "u1 parameter for regularization function).", 1.0);
208 }
209 
211 {
212 }
213 
215 {
216 
217  m_TemplatesLoaded = true;
218 
219  if (m_IsMCFlag == 0) {
220  //load data templates
221  std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
222  for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++) {
223  for (int j = 0; j < 11; j++) {
224  Ptemp[j] = (double)m_WaveformParameters->getPhotonParameters(i + 1)[j];
225  Htemp[j] = (double)m_WaveformParameters->getHadronParameters(i + 1)[j];
226  Dtemp[j] = (double)m_WaveformParameters->getDiodeParameters(i + 1)[j];
227  }
228  new (&m_SignalInterpolation[i][0]) SignalInterpolation2(Ptemp);
229  new (&m_SignalInterpolation[i][1]) SignalInterpolation2(Htemp);
230  new (&m_SignalInterpolation[i][2]) SignalInterpolation2(Dtemp);
231  }
232  } else {
233  //load mc template
234  std::vector<double> Ptemp(11), Htemp(11), Dtemp(11);
235  for (int j = 0; j < 11; j++) {
236  Ptemp[j] = (double)m_WaveformParametersForMC->getPhotonParameters()[j];
237  Htemp[j] = (double)m_WaveformParametersForMC->getHadronParameters()[j];
238  Dtemp[j] = (double)m_WaveformParametersForMC->getDiodeParameters()[j];
239  }
240  new (&m_SignalInterpolation[0][0]) SignalInterpolation2(Ptemp);
241  new (&m_SignalInterpolation[0][1]) SignalInterpolation2(Htemp);
242  new (&m_SignalInterpolation[0][2]) SignalInterpolation2(Dtemp);
243  }
244 }
245 
247 {
248 
249  m_IsMCFlag = Environment::Instance().isMC();
250  m_TemplatesLoaded = false;
251 
252  m_ADCtoEnergy.resize(ECLElementNumbers::c_NCrystals);
253  if (m_CrystalElectronics.isValid()) {
254  for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++)
255  m_ADCtoEnergy[i] = m_CrystalElectronics->getCalibVector()[i];
256  }
257  if (m_CrystalEnergy.isValid()) {
258  for (int i = 0; i < ECLElementNumbers::c_NCrystals; i++)
259  m_ADCtoEnergy[i] *= m_CrystalEnergy->getCalibVector()[i];
260  }
261 
262  /* Load covariance matrices from database. */
263  if (m_CovarianceMatrix) {
264  for (int id = 1; id <= ECLElementNumbers::c_NCrystals; id++) {
265  double buf[c_NFitPoints];
266  double reg[c_NFitPoints];
267  m_AutoCovariance->getAutoCovariance(id, buf);
268  double x0 = c_NFitPoints;
269  std::memcpy(reg, buf, c_NFitPoints * sizeof(double));
270  bool invertSuccess = makecovariance(m_PackedCovariance[id - 1], c_NFitPoints, reg);
271  double param_u2 = 1.0;
272  int idToLoad = id;
273  while (invertSuccess == false) {
274 
275  /* as x0-=1 iterates off-diagonal are suppressed. */
276  regularize(buf, reg, c_NFitPoints, x0 -= 1, m_u1, param_u2);
277  invertSuccess = makecovariance(m_PackedCovariance[id - 1], c_NFitPoints, reg);
278 
279  /* set off-diagonals to zero for final attempt*/
280  if (x0 == 1) param_u2 = 0.0;
281 
282  /* Indicates problem with matrix as identity should be invertible*/
283  if (x0 == 0) {
284  B2WARNING("Could not invert matrix for id " << id);
285  B2WARNING("Loading neighbour matrix for id " << id);
286  if (idToLoad > 1) {
287  m_AutoCovariance->getAutoCovariance(idToLoad = -1, buf);
288  } else {
289  m_AutoCovariance->getAutoCovariance(idToLoad += 1, buf);
290  }
291  std::memcpy(reg, buf, c_NFitPoints * sizeof(double));
292  }
293 
294  }
295  }
296  } else {
297  /* Default covariance matrix is identity for all crystals. */
298  double defaultCovariance[c_NFitPoints][c_NFitPoints];
299  CovariancePacked packedDefaultCovariance;
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;
304  }
305  }
306  int k = 0;
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];
310  k++;
311  }
312  }
313  ecl_waveform_fit_load_inverse_covariance(
314  packedDefaultCovariance.m_covMatPacked);
315  }
316 
317 }
318 
320 {
321  // ECL dataobjects
322  m_eclDSPs.isRequired();
323  m_eclDigits.isRequired();
324  // While we set a relation from ECLDsps to ECLDigits here, the relation
325  // is already register in previous modules: let's require it here
326  m_eclDSPs.registerRelationTo(m_eclDigits);
327 
328  //initializing fit minimizer
329  m_MinuitPhotonHadron = new TMinuit(4);
330  m_MinuitPhotonHadron->SetFCN(fcnPhotonHadron);
331  double arglist[10];
332  int ierflg = 0;
333  arglist[0] = -1;
334  m_MinuitPhotonHadron->mnexcm("SET PRIntout", arglist, 1, ierflg);
335  m_MinuitPhotonHadron->mnexcm("SET NOWarnings", arglist, 0, ierflg);
336  arglist[0] = 1;
337  m_MinuitPhotonHadron->mnexcm("SET ERR", arglist, 1, ierflg);
338  arglist[0] = 0;
339  m_MinuitPhotonHadron->mnexcm("SET STRategy", arglist, 1, ierflg);
340  arglist[0] = 1;
341  m_MinuitPhotonHadron->mnexcm("SET GRAdient", arglist, 1, ierflg);
342  arglist[0] = 1e-6;
343  m_MinuitPhotonHadron->mnexcm("SET EPSmachine", arglist, 1, ierflg);
344 
345  //initializing fit minimizer photon+hadron + background photon
346  m_MinuitPhotonHadronBackgroundPhoton = new TMinuit(6);
347  m_MinuitPhotonHadronBackgroundPhoton->SetFCN(fcnPhotonHadronBackgroundPhoton);
348  arglist[0] = -1;
349  m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET PRIntout", arglist, 1, ierflg);
350  m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET NOWarnings", arglist, 0, ierflg);
351  arglist[0] = 1;
352  m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET ERR", arglist, 1, ierflg);
353  arglist[0] = 0;
354  m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET STRategy", arglist, 1, ierflg);
355  arglist[0] = 1;
356  m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET GRAdient", arglist, 1, ierflg);
357  arglist[0] = 1e-6;
358  m_MinuitPhotonHadronBackgroundPhoton->mnexcm("SET EPSmachine", arglist, 1, ierflg);
359 
360  //flag for callback to load templates each run
361  m_TemplatesLoaded = false;
362 }
363 
365 {
367 
368  if (!m_TemplatesLoaded) {
369  /* Load templates once per run in first event that has saved waveforms. */
370  if (m_eclDSPs.getEntries() > 0)
371  loadTemplateParameterArray();
372  }
373 
374  for (ECLDsp& aECLDsp : m_eclDSPs) {
375 
376  aECLDsp.setTwoComponentTotalAmp(-1);
377  aECLDsp.setTwoComponentHadronAmp(-1);
378  aECLDsp.setTwoComponentDiodeAmp(-1);
379  aECLDsp.setTwoComponentChi2(-1);
380  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, -1);
381  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton, -1);
382  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, -1);
383  aECLDsp.setTwoComponentTime(-1);
384  aECLDsp.setTwoComponentBaseline(-1);
385  aECLDsp.setTwoComponentFitType(ECLDsp::poorChi2);
386 
387  const int id = aECLDsp.getCellId() - 1;
388 
389  // Filling array with ADC values.
390  for (int j = 0; j < ec.m_nsmp; j++)
391  fitA[j] = aECLDsp.getDspA()[j];
392 
393  //setting relation of eclDSP to aECLDigit
394  const ECLDigit* d = nullptr;
395  for (const ECLDigit& aECLDigit : m_eclDigits) {
396  if (aECLDigit.getCellId() - 1 == id) {
397  d = &aECLDigit;
398  aECLDsp.addRelationTo(&aECLDigit);
399  break;
400  }
401  }
402  if (d == nullptr)
403  continue;
404 
405  //Skipping low amplitude waveforms
406  if (d->getAmp() * m_ADCtoEnergy[id] < m_EnergyThreshold)
407  continue;
408 
409  //loading template for waveform
410  if (m_IsMCFlag == 0) {
411  //data cell id dependent
412  g_PhotonSignal = &m_SignalInterpolation[id][0];
413  g_HadronSignal = &m_SignalInterpolation[id][1];
414  } else {
415  // mc uses same waveform
416  g_PhotonSignal = &m_SignalInterpolation[0][0];
417  g_HadronSignal = &m_SignalInterpolation[0][1];
418  }
419 
420  //get covariance matrix for cell id
421  if (m_CovarianceMatrix) {
422  ecl_waveform_fit_load_inverse_covariance(
423  m_PackedCovariance[id].m_covMatPacked);
424  aNoise = m_PackedCovariance[id].sigma;
425  }
426 
427  /* Fit with photon and hadron templates (fit type = 0). */
428  double pedestal, amplitudePhoton, signalTime, amplitudeHadron,
429  amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2;
431  chi2 = -1;
432  fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
433  chi2);
434  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, chi2);
435 
436  /* If failed, try photon, hadron, and background photon (fit type = 1). */
437  if (chi2 >= m_Chi2Threshold27dof) {
438 
440  chi2 = -1;
441  fitPhotonHadronBackgroundPhoton(
442  pedestal, amplitudePhoton, signalTime, amplitudeHadron,
443  amplitudeBackgroundPhoton, timeBackgroundPhoton, chi2);
444  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton,
445  chi2);
446 
447  /* If failed, try diode fit (fit type = 2). */
448  if (chi2 >= m_Chi2Threshold25dof) {
449  /* Set second component to diode. */
450  g_HadronSignal = &m_SignalInterpolation[0][2];
451  fitType = ECLDsp::photonDiodeCrossing;
452  chi2 = -1;
453  fitPhotonHadron(pedestal, amplitudePhoton, signalTime, amplitudeHadron,
454  chi2);
455  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, chi2);
456 
457  /* Indicates that all fits tried had bad chi^2. */
458  if (chi2 >= m_Chi2Threshold27dof)
459  fitType = ECLDsp::poorChi2;
460  }
461 
462  }
463 
464  /* Storing fit results. */
465  aECLDsp.setTwoComponentTotalAmp(amplitudePhoton + amplitudeHadron);
466  if (fitType == ECLDsp::photonDiodeCrossing) {
467  aECLDsp.setTwoComponentHadronAmp(0.0);
468  aECLDsp.setTwoComponentDiodeAmp(amplitudeHadron);
469  } else {
470  aECLDsp.setTwoComponentHadronAmp(amplitudeHadron);
471  aECLDsp.setTwoComponentDiodeAmp(0.0);
472  }
473  aECLDsp.setTwoComponentChi2(chi2);
474  aECLDsp.setTwoComponentTime(signalTime);
475  aECLDsp.setTwoComponentBaseline(pedestal);
476  aECLDsp.setTwoComponentFitType(fitType);
477  if (fitType == ECLDsp::photonHadronBackgroundPhoton) {
478  aECLDsp.setbackgroundPhotonEnergy(amplitudeBackgroundPhoton);
479  aECLDsp.setbackgroundPhotonTime(timeBackgroundPhoton);
480  }
481  }
482 }
483 
485 {
486 }
487 
489 {
490 }
491 
493  double& pedestal, double& amplitudePhoton, double& signalTime,
494  double& amplitudeHadron, double& chi2)
495 {
496  //minuit parameters
497  double arglist[10] = {0};
498  int ierflg = 0;
499 
500  /* Setting initial fit parameters. */
501  double dt = 0.5;
502  double amax = 0;
503  int jmax = 6;
504  for (int j = 0; j < c_NFitPoints; j++) {
505  if (amax < fitA[j]) {
506  amax = fitA[j];
507  jmax = j;
508  }
509  }
510  double sumB0 = 0;
511  int jsum = 0;
512  for (int j = 0; j < c_NFitPoints; j++) {
513  if (j < jmax - 3 || jmax + 4 < j) {
514  sumB0 += fitA[j];
515  ++jsum;
516  }
517  }
518  double B0 = sumB0 / jsum;
519  amax -= B0;
520  if (amax < 0)
521  amax = 10;
522  double T0 = dt * (4.5 - jmax);
523  double A0 = amax;
524 
525  //initialize minimizer
526  m_MinuitPhotonHadron->mnparm(0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
527  m_MinuitPhotonHadron->mnparm(1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
528  m_MinuitPhotonHadron->mnparm(2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
529  m_MinuitPhotonHadron->mnparm(3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
530 
531  //perform fit
532  arglist[0] = 50000;
533  arglist[1] = 1.;
534  m_MinuitPhotonHadron->mnexcm("MIGRAD", arglist, 2, ierflg);
535 
536  double edm, errdef;
537  int nvpar, nparx, icstat;
538  m_MinuitPhotonHadron->mnstat(chi2, edm, errdef, nvpar, nparx, icstat);
539 
540  //get fit results
541  double error;
542  m_MinuitPhotonHadron->GetParameter(0, pedestal, error);
543  m_MinuitPhotonHadron->GetParameter(1, amplitudePhoton, error);
544  m_MinuitPhotonHadron->GetParameter(2, signalTime, error);
545  m_MinuitPhotonHadron->GetParameter(3, amplitudeHadron, error);
546 }
547 
549  double& pedestal, double& amplitudePhoton, double& signalTime,
550  double& amplitudeHadron, double& amplitudeBackgroundPhoton,
551  double& timeBackgroundPhoton, double& chi2)
552 {
553  double arglist[10] = {0};
554  int ierflg = 0;
555  double dt = 0.5;
556  double amax = 0; int jmax = 6;
557  for (int j = 0; j < c_NFitPoints; j++) {
558  if (amax < fitA[j]) {
559  amax = fitA[j];
560  jmax = j;
561  }
562  }
563 
564  double amax1 = 0; int jmax1 = 6;
565  for (int j = 0; j < c_NFitPoints; j++) {
566  if (j < jmax - 3 || jmax + 4 < j) {
567  if (j == 0) {
568  if (amax1 < fitA[j] && fitA[j + 1] < fitA[j]) {
569  amax1 = fitA[j];
570  jmax1 = j;
571  }
572  } else if (j == 30) {
573  if (amax1 < fitA[j] && fitA[j - 1] < fitA[j]) {
574  amax1 = fitA[j];
575  jmax1 = j;
576  }
577  } else {
578  if (amax1 < fitA[j] && fitA[j + 1] < fitA[j] && fitA[j - 1] < fitA[j]) {
579  amax1 = fitA[j];
580  jmax1 = j;
581  }
582  }
583  }
584  }
585 
586  double sumB0 = 0;
587  int jsum = 0;
588  for (int j = 0; j < c_NFitPoints; j++) {
589  if ((j < jmax - 3 || jmax + 4 < j) && (j < jmax1 - 3 || jmax1 + 4 < j)) {
590  sumB0 += fitA[j];
591  ++jsum;
592  }
593  }
594  double B0 = sumB0 / jsum;
595  amax -= B0;
596  amax = std::max(10.0, amax);
597  amax1 -= B0;
598  amax1 = std::max(10.0, amax1);
599  double T0 = dt * (4.5 - jmax);
600  double T01 = dt * (4.5 - jmax1);
601 
602  double A0 = amax, A01 = amax1;
603  m_MinuitPhotonHadronBackgroundPhoton->mnparm(
604  0, "B", B0, 10, B0 / 1.5, B0 * 1.5, ierflg);
605  m_MinuitPhotonHadronBackgroundPhoton->mnparm(
606  1, "Ag", A0, A0 / 20, 0, 2 * A0, ierflg);
607  m_MinuitPhotonHadronBackgroundPhoton->mnparm(
608  2, "T", T0, 0.5, T0 - 2.5, T0 + 2.5, ierflg);
609  m_MinuitPhotonHadronBackgroundPhoton->mnparm(
610  3, "Ah", 0., A0 / 20, -A0, 2 * A0, ierflg);
611  m_MinuitPhotonHadronBackgroundPhoton->mnparm(
612  4, "A2", A01, A01 / 20, 0, 2 * A01, ierflg);
613  m_MinuitPhotonHadronBackgroundPhoton->mnparm(
614  5, "T2", T01, 0.5, T01 - 2.5, T01 + 2.5, ierflg);
615 
616  // Now ready for minimization step
617  arglist[0] = 50000;
618  arglist[1] = 1.;
619  m_MinuitPhotonHadronBackgroundPhoton->mnexcm("MIGRAD", arglist, 2, ierflg);
620 
621  double edm, errdef;
622  int nvpar, nparx, icstat;
623  m_MinuitPhotonHadronBackgroundPhoton->mnstat(chi2, edm, errdef, nvpar, nparx, icstat);
624  double error;
625  m_MinuitPhotonHadronBackgroundPhoton->GetParameter(0, pedestal, error);
626  m_MinuitPhotonHadronBackgroundPhoton->GetParameter(1, amplitudePhoton, error);
627  m_MinuitPhotonHadronBackgroundPhoton->GetParameter(2, signalTime, error);
628  m_MinuitPhotonHadronBackgroundPhoton->GetParameter(3, amplitudeHadron, error);
629  m_MinuitPhotonHadronBackgroundPhoton->GetParameter(
630  4, amplitudeBackgroundPhoton, error);
631  m_MinuitPhotonHadronBackgroundPhoton->GetParameter(
632  5, timeBackgroundPhoton, error);
633 }
634 
635 SignalInterpolation2::SignalInterpolation2(const std::vector<double>& s)
636 {
637  double T0 = -0.2;
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]);
641 
642  ShaperDSP_t dsp(p, s[0]);
643  dsp.settimestride(c_dtn);
644  dsp.settimeseed(T0);
645  dd_t t[(c_nt + c_ntail)*c_ndt];
646  dsp.fillarray(sizeof(t) / sizeof(t[0]), t);
647 
648  for (int i = 0; i < c_nt * c_ndt; i++) {
649  m_FunctionInterpolation[i] = t[i].first;
650  m_DerivativeInterpolation[i] = t[i].second;
651  }
652  for (int i = 0; i < c_ntail; i++) {
653  int j = c_nt * c_ndt + i;
654  int k = c_nt * c_ndt + i * c_ndt;
655  m_FunctionInterpolation[j] = t[k].first;
656  m_DerivativeInterpolation[j] = t[k].second;
657  }
658  int i1 = c_nt * c_ndt + c_ntail - 2;
659  int i2 = c_nt * c_ndt + c_ntail - 1;
660  m_r0 = m_FunctionInterpolation[i2] / m_FunctionInterpolation[i1];
661  m_r1 = m_DerivativeInterpolation[i2] / m_DerivativeInterpolation[i1];
662 }
663 
665  double t0, double* function, double* derivatives) const
666 {
667  /* If before pulse start time (negative times), return 0. */
668  int k = 0;
669  while (t0 < 0) {
670  function[k] = 0;
671  derivatives[k] = 0;
672  t0 += c_dt;
673  ++k;
674  if (k >= c_NFitPoints)
675  return;
676  }
677 
678  /* Function and derivative values. */
679  double function0[c_NFitPoints], function1[c_NFitPoints];
680  double derivative0[c_NFitPoints], derivative1[c_NFitPoints];
681 
682  /* Interpolate first c_nt points (short time steps). */
683  double x = t0 * c_idtn;
684  double ix = floor(x);
685  double w = x - ix;
686  int j = ix;
687  double w2 = w * w;
688  double hw2 = 0.5 * w2;
689  double tw3 = ((1. / 6) * w) * w2;
690 
691  /* Number of interpolation points. */
692  int iMax = k + c_nt;
693  if (iMax > c_NFitPoints)
694  iMax = c_NFitPoints;
695 
696  /* Fill interpolation points. */
697  for (int i = k; i < iMax; ++i) {
698  function0[i] = m_FunctionInterpolation[j];
699  function1[i] = m_FunctionInterpolation[j + 1];
700  derivative0[i] = m_DerivativeInterpolation[j];
701  derivative1[i] = m_DerivativeInterpolation[j + 1];
702  j = j + c_ndt;
703  }
704 
705  /* Interpolation. */
706  #pragma omp simd
707  for (int i = k; i < iMax; ++i) {
708  double a[4];
709  double dfdt = (function1[i] - function0[i]) * c_idtn;
710  double fp = derivative1[i] + derivative0[i];
711  a[0] = function0[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;
719  }
720  t0 = t0 + c_dt * c_nt;
721  if (iMax == c_NFitPoints)
722  return;
723  k = iMax;
724 
725  /* Interpolate next c_ntail points (long time steps). */
726  x = t0 * c_idt;
727  ix = floor(x);
728  w = x - ix;
729  w2 = w * w;
730  hw2 = 0.5 * w2;
731  tw3 = ((1. / 6) * w) * w2;
732 
733  /* Number of interpolation points. */
734  iMax = k + c_ntail - 1;
735  if (iMax > c_NFitPoints)
736  iMax = c_NFitPoints;
737 
738  /* Interpolation. */
739  #pragma omp simd
740  for (int i = k; i < iMax; ++i) {
741  j = c_nt * c_ndt + i - k;
742  /*
743  * The interpolation step is the same as the distance between
744  * the fit points. It is possible to load the values in the interpolation
745  * loop while keeping its vectorization.
746  */
747  double f0 = m_FunctionInterpolation[j];
748  double f1 = m_FunctionInterpolation[j + 1];
749  double fp0 = m_DerivativeInterpolation[j];
750  double fp1 = m_DerivativeInterpolation[j + 1];
751  double a[4];
752  double dfdt = (f1 - f0) * c_idt;
753  double fp = fp1 + fp0;
754  a[0] = f0;
755  a[1] = 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;
762  }
763  if (iMax == c_NFitPoints)
764  return;
765  k = iMax;
766 
767  /* Exponential tail. */
768  while (k < c_NFitPoints) {
769  function[k] = function[k - 1] * m_r0;
770  derivatives[k] = derivatives[k - 1] * m_r1;
771  ++k;
772  }
773 }
774 
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
Class to store ECL ShaperDSP waveform ADC data.
Definition: ECLDsp.h:25
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
virtual void initialize() override
Initialize variables.
virtual void event() override
event per event.
virtual void endRun() override
end run.
void fitPhotonHadronBackgroundPhoton(double &pedestal, double &amplitudePhoton, double &signalTime, double &amplitudeHadron, double &amplitudeBackgroundPhoton, double &timeBackgroundPhoton, double &chi2)
Fit with photon, hadron, and background photon.
virtual void terminate() override
terminate.
void loadTemplateParameterArray()
Loads waveform templates from database.
virtual void beginRun() override
begin run.
void fitPhotonHadron(double &pedestal, double &amplitudePhoton, double &signalTime, double &amplitudeHadron, double &chi2)
Fit with photon and hadron.
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.