Belle II Software  release-06-01-15
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 // ECL
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>
17 
18 //FRAMEWORK
19 #include <framework/core/Environment.h>
20 #include <framework/database/DBObjPtr.h>
21 
22 //ROOT
23 #include <TMinuit.h>
24 #include <TMatrixD.h>
25 #include <TMatrixDSym.h>
26 #include <TDecompChol.h>
27 
28 #include <numeric>
29 
30 using namespace Belle2;
31 using namespace ECL;
32 
33 //-----------------------------------------------------------------
34 // Register the Modules
35 //-----------------------------------------------------------------
36 REG_MODULE(ECLWaveformFit)
37 //-----------------------------------------------------------------
38 // Implementation
39 //-----------------------------------------------------------------
40 
41 //anonymous namespace for data objects used by both ECLWaveformFitModule class and FCN2h funciton for MINUIT minimization.
42 namespace {
43 
44  //adc data array
45  std::vector<double> fitA(31);
46 
47  //g_si: photon template signal shape
48  //g_sih: hadron template signal shape
49  const SignalInterpolation2* g_si;
50  const SignalInterpolation2* g_sih;
51 
52  // covariance matrix and noise level
53  std::vector< std::vector<double> > currentCovMat;
54  double aNoise;
55 
56  //Function to minimize in photon template + hadron template fit. (chi2)
57  void FCN2h(int&, double* grad, double& f, double* p, int)
58  {
59  constexpr int N = 31;
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;
64 
65  //getting photon and hadron component shapes for set of fit parameters
66  val_der_t ADg[N], ADh[N];
67  g_si->getshape(T, ADg);
68  g_sih->getshape(T, ADh);
69 
70  //computing difference between current fit result and adc data array
71  for (int i = 0; i < N; ++i) df[i] = fitA[i] - (Ag * ADg[i].f0 + Ah * ADh[i].f0 + B);
72 
73  //computing chi2.
74  for (int i = 0; i < N; ++i) da[i] = std::inner_product(currentCovMat[i].begin(), currentCovMat[i].end(), df.begin(), 0.0);
75 
76  for (int i = 0; i < N; ++i) {
77  chi2 += da[i] * df[i];
78  gB -= da[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;
82  }
83 
84  f = chi2;
85  grad[0] = 2 * gB;
86  grad[1] = 2 * gAg;
87  grad[2] = 2 * gT;
88  grad[3] = 2 * gAh;
89  }
90 
91  //Function to minimize in photon template + hadron template + background photon fit. (chi2)
92  void FCN2h2(int&, double* grad, double& f, double* p, int)
93  {
94  const int N = 31;
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;
101 
102  //getting photon and hadron component shapes for set of fit parameters
103  val_der_t ADg[N], AD2[N], ADh[N];
104  g_si->getshape(T, ADg);
105  g_si->getshape(T2, AD2);//background photon
106  g_sih->getshape(T, ADh);
107 
108  //computing difference between current fit result and adc data array
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);
110 
111  //computing chi2.
112  for (int i = 0; i < N; ++i) da[i] = std::inner_product(currentCovMat[i].begin(), currentCovMat[i].end(), df.begin(), 0.0);
113 
114  for (int i = 0; i < N; ++i) {
115  chi2 += da[i] * df[i];
116  gB -= da[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);;
120 
121  gA2 -= da[i] * AD2[i].f0;
122  gT2 -= da[i] * AD2[i].f1 * A2;
123  }
124  f = chi2;
125  grad[0] = 2 * gB;
126  grad[1] = 2 * gAg;
127  grad[2] = 2 * gT;
128  grad[3] = 2 * gAh;
129  grad[4] = 2 * gA2;
130  grad[5] = 2 * gT2;
131  }
132 
133  // regularize autocovariance function by multipling it by the step
134  // function so elements above u0 become 0 and below are untouched.
135  void regularize(double* dst, const double* src, const int n, const double u0 = 13.0, const double u1 = 0.8)
136  {
137  for (int k = 0; k < n; k++) dst[k] = src[k] / (1 + exp((k - u0) / u1));
138  }
139 
140  // transform autocovariance function of 31 elements to the covariance matrix
141  bool makecovariance(CovariancePacked& M, const int nnoise, const double* acov)
142  {
143  const int ns = 31;
144  TMatrixDSym E(ns);
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];
148 
149  TDecompChol dc(E);
150  const bool status = dc.Invert(E);
151 
152  if (status) {
153  int count = 0;
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]);
158  }
159  return status;
160  }
161 
162  // to save space we keep only upper triangular part of the covariance matrix in float format
163  // here we inflate it to full square form in double format
164  void unpackcovariance(const CovariancePacked& matrixPacked)
165  {
166  const int ns = 31;
167  int count = 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++];
174  }
175  }
176  aNoise = matrixPacked.sigma;
177  }
178 
179 }
180 
181 // constructor
183 {
184  // Set module properties
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);
192 }
193 
194 // destructor
196 {
197 }
198 
199 //callback for loading templates from database
201 {
202 
203  m_TemplatesLoaded = true;
204 
205  if (m_IsMCFlag == 0) {
206  //load data templates
207  DBObjPtr<ECLDigitWaveformParameters> WavePars("ECLDigitWaveformParameters");
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];
214  }
215  new(&m_si[i][0]) SignalInterpolation2(Ptemp);
216  new(&m_si[i][1]) SignalInterpolation2(Htemp);
217  new(&m_si[i][2]) SignalInterpolation2(Dtemp);
218  }
219  } else {
220  //load mc template
221  DBObjPtr<ECLDigitWaveformParametersForMC> WaveParsMC("ECLDigitWaveformParametersForMC");
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];
227  }
228  new(&m_si[0][0]) SignalInterpolation2(Ptemp);
229  new(&m_si[0][1]) SignalInterpolation2(Htemp);
230  new(&m_si[0][2]) SignalInterpolation2(Dtemp);
231  }
232 }
233 
235 {
236 
237  m_IsMCFlag = Environment::Instance().isMC();
238  m_TemplatesLoaded = false;
239 
240  DBObjPtr<ECLCrystalCalib> Ael("ECLCrystalElectronics"), Aen("ECLCrystalEnergy");
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];
244 
245  //Load covariance matricies from database;
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());
253  double x0 = N;
254  reg = buf;
255  while (!makecovariance(m_c[id - 1], N, reg.data()))
256  regularize(buf.data(), reg.data(), N, x0 -= 1, 1);
257  }
258  } else {
259  //default covariance matrix is identity for all crystals
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;
267  }
268  }
269  }
270 
271 }
272 
274 {
275  // ECL dataobjects
276  m_eclDSPs.registerInDataStore();
277  m_eclDigits.registerInDataStore();
278 
279  //initializing fit minimizer
280  m_Minit2h = new TMinuit(4);
281  m_Minit2h->SetFCN(FCN2h);
282  double arglist[10];
283  int ierflg = 0;
284  arglist[0] = -1;
285  m_Minit2h->mnexcm("SET PRIntout", arglist, 1, ierflg);
286  m_Minit2h->mnexcm("SET NOWarnings", arglist, 0, ierflg);
287  arglist[0] = 1;
288  m_Minit2h->mnexcm("SET ERR", arglist, 1, ierflg);
289  arglist[0] = 0;
290  m_Minit2h->mnexcm("SET STRategy", arglist, 1, ierflg);
291  arglist[0] = 1;
292  m_Minit2h->mnexcm("SET GRAdient", arglist, 1, ierflg);
293  arglist[0] = 1e-6;
294  m_Minit2h->mnexcm("SET EPSmachine", arglist, 1, ierflg);
295 
296  //initializing fit minimizer photon+hadron + background photon
297  m_Minit2h2 = new TMinuit(6);
298  m_Minit2h2->SetFCN(FCN2h2);
299  arglist[0] = -1;
300  m_Minit2h2->mnexcm("SET PRIntout", arglist, 1, ierflg);
301  m_Minit2h2->mnexcm("SET NOWarnings", arglist, 0, ierflg);
302  arglist[0] = 1;
303  m_Minit2h2->mnexcm("SET ERR", arglist, 1, ierflg);
304  arglist[0] = 0;
305  m_Minit2h2->mnexcm("SET STRategy", arglist, 1, ierflg);
306  arglist[0] = 1;
307  m_Minit2h2->mnexcm("SET GRAdient", arglist, 1, ierflg);
308  arglist[0] = 1e-6;
309  m_Minit2h2->mnexcm("SET EPSmachine", arglist, 1, ierflg);
310 
311  //flag for callback to load templates each run
312  m_TemplatesLoaded = false;
313 }
314 
316 {
318 
319  if (!m_TemplatesLoaded) {
320  //load templates once per run in first event that has saved waveforms.
321  if (m_eclDSPs.getEntries() > 0) loadTemplateParameterArray();
322  }
323 
324  for (auto& aECLDsp : m_eclDSPs) {
325 
326  aECLDsp.setTwoComponentTotalAmp(-1);
327  aECLDsp.setTwoComponentHadronAmp(-1);
328  aECLDsp.setTwoComponentDiodeAmp(-1);
329  aECLDsp.setTwoComponentChi2(-1);
330  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, -1);
331  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton, -1);
332  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, -1);
333  aECLDsp.setTwoComponentTime(-1);
334  aECLDsp.setTwoComponentBaseline(-1);
335  aECLDsp.setTwoComponentFitType(ECLDsp::poorChi2);
336 
337  const int id = aECLDsp.getCellId() - 1;
338 
339  //Filling array with ADC values.
340  for (int j = 0; j < ec.m_nsmp; j++) fitA[j] = aECLDsp.getDspA()[j];
341 
342  //setting relation of eclDSP to aECLDigit
343  const ECLDigit* d = nullptr;
344  for (const auto& aECLDigit : m_eclDigits) {
345  if (aECLDigit.getCellId() - 1 == id) {
346  d = &aECLDigit;
347  aECLDsp.addRelationTo(&aECLDigit);
348  break;
349  }
350  }
351  if (d == nullptr) continue;
352 
353  //Skipping low amplitude waveforms
354  if (d->getAmp() * m_ADCtoEnergy[id] < m_EnergyThreshold) continue;
355 
356  //loading template for waveform
357  if (m_IsMCFlag == 0) {
358  //data cell id dependent
359  g_si = &m_si[id][0];
360  g_sih = &m_si[id][1];
361  } else {
362  // mc uses same waveform
363  g_si = &m_si[0][0];
364  g_sih = &m_si[0][1];
365  }
366 
367  //get covariance matrix for cell id
368  if (m_CovarianceMatrix) unpackcovariance(m_c[id]);
369 
370  //Calling optimized fit photon template + hadron template (fit type = 0)
371  double p2_b, p2_a, p2_t, p2_a1, p2_chi2, p_extraPhotonEnergy, p_extraPhotonTime;
373  p2_chi2 = -1;
374  Fit2h(p2_b, p2_a, p2_t, p2_a1, p2_chi2);
375  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadron, p2_chi2);
376 
377  //if hadron fit failed try hadron + background photon (fit type = 1)
378  if (p2_chi2 >= m_chi2Threshold27dof) {
379 
381  p2_chi2 = -1;
382  Fit2hExtraPhoton(p2_b, p2_a, p2_t, p2_a1, p_extraPhotonEnergy, p_extraPhotonTime, p2_chi2);
383  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonHadronBackgroundPhoton, p2_chi2);
384 
385  //hadron + background photon fit failed try diode fit (fit type = 2)
386  if (p2_chi2 >= m_chi2Threshold25dof) {
387  g_sih = &m_si[0][2];//set second component to diode
388  fitType = ECLDsp::photonDiodeCrossing;
389  p2_chi2 = -1;
390  Fit2h(p2_b, p2_a, p2_t, p2_a1, p2_chi2);
391  aECLDsp.setTwoComponentSavedChi2(ECLDsp::photonDiodeCrossing, p2_chi2);
392 
393  if (p2_chi2 >= m_chi2Threshold27dof) fitType = ECLDsp::poorChi2; //indicates all fits tried had bad chi2
394  }
395 
396  }
397 
398  //storing fit results
399  aECLDsp.setTwoComponentTotalAmp(p2_a + p2_a1);
400  if (fitType == ECLDsp::photonDiodeCrossing) {
401  aECLDsp.setTwoComponentHadronAmp(0.0);
402  aECLDsp.setTwoComponentDiodeAmp(p2_a1);
403  } else {
404  aECLDsp.setTwoComponentHadronAmp(p2_a1);
405  aECLDsp.setTwoComponentDiodeAmp(0.0);
406  }
407  aECLDsp.setTwoComponentChi2(p2_chi2);
408  aECLDsp.setTwoComponentTime(p2_t);
409  aECLDsp.setTwoComponentBaseline(p2_b);
410  aECLDsp.setTwoComponentFitType(fitType);
411  if (fitType == ECLDsp::photonHadronBackgroundPhoton) {
412  aECLDsp.setbackgroundPhotonEnergy(p_extraPhotonEnergy);
413  aECLDsp.setbackgroundPhotonTime(p_extraPhotonTime);
414  }
415  }
416 }
417 
418 // end run
420 {
421 }
422 
423 // terminate
425 {
426 }
427 
428 //Two component fit. Fits photon+hadron component hypothesis
429 void ECLWaveformFitModule::Fit2h(double& B, double& Ag, double& T, double& Ah, double& amin)
430 {
431  //minuit parameters
432  double arglist[10];
433  int ierflg = 0;
434 
435  // setting inital fit parameters
436  double dt = 0.5;
437  double amax = 0;
438  int jmax = 6;
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;
443  amax -= B0;
444  if (amax < 0) amax = 10;
445  double T0 = dt * (4.5 - jmax);
446  double A0 = amax;
447 
448  //initalize minimizer
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);
453 
454  //perform fit
455  arglist[0] = 50000;
456  arglist[1] = 1.;
457  m_Minit2h->mnexcm("MIGRAD", arglist, 2, ierflg);
458 
459  double edm, errdef;
460  int nvpar, nparx, icstat;
461  m_Minit2h->mnstat(amin, edm, errdef, nvpar, nparx, icstat);
462 
463  //get fit results
464  double ep;
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);
469 }
470 
471 //Two component fit background ith extra photon. Fits photon+hadron component + extra photon hypothesis
472 void ECLWaveformFitModule::Fit2hExtraPhoton(double& B, double& Ag, double& T, double& Ah, double& A2, double& T2, double& amin)
473 {
474  double arglist[10];
475  int ierflg = 0;
476  double dt = 0.5;
477  double amax = 0; int jmax = 6;
478  for (int j = 0; j < 31; j++) if (amax < fitA[j]) { amax = fitA[j]; jmax = j;}
479 
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;}
486  }
487 
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);
495 
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);
503 
504  // Now ready for minimization step
505  arglist[0] = 50000;
506  arglist[1] = 1.;
507  m_Minit2h2->mnexcm("MIGRAD", arglist, 2, ierflg);
508 
509  double edm, errdef;
510  int nvpar, nparx, icstat;
511  m_Minit2h2->mnstat(amin, edm, errdef, nvpar, nparx, icstat);
512  double ep;
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);
519 }
520 
521 
522 
523 //Signal interpolation code used for fast evaluation of shaperDSP templates
524 SignalInterpolation2::SignalInterpolation2(const std::vector<double>& s)
525 {
526  double T0 = -0.2;
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]);
530 
531  ShaperDSP_t dsp(p, s[0]);
532  dsp.settimestride(c_dtn);
533  dsp.settimeseed(T0);
534  dd_t t[(c_nt + c_ntail)*c_ndt];
535  dsp.fillarray(sizeof(t) / sizeof(t[0]), t);
536 
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;
542 }
543 
548 void SignalInterpolation2::getshape(double t0, val_der_t* A) const
549 {
550  const int iend0 = c_nt * c_ndt, iend1 = c_nt * c_ndt + c_ntail;
551  const val_der_t* Aend = A + 31;
552 
553  //if before pulse start time (negative times) return 0
554  while (t0 < 0) {
555  *A = {0, 0, 0};
556  if (++A >= Aend) return;
557  t0 += c_dt;
558  }
559 
560  //function below evaluates the template value and the first and second derivative values for the point.
561  double x = t0 * c_idtn, ix = floor(x), w = x - ix;
562  int i = 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) {
565  double a[4],
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;
569 
570  a[0] = f0;
571  a[1] = fp0;
572  a[2] = -((fp + fp0) - 3 * dfdt);
573  a[3] = ((fp) - 2 * dfdt);
574 
575  double b2 = 2 * a[2], b3 = 6 * a[3];
576  val_der_t y;
577  y.f0 = a[0] + dt * (a[1] * w + b2 * hw2 + b3 * tw3); //function value
578  y.f1 = a[1] + b2 * w + b3 * hw2; // first derivative of function value
579  y.f2 = (b2 + b3 * w) * idt; //second derivative of function value
580  return y;
581  };
582 
583  //signal interpolation for short time steps used for points at the beginning of the pulse where the pulse is quickly changing (eg rise)
584  //iend0 indicates first region of pulse
585  while (i < iend0) {
586  *A = I(i, c_idtn, c_dtn);
587  if (++A >= Aend) return;
588  i += c_ndt;
589  t0 += c_dt;
590  }
591 
592  x = t0 * c_idt; ix = floor(x); w = x - ix;
593  int j = ix;
594  i = (j - c_nt) + iend0;
595  w2 = w * w, hw2 = 0.5 * w2, tw3 = ((1. / 6) * w) * w2;
596 
597  //signal interpolation for long time steps used for points in the tail region of the pulse
598  //iend1 indicates end of pulse
599  while (i < iend1 - 1) {
600  *A = I(i++, c_idt, c_dt);
601  if (++A >= Aend) return;
602  }
603 
604  while (A < Aend) {
605  const val_der_t& p = *(A - 1);
606  val_der_t& y = *A++;
607  y.f0 = p.f0 * m_r0; // function value
608  y.f1 = p.f1 * m_r1; // first derivative of function value
609  y.f2 = 0; // second derivative of function value
610  }
611 }
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
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:370
void settimestride(double)
set grid step for function calculation
Definition: shaperdsp.cc:360
void fillarray(int, double *) const
fill array for amplitude and time calculation
Definition: shaperdsp.cc:380
bool isMC() const
Do we have generated, not real data?
Definition: Environment.cc:55
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:29
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.
Struct to keep upper triangle of the covariance matrix.
float sigma
sigma noise
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