Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:20:20

0001 #include "MbdSig.h"
0002 #include "MbdCalib.h"
0003 
0004 #include <phool/phool.h>
0005 
0006 #include <TF1.h>
0007 #include <TFile.h>
0008 #include <TGraphErrors.h>
0009 #include <TH2.h>
0010 #include <TMath.h>
0011 #include <TPad.h>
0012 #include <TSpectrum.h>
0013 #include <TSpline.h>
0014 #include <TTree.h>
0015 
0016 #include <algorithm>
0017 #include <fstream>
0018 #include <iostream>
0019 #include <iomanip>
0020 #include <limits>
0021 
0022 MbdSig::MbdSig(const int chnum, const int nsamp)
0023   : _ch{chnum}
0024   , _nsamples{nsamp}
0025 {
0026   // std::cout << "In MbdSig::MbdSig(" << _ch << "," << _nsamples << ")" << std::endl;
0027 }
0028 
0029 void MbdSig::Init()
0030 {
0031   TString name;
0032 
0033   name = "hrawpulse";
0034   name += _ch;
0035   hRawPulse = new TH1F(name, name, _nsamples, -0.5, _nsamples - 0.5);
0036   name = "hsubpulse";
0037   name += _ch;
0038   hSubPulse = new TH1F(name, name, _nsamples, -0.5, _nsamples - 0.5);
0039 
0040   // gRawPulse = new TGraphErrors(_nsamples);
0041   gRawPulse = new TGraphErrors();
0042   name = "grawpulse";
0043   name += _ch;
0044   gRawPulse->SetName(name);
0045   // gSubPulse = new TGraphErrors(_nsamples);
0046   gSubPulse = new TGraphErrors();
0047   name = "gsubpulse";
0048   name += _ch;
0049   gSubPulse->SetName(name);
0050   gSubPulse->GetHistogram()->SetXTitle("sample");
0051   gSubPulse->GetHistogram()->SetYTitle("ADC");
0052 
0053   hpulse = hRawPulse;  // hpulse,gpulse point to raw by default
0054   gpulse = gRawPulse;  // we switch to sub for default if ped is applied
0055 
0056   //ped0stats = std::make_unique<MbdRunningStats>(100);  // use the last 100 events for running pedestal
0057   ped0stats = new MbdRunningStats(100);  // use the last 100 events for running pedestal
0058   name = "hPed0_";
0059   name += _ch;
0060   hPed0 = new TH1F(name, name, 3000, -0.5, 2999.5);
0061   // hPed0 = new TH1F(name,name,10000,1,0); // automatically determine the range
0062   name = "hPedEvt_";
0063   name += _ch;
0064   hPedEvt = new TH1F(name, name, 3000, -0.5, 2999.5);
0065 
0066   SetTemplateSize(900, 1000, -10., 20.);
0067   // SetTemplateSize(300,300,0.,15.);
0068 
0069   // Set pedestal function
0070   ped_fcn = new TF1("ped_fcn","[0]",0,2);
0071   ped_fcn->SetLineColor(3);
0072 
0073   // Set tail function
0074   ped_tail = new TF1("ped_tail","[0]+[1]*exp(-[2]*x)",0,2);
0075   ped_tail->SetLineColor(2);
0076 
0077   // uncomment this to write out waveforms from events that have pileup from prev. crossing
0078   /*
0079   name = "mbdsig"; name += _ch; name += ".txt";
0080   _pileupfile = new ofstream(name);
0081   */
0082 }
0083 
0084 void MbdSig::SetTemplateSize(const Int_t nptsx, const Int_t nptsy, const Double_t begt, const Double_t endt)
0085 {
0086   template_npointsx = nptsx;
0087   template_npointsy = nptsy;
0088   template_begintime = begt;
0089   template_endtime = endt;
0090 
0091   template_y.resize(template_npointsx);
0092   template_yrms.resize(template_npointsx);
0093 
0094   Double_t xbinwid = (template_endtime - template_begintime) / (template_npointsx - 1);
0095   Double_t ybinwid = (1.1 + 0.1) / template_npointsy;  // yscale... should we vary this?
0096   
0097   
0098   delete h2Template;
0099   
0100   delete h2Residuals;
0101   
0102   TString name = "h2Template";
0103   name += _ch;
0104   h2Template = new TH2F(name, name, template_npointsx, template_begintime - (xbinwid / 2.), template_endtime + (xbinwid / 2),
0105                         template_npointsy, -0.1 + (ybinwid / 2.0), 1.1 + (ybinwid / 2.0));
0106 
0107   name = "h2Residuals";
0108   name += _ch;
0109   h2Residuals = new TH2F(name, name, template_npointsx, template_begintime - (xbinwid / 2.), template_endtime + (xbinwid / 2),
0110                          80, -20, 20);
0111 
0112   /*
0113   int nbins[] = { template_npointsx, nbinsy };
0114   Double_t lowrange[] = { template_begintime-xbinwid/2.0, -0.1+ybinwid/2.0 };
0115   Double_t highrange[] = { template_endtime+xbinwid/2.0, 1.1+ybinwid/2.0 };
0116   h2Template = new THnSparseF(name,name,2,nbins,lowrange,highrange);
0117   */
0118   // h2Template->cd( gDirectory );
0119 }
0120 
0121 void MbdSig::SetMinMaxFitTime(const Double_t mintime, const Double_t maxtime)
0122 {
0123   fit_min_time = mintime;
0124   fit_max_time = maxtime;
0125 }
0126 
0127 MbdSig::~MbdSig()
0128 {
0129   if ( _pileupfile )
0130   {
0131     _pileupfile->close();
0132   }
0133   delete hRawPulse;
0134   delete hSubPulse;
0135   delete gRawPulse;
0136   delete gSubPulse;
0137   delete hPed0;
0138   delete ped0stats;
0139   // h2Template->Write();
0140   delete h2Template;
0141   delete h2Residuals;
0142   delete hAmpl;
0143   delete hTime;
0144   delete template_fcn;
0145   delete ped_fcn;
0146   delete ped_tail;
0147 }
0148 
0149 void MbdSig::SetEventPed0PreSamp(const Int_t presample, const Int_t nsamps, const int max_samp)
0150 {
0151   ped_presamp = presample;
0152   ped_presamp_nsamps = nsamps;
0153   if ( ped_presamp_nsamps < 0 && max_samp > 0 )
0154   {
0155     ped_presamp_nsamps = max_samp - presample + 1;
0156   }
0157   ped_presamp_maxsamp = max_samp; // max of waveform
0158 }
0159 
0160 void MbdSig::SetCalib(MbdCalib *m)
0161 {
0162   _mbdcal = m;
0163   _pileup_p0 = m->get_pileup(_ch,0);
0164   _pileup_p1 = m->get_pileup(_ch,1);
0165   _pileup_p2 = m->get_pileup(_ch,2);
0166 }
0167 
0168 // This sets y, and x to sample number (starts at 0)
0169 void MbdSig::SetY(const Float_t* y, const int invert)
0170 {
0171   if (hRawPulse == nullptr)
0172   {
0173     Init();
0174   }
0175 
0176   hpulse->Reset();
0177   f_ampl = -9999.;
0178   f_time = -9999.;
0179 
0180   for (int isamp = 0; isamp < _nsamples; isamp++)
0181   {
0182     hRawPulse->SetBinContent(isamp + 1, y[isamp]);
0183     gRawPulse->SetPoint(isamp, Double_t(isamp), y[isamp]);
0184   }
0185 
0186   // Apply pedestal
0187   if (use_ped0 != 0 || minped0samp >= 0 || minped0x != maxped0x || ped_presamp != 0)
0188   {
0189     // std::cout << "sub" << std::endl;
0190  
0191     int ispileup = 0; // whether pileup event or not (from prev crossing)
0192                       // note pileup correction not implemented for CalcEventPed0(),
0193                       // but that is not used
0194 
0195     if (minped0samp >= 0)
0196     {
0197       CalcEventPed0(minped0samp, maxped0samp);
0198     }
0199     else if (minped0x != maxped0x)
0200     {
0201       CalcEventPed0(minped0x, maxped0x);
0202     }
0203     else if (ped_presamp != 0)
0204     {
0205       ispileup = CalcEventPed0_PreSamp(ped_presamp, ped_presamp_nsamps);
0206     }
0207 
0208     for (int isamp = 0; isamp < _nsamples; isamp++)
0209     {
0210       hSubPulse->SetBinContent(isamp + 1, invert * (y[isamp] - ped0));
0211       hSubPulse->SetBinError(isamp + 1, ped0rms);
0212       gSubPulse->SetPoint(isamp, (Double_t) isamp, invert * (y[isamp] - ped0));
0213       gSubPulse->SetPointError(isamp, 0., ped0rms);
0214     }
0215 
0216     if ( ispileup==1 && !std::isnan(_pileup_p0) )
0217     {
0218       Remove_Pileup();
0219     }
0220   }
0221 
0222   _evt_counter++;
0223 }
0224 
0225 void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert)
0226 {
0227   //_verbose = 100;
0228   if (hRawPulse == nullptr)
0229   {
0230     Init();
0231   }
0232 
0233   hRawPulse->Reset();
0234   hSubPulse->Reset();
0235   _status = 0;
0236 
0237   f_ampl = -9999.;
0238   f_time = -9999.;
0239 
0240   // std::cout << "_nsamples " << _nsamples << std::endl;
0241   // std::cout << "use_ped0 " << use_ped0 << "\t" << ped0 << std::endl;
0242 
0243   for (int isamp = 0; isamp < _nsamples; isamp++)
0244   {
0245     // std::cout << "aaa\t" << isamp << "\t" << x[isamp] << "\t" << y[isamp] << std::endl;
0246     hRawPulse->SetBinContent(isamp + 1, y[isamp]);
0247     gRawPulse->SetPoint(isamp, x[isamp], y[isamp]);
0248     gRawPulse->SetPointError(isamp, 0, 4.0);
0249   }
0250   if ( _verbose && _ch==9 )
0251   {
0252     gRawPulse->Draw("ap");
0253     gRawPulse->GetHistogram()->SetTitle(gRawPulse->GetName());
0254     gPad->SetGridy(1);
0255     PadUpdate();
0256   }
0257 
0258   if (use_ped0 != 0 || minped0samp >= 0 || minped0x != maxped0x || ped_presamp != 0)
0259   {
0260     int ispileup = 0; // whether pileup event or not (from prev crossing)
0261                       // note pileup correction not implemented for CalcEventPed0(),
0262                       // but that is not used
0263 
0264     if (minped0samp >= 0)
0265     {
0266       CalcEventPed0(minped0samp, maxped0samp);
0267     }
0268     else if (minped0x != maxped0x)
0269     {
0270       CalcEventPed0(minped0x, maxped0x);
0271     }
0272     else if (ped_presamp != 0)
0273     {
0274       ispileup = CalcEventPed0_PreSamp(ped_presamp, ped_presamp_nsamps);
0275     }
0276 
0277     for (int isamp = 0; isamp < _nsamples; isamp++)
0278     {
0279       if ( _verbose && isamp==(_nsamples-1) )
0280       {
0281         std::cout << "bbb ch " << _ch << "\t" << isamp << "\t" << x[isamp] << "\t" << invert*(y[isamp]-ped0) << std::endl;
0282       }
0283       hSubPulse->SetBinContent(isamp + 1, invert * (y[isamp] - ped0));
0284       hSubPulse->SetBinError(isamp + 1, ped0rms);
0285       gSubPulse->SetPoint(isamp, x[isamp], invert * (y[isamp] - ped0));
0286       gSubPulse->SetPointError(isamp, 0., ped0rms);
0287     }
0288 
0289     if ( ispileup==1 )
0290     {
0291       Remove_Pileup();
0292     }
0293 
0294     if ( _verbose && _ch==9 )
0295     {
0296       std::cout << "SetXY: ch " << _ch << std::endl;
0297       gSubPulse->Print("ALL");
0298     }
0299   }
0300 
0301   _evt_counter++;
0302   _verbose = 0;
0303 }
0304 
0305 void MbdSig::Remove_Pileup()
0306 {
0307   //_verbose = 100;
0308   _verbose = 0;
0309 
0310   /*
0311   if ( (_ch==238&&_evt_counter==7104) || (_ch==255&&_evt_counter==7762) )
0312   {
0313     _verbose = 100;
0314   }
0315   */
0316 
0317   if ( _verbose )
0318   {
0319     std::cout << PHWHERE << " evt ch " << _evt_counter << "\t" << _ch << std::endl;
0320   }
0321 
0322   if ( (_ch/8)%2 == 0 )   // time ch
0323   {
0324     float offset = _pileup_p0*gSubPulse->GetPointY(0);
0325 
0326     for (int isamp = 0; isamp < _nsamples; isamp++)
0327     {
0328       double x = gSubPulse->GetPointX(isamp);
0329       double y = gSubPulse->GetPointY(isamp);
0330 
0331       hSubPulse->SetBinContent( isamp + 1, y - offset );
0332       gSubPulse->SetPoint( isamp, x, y - offset );
0333     }
0334   }
0335   else
0336   {
0337     if ( fit_pileup == nullptr )
0338     {
0339       TString name = "fit_pileup"; name += _ch;
0340       fit_pileup = new TF1(name,"gaus",-0.1,4.1);
0341       fit_pileup->SetLineColor(2);
0342     }
0343 
0344     fit_pileup->SetRange(-0.1,4.1);
0345     fit_pileup->SetParameters( _pileup_p0*gSubPulse->GetPointY(0), _pileup_p1, _pileup_p2 );
0346     
0347     // fix par limits
0348     double plow{0.};
0349     double phigh{0.};
0350     fit_pileup->GetParLimits(2,plow,phigh);
0351     if ( phigh < _pileup_p2 )
0352     {
0353       phigh = 2*_pileup_p2;
0354       fit_pileup->SetParLimits(2,plow,phigh);
0355     }
0356 
0357     if ( _verbose )
0358     {
0359       gSubPulse->Fit( fit_pileup, "R" );
0360       gSubPulse->Draw("ap");
0361       PadUpdate();
0362     }
0363     else
0364     {
0365       gSubPulse->Fit( fit_pileup, "RNQ" );
0366     }
0367 
0368     for (int isamp = 0; isamp < _nsamples; isamp++)
0369     {
0370 
0371       double bkg = fit_pileup->Eval(isamp);
0372 
0373       double x = gSubPulse->GetPointX(isamp);
0374       double y = gSubPulse->GetPointY(isamp);
0375 
0376       float newval = static_cast<float>( y - bkg );
0377 
0378       hSubPulse->SetBinContent( isamp + 1, newval );
0379       gSubPulse->SetPoint( isamp, x, newval );
0380     }
0381   }
0382 
0383   if ( _verbose )
0384   {
0385     gSubPulse->Draw("ap");
0386     PadUpdate();
0387   }
0388 
0389   _verbose = 0;
0390 }
0391 
0392 Double_t MbdSig::GetSplineAmpl()
0393 {
0394   if (gSubPulse == nullptr)
0395   {
0396     std::cout << "gsub bad " << (uint64_t) gSubPulse << std::endl;
0397     return 0.;
0398   }
0399 
0400   TSpline3 s3("s3", gSubPulse);
0401 
0402   // First find maximum, to rescale
0403   f_ampl = -999999.;
0404   double step_size = 0.01;
0405   // std::cout << "step size " << step_size << std::endl;
0406   for (double ix = 0; ix < _nsamples; ix += step_size)
0407   {
0408     Double_t val = s3.Eval(ix);
0409     f_ampl = std::max(val, f_ampl);
0410   }
0411 
0412   return f_ampl;
0413 }
0414 
0415 void MbdSig::WritePedHist()
0416 {
0417   hPed0->Write();
0418 }
0419 
0420 void MbdSig::FillPed0(const Int_t sampmin, const Int_t sampmax)
0421 {
0422   Double_t x;
0423   Double_t y;
0424   for (int isamp = sampmin; isamp <= sampmax; isamp++)
0425   {
0426     gRawPulse->GetPoint(isamp, x, y);
0427     // gRawPulse->Print("all");
0428     hPed0->Fill(y);
0429 
0430     /*
0431     // chiu taken out
0432     ped0stats->Push( y );
0433     ped0 = ped0stats->Mean();
0434     ped0rms = ped0stats->RMS();
0435     */
0436 
0437     // std::cout << "ped0 " << _ch << " " << n << "\t" << ped0 << std::endl;
0438     // std::cout << "ped0 " << _ch << "\t" << ped0 << std::endl;
0439   }
0440 }
0441 
0442 void MbdSig::FillPed0(const Double_t begin, const Double_t end)
0443 {
0444   Double_t x;
0445   Double_t y;
0446   Int_t n = gRawPulse->GetN();
0447   for (int isamp = 0; isamp < n; isamp++)
0448   {
0449     gRawPulse->GetPoint(isamp, x, y);
0450     if (x >= begin && x <= end)
0451     {
0452       hPed0->Fill(y);
0453 
0454       /*
0455          ped0stats->Push( y );
0456          ped0 = ped0stats->Mean();
0457          ped0rms = ped0stats->RMS();
0458          */
0459 
0460       // std::cout << "ped0 " << _ch << " " << n << "\t" << x << "\t" << y << std::endl;
0461     }
0462 
0463     // quit if we are past the ped region
0464     if (x > end)
0465     {
0466       break;
0467     }
0468   }
0469 }
0470 
0471 void MbdSig::SetPed0(const Double_t mean, const Double_t rms)
0472 {
0473   ped0 = mean;
0474   ped0rms = rms;
0475   use_ped0 = 1;
0476   hpulse = hSubPulse;
0477   gpulse = gSubPulse;
0478   // if ( _ch==8 ) std::cout << "_ch " << _ch << " Ped = " << ped0 << std::endl;
0479 }
0480 
0481 // Get Event by Event Ped0 if requested
0482 void MbdSig::CalcEventPed0(const Int_t minpedsamp, const Int_t maxpedsamp)
0483 {
0484   // if (_ch==8) std::cout << "In MbdSig::CalcEventPed0(int,int)" << std::endl;
0485   hPedEvt->Reset();
0486 
0487   Double_t x;
0488   Double_t y;
0489   for (int isamp = minpedsamp; isamp <= maxpedsamp; isamp++)
0490   {
0491     gRawPulse->GetPoint(isamp, x, y);
0492 
0493     hPed0->Fill(y);
0494     hPedEvt->Fill(y);
0495     // ped0stats->Push( y );
0496     // if ( _ch==8 ) std::cout << "ped0stats " << isamp << "\t" << y << std::endl;
0497   }
0498 
0499   // use straight mean for pedestal
0500   // Could consider using fit to hPed0 to remove outliers
0501   float mean = hPedEvt->GetMean();
0502   float rms = hPedEvt->GetRMS();
0503 
0504   SetPed0(mean, rms);
0505   // if (_ch==8) std::cout << "ped0stats mean, rms " << mean << "\t" << rms << std::endl;
0506 }
0507 
0508 // Get Event by Event Ped0 if requested
0509 void MbdSig::CalcEventPed0(const Double_t minpedx, const Double_t maxpedx)
0510 {
0511   hPedEvt->Reset();
0512 
0513   Double_t x;
0514   Double_t y;
0515   Int_t n = gRawPulse->GetN();
0516 
0517   for (int isamp = 0; isamp < n; isamp++)
0518   {
0519     gRawPulse->GetPoint(isamp, x, y);
0520 
0521     if (x >= minpedx && x <= maxpedx)
0522     {
0523       hPed0->Fill(y);
0524       hPedEvt->Fill(y);
0525       // ped0stats->Push( y );
0526     }
0527   }
0528 
0529   // use straight mean for pedestal
0530   // Could consider using fit to hPed0 to remove outliers
0531   SetPed0(hPedEvt->GetMean(), hPedEvt->GetRMS());
0532 }
0533 
0534 // Get Event by Event Ped0, num samples before peak
0535 // presample is number of samples before peak, nsamps is how many samples
0536 // If difficult to get pedestal, use running mean from previous 100 events
0537 // If a prev event pileup is detected, return 1, otherwise, return 0
0538 int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps)
0539 {
0540   //std::cout << PHWHERE << std::endl;  //chiu
0541   //_verbose = 100;
0542   //ped0stats->Clear();
0543 
0544   int status = 0; // assume no pileup
0545 
0546   // Int_t n = gRawPulse->GetN();
0547   // Int_t max = gRawPulse->GetHistogram()->GetMaximumBin();
0548   Long64_t max = ped_presamp_maxsamp;
0549 
0550   // actual max from event
0551   Long64_t actual_max = TMath::LocMax(gRawPulse->GetN(), gRawPulse->GetY());
0552 
0553   if ( ped_presamp_maxsamp == -1 ) // if there is no maxsamp set, use the max found in this event
0554   {
0555     max = actual_max;
0556   }
0557 
0558   Int_t minsamp = max - presample - nsamps + 1;
0559   Int_t maxsamp = max - presample;
0560   //std::cout << "CalcEventPed0_PreSamp: ch ctr max " << _ch << "\t" << _evt_counter << "\t" << max << std::endl;
0561 
0562   if (minsamp < 0)
0563   {
0564     static int counter = 0;
0565     if ( counter<1 )
0566     {
0567       std::cout << PHWHERE << " ped minsamp " << minsamp << "\t" << max << "\t" << presample << "\t" << nsamps << std::endl;
0568       counter++;
0569     }
0570     minsamp = 0;
0571   }
0572   if (maxsamp < 0)
0573   {
0574     static int counter = 0;
0575     if ( counter<1 )
0576     {
0577       std::cout << PHWHERE << " ped maxsamp " << maxsamp << "\t" << max << "\t" << presample << std::endl;
0578       counter++;
0579     }
0580     maxsamp = minsamp;
0581   }
0582 
0583   if ( _verbose )
0584   {
0585     std::cout << "CalcEventPed0_Presamp(), ch " << _ch << std::endl;
0586   }
0587 
0588   double mean = ped0stats->Mean();
0589   //double rms = ped0stats->RMS();
0590   double rms = _mbdcal->get_pedrms(_ch);
0591   if ( std::isnan(rms) )
0592   {
0593     // ped calib doesn't exist, set to average
0594     rms = 5.0;
0595   }
0596 
0597   ped_fcn->SetRange(minsamp-0.1,maxsamp+0.1);
0598   ped_fcn->SetParameter(0,1500.);
0599 
0600   if ( gRawPulse->GetN()==0 )//chiu
0601   {
0602     std::cout << PHWHERE << " gRawPulse 0" << std::endl;
0603   }
0604 
0605   if ( _verbose )
0606   {
0607     gRawPulse->Fit( ped_fcn, "RQ" );
0608 
0609     double chi2ndf = ped_fcn->GetChisquare()/ped_fcn->GetNDF();
0610     if ( chi2ndf > 4.0 )
0611     {
0612       gRawPulse->Draw("ap");
0613       ped_fcn->Draw("same");
0614       PadUpdate();
0615     }
0616   }
0617   else
0618   {
0619     //std::cout << PHWHERE << std::endl;
0620     gRawPulse->Fit( ped_fcn, "RNQ" );
0621 
0622     double chi2ndf = ped_fcn->GetChisquare()/ped_fcn->GetNDF();
0623     if ( _pileupfile != nullptr && chi2ndf > 4.0 )
0624     {
0625       *_pileupfile << "ped " << _ch << " mean " << mean << "\t";
0626       for ( int i=0; i<gRawPulse->GetN(); i++)
0627       {
0628         *_pileupfile << std::setw(6) << gRawPulse->GetPointY(i);
0629       }
0630       *_pileupfile << std::endl;
0631     }
0632   }
0633 
0634   double chi2 = ped_fcn->GetChisquare();
0635   double ndf = ped_fcn->GetNDF();
0636 
0637   if ( chi2/ndf < 4.0 )
0638   {
0639     mean = ped_fcn->GetParameter(0);
0640 
0641     Double_t x;
0642     Double_t y;
0643 
0644     for (int isamp = minsamp; isamp <= maxsamp; isamp++)
0645     {
0646       gRawPulse->GetPoint(isamp, x, y);
0647 
0648       // exclude outliers
0649       if ( fabs(y-mean) < 4.0*rms )
0650       {
0651         ped0stats->Push( y );
0652       }
0653 
0654       if ( _verbose )
0655       {
0656         std::cout << "CalcEventPed0_PreSamp: ped0stats " << _ch << "\t" << _evt_counter << "\t" 
0657           << "isamp " << isamp << "\t" << x << "\t" << y << std::endl;
0658       }
0659     }
0660   }
0661   else
0662   {
0663     // ped fit was bad, we have signal contamination in ped region
0664     // or other thing going on
0665     status = 1;
0666 
0667     if ( ped0stats->Size() < ped0stats->MaxNum() && !std::isnan(_mbdcal->get_ped(_ch)) ) // use pre-calib for early events
0668     {
0669       mean = _mbdcal->get_ped(_ch);
0670     }
0671     else  // use running mean, once enough stats are accumulated, or if no pre-calib pedestals
0672     {
0673       mean = ped0stats->Mean();
0674 
0675       if ( _verbose )
0676       {
0677         gRawPulse->Draw("ap");
0678         PadUpdate();
0679 
0680         if ( _evt_counter<100 )
0681         {
0682           double ped0statsrms = ped0stats->RMS();
0683           std::cout << "aaa ch " << _ch << "\t" << _evt_counter << "\t" << mean << "\t" << ped0statsrms << std::endl;
0684         }
0685         std::string junk;
0686         std::cin >> junk;
0687       }
0688     }
0689 
0690     // use straight mean for pedestal
0691     // Could consider using fit to hPed0 to remove outliers
0692     //rms = ped0stats->RMS();
0693     //Double_t mean = hPed0->GetMean();
0694     //Double_t rms = hPed0->GetRMS();
0695   }
0696 
0697   SetPed0(mean, rms);
0698 
0699   if (_verbose > 0 && _evt_counter < 10)
0700   {
0701     std::cout << "CalcEventPed0_PreSamp: ped0stats " << _ch << "\t" << _evt_counter << "\t" << mean << "\t" << rms << std::endl;
0702     std::cout << "CalcEventPed0_PreSamp: ped0stats " << ped0stats->RMS() << std::endl;
0703   }
0704 
0705   _verbose = 0;
0706 
0707   return status;
0708 }
0709 
0710 Double_t MbdSig::LeadingEdge(const Double_t threshold)
0711 {
0712   // Find first point above threshold
0713   // We also make sure the next point is above threshold
0714   // to get rid of a high fluctuation
0715   int n = gSubPulse->GetN();
0716   Double_t* x = gSubPulse->GetX();
0717   Double_t* y = gSubPulse->GetY();
0718 
0719   int sample = -1;
0720   for (int isamp = 0; isamp < n; isamp++)
0721   {
0722     if (y[isamp] > threshold)
0723     {
0724       if (isamp == (n - 1) || y[isamp + 1] > threshold)
0725       {
0726         sample = isamp;
0727         break;
0728       }
0729     }
0730   }
0731   if (sample < 1)
0732   {
0733     return -9999.;  // no signal above threshold
0734   }
0735 
0736   // Linear Interpolation of start time
0737   Double_t dx = x[sample] - x[sample - 1];
0738   Double_t dy = y[sample] - y[sample - 1];
0739   Double_t dt1 = y[sample] - threshold;
0740 
0741   Double_t t0 = x[sample] - (dt1 * (dx / dy));
0742 
0743   return t0;
0744 }
0745 
0746 Double_t MbdSig::dCFD(const Double_t fraction_threshold)
0747 {
0748   // Find first point above threshold
0749   // We also make sure the next point is above threshold
0750   // to get rid of a high fluctuation
0751   int n = gSubPulse->GetN();
0752   Double_t* x = gSubPulse->GetX();
0753   Double_t* y = gSubPulse->GetY();
0754 
0755   // Get max amplitude
0756   Double_t ymax = TMath::MaxElement(n, y);
0757   if (f_ampl == -9999.)
0758   {
0759     f_ampl = ymax;
0760   }
0761 
0762   Double_t threshold = fraction_threshold * ymax;  // get fraction of amplitude
0763   // std::cout << "threshold = " << threshold << "\tymax = " << ymax <<std::endl;
0764 
0765   int sample = -1;
0766   for (int isamp = 0; isamp < n; isamp++)
0767   {
0768     if (y[isamp] > threshold)
0769     {
0770       if (isamp == (n - 1) || y[isamp + 1] > threshold)
0771       {
0772         sample = isamp;
0773         break;
0774       }
0775     }
0776   }
0777   if (sample < 1)
0778   {
0779     return -9999.;  // no signal above threshold
0780   }
0781 
0782   // Linear Interpolation of start time
0783   Double_t dx = x[sample] - x[sample - 1];
0784   Double_t dy = y[sample] - y[sample - 1];
0785   Double_t dt1 = y[sample] - threshold;
0786 
0787   Double_t t0 = x[sample] - (dt1 * (dx / dy));
0788 
0789   return t0;
0790 }
0791 
0792 Double_t MbdSig::MBDTDC(const Int_t max_samp)
0793 {
0794   // Get the amplitude of a fixed sample (max_samp) to get time
0795   // Used in MBD Time Channels
0796   Double_t* y = gSubPulse->GetY();
0797 
0798   if (y == nullptr)
0799   {
0800     std::cout << "ERROR y == 0" << std::endl;
0801     return std::numeric_limits<Double_t>::quiet_NaN();
0802   }
0803 
0804   f_time = y[max_samp];
0805 
0806   if ( y[2]>100. )
0807   {
0808     f_time = 0.;
0809   }
0810 
0811   /*
0812   if ( _ch==128 )
0813   {
0814     std::cout << "msig\t" << _ch << "\t" << f_time << "\t" << f_ampl << std::endl;
0815     gSubPulse->Print("ALL");
0816   }
0817   */
0818 
0819   return f_time;
0820 }
0821 
0822 Double_t MbdSig::Integral(const Double_t xmin, const Double_t xmax)
0823 {
0824   Int_t n = gSubPulse->GetN();
0825   Double_t* x = gSubPulse->GetX();
0826   Double_t* y = gSubPulse->GetY();
0827 
0828   f_integral = 0.;
0829   for (int ix = 0; ix < n; ix++)
0830   {
0831     if (x[ix] >= xmin && x[ix] <= xmax)
0832     {
0833       // Get dx
0834       Double_t dx = (x[ix + 1] - x[ix - 1]) / 2.0;
0835       f_integral += (y[ix] * dx);
0836     }
0837   }
0838 
0839   return f_integral;
0840 }
0841 
0842 void MbdSig::LocMax(Double_t& x_at_max, Double_t& ymax, Double_t xminrange, Double_t xmaxrange)
0843 {
0844   _verbose = 0;
0845   if ( _verbose && _ch==250 )
0846   {
0847     gSubPulse->Draw("ap");
0848     gPad->Modified();
0849     gPad->Update();
0850   }
0851 
0852   // Find index of maximum peak
0853   Int_t n = gSubPulse->GetN();
0854   Double_t* x = gSubPulse->GetX();
0855   Double_t* y = gSubPulse->GetY();
0856 
0857   // if flipped or equal, we search the whole range
0858   if (xmaxrange <= xminrange)
0859   {
0860     xminrange = -DBL_MAX;
0861     xmaxrange = DBL_MAX;
0862   }
0863 
0864   x_at_max = -DBL_MAX;
0865   ymax = -DBL_MAX;
0866 
0867   for (int i = 0; i < n; i++)
0868   {
0869     // Skip if out of range
0870     if (x[i] < xminrange)
0871     {
0872       continue;
0873     }
0874     if (x[i] > xmaxrange)
0875     {
0876       break;
0877     }
0878 
0879     if (y[i] > ymax)
0880     {
0881       ymax = y[i];
0882       x_at_max = x[i];
0883     }
0884   }
0885 
0886   if ( _verbose )
0887   {
0888     std::string junk;
0889     std::cin >> junk;
0890     std::cout << "MbdSig::LocMax, " << x_at_max << "\t" << ymax << std::endl;
0891     _verbose = 0;
0892   }
0893 }
0894 
0895 void MbdSig::LocMin(Double_t& x_at_min, Double_t& ymin, Double_t xminrange, Double_t xmaxrange)
0896 {
0897   // Find index of minimum peak (for neg signals)
0898   Int_t n = gSubPulse->GetN();
0899   Double_t* x = gSubPulse->GetX();
0900   Double_t* y = gSubPulse->GetY();
0901 
0902   // if flipped or equal, we search the whole range
0903   if (xmaxrange <= xminrange)
0904   {
0905     xminrange = -DBL_MAX;
0906     xmaxrange = DBL_MAX;
0907   }
0908 
0909   ymin = DBL_MAX;
0910 
0911   for (int i = 0; i < n; i++)
0912   {
0913     // Skip if out of range
0914     if (x[i] < xminrange)
0915     {
0916       continue;
0917     }
0918     if (x[i] > xmaxrange)
0919     {
0920       break;
0921     }
0922 
0923     if (y[i] < ymin)
0924     {
0925       ymin = y[i];
0926       x_at_min = x[i];
0927     }
0928   }
0929 
0930   // old way of getting locmax
0931   // int locmax = TMath::LocMin(n,y);
0932 }
0933 
0934 void MbdSig::Print()
0935 {
0936   Double_t x;
0937   Double_t y;
0938   std::cout << "CH " << _ch << std::endl;
0939   for (int isamp = 0; isamp < _nsamples; isamp++)
0940   {
0941     gpulse->GetPoint(isamp, x, y);
0942     std::cout << isamp << "\t" << x << "\t" << y << std::endl;
0943   }
0944 }
0945 
0946 void MbdSig::DrawWaveform()
0947 {
0948   int orig_verbose = _verbose;
0949   if ( _verbose <= 5 )
0950   {
0951     _verbose = 6;
0952   }
0953 
0954   gSubPulse->Draw("ap");
0955   gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName());
0956   gPad->SetGridy(1);
0957   if ( template_fcn!=nullptr )
0958   {
0959     template_fcn->Draw("same");  // should check if fit was made
0960   }
0961   PadUpdate();
0962 
0963   _verbose = orig_verbose;
0964 }
0965 
0966 void MbdSig::PadUpdate() const
0967 {
0968   // Make sure TCanvas is created externally!
0969   std::cout << PHWHERE << " PadUpdate\t_verbose = " << _verbose << std::endl;
0970   if ( _verbose>5 )
0971   {
0972     gPad->Modified();
0973     gPad->Update();
0974     std::cout << _ch << " ? ";
0975     if ( _verbose>10 )
0976     {
0977       std::string junk;
0978       std::cin >> junk;
0979 
0980       if (junk[0] == 'w' || junk[0] == 's')
0981       {
0982         TString name = "ch";
0983         name += _ch;
0984         name += ".png";
0985         gPad->SaveAs(name);
0986       }
0987     }
0988   }
0989 }
0990 
0991 Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par)
0992 {
0993   // par[0] is the amplitude (relative to the spline amplitude)
0994   // par[1] is the start time (in sample number)
0995   // x[0] units are in sample number
0996   Double_t xx = x[0] - par[1];
0997   Double_t f = 0.;
0998 
0999   int verbose = 0;
1000   if ( verbose )
1001   {
1002     std::cout << PHWHERE << " " << _ch << " x par0 par1 " << x[0] << "\t" << par[0] << "\t" << par[1] << std::endl;
1003   }
1004 
1005 
1006   // When fit is out of limits of good part of spline, ignore fit
1007   if (xx < template_begintime || xx > template_endtime || std::isnan(xx) )
1008   {
1009     TF1::RejectPoint();
1010 
1011     if ( std::isnan(xx) )
1012     {
1013       if (verbose > 0)
1014       {
1015     std::cout << PHWHERE << " " << _evt_counter << ", " << _ch
1016           << " ERROR x par0 par1 " << x[0] << "\t" << par[0] << "\t" << par[1] << std::endl;
1017     if ( x[0] == 0. )
1018     {
1019       gSubPulse->Print("ALL");
1020     }
1021       }
1022       return 0.;
1023     }
1024 
1025     if (xx < template_begintime)
1026     {
1027       // Double_t x0,y0;
1028       Double_t y0 = template_y[0];
1029       return par[0] * y0;
1030     }
1031     if (xx > template_endtime)
1032     {
1033       // Double_t x0,y0;
1034       Double_t y0 = template_y[template_npointsx - 1];
1035       return par[0] * y0;
1036     }
1037   }
1038 
1039   // Linear Interpolation of template
1040   Double_t x0 = 0.;
1041   Double_t y0 = 0.;
1042   Double_t x1 = 0.;
1043   Double_t y1 = 0.;
1044 
1045   // find the index in the vector which is closest to xx
1046   Double_t step = (template_endtime - template_begintime) / (template_npointsx - 1);
1047   Double_t index = (xx - template_begintime) / step;
1048   //std::cout << "xxx " << index << "\t" << xx << "\t" << template_begintime << "\t" << template_endtime << "\t" << step << std::endl;
1049 
1050   int ilow = TMath::FloorNint(index);
1051   int ihigh = TMath::CeilNint(index);
1052   if (ilow < 0 || ihigh >= template_npointsx)
1053   {
1054     if (verbose > 0)
1055     {
1056       std::cout << "ERROR, ilow ihigh " << ilow << "\t" << ihigh << std::endl;
1057       std::cout << " " << xx << " " << x[0] << " " << par[1] << std::endl;
1058     }
1059 
1060     if (ilow < 0)
1061     {
1062       ilow = 0;
1063     }
1064     else if (ihigh >= template_npointsx)
1065     {
1066       ihigh = template_npointsx - 1;
1067     }
1068   }
1069 
1070   if (ilow == ihigh)
1071   {
1072     f = par[0] * template_y[ilow];
1073   }
1074   else
1075   {
1076     x0 = template_begintime + ilow * step;
1077     y0 = template_y[ilow];
1078     x1 = template_begintime + ihigh * step;
1079     y1 = template_y[ihigh];
1080     f = par[0] * (y0 + ((y1 - y0) / (x1 - x0)) * (xx - x0));  // linear interpolation
1081   }
1082 
1083   // reject points with very bad rms in shape
1084   if (template_yrms[ilow] >= 1.0 || template_yrms[ihigh] >= 1.0)
1085   {
1086     TF1::RejectPoint();
1087     // return f;
1088   }
1089 
1090   // Reject points where ADC saturates
1091   int samp_point = static_cast<int>(x[0]);
1092   Double_t temp_x;
1093   Double_t temp_y;
1094   gRawPulse->GetPoint(samp_point, temp_x, temp_y);
1095   if (temp_y > 16370)
1096   {
1097     //if ( _ch==185 ) std::cout << "ADCSATURATED " << _ch << "\t" << samp_point << "\t" << temp_x << "\t" << temp_y << std::endl;
1098     TF1::RejectPoint();
1099   }
1100 
1101   //verbose = 0;
1102   return f;
1103 }
1104 
1105 // sampmax>0 means fit to the peak near sampmax
1106 int MbdSig::FitTemplate( const Int_t sampmax )
1107 {
1108   //std::cout << PHWHERE << std::endl;  //chiu
1109   //_verbose = 100; // uncomment to see fits
1110   //_verbose = 12;        // don't see pedestal fits
1111 
1112   // Check if channel is empty
1113   if (gSubPulse->GetN() == 0)
1114   {
1115     f_ampl = 0.;
1116     f_time = std::numeric_limits<Float_t>::quiet_NaN();
1117     std::cout << "ERROR, gSubPulse empty" << std::endl;
1118     return 1;
1119   }
1120 
1121   // Determine if channel is saturated
1122   Double_t *rawsamps = gRawPulse->GetY();
1123   Int_t nrawsamps = gRawPulse->GetN();
1124   int nsaturated = 0;
1125   for (int ipt=0; ipt<nrawsamps; ipt++)
1126   {
1127     if ( rawsamps[ipt] > 16370. )
1128     {
1129       nsaturated++;
1130     }
1131   }
1132   /*
1133   if ( nsaturated>2 && _ch==185 )
1134   {
1135     _verbose = 12;
1136   }
1137   */
1138 
1139 
1140   if (_verbose > 0)
1141   {
1142     std::cout << "Fitting ch " << _ch << std::endl;
1143   }
1144 
1145   // Get x and y of maximum
1146   Double_t x_at_max{-1.};
1147   Double_t ymax{0.};
1148   if ( sampmax>=0 )
1149   {
1150     gSubPulse->GetPoint(sampmax, x_at_max, ymax);
1151     if ( nsaturated<=3 )
1152     {
1153       x_at_max -= 2.0;
1154     }
1155     else
1156     {
1157       x_at_max -= 1.5;
1158       ymax = 16370.+nsaturated*2000.;
1159     }
1160   }
1161   else
1162   {
1163     ymax = TMath::MaxElement( gSubPulse->GetN(), gSubPulse->GetY() );
1164     x_at_max = TMath::LocMax( gSubPulse->GetN(), gSubPulse->GetY() );
1165   }
1166 
1167   // Threshold cut
1168   if ( ymax < 20. )
1169   {
1170     f_ampl = 0.;
1171     f_time = std::numeric_limits<Float_t>::quiet_NaN();
1172     if ( _verbose>20 )
1173     {
1174       // for checking pedestal
1175       std::cout << "skipping, ymax < 20" << std::endl;
1176       gSubPulse->Draw("ap");
1177       gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName());
1178       gPad->SetGridy(1);
1179       PadUpdate();
1180     }
1181 
1182     _verbose = 0;
1183     return 1;
1184   }
1185 
1186   template_fcn->SetParameters(ymax, x_at_max);
1187   // template_fcn->SetParLimits(1, fit_min_time, fit_max_time);
1188   // template_fcn->SetParLimits(1, 3, 15);
1189   // template_fcn->SetRange(template_min_xrange,template_max_xrange);
1190   if ( nsaturated<=3 )
1191   {
1192     template_fcn->SetRange(0, _nsamples);
1193   }
1194   else
1195   {
1196     template_fcn->SetRange(0, sampmax + nsaturated - 0.5);
1197   }
1198 
1199   if ( gSubPulse->GetN()==0 )//chiu
1200   {
1201     std::cout << PHWHERE << " gSubPulse 0" << std::endl;
1202   }
1203 
1204   if (_verbose == 0)
1205   {
1206     //std::cout << PHWHERE << std::endl;
1207     gSubPulse->Fit(template_fcn, "RNQ");
1208   }
1209   else
1210   {
1211     std::cout << "doing fit1 " << x_at_max << "\t" << ymax << std::endl;
1212     gSubPulse->Fit(template_fcn, "R");
1213     gSubPulse->Draw("ap");
1214     gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName());
1215     gPad->SetGridy(1);
1216     PadUpdate();
1217     //std::cout << "doing fit2 " << _verbose << std::endl;
1218     //std::cout << "doing fit3 " << _verbose << std::endl;
1219     //gSubPulse->Print("ALL");
1220   }
1221 
1222   // Get fit parameters
1223   f_ampl = template_fcn->GetParameter(0);
1224   f_time = template_fcn->GetParameter(1);
1225   if ( f_time<0. || f_time>_nsamples )
1226   {
1227     f_time = _nsamples*0.5;  // bad fit last time
1228   }
1229 
1230   // refit with new range to exclude after-pulses
1231   template_fcn->SetParameters( f_ampl, f_time );
1232   if ( nsaturated<=3 )
1233   {
1234     template_fcn->SetRange( 0., f_time+4.0 );
1235   }
1236   else
1237   {
1238     template_fcn->SetRange( 0., f_time+nsaturated+0.8 );
1239   }
1240 
1241   if (_verbose == 0)
1242   {
1243     //std::cout << PHWHERE << std::endl;
1244     int fit_status = gSubPulse->Fit(template_fcn, "RNQ");
1245     if ( fit_status<0 )
1246     {
1247       std::cout << PHWHERE << "\t" << fit_status << std::endl;
1248       gSubPulse->Print("ALL");
1249       gSubPulse->Draw("ap");
1250       gSubPulse->Fit(template_fcn, "R");
1251       std::cout << "ampl time before refit " << f_ampl << "\t" << f_time << std::endl;
1252       f_ampl = template_fcn->GetParameter(0);
1253       f_time = template_fcn->GetParameter(1);
1254       std::cout << "ampl time after  refit " << f_ampl << "\t" << f_time << std::endl;
1255       PadUpdate();
1256       std::string junk;
1257       std::cin >> junk;
1258     }
1259   }
1260   else
1261   {
1262     gSubPulse->Fit(template_fcn, "R");
1263     //gSubPulse->Print("ALL");
1264     std::cout << "ampl time before refit " << f_ampl << "\t" << f_time << std::endl;
1265     f_ampl = template_fcn->GetParameter(0);
1266     f_time = template_fcn->GetParameter(1);
1267     std::cout << "ampl time after  refit " << f_ampl << "\t" << f_time << std::endl;
1268   }
1269 
1270   f_ampl = template_fcn->GetParameter(0);
1271   f_time = template_fcn->GetParameter(1);
1272 
1273   //if ( f_time<0 || f_time>30 )
1274   //if ( (_ch==185||_ch==155||_ch==249) && (fabs(f_ampl) > 44000.) )
1275   //double chi2 = template_fcn->GetChisquare();
1276   //double ndf = template_fcn->GetNDF();
1277   //if ( (_ch==185||_ch==155||_ch==249) && (fabs(chi2/ndf) > 100.) && nsaturated > 3)
1278   if (_verbose > 0 && fabs(f_ampl) > 0.)
1279   {
1280     _verbose = 12;
1281     std::cout << "FitTemplate " << _ch << "\t" << f_ampl << "\t" << f_time << std::endl;
1282     std::cout << "            " << template_fcn->GetChisquare()/template_fcn->GetNDF() << std::endl;
1283     gSubPulse->Draw("ap");
1284     gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName());
1285     gPad->SetGridy(1);
1286     template_fcn->SetLineColor(4);
1287     template_fcn->Draw("same");
1288     PadUpdate();
1289   }
1290 
1291   _verbose = 0;
1292   return 1;
1293 }
1294 
1295 int MbdSig::SetTemplate(const std::vector<float>& shape, const std::vector<float>& sherr)
1296 {
1297   template_y = shape;
1298   template_yrms = sherr;
1299 
1300   if (_verbose)
1301   {
1302     std::cout << "SHAPE " << _ch << "\t" << template_y.size() << std::endl;
1303     for (size_t i = 0; i < template_y.size(); i++)
1304     {
1305       if (i % 10 == 0)
1306       {
1307         std::cout << i << ":\t" << std::endl;
1308       }
1309       std::cout << " " << template_y[i];
1310     }
1311     std::cout << std::endl;
1312   }
1313 
1314   if (template_fcn == nullptr)
1315   {
1316     TString name = "template_fcn";
1317     name += _ch;
1318     // template_fcn = new TF1(name,this,&MbdSig::TemplateFcn,template_min_xrange,template_max_xrange,2,"MbdSig","TemplateFcn");
1319     // template_fcn = new TF1(name,this,&MbdSig::TemplateFcn,-10,20,2,"MbdSig","TemplateFcn");
1320     template_fcn = new TF1(name, this, &MbdSig::TemplateFcn, 0, _nsamples, 2, "MbdSig", "TemplateFcn");
1321     template_fcn->SetParameters(1, 10);
1322     template_fcn->SetParName(0, "ampl");
1323     template_fcn->SetParName(1, "time");
1324     SetTemplateSize(900, 1000, -10., 20.);
1325 
1326     if (_verbose)
1327     {
1328       std::cout << "SHAPE " << _ch << std::endl;
1329       template_fcn->Draw("acp");
1330       gPad->Modified();
1331       gPad->Update();
1332     }
1333   }
1334 
1335   return 1;
1336 }