StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StFcsWaveformFitMaker.cxx
1 // $Id: StFcsWaveformFitMaker.cxx,v 1.2 2021/05/30 21:26:52 akio Exp $
2 // $Log: StFcsWaveformFitMaker.cxx,v $
3 // Revision 1.2 2021/05/30 21:26:52 akio
4 // Added mFitDrawOn=2 for resetting mHitIdx for end of page, instead of each event
5 // Increased accepted tb range as hit, need further tuning
6 //
7 // Revision 1.1 2021/03/30 13:40:13 akio
8 // FCS code after peer review and moved from $CVSROOT/offline/upgrades/akio
9 //
10 // Revision 1.18 2021/02/25 21:56:28 akio
11 // Int_t -> int
12 //
13 // Revision 1.17 2021/02/25 19:24:33 akio
14 // Modified for STAR code review (Hongwei)
15 //
16 // Revision 1.16 2021/02/13 13:43:09 akio
17 // Some cleanups
18 //
19 // Revision 1.15 2021/02/13 03:11:44 akio
20 // Added TGraphAsymmErrorsWithReset and separate resetGraph() and simplify getGraph(idx=-1)
21 //
22 // Revision 1.14 2021/02/11 18:45:00 akio
23 // fix getGraph(0,n) to getGraph(mHitIdx,n)
24 //
25 // Revision 1.13 2021/02/10 04:14:41 akio
26 // And Davids new draw functions
27 //
28 // Revision 1.12 2021/02/10 04:11:24 akio
29 // Code from David on improving TGraphArray housekeeping
30 //
31 // Revision 1.11 2021/01/26 18:43:14 akio
32 // Include David's fitter & holding of TGA for the event. Separate drawFit().
33 //
34 // Revision 1.10 2021/01/25 19:28:15 akio
35 // few changes to speed up
36 //
37 // Revision 1.9 2021/01/11 14:46:18 akio
38 // Adding another tail functional form, adding fit drawing to PDF
39 //
40 // Revision 1.8 2021/01/02 21:54:05 akio
41 // fix a typo
42 //
43 // Revision 1.7 2021/01/02 21:38:03 akio
44 // Fix some minor issues
45 //
46 // Revision 1.6 2021/01/02 21:04:53 akio
47 // added 11 for ped sub
48 //
49 // Revision 1.5 2020/09/17 19:01:52 akio
50 // fix bugs David reported
51 //
52 // Revision 1.4 2020/09/17 15:54:51 akio
53 // Add parameter limits so that fit won't go crazy, esp when main peak is large and 2nd peak from the main pulse found to form a peak
54 //
55 // Revision 1.3 2020/09/16 14:52:46 akio
56 // Use of TGraphAsymmErrors to deal with adc saturation
57 // Impelment gausFit() for gaussian fit
58 //
59 // Revision 1.2 2020/09/03 20:15:49 akio
60 // Adding res array for peak height/position/sigma and chi2
61 //
62 // Revision 1.1 2020/08/19 19:51:08 akio
63 // Initial version
64 //
65 
66 #include "StFcsWaveformFitMaker.h"
67 
68 ClassImp(StFcsWaveformFitMaker)
69 
70 #include "StMessMgr.h"
71 #include "StEvent/StEventTypes.h"
72 #include "StEvent/StFcsHit.h"
73 #include "StFcsDbMaker/StFcsDb.h"
74 #include "StFcsDbMaker/StFcsDbPulse.h"
75 
76 #include <cmath>
77 #include <chrono>
78 #include "TMath.h"
79 #include "TF1.h"
80 #include "TH1F.h"
81 #include "TH2F.h"
82 #include "TGraph.h"
83 #include "TGraphAsymmErrors.h"
84 #include "TGraphAsymmErrorsWithReset.h"
85 #include "TCanvas.h"
86 #include "TColor.h"
87 #include "TStyle.h"
88 #include "TROOT.h"
89 
90 
91 StFcsWaveformFitMaker::StFcsWaveformFitMaker(const char* name) : StMaker(name) {
92  mChWaveData.SetClass("TGraphAsymmErrors"); //Initialize with only one graph at first
93  mPulseFit = 0;
94 
95  mOutFile = 0;
96 
97  mEnergySelect[0]=13; //default PulseFit2 for Ecal
98  mEnergySelect[1]=13; //default PulseFit2 for Hcal
99  mEnergySelect[2]=1; //default sum8 for Pres
100 
101  //Values to divide sum8 method to match the fitted result as determined by looking at data from Run 22
102  mEnergySumScale[0] = 1.226;
103  mEnergySumScale[1] = 1.195;
104  mEnergySumScale[2] = 1.29;
105 
106  mAnaWaveform = true; //default is to compute integral for the waveform
107 
108  for( UShort_t i=0; i<7; ++i ){
109  if( i<3 ){
110  mH2_Dep0DepMod[i]=0;
111  mH2_Sum8Dep0[i]=0;
112  mH2_Sum8DepMod[i]=0;
113  }
114  if( i<6 ){
115  mH2F_AdcTbAkio[i] = 0;
116  mH2F_AdcTbMine[i] = 0;
117  mH2F_SumFitvSumWin[i] = 0;
118  mH2F_APeakvMPeak[i] = 0;
119  mH1F_PeakStart[i] = 0;
120  mH1F_PeakEnd[i] = 0;
121  mH2F_NOvsId[i] = 0;
122  }
123  mH2F_AdcTbValidPeak[i] = 0;
124  mH1F_NPeaks[i] = 0;
125  mH1F_NPeaksFiltered[i] = 0;
126  mH1F_Res0[i] = 0;
127  mH1F_Res0Zoom[i] = 0;
128  mH1F_Sum8Res0[i] = 0;
129  mH1F_Sum8Res0Zoom[i] = 0;
130  mH1F_FitRes0[i] = 0;
131  mH1F_FitRes0Zoom[i] = 0;
132  mH2F_Sum8vFit[i] = 0;
133  }
134 }
135 
136 StFcsWaveformFitMaker::~StFcsWaveformFitMaker() {
137  mChWaveData.Delete();
138  delete mPulseFit;
139  for( UShort_t i=0; i<7; ++i ){
140  if( i<3 ){
141  delete mH2_Dep0DepMod[i];
142  delete mH2_Sum8Dep0[i];
143  delete mH2_Sum8DepMod[i];
144  }
145  if( i<6 ){
146  delete mH2F_AdcTbAkio[i];
147  delete mH2F_AdcTbMine[i];
148  delete mH2F_SumFitvSumWin[i];
149  delete mH2F_APeakvMPeak[i];
150  delete mH1F_PeakStart[i];
151  delete mH1F_PeakEnd[i];
152  delete mH2F_NOvsId[i];
153  }
154  delete mH2F_AdcTbValidPeak[i];
155  delete mH1F_NPeaks[i];
156  delete mH1F_NPeaksFiltered[i];
157 
158  delete mH1F_Res0[i];
159  delete mH1F_Res0Zoom[i];
160  delete mH1F_Sum8Res0[i];
161  delete mH1F_Sum8Res0Zoom[i];
162  delete mH1F_FitRes0[i];
163  delete mH1F_FitRes0Zoom[i];
164  delete mH2F_Sum8vFit[i];
165  }
166  delete mTime;
167 
168  delete mH1_NPeaksAkio;
169  delete mH1_NPeaksFilteredAkio;
170 
171  delete mH1_PeakTiming;
172 
173  delete mH2_NPeakvsPeakXdiff;
174  delete mH2_NPeakvsPeakYratio;
175  delete mH1_VOverlap;
176  delete mH2_NOvsNPeaks;
177  delete mH2_VvsNOverlap;
178 
179  delete mH1_TimeFitPulse;
180 
181  delete mH2_HeightvsSigma;
182  delete mH2_HeightvsSigmaTrig;
183  delete mH1_ChiNdf;
184  delete mH2_HeightvsChiNdf;
185  delete mH2_MeanvsChiNdf;
186  delete mH2_SigmavsChiNdf;
187 
188  delete mH1_PeakTimingGaus;
189  delete mH1_PeakTimingPuls;
190  delete mH2_PeakTimingCompare;
191 
192  if( mOutFile!=0 ){ mOutFile->Close(); delete mOutFile; }
193 }
194 
195 void StFcsWaveformFitMaker::writeFile(std::string filename){
196  if( filename.size()==0 ){return;}
197  if( mOutFile!=0 ){ mOutFile->Close(); delete mOutFile; mOutFile=0; }
198  mOutFile = new TFile(filename.c_str(),"RECREATE");
199 }
200 
202 {
203  mTest=v;
204  if( mOutFile==0 ){ writeFile("test.root"); }//All test levels need to have a file output to write to
205  if( mTest==1 ){//Test level 1 is for testing the DEP triggering algorithm to currently selected energy method. If method is zero switch on most basic which is sum 8
206  if( mEnergySelect[0]==0 ){mEnergySelect[0]=1; mEnergySelect[1]=1; mEnergySelect[2]=1; }
207  }
208  if( mTest==2 ){//Test level 2 is for testing *StFcsPulseAna* to gausFit() which requires either energy select 10 or 11.
209  if( mEnergySelect[0]!=10 || mEnergySelect[0]!=11 ){ mEnergySelect[0]=10;}
210  if( mEnergySelect[1]!=10 || mEnergySelect[1]!=11 ){ mEnergySelect[1]=10;}
211  if( mEnergySelect[2]!=10 || mEnergySelect[2]!=11 ){ mEnergySelect[2]=10;}
212  }
213  if( mTest==3 ){//Test level 3 is for testing the steering code in PulseFit1() which is energy select 12
214  if( mEnergySelect[0]!=12 ){ mEnergySelect[0]=12; }
215  if( mEnergySelect[1]!=12 ){ mEnergySelect[1]=12; }
216  if( mEnergySelect[2]!=12 ){ mEnergySelect[2]=12; }
217  }
218  if( mTest==4 ){//Test level 4 is for testing fitting all signals using my pulsefit code
219  if( mEnergySelect[0]!=12 ){ mEnergySelect[0]=12; }
220  if( mEnergySelect[1]!=12 ){ mEnergySelect[1]=12; }
221  if( mEnergySelect[2]!=12 ){ mEnergySelect[2]=12; }
222  }
223  if( mTest==5 ){//Test level 5 is for testing timing on gausFit() and PulseFit1() so all is needed is that the energy select is not zero and drawing is off otherwise it will double up the hits in mChWaveData
224  if( mEnergySelect[0]==0 ){ mEnergySelect[0]=1; mEnergySelect[1]=1; mEnergySelect[2]=1; mFitDrawOn=0; }
225  }
226  if( mTest==6 ){//Test level 6 is for testing the steering code in PulseFit2()
227  if( mEnergySelect[0]!=13 ){ mEnergySelect[0]=13; }
228  if( mEnergySelect[1]!=13 ){ mEnergySelect[1]=13; }
229  if( mEnergySelect[2]!=13 ){ mEnergySelect[2]=13; }
230  }
231  if( mTest==7 ){//Test level 7 is for testing overall quality of PulseFit2()
232  if( mEnergySelect[0]!=13 ){ mEnergySelect[0]=13; }
233  if( mEnergySelect[1]!=13 ){ mEnergySelect[1]=13; }
234  if( mEnergySelect[2]!=1 ){ mEnergySelect[2]=1; }
235  }
236  if( mTest==8 ){//Test level 8 is for testing fitting quality from PulseFit2() from gausFit()
237  if( mEnergySelect[0]!=13 ){ mEnergySelect[0]=13; }
238  if( mEnergySelect[1]!=13 ){ mEnergySelect[1]=13; }
239  if( mEnergySelect[2]!=1 ){ mEnergySelect[2]=1; }
240  }
241 }
242 
243 void StFcsWaveformFitMaker::setTail(int v){mTail=v;}
244 
245 void StFcsWaveformFitMaker::Clear(Option_t* option) {
246  if(mFitDrawOn>=1) mHitIdx=0;
247  StMaker::Clear(option);
248 }
249 
250 int StFcsWaveformFitMaker::Init()
251 {
252  if(mFilename){
253  mCanvas=new TCanvas("FCSWaveFormFit","FCSWaveFormFit",10,10,2000,2000);
254  gStyle->SetOptStat(0);
255  char file[100];
256  if( mFitDrawOn>=0 ){
257  sprintf(file,"%s.pdf[",mFilename);//Opens fileA but does not save anything
258  mCanvas->Print(file);
259  }
260  }
261  if(mMeasureTime){
262  mTime=new TH1F("FitTime","FitTime;msec",1000,0,1000);
263  }
264  if(mFilter && mFilter[0]=='0'){
265  mTimeIntg[0]=new TH2F("Noboth", "No both; PeakTB; Integral",100,47.0,54.0,400,0.0,2000);
266  mTimeIntg[1]=new TH2F("NoFall", "No Fall; PeakTB; Integral",100,47.0,54.0,400,0.0,2000);
267  mTimeIntg[2]=new TH2F("NoRise", "No Rise; PeakTB; Integral",100,47.0,54.0,400,0.0,2000);
268  mTimeIntg[3]=new TH2F("Accepted","Accepted; PeakTB; Integral",100,47.0,54.0,400,0.0,2000);
269  }
270  if( mOutFile!=0 ){
271  for( UShort_t i=0; i<7; ++i ){
272  std::stringstream ss;
273  ss << i;
274  if( i<3 ){
275  if( mTest==1 ){
276  mH2_Dep0DepMod[i]=new TH2F( ("H2_Dep0DepMod_"+ss.str()).c_str(), ("Sum Dep0 vs DepMod "+ss.str()).c_str(),100,0,1000,100,0,1000);
277  mH2_Sum8Dep0[i]=new TH2F( ("H2_Sum8Dep0_"+ss.str()).c_str(), ("Sum 8 vs Dep0 "+ss.str()).c_str(),100,0,1000,100,0,1000);
278  mH2_Sum8DepMod[i]=new TH2F( ("H2_Sum8DepMod_"+ss.str()).c_str(), ("Sum 8 vs DepMod "+ss.str()).c_str(),100,0,1000,100,0,1000);
279  }
280  }
281  if( i<6 ){
282  if( mTest==2 ){
283  mH2F_AdcTbAkio[i] = new TH2F( ("H2_AdcTbAkio_"+ss.str()).c_str(),"Akio Peaks Adc vs. Tb",102,-1.5,100.5,4097,-0.5,4096.5);
284  mH2F_AdcTbMine[i] = new TH2F( ("H2_AdcTbMine_"+ss.str()).c_str(),"My Peaks Adc vs. Tb",102,-1.5,100.5,4097,-0.5,4096.5);
285  mH2F_SumFitvSumWin[i] = new TH2F( ("H2_SumFitvSumWin_"+ss.str()).c_str(),"Fitted Sum vs. Peak Window Sum",100,0,2000,100,0,2000);
286  mH2F_APeakvMPeak[i] = new TH2F( ("H2_APeakvMPeak_"+ss.str()).c_str(),"Peak Locations Akio v. Mine",80,-0.5,79.5,80,-0.5,79.5);
287  mH1F_PeakStart[i] = new TH1F( ("H1_PeakStart_"+ss.str()).c_str(),"PeakWindow start times",102,-1.5,100.5);
288  mH1F_PeakEnd[i] = new TH1F( ("H1_PeakEnd_"+ss.str()).c_str(),"PeakWindow end time",102,-1.5,100.5);
289  }
290  if( mTest==3 ){
291  mH2F_NOvsId[i] = new TH2F( ("H2_NOvsId_"+ss.str()).c_str(),"Number of overlaps vs. Ch Id", 748,-0.5,747.5, 11,-0.5,10.5);
292  }
293  }
294  //i<7 histograms
295  if( mTest==2 ){
296  if( i<1 ){ //Test=2 only needs 1 histogram
297  mH1F_NPeaks[i] = new TH1F( ("H1_NPeaks_"+ss.str()).c_str(),"Number of peaks from finder", 11,-0.5,10.5);
298  mH1F_NPeaksFiltered[i] = new TH1F( ("H1_NPeaksFiltered_"+ss.str()).c_str(),"Number of peaks from finder when a valid peak was found", 11,-0.5,10.5);
299  }
300  mH2F_AdcTbValidPeak[i] = new TH2F( ("H2_AdcTbValidPeak_"+ss.str()).c_str(),"Valid Peaks Adc vs. Tb",102,-1.5,100.5,4097,-0.5,4096.5);
301  }
302  if( mTest==3 || mTest==6 || mTest==7 || mTest==8 ){
303  mH1F_NPeaks[i] = new TH1F( ("H1_NPeaks_"+ss.str()).c_str(),"Number of peaks from finder", 11,-0.5,10.5);
304  mH1F_NPeaksFiltered[i] = new TH1F( ("H1_NPeaksFiltered_"+ss.str()).c_str(),"Number of peaks from finder when a valid peak was found", 11,-0.5,10.5);
305  mH1F_Res0[i] = new TH1F( ("H1_Res0_"+ss.str()).c_str(),"All ADC sums", 100,0,2000 );
306  mH1F_Res0Zoom[i] = new TH1F( ("H1_Res0Zoom_"+ss.str()).c_str(),"All ADC sums", 201,-0.5,200.5 );
307  }
308  if( mTest==3 || mTest==6 ){
309  mH1F_Sum8Res0[i] = new TH1F( ("H1_Sum8Res0_"+ss.str()).c_str(),"All ADC sums using sum 8", 100,0,2000 );
310  mH1F_Sum8Res0Zoom[i] = new TH1F( ("H1_Sum8Res0Zoom_"+ss.str()).c_str(),"All ADC sums using sum 8", 201,-0.5,200.5 );
311  }
312  if( mTest==3 || mTest==6 || mTest==8 ){
313  mH1F_FitRes0[i] = new TH1F( ("H1_FitRes0_"+ss.str()).c_str(),"All ADC sums using fitting", 100,0,2000 );
314  mH1F_FitRes0Zoom[i] = new TH1F( ("H1_FitRes0Zoom_"+ss.str()).c_str(),"All ADC sums using fitting", 201,-0.5,200.5 );
315  mH2F_Sum8vFit[i] = new TH2F(("H2_Sum8vFit_"+ss.str()).c_str(),"sum 8 vs fit sum", 100,0,2000, 100,0,2000);
316  }
317  }
318 
319  if( mTest==2 ){
320  mH1_PeakTiming = new TH1F("H1_PeakTiming","Timing to just find peak",200,0,5);
321  }
322  if( mTest==2 || mTest==8 ){
323  mH1_NPeaksAkio = new TH1F("H1_NPeaksAkio","Number of peaks from current method", 11,-0.5,10.5);
324  mH1_NPeaksFilteredAkio = new TH1F("H1_NPeaksFilteredAkio","Number of peaks from current method when a valid peak is found", 11,-0.5,10.5);
325  }
326  if( mTest==3 ){
327  mH2_NPeakvsPeakXdiff = new TH2F("H2_NPeakvsPeakXdiff","NPeak vs. Peak X difference", 41,-20.5,20.5, 11,-0.5,10.5);
328  mH2_NPeakvsPeakYratio = new TH2F("H2_NPeakvsPeakYratio","NPeak vs. Peak Y ratio", 100,0,10, 11,-0.5,10.5);
329  mH1_VOverlap = new TH1F("H1_VOverlap","Peak Compare values",4,-0.5,3.5 );
330  mH2_NOvsNPeaks = new TH2F("H2_NOvsNPeaks","Number of Overlapping peaks vs. Number of Peaks", 11,-0.5,10.5, 11,-0.5,10.5);
331  mH2_VvsNOverlap = new TH2F("H2_VvsNOverlap","Value of Comparison vs. Peak index", 21,-10.5,10.5, 4,-0.5,3.5);
332  }
333  if( mTest==3 || mTest==6 || mTest==8 ){
334  mH1_TimeFitPulse = new TH1F("H1_TimeFitPulse","FitTime;msec",1000,0,1000);
335  }
336  if( mTest==4 ){
337  mH2_HeightvsSigma = new TH2F("H2_HeightvsSigma","Fitted Peak Height vs. Sigma;Sigma;Height", 31,-0.5,30.5, 4000,-0.5,3999.5);
338  mH2_HeightvsSigmaTrig = new TH2F("H2_HeightvsSigmaTrig","Fitted Peak Height vs. Sigma Triggered Xing;Sigma;Height", 31,-0.5,30.5, 4000,-0.5,3999.5);
339  mH1_ChiNdf = new TH1F("H1_ChiNdf","Chi^2/NDF for all fits;Chi^2/NDF", 50,-0.5,99.5);
340  mH2_HeightvsChiNdf = new TH2F("H2_HeightvsChiNdf", "Peak Height TXing vs. Chi^2/NDF;Chi^2/NDF;Height", 50,-0.5,99.5, 500,-0.5,499.5);
341  mH2_MeanvsChiNdf = new TH2F("H2_MeanvsChiNdf", "Peak Mean TXing vs. Chi^2/NDF;Chi^2/NDF;Mean", 50,-0.5,99.5, 21,39.5,60.5 );
342  mH2_SigmavsChiNdf = new TH2F("H2_SigmavsChiNdf", "Peak Sigma TXing vs. Chi^2/NDF;Chi^2/NDF;Sigma", 50,-0.5,99.5, 21,-0.5,20.5 );
343  }
344  if( mTest==5 ){
345  mH1_PeakTimingGaus = new TH1F("H1_PeakTimingGaus","gausFit timing;msec", 1000,0,1000 );
346  mH1_PeakTimingPuls = new TH1F("H1_PeakTimingPuls","PulseFit timing;msec", 1000,0,1000 );
347  mH2_PeakTimingCompare = new TH2F("H2_PeakTimingCompare","PulseFit vs. gausFit;ms;ms", 200,0,6, 200,0,6 );
348  }
349  }
350  return StMaker::Init();
351 }
352 
353 int StFcsWaveformFitMaker::InitRun(int runNumber) {
354  LOG_DEBUG << "StFcsWaveformFitMaker initializing run" << endm;
355  mDb = static_cast<StFcsDb*>(GetDataSet("fcsDb"));
356  if (!mDb) {
357  LOG_ERROR << "StFcsWaveformFitMaker initializing failed due to no StFcsDb" << endm;
358  return kStErr;
359  }
360  mDbPulse = static_cast<StFcsDbPulse*>(GetDataSet("fcsPulse"));
361  if (!mDbPulse) {
362  LOG_ERROR << "StFcsWaveformFitMaker initializing failed due to no StFcsDbPulse" << endm;
363  return kStErr;
364  }
365  mDbPulse->setTail(mTail);
367  mPulseFit->setDbPulse(mDbPulse);
368 
369  return StMaker::InitRun(runNumber);
370 }
371 
373  if( mFilename ){
374  char file[200];
375  sprintf(file,"%s.pdf]",mFilename);
376  mCanvas->Print(file);
377  }
378  if(mMeasureTime){
379  printf("WFFit Time Mean=%f RMS=%f\n",mTime->GetMean(),mTime->GetRMS());
380  TCanvas *c= new TCanvas("FCSWFFTime","FCSWFFTime",10,10,800,800);
381  gStyle->SetOptStat(111110);
382  gStyle->SetLabelSize(0.02,"xy");
383  c->cd(1)->SetLogy();
384  mTime->Draw();
385  c->SaveAs(mMeasureTime);
386  delete c;
387  }
388  if(mFilter && mFilter[0]=='0'){
389  TCanvas *c= new TCanvas("Stage0","Stage0",10,10,800,800);
390  gStyle->SetOptStat(111110);
391  gStyle->SetLabelSize(0.02,"xy");
392  c->Divide(2,2);
393  c->cd(1)->SetLogy(); mTimeIntg[0]->Draw("colz");
394  c->cd(2)->SetLogy(); mTimeIntg[1]->Draw("colz");
395  c->cd(3)->SetLogy(); mTimeIntg[2]->Draw("colz");
396  c->cd(4)->SetLogy(); mTimeIntg[3]->Draw("colz");
397  c->SaveAs("stage0.png");
398  delete c;
399  }
400  if( mOutFile!=0 ){
401  mOutFile->cd();
402 
403  for( UShort_t i=0; i<7; ++i ){
404  if( i<3 ){
405  if( mH2_Dep0DepMod[i]!=0 ){mH2_Dep0DepMod[i]->Write();}
406  if( mH2_Sum8Dep0[i]!=0 ) {mH2_Sum8Dep0[i]->Write();}
407  if( mH2_Sum8DepMod[i]!=0 ){mH2_Sum8DepMod[i]->Write();}
408  }
409  if( i<6 ){
410  if( mH2F_AdcTbAkio[i]!=0 ) { mH2F_AdcTbAkio[i]->Write();}
411  if( mH2F_AdcTbMine[i]!=0 ) { mH2F_AdcTbMine[i]->Write();}
412  if( mH2F_SumFitvSumWin[i]!=0 ) { mH2F_SumFitvSumWin[i]->Write();}
413  if( mH2F_APeakvMPeak[i]!=0 ) { mH2F_APeakvMPeak[i]->Write();}
414  if( mH1F_PeakStart[i]!=0 ) { mH1F_PeakStart[i]->Write();}
415  if( mH1F_PeakEnd[i]!=0 ) { mH1F_PeakEnd[i]->Write();}
416  if( mH2F_NOvsId[i]!=0 ) { mH2F_NOvsId[i]->Write();}
417  }
418  if( mH2F_AdcTbValidPeak[i]!=0 ){ mH2F_AdcTbValidPeak[i]->Write();}
419  if( mH1F_NPeaks[i]!=0 ) { mH1F_NPeaks[i]->Write();}
420  if( mH1F_NPeaksFiltered[i]!=0 ){ mH1F_NPeaksFiltered[i]->Write();}
421 
422  if( mH1F_Res0[i]!=0 ) { mH1F_Res0[i]->Write();}
423  if( mH1F_Res0Zoom[i]!=0 ) { mH1F_Res0Zoom[i]->Write();}
424  if( mH1F_Sum8Res0[i]!=0 ) { mH1F_Sum8Res0[i]->Write();}
425  if( mH1F_Sum8Res0Zoom[i]!=0 ) { mH1F_Sum8Res0Zoom[i]->Write();}
426  if( mH1F_FitRes0[i]!=0 ) { mH1F_FitRes0[i]->Write();}
427  if( mH1F_FitRes0Zoom[i]!=0 ) { mH1F_FitRes0Zoom[i]->Write();}
428  if( mH2F_Sum8vFit[i]!=0 ) { mH2F_Sum8vFit[i]->Write();}
429  }
430 
431  if( mTime!=0 ){ mTime->Write(); }
432 
433  if( mH1_NPeaksAkio!=0 ){ mH1_NPeaksAkio->Write(); }
434  if( mH1_NPeaksFilteredAkio!=0 ){ mH1_NPeaksFilteredAkio->Write(); }
435  if( mH1_PeakTiming!=0 ){mH1_PeakTiming->Write();}
436 
437  if( mH2_NPeakvsPeakXdiff!=0 ) {mH2_NPeakvsPeakXdiff->Write();}
438  if( mH2_NPeakvsPeakYratio!=0) {mH2_NPeakvsPeakYratio->Write();}
439  if( mH1_VOverlap!=0 ) {mH1_VOverlap->Write();}
440  if( mH2_NOvsNPeaks!=0 ) {mH2_NOvsNPeaks->Write();}
441  if( mH2_VvsNOverlap!=0 ) {mH2_VvsNOverlap->Write();}
442  if( mH1_TimeFitPulse!=0 ) {mH1_TimeFitPulse->Write();}
443 
444  if( mH2_HeightvsSigma!=0 ) {mH2_HeightvsSigma->Write();}
445  if( mH2_HeightvsSigmaTrig!=0) {mH2_HeightvsSigmaTrig->Write();}
446  if( mH1_ChiNdf!=0 ) {mH1_ChiNdf->Write();}
447  if( mH2_HeightvsChiNdf!=0 ) {mH2_HeightvsChiNdf->Write();}
448  if( mH2_MeanvsChiNdf!=0 ) {mH2_MeanvsChiNdf->Write();}
449  if( mH2_SigmavsChiNdf!=0 ) {mH2_SigmavsChiNdf->Write();}
450 
451  if( mH1_PeakTimingGaus!=0 ) {mH1_PeakTimingGaus->Write();}
452  if( mH1_PeakTimingPuls!=0 ) {mH1_PeakTimingPuls->Write();}
453  if( mH2_PeakTimingCompare!=0) {mH2_PeakTimingCompare->Write();}
454 
455  //In case you want to save a particular graph needs mFitDrawOn==1
456  //TGraphAsymmErrors* g = getGraph(0,161);
457  //std::cout << "found graph:"<<g << std::endl;
458  //if( g!=0 ){ g->Write("GAE_det0id161"); }
459  }
460  return kStOK;
461 }
462 
464  LOG_DEBUG << "StFcsWaveformFitMaker Make!!!" << endm;
465 
466  //Get FCS hits from StEvent
467  StEvent* event = static_cast<StEvent*>(GetInputDS("StEvent"));
468  mFcsCollection=0;
469  if (event) mFcsCollection = event->fcsCollection();
470  if(!mFcsCollection) {
471  LOG_WARN << "StFcsWaveformFitMaker did not find fcsCollection in StEvent" << endm;
472  return kStWarn;
473  }
474 
475  if(mEnergySelect[0]==0) return kStOK; // don't touch energy, directly from MC
476 
477  //Loop over all hits and run waveform analysis of the choice
478  float res[8] = {0};
479  TF1* func=0;
480  for(int det=0; det<kFcsNDet; det++) {
481  StSPtrVecFcsHit& hits = mFcsCollection->hits(det);
482  int ehp = det/2;
483  int nhit=hits.size();
484  for(int i=0; i<nhit; i++){ //loop over all hits
485  memset(res,0,sizeof(res));
486  auto start=std::chrono::high_resolution_clock::now();
487 
488  //if we are geting pedestal from data
489  if(mPedMin>=0){
490  AnaPed( hits[i], res[6], res[7] );
491  mDb->setPedestal(hits[i]->ehp(), hits[i]->ns(), hits[i]->dep(), hits[i]->channel(), res[6] );
492  if(GetDebug()>1){
493  char name[100];
494  mDb->getName(hits[i]->ehp(), hits[i]->ns(), hits[i]->dep(), hits[i]->channel(),name);
495  LOG_DEBUG << name << " Pedestal ("<<mPedMax<<"-"<<mPedMin<<"+1)="<< res[6] <<std::endl;
496  }
497  }
498 
499  //run waveform analysis of the choice and store as AdcSum
500  float integral = hits[i]->adcSum();
501  if( mAnaWaveform ){
502  integral = analyzeWaveform(mEnergySelect[ehp],hits[i],res,func,res[6]);
503  hits[i]->setAdcSum(integral);
504  hits[i]->setFitPeak(res[2]);
505  hits[i]->setFitSigma(res[3]);
506  hits[i]->setFitChi2(res[4]);
507  hits[i]->setNPeak(res[5]);
508  }
509  //apply gain and update energy
510  float gain = mDb->getGain(hits[i]);
511  float gaincorr = mDb->getGainCorrection(hits[i]);
512  hits[i]->setEnergy(integral*gain*gaincorr);
513  if(GetDebug()>0){ printf("det=%1d id=%3d integ=%10.2f peak=%8.2f, sig=%8.4f chi2=%8.2f npeak=%2d ped=%8.2f pedrms=%4.2f\n",
514  det,hits[i]->id(),integral,res[2],res[3],res[4],int(res[5]),res[6],res[7]); }
515  if(mMeasureTime){
516  auto stop=std::chrono::high_resolution_clock::now();
517  long long usec = chrono::duration_cast<chrono::microseconds>(stop-start).count();
518  //printf("Fit Time = %lld usec\n",usec);
519  mTime->Fill(float(usec)/1000.0);
520  }
521  if( mTest==5 ){
522  auto startg = std::chrono::high_resolution_clock::now();
523  integral = analyzeWaveform(10,hits[i],res,func,res[6]);
524  auto stopg = std::chrono::high_resolution_clock::now();
525  long long usecg = chrono::duration_cast<chrono::microseconds>(stopg-startg).count();
526  auto startp = std::chrono::high_resolution_clock::now();
527  integral = analyzeWaveform(12,hits[i],res,func,res[6]);
528  auto stopp = std::chrono::high_resolution_clock::now();
529  long long usecp = chrono::duration_cast<chrono::microseconds>(stopp-startp).count();
530  mH1_PeakTimingGaus->Fill(float(usecg)/1000.0);
531  mH1_PeakTimingPuls->Fill(float(usecp)/1000.0);
532  mH2_PeakTimingCompare->Fill(float(usecg)/1000.0,float(usecp)/1000.0);
533  if( usecp>200000.0 ){ std::cout << getGraph()->GetName() << std::endl; }
534  }
535  }
536  }
537  return kStOk;
538 }
539 
541  TGraphAsymmErrorsWithReset* gae = (TGraphAsymmErrorsWithReset*)mChWaveData.ConstructedAt(mHitIdx);
542  gae->Reset();
543  if(mFitDrawOn) mHitIdx++;
544  return (TGraphAsymmErrors*)gae;
545 }
546 
547 TGraphAsymmErrors* StFcsWaveformFitMaker::getGraph(int idx){
548  if(idx<0){
549  if(mHitIdx>0) {idx=mHitIdx-1;}
550  else {idx=0;}
551  }
552  TGraphAsymmErrors* gae = (TGraphAsymmErrors*)mChWaveData.ConstructedAt(idx);
553  return gae;
554 }
555 
556 TGraphAsymmErrors* StFcsWaveformFitMaker::getGraph(int det, int id)
557 {
558  //Since mHitIdx may have been reset by call to clear use size of array instead this way you can find graphs even if Clear() has been called
559  for( Int_t i=0; i<mChWaveData.GetEntriesFast(); ++i ){
560  int det0 = -1;
561  int id0 = -1;
562  TGraphAsymmErrors* gae = (TGraphAsymmErrors*)mChWaveData.At(i);
563  StFcsDb::getFromName(gae->GetName(),det0,id0);
564  //std::cout << "|det0:"<<det0 << "|id0:"<<id0 << std::endl;
565  if( det0>=0 && det0==det ){
566  if( id0>=0 && id0==id ){
567  return gae;
568  }
569  }
570  }
571  LOG_ERROR << "Unable to find det:"<<det << " id:"<<id << " in graph array" << std::endl;
572  return 0;
573 }
574 
575 TGraphAsymmErrors* StFcsWaveformFitMaker::makeTGraphAsymmErrors(int n, double* tb, double* adc){
576  TGraphAsymmErrors* gae = resetGraph();
577  for(int i=0; i<n; ++i){
578  gae->SetPoint(i,tb[i],adc[i]);
579  StFcsDbPulse::setTGraphAsymmErrors(gae, i, adc[i],mError,mErrorSaturated);
580  }
581  return gae;
582 }
583 
584 TGraphAsymmErrors* StFcsWaveformFitMaker::makeTGraphAsymmErrors(TGraph* g){
585  int n = g->GetN();
586  double *t = g->GetX();
587  double *a = g->GetY();
588  return makeTGraphAsymmErrors(n, t, a);
589 }
590 
591 TGraphAsymmErrors* StFcsWaveformFitMaker::makeTGraphAsymmErrors(TH1* hist){
592  int NValues = hist->GetNbinsX();
593  TGraphAsymmErrors* gae = resetGraph();
594  for(int i=1; i<=NValues; ++i ){
595  double adc = hist->GetBinContent(i);
596  gae->SetPoint(i-1,hist->GetBinCenter(i),adc);
597  StFcsDbPulse::setTGraphAsymmErrors(gae,i-1,adc,mError,mErrorSaturated);
598  }
599  return gae;
600 }
601 
603  //int N = mMaxTB - mMinTB +1;
604  int n = hit->nTimeBin();
605  TGraphAsymmErrors* gae = resetGraph();
606  mDb->getName(hit->detectorId(),hit->id(),mDetName);
607  gae->SetName(mDetName);
608  int j=0;
609  for(int i=0; i<n; i++){
610  int tb=hit->timebin(i);
611  if(tb>=mMinTB){
612  int adc=hit->adc(i);
613  gae->SetPoint(j,tb,adc);
614  StFcsDbPulse::setTGraphAsymmErrors(gae,j,adc,mError,mErrorSaturated);
615  j++;
616  }
617  if(tb>=mMaxTB) break;
618  }
619  //printf("GetN()=%d gae=%d\n",gae->GetN(),gae);
620  return gae;
621 }
622 
623 
624 float StFcsWaveformFitMaker::AnaPed( TGraphAsymmErrors* g, float& ped, float& pedstd )
625 {
626  int n = g->GetN();
627  double *t = g->GetX();
628  double *a = g->GetY();
629  int p=0;
630  double sumsq = 0;//For variance
631  for(int i=0; i<n; i++){
632  int tb1=t[i];
633  if(mPedMin<=tb1 && tb1<=mPedMax){
634  p+=a[i];
635  sumsq += a[i]*a[i];
636  }
637  }
638  ped = float(p)/(mPedMax-mPedMin+1.0);
639  pedstd = sqrt( ( sumsq-((double(p)*double(p))/(mPedMax-mPedMin+1.0)) )/(mPedMax-mPedMin) );//Variance/StdDev using naive algorithm from https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
640  return ped;
641 }
642 
643 float StFcsWaveformFitMaker::AnaPed( StFcsHit* hit, float& ped, float& pedstd )
644 {
645  int p=0;
646  int n = hit->nTimeBin();
647  double sumsq = 0;//For variance
648  for(int i=0; i<n; i++){
649  int tb=hit->timebin(i);
650  if(mPedMin<=tb && tb<=mPedMax ){
651  int adc = hit->adc(i);
652  p+=adc;
653  sumsq += adc*adc;
654  }
655  if(tb>=mPedMax) break;
656  }
657  ped = p/(mPedMax-mPedMin+1.0);
658  pedstd = sqrt( ( sumsq-((p*p)/(mPedMax-mPedMin+1.0)) )/(mPedMax-mPedMin) );//Variance/StdDev using naive algorithm from https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
659  return ped;
660 }
661 
662 float StFcsWaveformFitMaker::analyzeWaveform(int select, TGraphAsymmErrors* g, float* res, TF1*& func, float ped){
663  if(func) delete func;
664  func=0;
665  float integral=0.0;
666  switch(select){
667  case 1: integral = sum8(g, res); break;
668  case 2: integral = sum16(g, res); break;
669  case 3: integral = highest(g, res); break;
670  case 4: integral = highest3(g, res); break;
671  case 10: integral = gausFit(g, res, func, ped); break;
672  case 11: integral = gausFitWithPed(g, res, func); break;
673  case 12: integral = PulseFit1(g,res,func,ped); break;
674  case 13: integral = PulseFit2(g,res,func,ped); break;
675  case 14: integral = PulseFitAll(g,res,func,ped); break;
676  case 15: integral = PulseFit2WithPed(g, res, func); break;
677  case 16: integral = PulseFitAllWithPed(g, res, func); break;
678  case 17: integral = PedFitPulseFit(g, res, func); break;
679  default:
680  LOG_WARN << "Unknown fit/sum method select=" << select << endm;
681  }
682  //if(func && (mFitDrawOn || mFilter ) && mFilename && mPage<=mMaxPage) drawFit(g,func);
683  int flag=1;
684  if(mFilter && mFilter[0]=='0'){
685  flag=0;
686  if(integral>0 && res[2]>47.0 && res[2]<54.0){
687  int peak=0;
688  double* t=g->GetX();
689  double* a=g->GetY();
690  for(int i=0; i<g->GetN()-1; i++){
691  int t0=t[i];
692  int t1=t[i+1];
693  int a0=a[i];
694  int a1=a[i+1];
695  int dt=t1-t0;
696  int da=a1-a0;
697  if(GetDebug()) printf("AAA t0=%4d t1=%4d a0=%4d a1=%4d dt=%4d da=%5d ",t0,t1,a0,a1,dt,da);
698  if(t0==mCenterTB-3 && dt==1){
699  if(da>0) {
700  peak+=1;
701  if(GetDebug()) printf("R");
702  }
703  else {if(GetDebug()) printf("X");}
704  }
705  if(t0==mCenterTB+3 && dt==1){
706  if(da<0) {
707  peak+=2;
708  if(GetDebug()) printf("F");
709  }
710  else {if(GetDebug()) printf("X");}
711  }
712  if(GetDebug()) printf("\n");
713  }
714  printf("BBB Intg=%8.2f peak=%6.2f Raise/Fall=%1d\n",integral,res[2],peak);
715  if(peak<3 && integral>50 && res[2]>49) flag=1;
716  mTimeIntg[peak]->Fill(res[2],integral);
717  }
718  }else if(mFilter){
719  flag=0;
720  TString dname(mDetName);
721  if(integral>50 && dname.Contains(mFilter)) flag=1;
722  }
723  if(mFitDrawOn && flag && mFilename && mPage<=mMaxPage) {
724  printf("hit:%u det=%s func=%p mFitDrawOn=%d mFilter=%s mFilename=%s mPage=%d mMaxPage=%d integral=%f\n",
725  mHitIdx,mDetName,(void*)func,mFitDrawOn,mFilter,mFilename,mPage,mMaxPage,integral);
726  drawFit(g,func);
727  }
728 
729  if( mOutFile!=0 ){
730  if( mTest==1 ){
731  int det = 0; int ch=0;
732  mDb->getFromName( g->GetName(), det,ch );
733  int sumdep0 = StFcsPulseAna::SumDep0(g,centerTB()-3);
734  int sumdepmod = StFcsPulseAna::SumDep0Mod(g,centerTB()-3);
735  if( sumdep0>sumdepmod ){std::cout << " - StFcsWaveformFitMaker::analyzeWaveform|SumDep0:"<<sumdep0 << "|SumDepMod:"<<sumdepmod << endl;}
736  mH2_Dep0DepMod[det/2]->Fill(sumdepmod,sumdep0);
737  mH2_Sum8Dep0[det/2]->Fill(sumdep0,integral);
738  mH2_Sum8DepMod[det/2]->Fill(sumdepmod,integral);
739  }
740  if( mTest==7 ){
741  int det0 = 0; int ch0=0;
742  mDb->getFromName( g->GetName(), det0,ch0 );
743  mH1F_Res0[det0]->Fill(res[0]);
744  mH1F_Res0Zoom[det0]->Fill(res[0]);
745  mH1F_Res0[6]->Fill(res[0]);
746  mH1F_Res0Zoom[6]->Fill(res[0]);
747  }
748  }
749  return integral;
750 }
751 
752 float StFcsWaveformFitMaker::analyzeWaveform(int select, int n, double* tb, double* adc, float* res, TF1*& func, float ped){
753  TGraphAsymmErrors* gae = makeTGraphAsymmErrors(n,tb,adc);
754  return analyzeWaveform(select, gae, res, func,ped);
755 }
756 
757 float StFcsWaveformFitMaker::analyzeWaveform(int select, TGraph* g, float* res, TF1*& func, float ped){
758  TGraphAsymmErrors* gae = makeTGraphAsymmErrors(g);
759  return analyzeWaveform(select,gae,res,func,ped);
760 }
761 
762 float StFcsWaveformFitMaker::analyzeWaveform(int select, StFcsHit* hit, float* res, TF1*& func, float ped){
763  TGraphAsymmErrors* gae = makeTGraphAsymmErrors(hit);
764  return analyzeWaveform(select, gae, res, func, ped);
765 }
766 
767 float StFcsWaveformFitMaker::sum8(TGraphAsymmErrors* g, float* res){
768  int min = mCenterTB-3;
769  int max = mCenterTB+4;
770  int n = g->GetN();
771  double *t = g->GetX();
772  double *a = g->GetY();
773  float sum=0;
774  float tsum=0;
775  for(int i=0; i<n; i++){
776  double tb=t[i];
777  if(tb>=min && tb<=max) {
778  sum += a[i];
779  tsum += a[i] * tb;
780  }
781  }
782  //res[0]/=1.226; //Compensate for fitting sum in ECal. Only turn on for testing comparisons
783  if( fabs(res[7]) > 0.000001 ){ sum -= res[6]*8; }//pedestal subtraction for sum8. 8 timebi sum, so pedestal*8 is integrated sum of pedestal.
784  res[0]=sum;
785  if(sum>0) res[2]=tsum/sum;
786  return sum;
787 }
788 
789 float StFcsWaveformFitMaker::sum16(TGraphAsymmErrors* g, float* res){
790  int min = mCenterTB-3-4; // 16 timebin sum means from center - 7
791  int max = mCenterTB+4+4; // tp center + 8
792  int n = g->GetN();
793  double *t = g->GetX();
794  double *a = g->GetY();
795  float sum=0;
796  float tsum=0;
797  for(int i=0; i<n; i++){
798  double tb=t[i];
799  if(tb>=min && tb<=max) {
800  sum += a[i];
801  tsum += a[i] * tb;
802  }
803  }
804  if( fabs(res[7]) > 0.000001 ){ sum -= res[6]*16; }//pedestal subtraction for sum16. 16 timebin sum, so pedestal*16 is integrated sum of pedestal.
805  res[0]=sum;
806  if(sum>0) res[2]=tsum/sum;
807  return sum;
808 }
809 
810 float StFcsWaveformFitMaker::highest(TGraphAsymmErrors* g, float* res){
811  int min = mCenterTB-3;
812  int max = mCenterTB+4;
813  int n = g->GetN();
814  double *t = g->GetX();
815  double *a = g->GetY();
816  float maxadc=0;
817  int maxtb=0;
818  for(int i=0; i<n; i++){ //find max adc witin triggered xing
819  float tb=t[i];
820  if(tb>=min && tb<=max) {
821  float adc=a[i];
822  if(adc>maxadc){
823  maxadc=adc;
824  maxtb=tb;
825  }
826  }
827  }
829  if( fabs(res[7]) > 0.000001 ){ maxadc -= res[6]; }//pedestal subtraction for highest.
830  res[0]=maxadc / 0.2; //this is estimated "full integral"
831  res[1]=maxadc; //this is peak height
832  res[2]=maxtb; //this is peak position [timebin]
833  //res[3]=0.0; //no width from this method
834  //res[4]=0.0; //no chi2 from this
835  //res[5]=0.0; //no # of peaks
836 
837  return maxadc; //this is the highest
838 }
839 
840 float StFcsWaveformFitMaker::highest3(TGraphAsymmErrors* g, float* res){
841  int min = mCenterTB-3;
842  int max = mCenterTB+4;
843  int n = g->GetN();
844  double *t = g->GetX();
845  double *a = g->GetY();
846  float sum=0, tsum=0, maxadc=0;
847  int maxtb=0;
848  for(int i=0; i<n; i++){ //find max adc witin triggered xing
849  float tb=t[i];
850  if(tb>=min && tb<=max) {
851  float adc=a[i];
852  if(adc>maxadc){
853  maxadc=adc;
854  maxtb=tb;
855  }
856  }
857  }
858  for(int i=0; i<n; i++){ //sum 3TB around max within 8 timebins
859  float tb=t[i];
860  if(tb>=min && tb<=max && tb>=maxtb-1 && tb<=maxtb+1) {
861  sum += a[i];
862  tsum += a[i] * tb;
863  }
864  }
866  if( fabs(res[7]) > 0.000001 ){ sum -= res[6]*3; }//pedestal subtraction for highest3. Since 3 timebin sum pedestal*3 is integrated pedestal
867  res[0]= sum / 0.555; //this is estimated "full integral"
868  res[1]= maxadc; //this is peak height
869  if(sum>0) res[2]= tsum/sum; //this is averaged peak position [timebin]
870  //res[3]= 0.0; //no sigma from this
871  //res[4]= 0.0; //no chi2 from this
872  //res[5]= 0.0; //no # of peak
873  return sum; //this is the 3 timebin sum
874 }
875 
876 float StFcsWaveformFitMaker::gausFit(TGraphAsymmErrors* g, float* res, TF1*& func, float ped){
877  char Opt[10]="QN ";
878  if(GetDebug()>2) sprintf(Opt," ");
879  if(GetDebug()>3) sprintf(Opt,"V ");
880  //find peaks and set parameters
881  int trgmin = mCenterTB-4.5;
882  int trgmax = mCenterTB+5.5;
883  int n = g->GetN();
884  double *t = g->GetX();
885  double *a = g->GetY();
886  double para[100];
887  int npeak=0;
888  int trgx = -1;
889  double mindt = 1000;
890  double tb0,tb1,tb2;
891  double adc0,adc1,adc2;
892 
893  if(mFilter && GetDebug()>0){
894  TString dname(mDetName);
895  if(! dname.Contains(mFilter)) return res[0];
896  printf("%s mMinTB=%d mMaxTB=%d : ",
897  mDetName,mMinTB+8,mMaxTB-20);
898  for(int i=1; i<n-1; i++){
899  tb1=t[i];
900  if(tb1>=mMinTB+8 && tb1<=mMaxTB-20){
901  printf("%4d ",int(a[i]));
902  }
903  }
904  printf("\n");
905  }
906 
907  for(int i=1; i<n-1; i++){
908  tb1=t[i];
909  if(tb1>=mMinTB && tb1<=mMaxTB){
910  adc1=a[i];
911  if(adc1-ped<mMinAdc) continue;
912  tb0=t[i-1];
913  if(tb1-tb0>1.1) {adc0 = 0;}
914  else {adc0 = a[i-1];}
915  tb2=t[i+1];
916  if(tb2-tb1>1.1) {adc2 = 0;}
917  else {adc2 = a[i+1];}
918  // printf("i=%3d tb0=%4.0lf tb1=%4.0lf tb2=%4.0lf adc0=%5.0lf adc1=%5.0lf adc2=%5.0lf\n",
919  // i,tb0,tb1,tb2,adc0,adc1,adc2);
920  if( (adc1>adc0 || tb1==mMinTB) && adc1>=adc2){ //if falling from starting point, make it peak
921  para[1+npeak*3+1] = adc1;
922  para[1+npeak*3+2] = tb1;
923  para[1+npeak*3+3] = mDbPulse->GSigma();
924  double dt = fabs(tb1 - mCenterTB);
925  if(trgmin<tb1 && tb1<trgmax && dt < mindt) { //find closest to center within trigger xing
926  mindt = dt;
927  trgx = npeak;
928  }
929  if(GetDebug()>1) printf("peak npeak=%2d tb=%4.0lf adc=%5.0lf\n",npeak,tb1,adc1);
930  npeak++;
931  }
932  }
933  }
934 
935  Int_t compidx = -1;
936  int myNpeaks = -1;
937  int npeakidx = -1;
938  int mypeakidx = -1;
939  if( mTest==2 || mTest==8 ){
940  //For comparing with pulse fit analysis class
941  if( mPulseFit==0 ){mPulseFit = new StFcsPulseAna(g); SetupDavidFitterMay2022(); }//Setup only needs to be called once as those values will not get reset when data changes.
942  else{ mPulseFit->SetData(g); }
943  compidx = mPulseFit->FoundPeakIndex();
944  mH1_NPeaksAkio->Fill(npeak);
945  if( trgx>=0 ){ mH1_NPeaksFilteredAkio->Fill(npeak); }//peaks inside triggered crossing
946  if( mTest==2 ){
947  auto start=std::chrono::high_resolution_clock::now();
948  if( compidx<0 ){ compidx = mPulseFit->AnalyzeForPeak(); }
949  auto stop=std::chrono::high_resolution_clock::now();
950  long long usec = chrono::duration_cast<chrono::microseconds>(stop-start).count();
951  //printf("Fit Time = %lld usec\n",usec);
952  mH1_PeakTiming->Fill(float(usec)/1000.0);
953 
954  myNpeaks = mPulseFit->NPeaks();
955  mH1F_NPeaks[0]->Fill(myNpeaks);
956  if( 0<=compidx && compidx<myNpeaks ){ mH1F_NPeaksFiltered[0]->Fill(myNpeaks); }
957  npeakidx = npeak<=4?npeak:5;
958  mypeakidx = myNpeaks<=4?myNpeaks:5;
959  //std::cout << "|npeakidx:"<< npeakidx << "|mypeakidx:"<< mypeakidx << std::endl;
960  //bool checkpeak = false; //This is to check a zero peak with a large adc value in triggered crossing
961  for( int i=0; i<g->GetN(); ++i ){
962  mH2F_AdcTbAkio[npeakidx]->Fill(t[i],a[i]);
963  mH2F_AdcTbMine[mypeakidx]->Fill(t[i],a[i]);
964  //if( mypeakidx==0 ){ if( 40<t[i] && t[i]<=60 ){ if( a[i]>20 ){ checkpeak=true; } } }
965  if( mPulseFit->ValidPeakIdx() ){mH2F_AdcTbValidPeak[mypeakidx]->Fill(t[i],a[i]);}
966  else{ mH2F_AdcTbValidPeak[6]->Fill(t[i],a[i]); }
967  //std::cout << "- |i:"<<i << "|t:"<<t[i] << "|a:"<< a[i] << std::endl;
968  }
969  }
970  }
971  //Continue with rest of peak finding
972 
973  if(npeak>0 && npeak<mMaxPeak){
974  //func = new TF1("waveform",this,&StFcsWaveformFitMaker::multiPulseShape,mMinTB,mMaxTB,2+npeak*3);//Old way
975  //func = new TF1("waveform",mDbPulse,&StFcsDbPulse::multiPulseShape,mMinTB,mMaxTB,2+npeak*3);//For reference
976  func = mDbPulse->createPulse(mMinTB,mMaxTB,2+npeak*3);//Needs to have name "waveform"
977  func->SetLineColor(6);
978  func->SetParameters(para);
979  func->FixParameter(0,npeak);
980  func->FixParameter(1,ped);
981  for(int i=0; i<npeak; i++){
982  func->SetParLimits(1+i*3+1,0.0,40000.0); //limit peak not to go negative
983  int j=1+i*3+2;
984  func->SetParLimits(j,para[j]-2.0,para[j]+2.0); //limit peak position to +- 2TB
985  func->SetParLimits(1+i*3+3,0.5,10.0); //limit sigma to go too narrow or wide
986  }
987  //TFitResultPtr result = g->Fit("waveform",Opt,"",mMinTB,mMaxTB);
988  TFitResultPtr result = g->Fit(func,Opt,"",mMinTB,mMaxTB);
989  if(trgx>=0){ // return pulse closest to center of triggered xing
990  res[1] = func->GetParameter(trgx*3 + 2);
991  res[2] = func->GetParameter(trgx*3 + 3);
992  res[3] = func->GetParameter(trgx*3 + 4);
993  res[4] = func->GetChisquare()/func->GetNDF();
994  res[5] = npeak;
995  res[0] = res[1]*res[3]*StFcsDbPulse::sqrt2pi();
996  }else{ // no peak found in triggered xing
997  //res[1] = 0.0;
998  //res[2] = 0.0;
999  //res[3] = 0.0;
1000  res[4] = func->GetChisquare()/func->GetNDF();
1001  res[5] = npeak;
1002  //res[0] = 0.0;
1003  }
1004  }else if(npeak>=mMaxPeak){
1005  res[5] = npeak;
1006  sum8(g, res); // too many peak, taking sum8
1007  res[0]/=1.21; // normalized by 1/1.21
1008  LOG_INFO << Form("%s Finding too many peaks npeak=%d. Skip fitting. Taking Sum8",mDetName,npeak)<<endm;
1009  }
1010  //printf("func=%d res=%f\n",func,res[0]);
1011 
1012  //For comparing to my peak finder
1013  if( mTest==2 ){
1014  if( npeakidx==mypeakidx){mH2F_SumFitvSumWin[npeakidx]->Fill(mPulseFit->SumWindow(),res[0]);}
1015  if( npeakidx==mypeakidx){
1016  Double_t peakloc = 0;
1017  if( 0<=compidx && compidx<myNpeaks ){ peakloc=mPulseFit->GetPeak(compidx).mPeakX; }
1018  mH2F_APeakvMPeak[npeakidx]->Fill(peakloc,res[2]);
1019  }
1020  mH1F_PeakStart[mypeakidx]->Fill(mPulseFit->PeakStart());
1021  mH1F_PeakEnd[mypeakidx]->Fill(mPulseFit->PeakEnd());
1022  }
1023  return res[0];
1024 }
1025 
1026 void StFcsWaveformFitMaker::drawFit(TGraphAsymmErrors* gg, TF1* func){
1027  const int MAXPAD=4*4;
1028  if(gg==0){
1029  LOG_WARN<<"Found no TGraphAsymmErrors at mHitIdx="<<mHitIdx<<endm;
1030  return;
1031  }
1032 
1033  static int skip=0;
1034  //printf("skip=%d mSkip=%d mPage=%d mMaxPage=%d mPad=%d\n",skip,mSkip,mPage,mMaxPage,mPad);
1035  if(skip>mSkip){
1036  skip=0;
1037  }
1038  if(skip>0){
1039  skip++;
1040  }else{
1041  skip++;
1042  if(mPad==0) { mCanvas->Clear(); mCanvas->Divide(4,4);}
1043  mPad++;
1044  mCanvas->cd(mPad);
1045  gg->SetTitle(mDetName);
1046  gg->Draw("ALP");
1047  if( func!=0 ){
1048  func->SetLineColor(kRed);
1049  func->SetLineWidth(2);
1050  func->DrawCopy("LSAME");
1051  }
1052  if( mPulseFit!=0 ){
1053  int det=-1;
1054  int ch=-1;
1055  StFcsDb::getFromName(gg->GetName(),det,ch);
1056  char post[50];
1057  sprintf(post,"_D%dC%d",det,ch);
1058  StFcsPulseAna* ana = (StFcsPulseAna*)mPulseFit->DrawCopy("LP;A",post,gg);//Sets 'kCanDelete' so canvas will delete the copy
1059  ana->SetLineColor(kBlue);
1060  ana->SetMarkerColor(kBlue);
1061  ana->SetMarkerStyle(4);
1062  ana->SetMarkerSize(0.5);
1063  }
1064 
1065  if(mPad==MAXPAD){
1066  char file[100];
1067  sprintf(file,"%s.pdf",mFilename);
1068  //if(mMaxPage==0) {sprintf(file,"%s.pdf",mFilename);}
1069  //else if(mPage==0) {sprintf(file,"%s.pdf(",mFilename);}
1070  //else if(mPage==mMaxPage) {sprintf(file,"%s.pdf",mFilename); mPad=-1; mFitDrawOn=0; mHitIdx=0;}
1071  //else {sprintf(file,"%s.pdf",mFilename);}
1072  printf("Saving pdf with [%s] mPage=%d mPad=%d\n",file,mPage,mPad);
1073  mCanvas->Print(file);
1074  // for(int i=0; i<MAXPAD; i++) if(gg[i]) delete gg[i];
1075  if(mPage==mMaxPage){ mPad=-9999; /*mPad=-1;*/ mFitDrawOn=0; mHitIdx=0; }
1076  else { mPad=0; }
1077  mPage++;
1078  if(mFitDrawOn==2) mHitIdx=0;
1079  }
1080  }
1081 }
1082 
1083 void StFcsWaveformFitMaker::drawCh(UInt_t detid, UInt_t ch) const
1084 {
1085  for( UInt_t i=0; i<mHitIdx; ++i ){
1086  int det = -1;
1087  int id = -1;
1088  TGraphAsymmErrors* ggdraw = (TGraphAsymmErrors*)mChWaveData.At(i);
1089  StFcsDb::getFromName(ggdraw->GetName(),det,id);
1090  if( det>=0 && det==static_cast<int>(detid) ){
1091  if( id>=0 && id==static_cast<int>(ch) ){
1092  ggdraw->Draw("APL");
1093  ggdraw->SetLineColor(kBlack);
1094  ggdraw->SetMarkerColor(kBlack);
1095  ggdraw->SetMarkerStyle(4);
1096  ggdraw->SetMarkerSize(0.5);
1097  ggdraw->GetXaxis()->SetTitle("timebin");
1098  ggdraw->GetYaxis()->SetTitle("ADC");
1099  if( mPulseFit!=0 ){
1100  int det=-1;
1101  int ch=-1;
1102  StFcsDb::getFromName(ggdraw->GetName(),det,ch);
1103  char post[50];
1104  sprintf(post,"_D%dC%d",det,ch);
1105  StFcsPulseAna* ana = mPulseFit->DrawCopy("LP;E",post,ggdraw);//Sets 'kCanDelete' so an external canvas will delete this object when "Clear" is called
1106  ana->GetData()->SetLineColor(kBlue);
1107  ana->GetData()->SetMarkerColor(kBlue);
1108  ana->GetData()->SetMarkerStyle(4);
1109  ana->GetData()->SetMarkerSize(0.5);
1110  //ana->ResetPeak();
1111  //ana->SetDebug(5);
1112  //mPulseFit->Print();
1113  //ana->Print();
1114  }
1115  }
1116  }
1117  }
1118 }
1119 
1120 void StFcsWaveformFitMaker::drawDualFit(UInt_t detid, UInt_t ch)
1121 {
1122  for( UInt_t i=0; i<mHitIdx; ++i ){
1123  int det = -1;
1124  int id = -1;
1125  TGraphAsymmErrors* ggdraw = (TGraphAsymmErrors*)mChWaveData.At(i);
1126  StFcsDb::getFromName(ggdraw->GetName(),det,id);
1127  if( det>=0 && det==static_cast<int>(detid) ){
1128  if( id>=0 && id==static_cast<int>(ch) ){
1129  char post[50];
1130  sprintf(post,"_D%dC%d",detid,ch);
1131  ggdraw->SetTitle(post);
1132  ggdraw->Draw("APL");
1133  ggdraw->SetLineColor(kBlack);
1134  ggdraw->SetMarkerColor(kBlack);
1135  ggdraw->SetMarkerStyle(4);
1136  ggdraw->SetMarkerSize(0.5);
1137  ggdraw->GetXaxis()->SetTitle("timebin");
1138  ggdraw->GetYaxis()->SetTitle("ADC");
1139  if( mPulseFit!=0 ){
1140  StFcsPulseAna* ana = mPulseFit->DrawCopy("LP;E",post,ggdraw);//Sets 'kCanDelete' so an external canvas will delete this object when "Clear" is called
1141  ana->GetData()->SetLineColor(kBlue);
1142  ana->GetData()->SetMarkerColor(kBlue);
1143  ana->GetData()->SetMarkerStyle(4);
1144  ana->GetData()->SetMarkerSize(0.5);
1145  Int_t compidx = ana->FoundPeakIndex();
1146  if( compidx<0 ){ compidx = ana->AnalyzeForPeak(); }
1147  int npeaks = ana->NPeaks();
1148  //std::cout << "|det:"<<det << "|ch:"<<ch << std::endl;
1149  //std::cout << " + |B::npeaks:"<<npeaks << "|compidx:"<<compidx << std::endl;
1150  if( compidx<npeaks ){
1151  int trigfitidx = compidx;//this is starting condition is needed to pick out the right index
1152  //Hack to replicate NPeaksPrePost function
1153  //make initial window 1 RHIC crossing
1154  Double_t xmin = mCenterTB - mDbPulse->TBPerRC()/2;
1155  Double_t xmax = mCenterTB + mDbPulse->TBPerRC()/2;
1156  //@[August 25, 2022](David Kapukchyan)>In future use varaiables as opposed to constants??
1157  int prexing = 3*mDbPulse->TBPerRC();//Pre-crossing more important than post-crossing so use wider range for pre-crossing
1158  int postxing = 2*mDbPulse->TBPerRC();
1159  bool foundtrigidx = false;
1160  std::vector<int> validpeakidx; //store all valid indexes for peaks around the triggered crossing
1161  for( int i=0; i<ana->NPeaks(); ++i ){
1162  if( (mCenterTB-prexing) < ana->GetPeak(i).mPeakX && ana->GetPeak(i).mPeakX < (mCenterTB+postxing) ){
1163  if( !foundtrigidx && trigfitidx==i ){ foundtrigidx = true; trigfitidx = validpeakidx.size(); }//do before adding i to vector so that when i does get added the triggered crossing index matches
1164  if( !validpeakidx.empty() && validpeakidx.back()!=(i-1) ){ LOG_ERROR << "StFcsWaveformFitMaker::dualFit: Found indices are not linear" << endm; }
1165  validpeakidx.push_back(i);
1166  if( xmin > ana->GetPeak(i).mStartX ){ xmin = ana->GetPeak(i).mStartX; }
1167  if( xmax < ana->GetPeak(i).mEndX ){ xmax = ana->GetPeak(i).mEndX; }
1168  }
1169  }
1170  if( !foundtrigidx ){ LOG_ERROR << "StFcsWaveformFitMaker::dualFit: Unable to find a matching triggered crossing possibly due to improper use of function" << endm; }
1171  //End of Hack
1172  npeaks = validpeakidx.size();
1173  if( npeaks>0 && npeaks<mMaxPeak ){
1174  TF1* func_PulseFit = mDbPulse->createPulse(xmin,xmax,2+npeaks*3);//only fit inside the range of valid peaks
1175  ana->SetFitPars(func_PulseFit,validpeakidx.front(),validpeakidx.back());
1176  if( func_PulseFit->GetParameter(0)==0 ){ LOG_ERROR << "StFcsWaveformFitMaker::drawDualFit: Unable to set function parameters, bad peak indicies" << endl; }
1177  //ana->SetSignal(func);
1178  TFitResultPtr result = ggdraw->Fit(func_PulseFit,"BNRQ");
1179  //compidx no longer equal to index to triggered crossing peak
1180  func_PulseFit->SetLineColor(kBlack);
1181  func_PulseFit->SetLineWidth(1);
1182  func_PulseFit->SetBit(kCanDelete);
1183  func_PulseFit->Draw("same");
1184  }
1185  }
1186  }
1187  TF1* func_gaus = 0;
1188  float gausres[8] = {0};
1189  gausFit( ggdraw , gausres, func_gaus );
1190  if( func_gaus!=0 ){
1191  func_gaus->SetLineColor(kGreen);
1192  func_gaus->SetLineWidth(1);
1193  func_gaus->SetBit(kCanDelete);
1194  func_gaus->SetParameter(1,0.5);
1195  func_gaus->Draw("same");
1196  }
1197  }//ch check
1198  }//detid check
1199  }//hit loop
1200 }
1201 
1202 float StFcsWaveformFitMaker::gausFitWithPed(TGraphAsymmErrors* g, float* res, TF1*& func){
1203  if( fabs(res[7]) < 0.000001 ){AnaPed( g, res[6], res[7] ); } //Only call AnaPed if pedestal hasn't already been calculated and stored in res. res[7] will be nonzero only if AnaPed was already called.
1204  LOG_DEBUG << "Pedestal ("<<mPedMax<<"-"<<mPedMin<<"+1)=" << res[6]<<" +- "<<res[7] << endm;
1205  return gausFit(g, res, func, res[6]);
1206 }
1207 
1208 void StFcsWaveformFitMaker::drawRegion(int det, int col_low, int row_low, int col_high, int row_high, int event){
1209  const int MAXPAD = 16;
1210  int NumDrawnPad[MAXPAD]={0};//To keep track of how much was drawn on each pad
1211  //Keep track of minimum and maximum y for each pad x should be same so leave as is
1212  Double_t MinY[MAXPAD] = {0};
1213  Double_t MaxY[MAXPAD] = {0};
1214  int MaxDrawPad=0;
1215  //int MaxCol = mDb->nColumn(det);
1216  //int MaxRow = mDb->nRow(det);
1217 
1218  if( det<2 ){MaxDrawPad=6;}//Maximum to draw on one pad for Ecal
1219  else if( det>1 && det<4 ){MaxDrawPad=4;}//Maximum to draw on one pad for Hcal
1220  else{ LOG_ERROR<< "StFcsWaveformFitMaker::drawRegion(): This function only works for det<4"<<endm; return; }
1221 
1222  if( mCanvas==0 ){ mCanvas = new TCanvas("mCanvas","FCSWaveFormFit",10,10,2000,2000); }
1223  //gStyle->SetOptStat(0);
1224  else{
1225  //mCanvas->Clear("nodelete");
1226  mCanvas->Clear();
1227  }
1228  mCanvas->Divide(4,4);
1229 
1230  //Need to loop to mHitIdx since that is the most hits for a given event and this function should be only used after all data is read in. This prevents reading old event that may have had more hits.
1231  for( unsigned int iCh=0; iCh<mHitIdx; ++iCh ){
1232  TGraphAsymmErrors* gTemp = (TGraphAsymmErrors*)mChWaveData.ConstructedAt(iCh);
1233  if( gTemp->GetN()==0 ){continue;}
1234  //std::cout << "DEBUG::drawRegion|Name:"<<gTemp->GetName()<<"|size:"<<gTemp->GetN() << std::endl;
1235  int Chdet,Chid;
1236  StFcsDb::getFromName(gTemp->GetName(),Chdet,Chid);
1237  if( det!=Chdet ){continue;}
1238  int col = mDb->getColumnNumber(Chdet,Chid);
1239  int row = mDb->getRowNumber(Chdet,Chid);
1240  if( !(col_low<=col && col<=col_high) || !(row_low<=row && row<=row_high) ){continue;}//Skip columns and rows not in range
1241 
1242  mPad = StFcsDbPulse::PadNum4x4(det,col,row);//Won't return zero unless invalid column/row
1243  TPad* padTemp = (TPad*)mCanvas->cd( mPad-- );//Post-incrment should return old value
1244  //Since mPad is a number from 1-16 need to offset by one to get 0-15 for array
1245  int color = 100-((static_cast<double>(NumDrawnPad[mPad])/static_cast<double>(MaxDrawPad))*(100-51));//Some suitable rainbow root colors (100=red, 51=purple)
1246  gTemp->SetLineColor(color);
1247  gTemp->SetMarkerColor(color);
1248  gTemp->SetMarkerStyle(NumDrawnPad[mPad]+24);//Some suitable root styles
1249  gTemp->SetMarkerSize(0.5);
1250  //std::cout << " - |Pad:"<<mPad<<"|Num:"<<NumDrawnPad[mPad] << std::endl;
1251  if( NumDrawnPad[mPad]==0 ){
1252  padTemp->cd();
1253  gTemp->Draw("APL");
1254  MinY[mPad]=padTemp->GetUymin();
1255  MaxY[mPad]=padTemp->GetUymax();
1256  }
1257  else{
1258  gTemp->Draw("PL");
1259  Double_t YminNew=5000; Double_t YmaxNew=-5;
1260  StFcsDbPulse::getYMinMax(gTemp,YminNew,YmaxNew);
1261  if( YminNew<MinY[mPad] ){MinY[mPad]=YminNew;}
1262  if( YmaxNew>MaxY[mPad] ){MaxY[mPad]=YmaxNew;}
1263  ((TGraphAsymmErrors*)padTemp->GetListOfPrimitives()->At(1))->GetYaxis()->SetRangeUser(MinY[mPad],MaxY[mPad]);//For this function first graph in list of primitives is the graph with axis object (First object of list is TFrame)
1264  padTemp->Draw();//Update axes
1265  }
1266  if( (++NumDrawnPad[mPad]) > MaxDrawPad ){LOG_WARN << "StFcsWaveformFitMaker::drawRegion(): Drawing too many on one pad"<<endm;}
1267  }
1268  std::stringstream SS_name;
1269  SS_name << "Det"<<det << "_Cl"<<col_low << "Rl"<<row_low << "_Ch"<<col_high << "Rh"<<row_high << "_Event"<<event <<".png";
1270  mCanvas->SaveAs( SS_name.str().c_str() );
1271 }
1272 
1273 void StFcsWaveformFitMaker::drawEvent(int det, int event){
1274  if( det<=1 )//Ecal
1275  {
1276  drawRegion(det, 1,1, 8,12, event);//top left
1277  drawRegion(det, 9,1, 16,12, event);//top middle
1278  drawRegion(det, 17,1, 24,12, event);//top right
1279 
1280  drawRegion(det, 1,13, 8,24, event);//middle left
1281  drawRegion(det, 9,13, 16,24, event);//middle middle
1282  drawRegion(det, 17,13, 24,24, event);//middle right
1283 
1284  drawRegion(det, 1,25, 8,36, event);//bottom left
1285  drawRegion(det, 9,25, 16,36, event);//bottom middle
1286  drawRegion(det, 17,25, 24,36, event);//bottom right
1287  }
1288  if( det>1 && det<4 )//Hcal
1289  {
1290  drawRegion(det, 1,1, 8,8, event);//top left
1291  drawRegion(det, 9,1, 16,8, event);//top right
1292 
1293  drawRegion(det, 1,9, 8,16, event);//middle left
1294  drawRegion(det, 9,9, 16,16, event);//midle right
1295 
1296  drawRegion(det, 1,17, 8,24, event);//bottom left
1297  drawRegion(det, 9,17, 16,24,event);//bottom right
1298  }
1299 }
1300 
1302  //int Nentries = mChWaveData.GetEntries();//Just to prevent multiple evaluation since ROOT loops through array to count elements
1303  for( unsigned int iCh=0; iCh<mHitIdx; ++iCh ){
1304  TGraphAsymmErrors* gTemp = (TGraphAsymmErrors*)mChWaveData.At(iCh);
1305  std::cout << "|Index:"<<iCh<<"|Name:"<<gTemp->GetName()<<"|Size:"<<gTemp->GetN() << std::endl;
1306  }
1307 }
1308 
1310  std::cout << "StFcsWaveformFitMaker Internal State" << std::endl
1311  << " - mMeasureTime:" << mMeasureTime << std::endl
1312  << " - mEnergySelect[ecal,hcal,pres]:" << "["<<mEnergySelect[0] << "," << mEnergySelect[1] << "," << mEnergySelect[2] << "]" << std::endl
1313  << " - mEnergySumScale[ecal,hcal,pres]:" << "["<<mEnergySumScale[0] << "," << mEnergySumScale[1] << "," << mEnergySumScale[2] << "]" << std::endl
1314  << " - mCenterTB:" << mCenterTB << std::endl
1315  << " - mMinTB:" << mMinTB << std::endl
1316  << " - mMaxTB:" << mMaxTB << std::endl
1317  << " - mError:" << mError << std::endl
1318  << " - mErrorSaturated:" << mErrorSaturated << std::endl
1319  << " - mAdcSaturation:" << mAdcSaturation << std::endl
1320  << " - mPedMin:" << mPedMin << std::endl
1321  << " - mPedMax:" << mPedMax << std::endl
1322  << " - mMinAdc:" << mMinAdc << std::endl
1323  << " - mTail:" << mTail << std::endl
1324  << " - mMaxPeak:" << mMaxPeak << std::endl
1325  << " - mMaxPage:" << mMaxPage << std::endl
1326  << " - mSkip:" << mSkip << std::endl
1327  << " - mFilename:" << mFilename << std::endl
1328  //<< " - mFilter:" << (mFilter==0?0:mFilter) << std::endl
1329  << " - mFitDrawOn:" << mFitDrawOn << std::endl
1330  << std::endl;
1331 }
1332 
1333 float StFcsWaveformFitMaker::PulseFit1(TGraphAsymmErrors* gae, float* res, TF1*& func, float ped)
1334 {
1335  if( mPulseFit==0 ){mPulseFit = new StFcsPulseAna(gae); SetupDavidFitterMay2022();}
1336  else{ mPulseFit->SetData(gae); }//Resets finder
1337  if( fabs(res[7]) > 0.000001 ){ mPulseFit->SetBaseline(ped,res[7]); }//only change pedestal if standard deviation is greater than 0, which only happens if a pedestal is calculated
1338  if( GetDebug()>2 ){mPulseFit->SetDebug(1);}
1339 
1340  Int_t compidx = mPulseFit->FoundPeakIndex();
1341  if( compidx<0 ){ compidx = mPulseFit->AnalyzeForPeak(); }
1342  int npeaks = mPulseFit->NPeaks();
1343 
1344  int det0 = 0; int ch0=0;
1345  mDb->getFromName( gae->GetName(), det0,ch0 );
1346 
1347  if( mTest==4 ){
1348  if( compidx==npeaks ){ res[0] = 0; return res[0]; }
1349  func = mDbPulse->createPulse(mMinTB,mMaxTB,2+npeaks*3);
1350  mPulseFit->SetFitPars(func);
1351  TFitResultPtr result = gae->Fit(func,"BNRQ");
1352  for( int i=0; i<npeaks; ++i ){
1353  mH2_HeightvsSigma->Fill( func->GetParameter(1+i*3+3),func->GetParameter(1+i*3+1) );
1354  }
1355  res[5] = npeaks;
1356  res[1] = func->GetParameter(compidx*3 + 2);
1357  res[2] = func->GetParameter(compidx*3 + 3);
1358  res[3] = func->GetParameter(compidx*3 + 4);
1359  res[4] = func->GetChisquare()/func->GetNDF();
1360  res[0] = res[1]*res[3]*StFcsDbPulse::sqrt2pi();
1361  mH2_HeightvsSigmaTrig->Fill(res[3],res[1]);
1362  mH1_ChiNdf->Fill(res[4]);
1363  mH2_HeightvsChiNdf->Fill(res[4],res[1]);
1364  mH2_MeanvsChiNdf->Fill(res[4],res[2]);
1365  mH2_SigmavsChiNdf->Fill(res[4],res[3]);
1366 
1367  return res[0];
1368  }
1369 
1370  //std::cout << "|compidx:"<<compidx << "|npeaks:"<<npeaks <<std::endl;
1371  if( mTest==3 ){
1372  mH1F_NPeaks[det0]->Fill(npeaks);
1373  mH1F_NPeaks[6]->Fill(npeaks);
1374  }
1375  if( compidx==npeaks ){ res[0] = 0; }//no found peak case sum is 0
1376  else if( npeaks<=1 ){ //0 or 1 peak case with a valid peak; do sum 8
1377  if( mTest==3 ){
1378  mH1F_NPeaksFiltered[det0]->Fill(npeaks);
1379  mH1F_NPeaksFiltered[6]->Fill(npeaks);
1380  }
1381  res[0] = sum8(gae,res);
1382  //Scale sum8 to match fitted sum (These may need to be confirmed by data year by year)
1383  if( det0==0 || det0==1 ){res[0]/=mEnergySumScale[0];}
1384  if( det0==2 || det0==3 ){res[0]/=mEnergySumScale[1];}
1385  if( det0==4 || det0==5 ){res[0]/=mEnergySumScale[2];}
1386  res[1] = mPulseFit->GetPeak(compidx).mPeakY;
1387  res[2] = mPulseFit->GetPeak(compidx).mPeakX;
1388  res[3] = mDbPulse->GSigma();
1389  res[4] = -1;
1390  }
1391  else{ //More than 1 peak and valid peak found
1392  if( mTest==3 ){
1393  mH1F_NPeaksFiltered[det0]->Fill(npeaks);
1394  mH1F_NPeaksFiltered[6]->Fill(npeaks);
1395  //int mypeakidx = (npeaks<=5)?(npeaks-2):3;
1396  double xfound = mPulseFit->GetPeak(compidx).mPeakX;
1397  double yfound = mPulseFit->GetPeak(compidx).mPeakY;
1398  for( Int_t i=0; i<npeaks; ++i ){
1399  if( i==compidx ){ continue; }
1400  double x = mPulseFit->GetPeak(i).mPeakX;
1401  double y = mPulseFit->GetPeak(i).mPeakY;
1402  mH2_NPeakvsPeakXdiff->Fill(xfound-x,npeaks);
1403  mH2_NPeakvsPeakYratio->Fill(yfound/y,npeaks);
1404  }
1405  }
1406  int numoverlaps = 0;
1407  for( Int_t i=0; i<npeaks; ++i ){
1408  if( i==compidx ){ continue; }
1409  if( mTest==3 ){
1410  int comp = PeakCompare( mPulseFit->GetPeak(compidx),mPulseFit->GetPeak(i) );
1411  mH1_VOverlap->Fill(comp);
1412  mH2_VvsNOverlap->Fill(i-compidx,comp);
1413  if( comp!=0 ){ ++numoverlaps; }
1414  }
1415  else{ if(PeakCompare( mPulseFit->GetPeak(compidx),mPulseFit->GetPeak(i) )!=0 ){ ++numoverlaps; } }
1416  }
1417  if( numoverlaps>0 ){
1418  //res[0] = mPulseFit->FitSignal(mMinTb,mMaxTb);
1419  auto start=std::chrono::high_resolution_clock::now();//for timing studies can be commented out as long as not testing
1420  func = mDbPulse->createPulse(mMinTB,mMaxTB,2+npeaks*3);
1421  mPulseFit->SetFitPars(func);
1422  //mPulseFit->SetSignal(func);
1423  TFitResultPtr result = gae->Fit(func,"BNRQ");
1424  res[1] = func->GetParameter(compidx*3 + 2);
1425  res[2] = func->GetParameter(compidx*3 + 3);
1426  res[3] = func->GetParameter(compidx*3 + 4);
1427  res[4] = func->GetChisquare()/func->GetNDF();
1428  res[0] = res[1]*res[3]*StFcsDbPulse::sqrt2pi();
1429  if( mTest==3 ){
1430  auto stop=std::chrono::high_resolution_clock::now();
1431  long long usec = chrono::duration_cast<chrono::microseconds>(stop-start).count();
1432  mH1_TimeFitPulse->Fill(float(usec)/1000.0);
1433  mH2F_NOvsId[det0]->Fill(ch0,numoverlaps);
1434  mH2_NOvsNPeaks->Fill(npeaks,numoverlaps);
1435  //printf("Fit Time = %lld usec\n",usec);
1436  }
1437  }
1438  else{//Don't need to fit as other peaks don't contribute to found peak
1439  res[0] = sum8(gae,res);
1440  //Scale sum8 to match fitted sum (These may need to be confirmed by data year by year)
1441  if( det0==0 || det0==1 ){res[0]/=mEnergySumScale[0];}
1442  if( det0==2 || det0==3 ){res[0]/=mEnergySumScale[1];}
1443  if( det0==4 || det0==5 ){res[0]/=mEnergySumScale[2];}
1444  res[1] = mPulseFit->GetPeak(compidx).mPeakY;
1445  res[2] = mPulseFit->GetPeak(compidx).mPeakX;
1446  res[3] = mDbPulse->GSigma();
1447  res[4] = -1;
1448  }
1449  }
1450  res[5] = npeaks;//change to number of peaks in pre2 and post1 (number of peaks fitted)
1451  if( mTest==3 ){
1452  mH1F_Res0[det0]->Fill(res[0]);
1453  mH1F_Res0Zoom[det0]->Fill(res[0]);
1454  mH1F_Res0[6]->Fill(res[0]);
1455  mH1F_Res0Zoom[6]->Fill(res[0]);
1456  float sum8res[8] = {0};
1457  sum8( gae ,sum8res );
1458  mH1F_Sum8Res0[det0]->Fill(sum8res[0]);
1459  mH1F_Sum8Res0Zoom[det0]->Fill(sum8res[0]);
1460  mH1F_Sum8Res0[6]->Fill(sum8res[0]);
1461  mH1F_Sum8Res0Zoom[6]->Fill(sum8res[0]);
1462  float savesum8 = sum8res[0];
1463  //Scale sum8 to match fitted sum
1464  //if( det0==0 || det0==1 ){savesum8/=1.226;}
1465  //if( det0==2 || det0==3 ){savesum8/=1.195;}
1466  //if( det0==4 || det0==5 ){savesum8/=1.29;}
1467 
1468  if( npeaks>=1 ){//No found peak skip fitting
1469  if( func==0 ){//No fit performed above so do a fit now
1470  //Here I will reuse the sum8res array
1471  func = mDbPulse->createPulse(mMinTB,mMaxTB,2+npeaks*3);
1472  mPulseFit->SetFitPars(func);
1473  TFitResultPtr result = gae->Fit(func,"BNRQ");
1474  sum8res[5] = npeaks;
1475  sum8res[1] = func->GetParameter(compidx*3 + 2);
1476  sum8res[2] = func->GetParameter(compidx*3 + 3);
1477  sum8res[3] = func->GetParameter(compidx*3 + 4);
1478  sum8res[4] = func->GetChisquare()/func->GetNDF();
1479  sum8res[0] = sum8res[1]*sum8res[3]*StFcsDbPulse::sqrt2pi();
1480  mH1F_FitRes0[det0]->Fill(sum8res[0]);
1481  mH1F_FitRes0Zoom[det0]->Fill(sum8res[0]);
1482  mH1F_FitRes0[6]->Fill(sum8res[0]);
1483  mH1F_FitRes0Zoom[6]->Fill(sum8res[0]);
1484 
1485  mH2F_Sum8vFit[det0]->Fill(sum8res[0],savesum8);
1486  mH2F_Sum8vFit[6]->Fill(sum8res[0],savesum8);
1487  }
1488  else{//Fit was done above so just save that result
1489  mH1F_FitRes0[det0]->Fill(res[0]);
1490  mH1F_FitRes0Zoom[det0]->Fill(res[0]);
1491  mH1F_FitRes0[6]->Fill(res[0]);
1492  mH1F_FitRes0Zoom[6]->Fill(res[0]);
1493  mH2F_Sum8vFit[det0]->Fill(res[0],savesum8);
1494  mH2F_Sum8vFit[6]->Fill(res[0],savesum8);
1495  }
1496  }
1497  }
1498 
1499  return res[0];
1500 }
1501 
1502 float StFcsWaveformFitMaker::PulseFit2(TGraphAsymmErrors* gae, float* res, TF1*& func, float ped)
1503 {
1504  if( mPulseFit==0 ){mPulseFit = new StFcsPulseAna(gae); SetupDavidFitterMay2022();}
1505  else{ mPulseFit->SetData(gae); }//Resets finder
1506  if( fabs(res[7]) > 0.000001 ){ mPulseFit->SetBaseline(ped,res[7]); }//only change pedestal if standard deviation is greater than 0, which only happens if a pedestal is calculated
1507  if( GetDebug()>2 ){mPulseFit->SetDebug(1);}
1508 
1509  Int_t compidx = mPulseFit->FoundPeakIndex();
1510  if( compidx<0 ){ compidx = mPulseFit->AnalyzeForPeak(); }
1511  int npeaks = mPulseFit->NPeaks();
1512 
1513  int det0 = 0; int ch0=0;
1514  mDb->getFromName( gae->GetName(), det0,ch0 );
1515 
1516  if( mTest==6 || mTest==8 ){
1517  mH1F_NPeaks[det0]->Fill(npeaks);
1518  mH1F_NPeaks[6]->Fill(npeaks);
1519  }
1520  if( compidx==npeaks ){ res[0] = 0; }//no found peak case sum is 0
1521  else if( (mTest==8?(npeaks<1):(npeaks<=1)) ){ //0 or 1 peak case with a valid peak; do sum 8; if test==8 then do for all peaks
1522  //else if( npeaks<=1 ){
1523  res[0] = sum8(gae,res);
1524  //Scale sum8 to match fitted sum (These may need to be confirmed by data year by year)
1525  if( det0==0 || det0==1 ){res[0]/=mEnergySumScale[0];}
1526  if( det0==2 || det0==3 ){res[0]/=mEnergySumScale[1];}
1527  if( det0==4 || det0==5 ){res[0]/=mEnergySumScale[2];}
1528  res[1] = mPulseFit->GetPeak(compidx).mPeakY;
1529  res[2] = mPulseFit->GetPeak(compidx).mPeakX;
1530  res[3] = mDbPulse->GSigma();
1531  res[4] = -1;
1532  }
1533  else{ //More than 1 peak and valid peak found
1534  Double_t xmin=0;
1535  Double_t xmax=1;
1536  int trigfitidx = compidx;//this is starting condition is needed to pick out the right index
1537  std::vector<int> validindex = NPeaksPrePost(trigfitidx,xmin,xmax);//Check for peaks near triggered crossing (counts triggered crosing peak)
1538  npeaks = validindex.size();
1539  if( mTest==6 || mTest==7 || mTest==8 ){
1540  mH1F_NPeaksFiltered[det0]->Fill(npeaks);
1541  mH1F_NPeaksFiltered[6]->Fill(npeaks);
1542  }
1543  if( ((mTest==8)?(npeaks>=1 && npeaks<mMaxPeak):(npeaks>1)) ){//If equal to one then still don't need to fit, unless mTest==8 then fit 1 peak cases
1544  auto start=std::chrono::high_resolution_clock::now();//for timing studies can be commented out as long as not testing
1545  func = mDbPulse->createPulse(xmin,xmax,2+npeaks*3);//only fit inside the range of valid peaks
1546  mPulseFit->SetFitPars( func, validindex.front(), validindex.back() );
1547  if( func->GetParameter(0)==0 ){ LOG_ERROR << "StFcsWaveformFitMaker::PulseFit2: Unable to set function parameters, bad peak indicies" << endl; }
1548  //mPulseFit->SetSignal(func);
1549  TFitResultPtr result = gae->Fit(func,"BNRQ");
1550  //compidx no longer equal to index to triggered crossing peak
1551  res[1] = func->GetParameter(trigfitidx*3 + 2);
1552  res[2] = func->GetParameter(trigfitidx*3 + 3);
1553  res[3] = func->GetParameter(trigfitidx*3 + 4);
1554  res[4] = func->GetChisquare()/func->GetNDF();
1555  res[0] = res[1]*res[3]*StFcsDbPulse::sqrt2pi();
1556  if( mTest==6 || mTest==8 ){
1557  auto stop=std::chrono::high_resolution_clock::now();
1558  long long usec = chrono::duration_cast<chrono::microseconds>(stop-start).count();
1559  mH1_TimeFitPulse->Fill(float(usec)/1000.0);
1560  //printf("Fit Time = %lld usec\n",usec);
1561  }
1562  }
1563  else{//Don't need to fit as other peaks don't contribute to found peak
1564  res[0] = sum8(gae,res);
1565  //Scale sum8 to match fitted sum (These may need to be confirmed by data year by year)
1566  if( det0==0 || det0==1 ){res[0]/=mEnergySumScale[0];}
1567  if( det0==2 || det0==3 ){res[0]/=mEnergySumScale[1];}
1568  if( det0==4 || det0==5 ){res[0]/=mEnergySumScale[2];}
1569  res[1] = mPulseFit->GetPeak(compidx).mPeakY;
1570  res[2] = mPulseFit->GetPeak(compidx).mPeakX;
1571  res[3] = mDbPulse->GSigma();
1572  res[4] = -1;
1573  }
1574  }
1575  res[5] = npeaks;//number of peaks in pre2 and post1 (number of fitted peaks)
1576 
1577  if( mTest==6 ){
1578  mH1F_Res0[det0]->Fill(res[0]);
1579  mH1F_Res0Zoom[det0]->Fill(res[0]);
1580  mH1F_Res0[6]->Fill(res[0]);
1581  mH1F_Res0Zoom[6]->Fill(res[0]);
1582  float sum8res[8] = {0};
1583  sum8( gae ,sum8res );
1584  mH1F_Sum8Res0[det0]->Fill(sum8res[0]);
1585  mH1F_Sum8Res0Zoom[det0]->Fill(sum8res[0]);
1586  mH1F_Sum8Res0[6]->Fill(sum8res[0]);
1587  mH1F_Sum8Res0Zoom[6]->Fill(sum8res[0]);
1588  float savesum8 = sum8res[0];
1589  //if( det0==0 || det0==1 ){savesum8/=1.226;}
1590  //if( det0==2 || det0==3 ){savesum8/=1.195;}
1591  //if( det0==4 || det0==5 ){savesum8/=1.29;}
1592 
1593  if( mPulseFit->NPeaks()>=1 ){//No found peak skip fitting
1594  TF1* testfunc = mDbPulse->createPulse(mMinTB,mMaxTB,2+(mPulseFit->NPeaks())*3);//Want to compare when doing fit to all peaks
1595  //Here I will reuse the sum8res array
1596  mPulseFit->SetFitPars(testfunc);
1597  TFitResultPtr result = gae->Fit(testfunc,"BNRQ");
1598  sum8res[5] = mPulseFit->NPeaks();
1599  sum8res[1] = testfunc->GetParameter(compidx*3 + 2);
1600  sum8res[2] = testfunc->GetParameter(compidx*3 + 3);
1601  sum8res[3] = testfunc->GetParameter(compidx*3 + 4);
1602  sum8res[4] = testfunc->GetChisquare()/testfunc->GetNDF();
1603  sum8res[0] = sum8res[1]*sum8res[3]*StFcsDbPulse::sqrt2pi();
1604  mH1F_FitRes0[det0]->Fill(sum8res[0]);
1605  mH1F_FitRes0Zoom[det0]->Fill(sum8res[0]);
1606  mH1F_FitRes0[6]->Fill(sum8res[0]);
1607  mH1F_FitRes0Zoom[6]->Fill(sum8res[0]);
1608 
1609  mH2F_Sum8vFit[det0]->Fill(sum8res[0],savesum8);
1610  mH2F_Sum8vFit[6]->Fill(sum8res[0],savesum8);
1611  }
1612  }
1613  if( mTest==8 ){
1614  mH1F_Res0[det0]->Fill(res[0]);
1615  mH1F_Res0Zoom[det0]->Fill(res[0]);
1616  mH1F_Res0[6]->Fill(res[0]);
1617  mH1F_Res0Zoom[6]->Fill(res[0]);
1618  TF1* testfunc = 0;
1619  float gausres[8] = {0};
1620  gausFit( gae , gausres, testfunc );
1621  mH1F_FitRes0[det0]->Fill(gausres[0]);
1622  mH1F_FitRes0Zoom[det0]->Fill(gausres[0]);
1623  mH1F_FitRes0[6]->Fill(gausres[0]);
1624  mH1F_FitRes0Zoom[6]->Fill(gausres[0]);
1625 
1626  mH2F_Sum8vFit[det0]->Fill(gausres[0],res[0]);
1627  mH2F_Sum8vFit[6]->Fill(gausres[0],res[0]);
1628  }
1629 
1630  return res[0];
1631 }
1632 
1633 float StFcsWaveformFitMaker::PulseFitAll(TGraphAsymmErrors* gae, float* res, TF1*& func, float ped)
1634 {
1635  if( mPulseFit==0 ){mPulseFit = new StFcsPulseAna(gae); SetupDavidFitterMay2022();}
1636  else{ mPulseFit->SetData(gae); }//Resets finder
1637  if( fabs(res[7]) > 0.000001 ){ mPulseFit->SetBaseline(ped,res[7]); }//only change pedestal if standard deviation is greater than 0, which only happens if a pedestal is calculated
1638  if( GetDebug()>2 ){mPulseFit->SetDebug(1);}
1639 
1640  Int_t compidx = mPulseFit->FoundPeakIndex();
1641  if( compidx<0 ){ compidx = mPulseFit->AnalyzeForPeak(); }
1642  int npeaks = mPulseFit->NPeaks();
1643 
1644  int det0 = 0; int ch0=0;
1645  mDb->getFromName( gae->GetName(), det0,ch0 );
1646 
1647  //std::cout << "det0:"<<det0 << "|ch0:"<<ch0 << "|npeaks:"<<npeaks << std::endl;
1648  if( compidx==npeaks || npeaks==0 ){
1649  res[0] = sum8(gae,res);
1650  //Scale sum8 to match fitted sum (These may need to be confirmed by data year by year)
1651  if( det0==0 || det0==1 ){res[0]/=mEnergySumScale[0];}
1652  if( det0==2 || det0==3 ){res[0]/=mEnergySumScale[1];}
1653  if( det0==4 || det0==5 ){res[0]/=mEnergySumScale[2];}
1655  res[2] = mCenterTB;
1656  res[3] = mDbPulse->GSigma();
1657  res[4] = -1;
1658  res[5] = npeaks;
1659  return res[0];
1660  }
1661  Double_t xmin=mPulseFit->GetPeak(0).mStartX;
1662  Double_t xmax=mPulseFit->GetPeak(npeaks-1).mEndX;
1663 
1664  func = mDbPulse->createPulse(xmin,xmax,2+npeaks*3);//only fit inside the range of valid peaks
1665  mPulseFit->SetFitPars( func );
1666  if( func->GetParameter(0)==0 ){ LOG_ERROR << "StFcsWaveformFitMaker::PulseFitAll: Unable to set function parameters, bad peak indicies" << endl; }
1667  TFitResultPtr result = gae->Fit(func,"BNRQ");
1668  //compidx no longer equal to index to triggered crossing peak
1669  res[1] = func->GetParameter(compidx*3 + 2);
1670  res[2] = func->GetParameter(compidx*3 + 3);
1671  res[3] = func->GetParameter(compidx*3 + 4);
1672  res[4] = func->GetChisquare()/func->GetNDF();
1673  res[0] = res[1]*res[3]*StFcsDbPulse::sqrt2pi();
1674 
1675  res[5] = npeaks;//number of fitted peaks
1676 
1677  return res[0];
1678 }
1679 
1680 float StFcsWaveformFitMaker::PulseFit2WithPed(TGraphAsymmErrors* gae, float* res, TF1*& func)
1681 {
1682  if( fabs(res[7]) < 0.000001 ){AnaPed( gae, res[6], res[7] ); } //Only call AnaPed if pedestal hasn't already been calculated and stored in res. res[7] will be nonzero only if AnaPed was already called.
1683  return PulseFit2(gae,res,func,res[6]);
1684 }
1685 
1686 float StFcsWaveformFitMaker::PulseFitAllWithPed(TGraphAsymmErrors* gae, float* res, TF1*& func)
1687 {
1688  if( fabs(res[7]) < 0.000001 ){AnaPed( gae, res[6], res[7] ); } //Only call AnaPed if pedestal hasn't already been calculated and stored in res. res[7] will be nonzero only if AnaPed was already called.
1689  return PulseFitAll(gae,res,func,res[6]);
1690 }
1691 
1692 float StFcsWaveformFitMaker::PedFitPulseFit(TGraphAsymmErrors* gae, float* res, TF1*& func)
1693 {
1694  if( mPulseFit==0 ){mPulseFit = new StFcsPulseAna(gae); SetupDavidFitterMay2022();}
1695  else{mPulseFit->SetData(gae);}//Resets finder
1696  if( GetDebug()>2){mPulseFit->SetDebug(1);}
1697 
1699  res[6] = mPulseFit->Baseline();
1700  res[7] = mPulseFit->BaselineSigma();
1701 
1702  return PulseFitAll(gae,res,func,res[6]);
1703 }
1704 
1705 int StFcsWaveformFitMaker::GenericPadPos(int value, int Nvals, int PadNums )
1706 {
1707  if( value<=0 ){return ceil( static_cast<double>(value+(Nvals*PadNums))/static_cast<double>(Nvals) );}
1708  else{ return GenericPadPos(value-(Nvals*PadNums), Nvals, PadNums); }
1709 }
1710 
1711 int StFcsWaveformFitMaker::PadNum4x4(int det, int col, int row)
1712 {
1713  int ncol = 0;
1714  int nrow = 0;
1715  if( det<=1 ){
1716  ncol = 2;
1717  nrow = 3;
1718  }
1719  else if( 1<det && det<=3 ){
1720  ncol = 2;
1721  nrow = 2;
1722  }
1723  else{ LOG_ERROR << "StFcsWaveformFitMaker::PadNum4x4: This only works for Ecal and Hcal" << endm; return 0;}
1724  int padcol = GenericPadPos(col,ncol,4);
1725  int padrow = GenericPadPos(row,nrow,4);
1726  return 4*(padrow-1)+padcol;
1727 }
1728 
1730 {
1731  //return true;
1732  double xdiff = fabs(pwin1.mPeakX-pwin2.mPeakX);
1733  double yratio = pwin1.mPeakY/pwin2.mPeakY;
1734  unsigned int result = 0;//Bit vector to store results of checks
1735  // + First bit xdiff cut
1736  // + Second bit yratio cut
1737  //@[June 22, 2022](David Kapukchyan)>After looking at some plots from Test==3 an xdiff>10 seems like a good cutoff for no overlap between peaks and a y-ratio>2.0
1738  //check peak-y difference if greater than some value no overlap
1739  //check sum8 of both and if both small no overlap
1740  if( xdiff<10.0 ){ result |= 1<<0; }
1741  if( yratio<2.0 ){ result |= 1<<1; }
1742  return result;
1743 }
1744 
1745 std::vector<int> StFcsWaveformFitMaker::NPeaksPrePost(int& trigidx,Double_t& xmin, Double_t &xmax) const
1746 {
1747  //make initial window 1 RHIC crossing
1748  xmin = mCenterTB - mDbPulse->TBPerRC()/2;
1749  xmax = mCenterTB + mDbPulse->TBPerRC()/2;
1750  //@[August 25, 2022](David Kapukchyan)>In future use varaiables as opposed to constants??
1751  int prexing = 3*mDbPulse->TBPerRC();//Pre-crossing more important than post-crossing so use wider range for pre-crossing
1752  int postxing = 2*mDbPulse->TBPerRC();
1753  bool foundtrigidx = false;
1754  std::vector<int> valididx; //store all valid indexes for peaks around the triggered crossing
1755  //std::cout << "|prexing:" << mCenterTB-prexing << "|postxing:"<<mCenterTB+postxing << std::endl;
1756  for( int i=0; i<mPulseFit->NPeaks(); ++i ){
1757  //std::cout << "-|i:" << i << "|peakx:"<<mPulseFit->GetPeak(i).mPeakX << std::endl;
1758  if( (mCenterTB-prexing) < mPulseFit->GetPeak(i).mPeakX && mPulseFit->GetPeak(i).mPeakX < (mCenterTB+postxing) ){
1759  //if pre crossing peak hits zero then don't need to fit pre-crossing (this can be done by checking if pre-endx==trigB-startx??
1760  if( !foundtrigidx && trigidx==i ){ foundtrigidx = true; trigidx = valididx.size(); }//do before adding i to vector so that when i does get added the triggered crossing index matches
1761  if( !valididx.empty() && valididx.back()!=(i-1) ){ LOG_ERROR << "StFcsWaveformFitMaker::NPeaksPrePost: Found indices are not linear" << endm; }
1762  valididx.push_back(i);
1763  if( xmin > mPulseFit->GetPeak(i).mStartX ){ xmin = mPulseFit->GetPeak(i).mStartX; }
1764  if( xmax < mPulseFit->GetPeak(i).mEndX ){ xmax = mPulseFit->GetPeak(i).mEndX; }
1765  }
1766  }
1767  if( !foundtrigidx ){ LOG_ERROR << "StFcsWaveformFitMaker::NPeaksPrePost: Unable to find a matching triggered crossing possibly due to improper use of function" << endm; }
1768  return valididx;
1769 }
1770 
1772 {
1773  if( mPulseFit==0 ){ mPulseFit = new StFcsPulseAna(); }
1774  //Need to set baseline to zero, or greater than zero, to prevent baseline finding.
1775  //This is good for zero-suppressed data but should be left unset otherwise. Also can be used to adjust adc threshold
1776  //for acceptance by changing the 0.75 to some other number (default ADC acceptance = 4.0*0.75)
1777  mPulseFit->SetBaseline(ped,0.39);
1779  mPulseFit->SetRange(-4,0,2000,5000);
1780  mPulseFit->SetSearchWindow(centerTB(),4);//Check +- 4tb around triggered crossing; some suitable starting search parameter may need to be adjusted based on data
1781  mPulseFit->SetContinuity(1.0);
1782  return mPulseFit;
1783 }
1784 
1786 {
1787  if( mPulseFit==0 ){return;}
1788  InitFitter(ped);
1789  //mPulseFit->SetFilter(1,1);//Mean filter with "radius" 1
1790  //mPulseFit->SetFilter(1,2);//Mean filter with "radius" 2
1791  //mPulseFit->SetFilter(2,1,0.5);//Gaus filter with "radius" 1 and sigma 0.5.
1792  //mPulseFit->SetFilter(2,3,1);//Gaus filter with "radius" 2 and sigma 1.
1793  //Parameters for peak tunneling method,
1794  mPulseFit->SetTunnelScale(1.0);
1795  mPulseFit->SetTunnelSigma(1.5);
1796  mPulseFit->SetTunnelThreshold(-0.001);//Negative value <=-1 means do merging after peak finding, positive value <=1 means do merging wiht peak finding
1797  //Below are some other thresholds for testing
1798  //mPulseFit->SetTunnelThreshold(-0.9);//Negative value >=-1 means do merging after peak finding
1799  //mPulseFit->SetTunnelThreshold(0.1);//Negative value >=-1 means do merging after peak finding
1800  //mPulseFit->SetTunnelThreshold(-2.0);//Negative value >=-1 means do merging after peak finding
1801 }
1802 
TH2F * mH2_MeanvsChiNdf
Histogram of height vs. chi^2/ndf for all fits.
float sum8(TGraphAsymmErrors *g, float *res)
mEnergySelect=1
void drawCh(UInt_t detid, UInt_t ch) const
Draw a single channel on the current canvas/pad.
float PedFitPulseFit(TGraphAsymmErrors *g, float *res, TF1 *&f)
mEnergySelect=17, first find pedestal using #StFcsPulseAna::AnalyzePedestal() then call PulseFitAll()...
int getColumnNumber(int det, int id) const
get the row number for the channel
Definition: StFcsDb.cxx:490
static int PadNum4x4(int det, int col, int row)
Helper function for drawRegion()
virtual TGraphAsymmErrors * GetData() const
Overwrite from PeakAna to type convert for StFcsWaveformFitMaker.
Definition: StFcsPulseAna.h:57
void setPedestal(int ehp, int ns, int dep, int ch, float ped)
get Pedestal
Definition: StFcsDb.cxx:2120
TH2F * mH2_SigmavsChiNdf
Histogram of chi^2/ndf for all fits.
float analyzeWaveform(int select, TGraphAsymmErrors *g, float *res, TF1 *&f, float ped=0.0)
Perfom the analysis using selected method.
void printSetup() const
Print contents of internal variables.
float PulseFit1(TGraphAsymmErrors *g, float *res, TF1 *&f, float ped=0.0)
mEnergySelect=12, find and fit selected peaks around triggered crossing using PeakCompare() ...
float highest(TGraphAsymmErrors *g, float *res)
mEnergySelect=3
TH1F * mH1F_PeakStart[6]
PeakWindow Starting x-values
void drawDualFit(UInt_t detid, UInt_t ch)
Special draw function, to compare fits for a single channel.
static Int_t getYMinMax(TGraphAsymmErrors *gae, Double_t &Ymin, Double_t &Ymax, Double_t xmin=-5, Double_t xmax=2000)
Finds minimum and maximum y-values in a TGraph and returns index for max y.
static int SumDep0Mod(TGraphAsymmErrors *gdata, int Start, int ped=0)
Test my modified sum method to DEP board.
TH1F * mH1_TimeFitPulse
Histogram to time how long just the fitting takes in PulseFit1() and PulseFit2()
void setTail(int v)
Set tail parameters to use for #mDbPulse, see StFcsDbPulse::setTail()
TH1F * mH1_PeakTimingGaus
Histogram to test timing of gausFit()
float getGainCorrection(int det, int id) const
get the gain for the channel for 8 timebin sum
Definition: StFcsDb.cxx:952
TF1 * createPulse(double xlow=0, double xhigh=1, int npars=5)
Function to create pulse shape for FCS, 5 parameters is minimum.
int getRowNumber(int det, int id) const
maximum number of id
Definition: StFcsDb.cxx:485
float PulseFit2WithPed(TGraphAsymmErrors *g, float *res, TF1 *&f)
mEnergySelect=15, first find pedestal using #AnaPed(), then call PulseFit2()
const PeakWindow & GetPeak(UInt_t peakidx) const
Definition: PeakAna.h:228
TGraphAsymmErrors * getGraph(int idx=-1)
Return TGraphAsymmErrors at idx.
Int_t FoundPeakIndex() const
Definition: PeakAna.h:233
void SetSearchWindow(Double_t peak, Double_t width)
Sets peak search parameters.
Definition: PeakAna.cxx:349
void SetTunnelThreshold(Double_t value)
Definition: PeakAna.cxx:376
virtual void SetData(TGraph *graph)
sets new data for PeakAna
Definition: PeakAna.cxx:302
TH2F * mH2F_SumFitvSumWin[6]
Sum from Akio&#39;s Fit function vs. Sum from my found peak window for different number of peaks...
TGraphAsymmErrors * makeTGraphAsymmErrors(int n, double *t, double *adc)
Create TGraphAsymmErrors from given timebin and adc data.
TH1F * mH1_NPeaksFilteredAkio
Number of peaks found by gausFit() for signals that had a triggered crossing.
TH2F * mH2_NOvsNPeaks
NO (Number of overlaps) vs. Number of peaks.
virtual void Clear(Option_t *option="")
User defined functions.
Definition: StMaker.cxx:634
TClonesArray mChWaveData
Contains all graph data.
void getName(int det, int id, char name[])
get the DEP/ch id
Definition: StFcsDb.cxx:505
TGraphAsymmErrors * resetGraph()
Create or Reset TGraphAsymmErrors (at #mHitIdx)
int PeakCompare(const PeakWindow &pwin1, const PeakWindow &pwin2)
Compare if two peaks overlap and return a bit vector of tests passed/failed.
TH2F * mH2_VvsNOverlap
Compare value for that peak comparison vs. Overlap index.
static double sqrt2pi()
sqrt(2*TMath::Pi)
Definition: StFcsDbPulse.h:37
void printArray() const
Print contents of mChWaveData, excluding timebin and adc information.
TH1F * mH1_PeakTiming
Timing for just peak finding.
Double_t PeakEnd()
Found Signal ending x-value.
Definition: PeakAna.h:250
TH1F * mH1_PeakTimingPuls
Histogram to test timing of PulseFit1()
TH1F * mH1F_FitRes0Zoom[7]
same as mH1F_FitRes0 with finer bining at low end
void AnalyzeForPedestal()
Analyze graph data to determine baseline internally.
StFcsPulseAna * InitFitter(Double_t ped=0)
Sets up basic values needed by StFcsPulseAna.
static void setTGraphAsymmErrors(TGraphAsymmErrors *gae, const int &i, const double &adc, double Yerr, double YerrSat)
Figure out and set the errors on FCS pulse data stored in a TGraphAsymmErrors object.
TH2F * mH2_PeakTimingCompare
Histogram to test timing between PulseFit1() vs. gausFit()
void SetupDavidFitterMay2022(Double_t ped=0)
This special function is used to set all the parameters for StFcsPulseAna based on cosmic and Run 22 ...
float PulseFitAllWithPed(TGraphAsymmErrors *g, float *res, TF1 *&f)
mEnergySelect=16, first find pedestal using #AnaPed(), then call PulseFitAll()
void SetBaseline(Double_t base, Double_t sigma)
Definition: PeakAna.cxx:330
Double_t mPeakX
x-value of peak position as determined by SetPeak()
Definition: PeakWindow.h:76
void SetRange(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax)
Sets the absolute range of the data.
Definition: PeakAna.cxx:342
void drawEvent(int det, int event=0)
Utilizes drawRegion() to draw all channels in an event.
TH1F * mH1_ChiNdf
Histogram of chi^2/ndf for all fits.
void SetDebug(UInt_t level)
Definition: PeakAna.h:275
TH1F * mH1F_Res0Zoom[7]
Histogram of all res[0] with finer bining at low end.
TH2F * mH2F_APeakvMPeak[6]
PeakLocations from Akio vs. Mine.
float gausFit(TGraphAsymmErrors *g, float *res, TF1 *&f, float ped=0.0)
mEnergySelect=10
TH1F * mH1F_PeakEnd[6]
PeakWindow Ending x-values
void SetTunnelScale(Double_t value)
Definition: PeakAna.cxx:363
static int PadNum4x4(int det, int col, int row)
Function that gives pad number when drawing a specific detector id.
virtual StFcsPulseAna * DrawCopy(Option_t *opt="", const char *name_postfix="_copy", TGraph *graph=0) const
Clone and draw, see PeakAna::Draw() for options.
TH1F * mH1F_Sum8Res0[7]
Histogram of &quot;res[0]&quot; using sum8 regardless of method called.
Double_t PeakStart()
Found Signal starting x-value.
Definition: PeakAna.h:249
float getGain(int det, int id) const
get sampling fraction
Definition: StFcsDb.cxx:928
Int_t SumWindow()
Sum the ADC in the peak defined by mFoundPeak and subtract the baseline.
TH2F * mH2_HeightvsChiNdf
Histogram of height vs. chi^2/ndf for all fits.
float highest3(TGraphAsymmErrors *g, float *res)
mEnergySelect=4
void SetBaselineSigmaScale(Double_t scale)
Definition: PeakAna.cxx:337
TH2F * mH2F_Sum8vFit[7]
Histograms of Fit res[0] vs. sum8 res[0].
void drawFit(TGraphAsymmErrors *gg, TF1 *func)
Draw a single TGraph.
virtual void Clear(Option_t *option="")
User defined functions.
Double_t BaselineSigma() const
Definition: PeakAna.h:179
TH2F * mH2F_AdcTbValidPeak[7]
Adc vs. Tb from my algorithm that had a peak at #mCenterTb (Need an extra one for non-valid peaks) ...
void SetFitPars(TF1 *&func, int start=-1, int end=-1)
Set the parameters of an external TF1 function that has the form of StFcsDbPulse::multiPulseShape(), optionally only set fit paramaters for peaks from index start up to and including end.
TH2F * mH2_HeightvsSigma
Histogram of all fitted peak heights vs. their sigma.
TH2F * mH2_HeightvsSigmaTrig
Histogram of height of fitted peaks in triggered crossing vs. their sigma.
TH1F * mH1F_FitRes0[7]
Histogram of &quot;res[0]&quot; from fit regardless of method called.
TH2F * mH2F_AdcTbAkio[6]
Adc vs. Tb for different number of peaks Akio method.
float PulseFitAll(TGraphAsymmErrors *g, float *res, TF1 *&f, float ped=0.0)
mEnergySelect=14, fit all peaks less than mMaxPeak
TH1F * mH1F_Res0[7]
Histogram of all res[0] regardless of method.
TH2F * mH2F_NOvsId[6]
NO (number of overlaps) vs channel id for the 6 detector ids.
TH1F * mH1F_NPeaks[7]
Number of peaks found by peak finder StFcsPulseAna.
void SetContinuity(Double_t val)
Definition: PeakAna.h:293
Definition: Stypes.h:42
double TBPerRC() const
Definition: StFcsDbPulse.h:41
Definition: Stypes.h:40
void writeFile(std::string filename)
Use to change the name of the file where test histograms will be saved.
static int SumDep0(TGraphAsymmErrors *gdata, int Start, int ped=0)
Test of sum method in DEP board.
TH2F * mH2_NPeakvsPeakYratio
Number of peaks vs. Peak Y ratio.
int mTest
Variable to use when testing StFcsWaveformFitMaker algorithms.
Double_t mStartX
x value for start of the peak window
Definition: PeakWindow.h:71
void setTest(int v)
Set test level. Intended to be used for single files. Output file name can be changed with writeFile(...
TH1F * mH1F_Sum8Res0Zoom[7]
same as mH1F_Sum8Res0 with finer bining at low end
void setDbPulse(StFcsDbPulse *p)
Definition: StFcsPulseAna.h:63
virtual Int_t AnalyzeForPeak()
Overwritten from PeakAna to process peak tunneling after finding all peaks.
Double_t Baseline() const
Definition: PeakAna.h:178
bool ValidPeakIdx() const
Definition: PeakAna.cxx:204
float gausFitWithPed(TGraphAsymmErrors *g, float *res, TF1 *&f)
mEnergySelect=11
int NPeaks() const
Definition: PeakAna.h:246
StFcsPulseAna * mPulseFit
Pointer to peak finder used by some analysis methods.
TH2F * mH2_NPeakvsPeakXdiff
Number of peaks vs. Peak X diff.
std::vector< int > NPeaksPrePost(int &trigidx, Double_t &xmin, Double_t &xmax) const
Finds out how many peaks are within a fixed number of pre-crossings and post-crossings.
Double_t mEndX
x value for end of the peak window
Definition: PeakWindow.h:72
Double_t BaselineSigmaScale() const
Definition: PeakAna.h:180
static int GenericPadPos(int value, int Nvals, int PadNums)
Helper function for PadNum4x4.
void drawRegion(int det, int col_low, int row_low, int col_high, int row_high, int event=0)
draw a region of the Ecal or Hcal
Definition: Stypes.h:44
float sum16(TGraphAsymmErrors *g, float *res)
mEnergySelect=2
double GSigma() const
Definition: StFcsDbPulse.h:66
float PulseFit2(TGraphAsymmErrors *g, float *res, TF1 *&f, float ped=0.0)
mEnergySelect=13, (default) find and fit selected peaks around triggered crossing using NPeaksPrePost...
Double_t mPeakY
y-value at mP_Peak
Definition: PeakWindow.h:77
static void getFromName(const char name[], int &det, int &id)
Get Name of a channel.
Definition: StFcsDb.cxx:547
TFile * mOutFile
Root output file for testing.
void setTail(int tail)
Sets the variables needed by the sum of xexp functions that describe the tail of the pulse shape...
TH1F * mH1_VOverlap
Value of overlap.
TH1F * mH1_NPeaksAkio
Number of peaks found by gausFit()
TH1F * mH1F_NPeaksFiltered[7]
Number of peaks for cases where a peak around #mCenterTB was found.
TH2F * mH2F_AdcTbMine[6]
Adc vs. Tb for different number of peaks my method.
Definition: Stypes.h:41
void SetTunnelSigma(Double_t value)
Definition: PeakAna.cxx:367