Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MbdSig.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MbdSig.cc
1 #include "MbdSig.h"
2 
3 #include <TF1.h>
4 #include <TFile.h>
5 #include <TGraphErrors.h>
6 #include <TH2.h>
7 #include <TMath.h>
8 #include <TPad.h>
9 #include <TSpectrum.h>
10 #include <TSpline.h>
11 #include <TTree.h>
12 
13 #include <fstream>
14 #include <iostream>
15 #include <limits>
16 
17 using namespace std;
18 
19 MbdSig::MbdSig(const int chnum, const int nsamp)
20  : ch{chnum}
21  , nsamples{nsamp}
22  , f_ampl{0}
23  , f_time{0}
25  , // time shift from fit
27  , // time shift from fit
28  hRawPulse{nullptr}
29  , hSubPulse{nullptr}
30  , hpulse{nullptr}
31  , gRawPulse{nullptr}
32  , gSubPulse{nullptr}
33  , gpulse{nullptr}
34  , hPed0{nullptr}
35  , ped0{0}
36  , // ped average
38  , use_ped0{0}
39  , minped0samp{-9999}
40  , maxped0samp{-9999}
41  , minped0x{0.}
42  , maxped0x{0.}
43  ,
44  // time_calib{0},
45  h2Template{nullptr}
46  , h2Residuals{nullptr}
47  ,
48  // range of good amplitudes for templates
49  // units are usually in ADC counts
50  hAmpl{nullptr}
51  , hTime{nullptr}
56  ,
57  // template_min_good_amplitude{20.},
58  // template_max_good_amplitude{4080},
59  // template_min_xrange{0},
60  // template_max_xrange{0},
61  template_fcn{nullptr}
62  , verbose{0}
63 {
64  // cout << "In MbdSig::MbdSig(" << ch << "," << nsamples << ")" << endl;
65 }
66 
67 void MbdSig::Init()
68 {
69  TString name;
70 
71  name = "hrawpulse";
72  name += ch;
73  hRawPulse = new TH1F(name, name, nsamples, -0.5, nsamples - 0.5);
74  name = "hsubpulse";
75  name += ch;
76  hSubPulse = new TH1F(name, name, nsamples, -0.5, nsamples - 0.5);
77 
78  // gRawPulse = new TGraphErrors(nsamples);
79  gRawPulse = new TGraphErrors();
80  name = "grawpulse";
81  name += ch;
82  gRawPulse->SetName(name);
83  // gSubPulse = new TGraphErrors(nsamples);
84  gSubPulse = new TGraphErrors();
85  name = "gsubpulse";
86  name += ch;
87  gSubPulse->SetName(name);
88 
89  hpulse = hRawPulse; // hpulse,gpulse point to raw by default
90  gpulse = gRawPulse; // we switch to sub for default if ped is applied
91 
92  // ped0stats = new RunningStats();
93  name = "hPed0_";
94  name += ch;
95  hPed0 = new TH1F(name, name, 16384, -0.5, 16383.5);
96  // hPed0 = new TH1F(name,name,10000,1,0); // automatically determine the range
97 
98  SetTemplateSize(900, 1000, -10., 20.);
99  // SetTemplateSize(300,300,0.,15.);
100 }
101 
102 void MbdSig::SetTemplateSize(const Int_t nptsx, const Int_t nptsy, const Double_t begt, const Double_t endt)
103 {
104  template_npointsx = nptsx;
105  template_npointsy = nptsy;
106  template_begintime = begt;
107  template_endtime = endt;
108 
111 
112  Double_t xbinwid = (template_endtime - template_begintime) / (template_npointsx - 1);
113  Double_t ybinwid = (1.1 + 0.1) / template_npointsy; // yscale... should we vary this?
114  if (h2Template)
115  {
116  delete h2Template;
117  }
118  if (h2Residuals)
119  {
120  delete h2Residuals;
121  }
122 
123  TString name = "h2Template";
124  name += ch;
125  h2Template = new TH2F(name, name, template_npointsx, template_begintime - xbinwid / 2., template_endtime + xbinwid / 2,
126  template_npointsy, -0.1 + ybinwid / 2.0, 1.1 + ybinwid / 2.0);
127 
128  name = "h2Residuals";
129  name += ch;
130  h2Residuals = new TH2F(name, name, template_npointsx, template_begintime - xbinwid / 2., template_endtime + xbinwid / 2,
131  80, -20, 20);
132 
133  /*
134  int nbins[] = { template_npointsx, nbinsy };
135  Double_t lowrange[] = { template_begintime-xbinwid/2.0, -0.1+ybinwid/2.0 };
136  Double_t highrange[] = { template_endtime+xbinwid/2.0, 1.1+ybinwid/2.0 };
137  h2Template = new THnSparseF(name,name,2,nbins,lowrange,highrange);
138  */
139  // h2Template->cd( gDirectory );
140 }
141 
142 void MbdSig::SetMinMaxFitTime(const Double_t mintime, const Double_t maxtime)
143 {
144  fit_min_time = mintime;
145  fit_max_time = maxtime;
146 }
147 
149 {
150  delete hRawPulse;
151  delete hSubPulse;
152  delete gRawPulse;
153  delete gSubPulse;
154  // delete ped0stats;
155  delete hPed0;
156  // h2Template->Write();
157  delete h2Template;
158  delete h2Residuals;
159  delete hAmpl;
160  delete hTime;
161  delete template_fcn;
162 }
163 
164 // This sets y, and x to sample number (starts at 0)
165 void MbdSig::SetY(const Float_t* y, const int invert)
166 {
167  if (hRawPulse == nullptr)
168  {
169  Init();
170  }
171 
172  hpulse->Reset();
173  f_ampl = -9999.;
174  f_time = -9999.;
175 
176  for (int isamp = 0; isamp < nsamples; isamp++)
177  {
178  hRawPulse->SetBinContent(isamp + 1, y[isamp]);
179  gRawPulse->SetPoint(isamp, Double_t(isamp), y[isamp]);
180  }
181 
182  // Apply pedestal
183  if (use_ped0 != 0 || minped0samp >= 0 || minped0x != maxped0x || ped_presamp != 0)
184  {
185  // cout << "sub" << endl;
186 
187  if (minped0samp >= 0)
188  {
190  }
191  else if (minped0x != maxped0x)
192  {
194  }
195  else if (ped_presamp != 0)
196  {
198  }
199 
200  for (int isamp = 0; isamp < nsamples; isamp++)
201  {
202  hSubPulse->SetBinContent(isamp + 1, invert * (y[isamp] - ped0));
203  hSubPulse->SetBinError(isamp + 1, ped0rms);
204  gSubPulse->SetPoint(isamp, (Double_t) isamp, invert * (y[isamp] - ped0));
205  gSubPulse->SetPointError(isamp, 0., ped0rms);
206  }
207  }
208 }
209 
210 void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert)
211 {
212  if (hRawPulse == nullptr)
213  {
214  Init();
215  }
216 
217  hRawPulse->Reset();
218  hSubPulse->Reset();
219  _status = 0;
220 
221  f_ampl = -9999.;
222  f_time = -9999.;
223 
224  // cout << "nsamples " << nsamples << endl;
225  // cout << "use_ped0 " << use_ped0 << "\t" << ped0 << endl;
226 
227  for (int isamp = 0; isamp < nsamples; isamp++)
228  {
229  // cout << "aaa\t" << isamp << "\t" << x[isamp] << "\t" << y[isamp] << endl;
230  hRawPulse->SetBinContent(isamp + 1, y[isamp]);
231  gRawPulse->SetPoint(isamp, x[isamp], y[isamp]);
232  }
233 
234  if (use_ped0 != 0 || minped0samp >= 0 || minped0x != maxped0x || ped_presamp != 0)
235  {
236  if (minped0samp >= 0)
237  {
239  }
240  else if (minped0x != maxped0x)
241  {
243  }
244  else if (ped_presamp != 0)
245  {
247  }
248 
249  for (int isamp = 0; isamp < nsamples; isamp++)
250  {
251  // How do we handle data which is not in samples, but is in time,
252  // such as DRS4 data
253  // if ( isamp==(nsamples-1) ) cout << "bbb\t" << isamp << "\t" << x[isamp] << "\t" << invert*(y[isamp]-ped0) << endl;
254  hSubPulse->SetBinContent(isamp + 1, invert * (y[isamp] - ped0));
255  hSubPulse->SetBinError(isamp + 1, ped0rms);
256  gSubPulse->SetPoint(isamp, x[isamp], invert * (y[isamp] - ped0));
257  gSubPulse->SetPointError(isamp, 0., ped0rms);
258  }
259  }
260 }
261 
262 Double_t MbdSig::GetSplineAmpl()
263 {
264  if (gSubPulse == nullptr)
265  {
266  cout << "gsub bad " << (uint64_t) gSubPulse << endl;
267  return 0.;
268  }
269 
270  TSpline3 s3("s3", gSubPulse);
271 
272  // First find maximum, to rescale
273  f_ampl = -999999.;
274  double step_size = 0.01;
275  // cout << "step size " << step_size << endl;
276  for (double ix = 0; ix < nsamples; ix += step_size)
277  {
278  Double_t val = s3.Eval(ix);
279  if (val > f_ampl)
280  {
281  f_ampl = val;
282  }
283  }
284 
285  return f_ampl;
286 }
287 
288 void MbdSig::FillPed0(const Int_t sampmin, const Int_t sampmax)
289 {
290  Double_t x, y;
291  for (int isamp = sampmin; isamp <= sampmax; isamp++)
292  {
293  gRawPulse->GetPoint(isamp, x, y);
294  // gRawPulse->Print("all");
295  hPed0->Fill(y);
296 
297  /*
298  // chiu taken out
299  ped0stats->Push( y );
300  ped0 = ped0stats->Mean();
301  ped0rms = ped0stats->RMS();
302  */
303 
304  // cout << "ped0 " << ch << " " << n << "\t" << ped0 << endl;
305  // cout << "ped0 " << ch << "\t" << ped0 << endl;
306  }
307 }
308 
309 void MbdSig::FillPed0(const Double_t begin, const Double_t end)
310 {
311  Double_t x, y;
312  Int_t n = gRawPulse->GetN();
313  for (int isamp = 0; isamp < n; isamp++)
314  {
315  gRawPulse->GetPoint(isamp, x, y);
316  if (x >= begin && x <= end)
317  {
318  hPed0->Fill(y);
319 
320  /*
321  ped0stats->Push( y );
322  ped0 = ped0stats->Mean();
323  ped0rms = ped0stats->RMS();
324  */
325 
326  // cout << "ped0 " << ch << " " << n << "\t" << x << "\t" << y << endl;
327  }
328 
329  // quit if we are past the ped region
330  if (x > end)
331  {
332  break;
333  }
334  }
335 }
336 
337 void MbdSig::SetPed0(const Double_t mean, const Double_t rms)
338 {
339  ped0 = mean;
340  ped0rms = rms;
341  use_ped0 = 1;
342  hpulse = hSubPulse;
343  gpulse = gSubPulse;
344  // if ( ch==8 ) cout << "ch " << ch << " Ped = " << ped0 << endl;
345 }
346 
347 // Get Event by Event Ped0 if requested
348 void MbdSig::CalcEventPed0(const Int_t minpedsamp, const Int_t maxpedsamp)
349 {
350  // if (ch==8) cout << "In MbdSig::CalcEventPed0(int,int)" << endl;
351  hPed0->Reset();
352  // ped0stats->Clear();
353 
354  Double_t x, y;
355  for (int isamp = minpedsamp; isamp <= maxpedsamp; isamp++)
356  {
357  gRawPulse->GetPoint(isamp, x, y);
358 
359  hPed0->Fill(y);
360  // ped0stats->Push( y );
361  // if ( ch==8 ) cout << "ped0stats " << isamp << "\t" << y << endl;
362  }
363 
364  // use straight mean for pedestal
365  // Could consider using fit to hPed0 to remove outliers
366  float mean = hPed0->GetMean();
367  float rms = hPed0->GetRMS();
368 
369  // SetPed0( ped0stats->Mean(), ped0stats->RMS() );
370 
371  SetPed0(mean, rms);
372  // if (ch==8) cout << "ped0stats mean, rms " << mean << "\t" << rms << endl;
373 }
374 
375 // Get Event by Event Ped0 if requested
376 void MbdSig::CalcEventPed0(const Double_t minpedx, const Double_t maxpedx)
377 {
378  hPed0->Reset();
379  // ped0stats->Clear();
380 
381  Double_t x, y;
382  Int_t n = gRawPulse->GetN();
383 
384  for (int isamp = 0; isamp < n; isamp++)
385  {
386  gRawPulse->GetPoint(isamp, x, y);
387 
388  if (x >= minpedx && x <= maxpedx)
389  {
390  hPed0->Fill(y);
391  // ped0stats->Push( y );
392  }
393  }
394 
395  // use straight mean for pedestal
396  // Could consider using fit to hPed0 to remove outliers
397  SetPed0(hPed0->GetMean(), hPed0->GetRMS());
398  /*
399  Double_t mean = ped0stats->Mean();
400  Double_t rms = ped0stats->RMS();
401  SetPed0( mean, rms );
402  */
403  // cout << "ped0stats " << mean << "\t" << rms << endl;
404 }
405 
406 // Get Event by Event Ped0, num samples before peak
407 // presample is number of samples before peak, nsamps is how many samples
408 void MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps)
409 {
410  hPed0->Reset();
411  // ped0stats->Clear();
412 
413  Double_t x, y;
414  // Int_t n = gRawPulse->GetN();
415  // Int_t max = gRawPulse->GetHistogram()->GetMaximumBin();
416  Long64_t max = TMath::LocMax(gRawPulse->GetN(), gRawPulse->GetY());
417  Int_t minsamp = max - presample - nsamps + 1;
418  Int_t maxsamp = max - presample;
419  // cout << "CalcEventPed0_PreSamp: " << max << endl;
420 
421  if (minsamp < 0)
422  {
423  minsamp = 0;
424  _status = 1; // bad pedestal
425  }
426  if (maxsamp < 0)
427  {
428  maxsamp = 0;
429  _status = 1;
430  }
431 
432  for (int isamp = minsamp; isamp <= maxsamp; isamp++)
433  {
434  gRawPulse->GetPoint(isamp, x, y);
435 
436  hPed0->Fill(y);
437  // ped0stats->Push( y );
438  }
439 
440  // use straight mean for pedestal
441  // Could consider using fit to hPed0 to remove outliers
442  // Double_t mean = ped0stats->Mean();
443  // Double_t rms = ped0stats->RMS();
444  Double_t mean = hPed0->GetMean();
445  Double_t rms = hPed0->GetRMS();
446  SetPed0(mean, rms);
447  static int counter = 0;
448  if (verbose > 0 && counter < 10)
449  {
450  cout << "CalcEventPed0_PreSamp: ped0stats " << mean << "\t" << rms << endl;
451  counter++;
452  }
453 }
454 
455 Double_t MbdSig::LeadingEdge(const Double_t threshold)
456 {
457  // Find first point above threshold
458  // We also make sure the next point is above threshold
459  // to get rid of a high fluctuation
460  int n = gSubPulse->GetN();
461  Double_t* x = gSubPulse->GetX();
462  Double_t* y = gSubPulse->GetY();
463 
464  int sample = -1;
465  for (int isamp = 0; isamp < n; isamp++)
466  {
467  if (y[isamp] > threshold)
468  {
469  if (isamp == (n - 1) || y[isamp + 1] > threshold)
470  {
471  sample = isamp;
472  break;
473  }
474  }
475  }
476  if (sample < 1)
477  {
478  return -9999.; // no signal above threshold
479  }
480 
481  // Linear Interpolation of start time
482  Double_t dx = x[sample] - x[sample - 1];
483  Double_t dy = y[sample] - y[sample - 1];
484  Double_t dt1 = y[sample] - threshold;
485 
486  Double_t t0 = x[sample] - dt1 * (dx / dy);
487 
488  return t0;
489 }
490 
491 Double_t MbdSig::dCFD(const Double_t fraction_threshold)
492 {
493  // Find first point above threshold
494  // We also make sure the next point is above threshold
495  // to get rid of a high fluctuation
496  int n = gSubPulse->GetN();
497  Double_t* x = gSubPulse->GetX();
498  Double_t* y = gSubPulse->GetY();
499 
500  // Get max amplitude
501  Double_t ymax = TMath::MaxElement(n, y);
502  if (f_ampl == -9999.)
503  {
504  f_ampl = ymax;
505  }
506 
507  Double_t threshold = fraction_threshold * ymax; // get fraction of amplitude
508  // cout << "threshold = " << threshold << "\tymax = " << ymax <<endl;
509 
510  int sample = -1;
511  for (int isamp = 0; isamp < n; isamp++)
512  {
513  if (y[isamp] > threshold)
514  {
515  if (isamp == (n - 1) || y[isamp + 1] > threshold)
516  {
517  sample = isamp;
518  break;
519  }
520  }
521  }
522  if (sample < 1)
523  {
524  return -9999.; // no signal above threshold
525  }
526 
527  // Linear Interpolation of start time
528  Double_t dx = x[sample] - x[sample - 1];
529  Double_t dy = y[sample] - y[sample - 1];
530  Double_t dt1 = y[sample] - threshold;
531 
532  Double_t t0 = x[sample] - dt1 * (dx / dy);
533 
534  return t0;
535 }
536 
537 Double_t MbdSig::MBD(const Int_t max_samp)
538 {
539  // Get the amplitude of the sample number to get time
540  Double_t* y = gSubPulse->GetY();
541 
542  if (y == nullptr)
543  {
544  std::cout << "ERROR y == 0" << std::endl;
545  return NAN;
546  }
547 
548  // SHOULD INCLUDE TIME CALIBRATION HERE
549  f_time = y[max_samp];
550 
551  // Get max amplitude, and set it if it hasn't already been set
552  int n = gSubPulse->GetN();
553  Double_t ymax = TMath::MaxElement(n, y);
554  if (f_ampl == -9999.)
555  {
556  f_ampl = ymax;
557  }
558 
559  return f_time;
560 }
561 
562 Double_t MbdSig::Integral(const Double_t xmin, const Double_t xmax)
563 {
564  Int_t n = gSubPulse->GetN();
565  Double_t* x = gSubPulse->GetX();
566  Double_t* y = gSubPulse->GetY();
567 
568  f_integral = 0.;
569  for (int ix = 0; ix < n; ix++)
570  {
571  if (x[ix] >= xmin && x[ix] <= xmax)
572  {
573  // Get dx
574  Double_t dx = (x[ix + 1] - x[ix - 1]) / 2.0;
575  f_integral += (y[ix] * dx);
576  }
577  }
578 
579  return f_integral;
580 }
581 
582 void MbdSig::LocMax(Double_t& x_at_max, Double_t& ymax, Double_t xminrange, Double_t xmaxrange)
583 {
584  // Find index of maximum peak
585  Int_t n = gSubPulse->GetN();
586  Double_t* x = gSubPulse->GetX();
587  Double_t* y = gSubPulse->GetY();
588 
589  // if flipped or equal, we search the whole range
590  if (xmaxrange <= xminrange)
591  {
592  xminrange = -DBL_MAX;
593  xmaxrange = DBL_MAX;
594  }
595 
596  x_at_max = -DBL_MAX;
597  ymax = -DBL_MAX;
598 
599  for (int i = 0; i < n; i++)
600  {
601  // Skip if out of range
602  if (x[i] < xminrange)
603  {
604  continue;
605  }
606  if (x[i] > xmaxrange)
607  {
608  break;
609  }
610 
611  if (y[i] > ymax)
612  {
613  ymax = y[i];
614  x_at_max = x[i];
615  }
616  }
617 }
618 
619 void MbdSig::LocMin(Double_t& x_at_max, Double_t& ymin, Double_t xminrange, Double_t xmaxrange)
620 {
621  // Find index of minimum peak (for neg signals)
622  Int_t n = gSubPulse->GetN();
623  Double_t* x = gSubPulse->GetX();
624  Double_t* y = gSubPulse->GetY();
625 
626  // if flipped or equal, we search the whole range
627  if (xmaxrange <= xminrange)
628  {
629  xminrange = -DBL_MAX;
630  xmaxrange = DBL_MAX;
631  }
632 
633  ymin = DBL_MAX;
634 
635  for (int i = 0; i < n; i++)
636  {
637  // Skip if out of range
638  if (x[i] < xminrange)
639  {
640  continue;
641  }
642  if (x[i] > xmaxrange)
643  {
644  break;
645  }
646 
647  if (y[i] < ymin)
648  {
649  ymin = y[i];
650  x_at_max = x[i];
651  }
652  }
653 
654  // old way of getting locmax
655  // int locmax = TMath::LocMin(n,y);
656 }
657 
658 void MbdSig::Print()
659 {
660  Double_t x, y;
661  cout << "CH " << ch << endl;
662  for (int isamp = 0; isamp < nsamples; isamp++)
663  {
664  gpulse->GetPoint(isamp, x, y);
665  cout << isamp << "\t" << x << "\t" << y << endl;
666  }
667 }
668 
669 void MbdSig::PadUpdate()
670 {
671  // Make sure TCanvas is created externally!
672  gPad->Modified();
673  gPad->Update();
674  cout << ch << " ? ";
675  TString junk;
676  cin >> junk;
677 
678  if (junk[0] == 'w' || junk[0] == 's')
679  {
680  TString name = "ch";
681  name += ch;
682  name += ".png";
683  gPad->SaveAs(name);
684  }
685 }
686 
687 Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par)
688 {
689  // par[0] is the amplitude (relative to the spline amplitude)
690  // par[1] is the start time (in sample number)
691  // x[0] units are in sample number
692  Double_t xx = x[0] - par[1];
693  Double_t f = 0.;
694 
695  // verbose = 100;
696 
697  // When fit is out of limits of good part of spline, ignore fit
698  if (xx < template_begintime || xx > template_endtime)
699  {
700  TF1::RejectPoint();
701  if (xx < template_begintime)
702  {
703  // Double_t x0,y0;
704  Double_t y0 = template_y[0];
705  return par[0] * y0;
706  }
707  else if (xx > template_endtime)
708  {
709  // Double_t x0,y0;
710  Double_t y0 = template_y[template_npointsx - 1];
711  return par[0] * y0;
712  }
713  }
714 
715  // Linear Interpolation of template
716  Double_t x0 = 0.;
717  Double_t y0 = 0.;
718  Double_t x1 = 0.;
719  Double_t y1 = 0.;
720 
721  // find the index in the vector which is closest to xx
722  Double_t step = (template_endtime - template_begintime) / (template_npointsx - 1);
723  Double_t index = (xx - template_begintime) / step;
724 
725  int ilow = TMath::FloorNint(index);
726  int ihigh = TMath::CeilNint(index);
727  if (ilow < 0 || ihigh >= template_npointsx)
728  {
729  if (verbose > 0)
730  {
731  cout << "ERROR, ilow ihigh " << ilow << "\t" << ihigh << endl;
732  cout << " " << xx << " " << x[0] << " " << par[1] << endl;
733  }
734 
735  if (ilow < 0)
736  {
737  ilow = 0;
738  }
739  else if (ihigh >= template_npointsx)
740  {
741  ihigh = template_npointsx - 1;
742  }
743  }
744 
745  if (ilow == ihigh)
746  {
747  f = par[0] * template_y[ilow];
748  }
749  else
750  {
751  x0 = template_begintime + ilow * step;
752  y0 = template_y[ilow];
753  x1 = template_begintime + ihigh * step;
754  y1 = template_y[ihigh];
755  f = par[0] * (y0 + ((y1 - y0) / (x1 - x0)) * (xx - x0)); // linear interpolation
756  }
757 
758  // reject points with very bad rms in shape
759  if (template_yrms[ilow] >= 1.0 || template_yrms[ihigh] >= 1.0)
760  {
761  TF1::RejectPoint();
762  // return f;
763  }
764 
765  // Reject points where ADC saturates
766  int samp_point = static_cast<int>(x[0]);
767  Double_t temp_x, temp_y;
768  gRawPulse->GetPoint(samp_point, temp_x, temp_y);
769  if (temp_y > 16370)
770  {
771  // cout << "XXXX " << ch << "\t" << samp_point << "\t" << temp_x << "\t" << temp_y << std::endl;
772  TF1::RejectPoint();
773  }
774 
775  // verbose = 0;
776  return f;
777 }
778 
780 {
781  // verbose = 100; // uncomment to see fits
782  if (verbose > 0)
783  {
784  cout << "Fitting ch " << ch << endl;
785  }
786 
787  // Check if channel is empty
788  if (gSubPulse->GetN() == 0)
789  {
790  f_ampl = -9999.;
791  f_time = -9999.;
792  // cout << "gSubPulse empty" << endl;
793  return 1;
794  }
795 
796  // Get x-position of maximum
797  Double_t x_at_max, ymax;
798  // LocMax(x_at_max, ymax);
799 
800  Int_t xsamp = (fit_min_time + fit_max_time) / 2 + 2; // use max samp
801  gSubPulse->GetPoint(xsamp, x_at_max, ymax);
802 
803  template_fcn->SetParameters(ymax, x_at_max);
804  // template_fcn->SetParLimits(1, fit_min_time, fit_max_time);
805  // template_fcn->SetParLimits(1, 3, 15);
806  // template_fcn->SetRange(template_min_xrange,template_max_xrange);
807  template_fcn->SetRange(0, nsamples);
808 
809  if (verbose == 0)
810  {
811  gSubPulse->Fit(template_fcn, "RNQ");
812  }
813  else
814  {
815  gSubPulse->Fit(template_fcn, "R");
816  }
817 
818  // Get fit parameters
819  f_ampl = template_fcn->GetParameter(0);
820  f_time = template_fcn->GetParameter(1);
821 
822  if (verbose > 0 && fabs(f_ampl) > 0.)
823  {
824  cout << "FitTemplate " << ch << "\t" << f_ampl << "\t" << f_time << endl;
825  gSubPulse->Draw("ap");
826  template_fcn->SetLineColor(4);
827  template_fcn->Draw("same");
828  PadUpdate();
829  }
830 
831  // verbose = 0;
832  return 1;
833 }
834 
835 int MbdSig::SetTemplate(const std::vector<float>& shape, const std::vector<float>& sherr)
836 {
837  template_y = shape;
838  template_yrms = sherr;
839 
840  if (verbose)
841  {
842  std::cout << "SHAPE " << ch << "\t" << template_y.size() << std::endl;
843  for (size_t i = 0; i < template_y.size(); i++)
844  {
845  if (i % 10 == 0)
846  {
847  std::cout << i << ":\t" << std::endl;
848  }
849  std::cout << " " << template_y[i];
850  }
851  std::cout << std::endl;
852  }
853 
854  if (template_fcn == nullptr)
855  {
856  TString name = "template_fcn";
857  name += ch;
858  // template_fcn = new TF1(name,this,&MbdSig::TemplateFcn,template_min_xrange,template_max_xrange,2,"MbdSig","TemplateFcn");
859  // template_fcn = new TF1(name,this,&MbdSig::TemplateFcn,-10,20,2,"MbdSig","TemplateFcn");
860  template_fcn = new TF1(name, this, &MbdSig::TemplateFcn, 0, nsamples, 2, "MbdSig", "TemplateFcn");
861  template_fcn->SetParameters(1, 10);
862  SetTemplateSize(900, 1000, -10., 20.);
863 
864  if (verbose)
865  {
866  std::cout << "SHAPE " << ch << std::endl;
867  template_fcn->Draw("acp");
868  gPad->Modified();
869  gPad->Update();
870  }
871  }
872 
873  return 1;
874 }