AdcPedestalFitter_tool.cc
Go to the documentation of this file.
1 // AdcPedestalFitter_tool.cc
2 
3 #include "AdcPedestalFitter.h"
9 #include <iostream>
10 #include <fstream>
11 #include <sstream>
12 #include <iomanip>
13 #include "TDirectory.h"
14 #include "TFile.h"
15 #include "TH1F.h"
16 #include "TF1.h"
17 #include "TROOT.h"
18 #include "TError.h"
19 #include "TFitResult.h"
20 #include "TFitter.h"
21 #include "TLatex.h"
22 
23 using std::string;
24 using std::cout;
25 using std::endl;
26 using std::ofstream;
27 using std::ostream;
28 using std::ostringstream;
29 using std::setw;
30 using std::fixed;
31 using std::setprecision;
32 using std::vector;
33 
34 using Index = unsigned int;
35 using NameSet = std::set<string>;
36 
37 //**********************************************************************
38 // Local definitions.
39 //**********************************************************************
40 
41 namespace {
42 
43 void copyMetadata(const DataMap& res, AdcChannelData& acd) {
44  acd.metadata["fitPedFractionLow"] = res.getFloat("fitFractionLow");
45  acd.metadata["fitPedFractionHigh"] = res.getFloat("fitFractionHigh");
46  acd.metadata["fitPedestal"] = res.getFloat("fitPedestal");
47  acd.metadata["fitPedRms"] = res.getFloat("fitPedestalRms");
48  acd.metadata["fitPedChiSquare"] = res.getFloat("fitChiSquare");
49  acd.metadata["fitPedReducedChiSquare"] = res.getFloat("fitReducedChiSquare");
50  acd.metadata["fitPedPeakBinFraction"] = res.getFloat("fitPeakBinFraction");
51  acd.metadata["fitPedPeakBinExcess"] = res.getFloat("fitPeakBinExcess");
52  acd.metadata["fitPedNBinsRemoved"] = res.getFloat("fitNBinsRemoved");
53 }
54 
55 //void handleRootError(int level, bool doAbort, const char* clocation, const char* cmsg) {
56 // cout << "AdcPedestalFitter::handleRootError: "
57 // << "Received Root error: level=" << level
58 // << ", doAbort=" << (doAbort ? "true" : "false")
59 // << ", location=" << clocation
60 // << ": " << cmsg << endl;
61 //}
62 
63 } // end unnamed namespace
64 
65 //**********************************************************************
66 // Class methods.
67 //**********************************************************************
68 
70 : m_LogLevel(ps.get<int>("LogLevel")),
71  m_AdcRange(ps.get<Name>("AdcRange")),
72  m_FitOpt(ps.get<Index>("FitOpt")),
73  m_FitPrecision(ps.get<float>("FitPrecision")),
74  m_SkipFlags(ps.get<IndexVector>("SkipFlags")),
75  m_AdcFitRange(ps.get<Name>("AdcFitRange")),
76  m_FitRmsMin(ps.get<Name>("FitRmsMin")),
77  m_FitRmsMax(ps.get<Name>("FitRmsMax")),
78  m_RemoveStickyCode(ps.get<bool>("RemoveStickyCode")),
79  m_HistName(ps.get<string>("HistName")),
80  m_HistTitle(ps.get<string>("HistTitle")),
81  m_PlotFileName(ps.get<string>("PlotFileName")),
82  m_RootFileName(ps.get<string>("RootFileName")),
83  m_PlotSizeX(ps.get<Index>("PlotSizeX")),
84  m_PlotSizeY(ps.get<Index>("PlotSizeY")),
85  m_PlotShowFit(ps.get<Index>("PlotShowFit")),
86  m_PlotSplitX(ps.get<Index>("PlotSplitX")),
87  m_PlotSplitY(ps.get<Index>("PlotSplitY")),
88  m_prdtool(nullptr),
89  m_pstate(new State) {
90  const string myname = "AdcPedestalFitter::ctor: ";
92  string stringBuilder = "adcStringBuilder";
93  m_adcStringBuilder = ptm->getShared<AdcChannelStringTool>(stringBuilder);
94  if ( m_adcStringBuilder == nullptr ) {
95  cout << myname << "WARNING: AdcChannelStringTool not found: " << stringBuilder << endl;
96  }
97  for ( Index flg : m_SkipFlags ) m_skipFlags.insert(flg);
98  // Set the vector of fit options.
99  // These are tried in turn until one succeeds.
100  {
101  Name foptLsq = "WWB";
102  // Nov2018: Likelihood fit better handles pdsp run 5803 event 86 channel 7309.
103  Name foptLik = "LWB";
104  if ( m_FitOpt == 0 ) {
105  if ( m_LogLevel > 0 ) cout << myname << "Mean used in place of pedestal fit." << endl;
106  } else if ( m_FitOpt == 1 ) {
107  m_fitOpts.push_back(foptLsq);
108  if ( m_LogLevel > 0 ) cout << myname << "Chi-square fit used for pedestal." << endl;
109  } else if ( m_FitOpt == 2 ) {
110  m_fitOpts.push_back(foptLik);
111  if ( m_LogLevel > 0 ) cout << myname << "Likelihood fit used for pedestal." << endl;
112  } else if ( m_FitOpt == 3 ) {
113  if ( m_LogLevel > 0 ) cout << myname << "Chi-square/likelihood fit used for pedestal." << endl;
114  m_fitOpts.push_back(foptLsq);
115  m_fitOpts.push_back(foptLik);
116  } else if ( m_FitOpt != 0.0 ) {
117  cout << "WARNING: Invalid FitOpt: " << m_FitOpt << ". Not fit will be performed." << endl;
118  }
119  }
120  // Fetch the formula parameters.
121  m_tfs["AdcRange"] = new RootParFormula("adcRange", m_AdcRange);
122  m_tfs["AdcFitRange"] = new RootParFormula("adcFitRange", m_AdcFitRange);
123  m_tfs["FitRmsMin"] = new RootParFormula("fitRmsMin", m_FitRmsMin);
124  m_tfs["FitRmsMax"] = new RootParFormula("fitRmsMax", m_FitRmsMax);
125  m_haveFormulaParams = false;
126  for ( const auto& itf : m_tfs ) {
127  if ( itf.second->npar() > 0 ) m_haveFormulaParams = true;
128  }
129  if ( m_haveFormulaParams ) {
130  string stnam = "runDataTool";
131  m_prdtool = ptm->getShared<RunDataTool>(stnam);
132  if ( m_prdtool == nullptr ) {
133  cout << myname << "ERROR: RunDataTool " << stnam
134  << " not found. Formulas will not be evaluated." << endl;
135  } else {
136  cout << myname << "RunDataTool retrieved." << endl;
137  }
138  } else {
139  cout << myname << "No formula parameters. RunDataTool is not retrieved." << endl;
140  }
141  if ( m_LogLevel >= 1 ) {
142  cout << myname << "Configuration parameters:" << endl;
143  cout << myname << " LogLevel: " << m_LogLevel << endl;
144  cout << myname << " AdcRange: " << m_AdcRange << endl;
145  cout << myname << " FitOpt: " << m_FitOpt << endl;
146  cout << myname << " FitPrecision: " << m_FitPrecision << endl;
147  cout << myname << " SkipFlags: [";
148  bool first = true;
149  for ( Index flg : m_SkipFlags ) {
150  if ( first ) first = false;
151  else cout << ", ";
152  cout << flg;
153  }
154  cout << "]" << endl;
155  cout << myname << " AdcFitRange: " << m_AdcFitRange << endl;
156  cout << myname << " FitRmsMin: " << m_FitRmsMin << endl;
157  cout << myname << " FitRmsMax: " << m_FitRmsMax << endl;
158  cout << myname << " RemoveStickyCode: " << m_RemoveStickyCode << endl;
159  cout << myname << " HistName: " << m_HistName << endl;
160  cout << myname << " HistTitle: " << m_HistTitle << endl;
161  cout << myname << " PlotFileName: " << m_PlotFileName << endl;
162  cout << myname << " RootFileName: " << m_RootFileName << endl;
163  cout << myname << " PlotSizeX: " << m_PlotSizeX << endl;
164  cout << myname << " PlotSizeY: " << m_PlotSizeY << endl;
165  cout << myname << " PlotShowFit: " << m_PlotShowFit << endl;
166  cout << myname << " PlotSplitX: " << m_PlotSplitX << endl;
167  cout << myname << " PlotSplitY: " << m_PlotSplitY << endl;
168  }
169 }
170 
171 //**********************************************************************
172 
174  const string myname = "AdcPedestalFitter::view: ";
175  if ( m_LogLevel >= 3 ) cout << myname << "Calling " << endl;
176  TPadManipulator* pman = nullptr;
177  if ( m_PlotFileName.size() ) {
178  pman = new TPadManipulator;
180  }
181  DataMap res = getPedestal(acd);
182  fillChannelPad(res, acd, pman);
183  if ( pman != nullptr ) {
184  string pfname = nameReplace(m_PlotFileName, acd, false);
185  if ( m_LogLevel >= 3 ) cout << myname << "Creating plot " << pfname << endl;
186  pman->print(pfname);
187  delete pman;
188  }
189  if ( m_LogLevel >= 3 ) cout << myname << "Called " << endl;
190  //TH1* phped = res.getHist("pedestal");
191  //if ( res.haveHist("pedestal") ) res.setHist("pedestal", phped, true);
192  return res;
193 }
194 
195 //**********************************************************************
196 
198  const string myname = "AdcPedestalFitter::update: ";
199  DataMap res = view(acd);
200  if ( res.status() != 0 ) return res;
201  if ( m_LogLevel >= 3 ) cout << myname << "Old pedestal: " << acd.pedestal << endl;
202  acd.pedestal = res.getFloat("fitPedestal");
203  acd.pedestalRms = res.getFloat("fitPedestalRms");
204  copyMetadata(res, acd);
205  if ( m_LogLevel >= 3 ) cout << myname << "New pedestal: " << acd.pedestal << endl;
206  return res;
207 }
208 
209 //**********************************************************************
210 
212  const string myname = "AdcPedestalFitter::updateMap: ";
213  DataMap ret;
214  Index nPedFitGood = 0;
215  Index nPedFitFail = 0;
216  if ( m_LogLevel >= 2 ) cout << myname << "Fitting " << acds.size() << " channels." << endl;
217  Index npad = 0;
218  Index npadx = 0;
219  Index npady = 0;
220  bool doPlot = m_PlotFileName.size() && m_PlotSplitX > 0;
221  if ( doPlot ) {
222  npadx = m_PlotSplitX;
224  npad = npadx*npady;
225  }
226  if ( m_LogLevel >= 2 ) {
227  cout << myname << "Pad count is " << npad << " (" << npady << " x " << npadx << ")" << endl;
228  }
229  TPadManipulator* pmantop = nullptr;
230  // Loop over channels.
231  Index nacd = acds.size();
232  Index iacd = 0;
233  vector<int> fitStats(nacd, 999);
234  vector<float> fitPedestals(nacd, 0.0);
235  vector<float> fitPedestalRmss(nacd, 0.0);
236  string plotFileName = "";
237  for ( auto& acdPair : acds ) {
238  const AdcChannelData& acd = acdPair.second;
239  AdcChannelData& acdMutable = acdPair.second;
240  if ( m_LogLevel >= 3 ) cout << myname << " " << iacd << ": Processing channel " << acd.channel() << endl;
241  // If needed, create a new canvas.
242  if ( npad > 0 && pmantop == nullptr ) {
243  if ( m_LogLevel >= 3 ) cout << myname << " Creating canvas." << endl;
244  pmantop = new TPadManipulator;
246  if ( npad > 1 ) pmantop->split(npady, npady);
247  plotFileName = nameReplace(m_PlotFileName, acd, false);
248  }
249  Index ipad = npad == 0 ? 0 : iacd % npad;
250  TPadManipulator* pman = pmantop == nullptr ? nullptr : pmantop->man(ipad);
251  DataMap tmpres = getPedestal(acd);
252  fillChannelPad(tmpres, acd, pman);
253  fitStats[iacd] = tmpres.status();
254  float fitPedestal = 0.0;
255  float fitPedestalRms = 0.0;
256  if ( tmpres.status() == 0 ) {
257  ++nPedFitGood;
258  fitPedestal = tmpres.getFloat("fitPedestal");
259  fitPedestalRms = tmpres.getFloat("fitPedestalRms");
260  copyMetadata(tmpres, acdMutable);
261  } else {
262  ++nPedFitFail;
263  }
264  fitPedestals[iacd] = fitPedestal;
265  fitPedestalRmss[iacd] = fitPedestalRms;
266  // If needed, print and delete the canvas.
267  ++iacd;
268  bool lastpad = (++ipad == npad) || (iacd == nacd);
269  if ( lastpad && pmantop != nullptr ) {
270  if ( m_LogLevel >= 3 ) cout << myname << " Creating plot " << plotFileName << endl;
271  pmantop->print(plotFileName);
272  delete pmantop;
273  pmantop = nullptr;
274  }
275  }
276  iacd = 0;
277  for ( auto& acdPair : acds ) {
278  AdcChannelData& acd = acdPair.second;
279  acd.pedestal = fitPedestals[iacd];
280  acd.pedestalRms = fitPedestalRmss[iacd];
281  ++iacd;
282  }
283  if ( m_LogLevel >= 2 ) {
284  cout << myname << " # good pedestal fits: " << nPedFitGood << endl;
285  cout << myname << " # fail pedestal fits: " << nPedFitFail << endl;
286  }
287  ret.setInt("nPedFitGood", nPedFitGood);
288  ret.setInt("nPedFitFail", nPedFitFail);
289  ret.setIntVector("fitStats", fitStats);
290  ret.setIntVector("fitStats", fitStats);
291  ret.setFloatVector("fitPedestals", fitPedestals);
292  ret.setFloatVector("fitPedestalRmss", fitPedestalRmss);
293  return ret;
294 }
295 
296 //**********************************************************************
297 
299  const string myname = "AdcPedestalFitter::beginEvent: ";
300  DataMap res;
301  ++state().nevt;
302  if ( evi.run == state().run ) return res;
303  if ( m_LogLevel >= 2 ) {
304  cout << myname << "Setting run " << evi.run << endl;
305  }
306  state().run = evi.run;
307  string msg;
308  if ( m_haveFormulaParams ) {
309  RunData rdat;
310  if ( m_prdtool == nullptr ) {
311  msg = "WARNING: RunData tool not found. Using default parameters.";
312  } else {
313  rdat = m_prdtool->runData(evi.run);
314  }
315  if ( msg.size() == 0 && ! rdat.isValid() ) {
316  msg = "WARNING: RunData not found. Using default parameters.";
317  }
318  if ( msg.size() ) {
319  cout << myname << msg << endl;
320  rdat.setGain(14.0);
321  rdat.setShaping(2.0);
322  }
323  for ( auto& itr : m_tfs ) {
324  ParFormula& form = *itr.second;
325  form.unsetParValues();
326  rdat.setFormulaPars(form);
327  if ( form.unsetPars().size() ) {
328  cout << "ERROR: Formula " << form.name() << " has unset parameters: [";
329  bool first = true;
330  for ( string spar : form.unsetPars() ) {
331  if ( first ) first = false;
332  else cout << ", ";
333  cout << spar;
334  }
335  cout << "]" << endl;
336  }
337  if ( form.resetPars().size() ) {
338  cout << "WARNING: Formula " << form.name() << " has reset parameters" << endl;
339  }
340  }
341  }
342  return res;
343 }
344 
345 //**********************************************************************
346 
347 string AdcPedestalFitter::
348 nameReplace(string name, const AdcChannelData& acd, bool isTitle) const {
350  if ( pnbl == nullptr ) return name;
351  DataMap dm;
352  return pnbl->build(acd, dm, name);
353 }
354 
355 //**********************************************************************
356 
357 DataMap
359  const string myname = "AdcPedestalFitter::getPedestal: ";
360  DataMap res;
361  if ( m_LogLevel >= 2 ) cout << myname << "Fitting pedestal for channel " << acd.channel() << endl;
362  string hnameBase = m_HistName;
363  string htitlBase = m_HistTitle;
364  Index nsam = acd.raw.size();
365  if ( nsam == 0 ) {
366  if ( m_LogLevel >= 2 ) cout << myname << "WARNING: Raw data is empty." << endl;
367  return res.setStatus(1);
368  }
369  // If we need RunData parameters and Make sure that beginEvent has been called to
370  // evaluate formulas.
371  if ( m_haveFormulaParams && state().nevt == 0 ) {
372  cout << myname << "WARNING: Calling beginEvent to evaluate formulas." << endl;
373  beginEvent(acd.getEventInfo());
374  }
375  // Flag samples to keep in pedestal fit.
376  //return res;
377  vector<bool> keep(nsam, true);
378  Index nkeep = 0;
379  Index nskip = 0;
380  for ( Index isam=0; isam<nsam; ++isam ) {
381  if ( isam >= acd.flags.size() ) {
382  if ( m_LogLevel >= 2 ) cout << myname << "WARNING: flags are missing." << endl;
383  nkeep += nsam - isam; // 2021-04-30: Keep unflagged samples
384  break;
385  }
386  Index flg = acd.flags[isam];
387  if ( m_skipFlags.count(flg) ) {
388  keep[isam] = false;
389  ++nskip;
390  } else {
391  ++nkeep;
392  }
393  }
394  if ( nkeep == 0 ) {
395  if ( m_LogLevel >= 2 ) cout << myname << "WARNING: No raw data is selected." << endl;
396  return res.setStatus(2);
397  }
398  string hname = nameReplace(hnameBase, acd, false);
399  string htitl = nameReplace(htitlBase, acd, true);
400  htitl += "; ADC count; # samples";
401  Index adcRange = m_tfs.at("AdcRange")->eval();
402  if ( state().pfitter == nullptr || adcRange != state().adcRange ) {
403  cout << myname << "New ADC range is " << adcRange << endl;
404  state().pfitter = new TF1("pedgaus", "gaus", 0, adcRange, TF1::EAddToList::kNo);
405  }
406  state().adcRange = adcRange;
407  unsigned int nadc = adcRange;
408  unsigned int rebin = 10;
409  unsigned int nbin = (nadc + rebin - 0.01)/rebin;
410  double xmax = rebin*nbin;
411  string hnamr = hname + "_rebin";
412  TH1* phr = new TH1F(hnamr.c_str(), htitl.c_str(), nbin, 0, xmax);
413  phr->SetDirectory(0);
414  IndexVector rcounts(nbin, 0);
415  for ( Index isam=0; isam<nsam; ++isam ) {
416  if ( keep[isam] ) {
417  Index iadc = acd.raw[isam];
418  Index ibin = iadc/10;
419  if ( ibin >= nbin ) cout << myname << "ERROR: Too many ADC counts for channel " << acd.channel()
420  << " sample " << isam << ": " << iadc << endl;
421  else ++rcounts[ibin];
422  }
423  }
424  for ( Index ibin=0; ibin<nbin; ++ibin ) {
425  phr->SetBinContent(ibin+1, rcounts[ibin]);
426  }
427  double wadc = m_tfs.at("AdcFitRange")->eval();
428  if ( wadc < 10 ) {
429  cout << myname << "INFO: Invalid fit range: " << wadc << " < 10 ADC counts" << endl;
430  return res.setStatus(3);
431  }
432  if ( m_LogLevel >= 4 ) cout << myname << "INFO: Width = " << wadc << " ADC counts" << endl;
433  int rbinmax1 = phr->GetMaximumBin();
434  double adcmax = phr->GetBinCenter(rbinmax1);
435  double adc1 = adcmax - 0.5*wadc;
436  double adc2 = adc1 + wadc;
437  if ( m_RemoveStickyCode ) {
438  double radcmax1 = phr->GetBinCenter(rbinmax1);
439  double radcmean = phr->GetMean();
440  double radcsum1 = phr->Integral();
441  // Max may be due to a sticky code. Reduce it and find the next maximum.
442  double tmpval = 0.5*(phr->GetBinContent(rbinmax1-1)+phr->GetBinContent(rbinmax1+1));
443  phr->SetBinContent(rbinmax1, tmpval);
444  int rbinmax2 = phr->GetMaximumBin();
445  double radcsum2 = phr->Integral();
446  // Evaluate the histogram mean and peak position.
447  // If the peak removal has not removed too much data, these values are
448  // re-evaluated using the peak-removed histogram.
449  double adcmean = radcmean; // Mean position.
450  int rbinmax = rbinmax1; // Peak position.
451  if ( radcsum2 > 0.01*radcsum1 ) {
452  // Define the max to be the first value if the two maxima are close or the
453  // average if they are far part.
454  if ( abs(rbinmax2-rbinmax1) > 1 ) {
455  rbinmax = (rbinmax1 + rbinmax2)/2;
456  adcmean = phr->GetMean();
457  }
458  }
459  adcmax = phr->GetBinCenter(rbinmax);
460  // Make sure the peak bin stays in range.
461  if ( abs(adcmax-radcmax1) > 0.45*wadc ) adcmax = radcmax1;
462  adc1 = adcmax - 0.5*wadc;
463  adc1 = 10*int(adc1/10);
464  if ( adcmean > adcmax + 10) adc1 += 10;
465  adc2 = adc1 + wadc;
466  if ( radcmax1 < adc1 || radcmax1+1.0 > adc2 ) {
467  cout << myname << "WARNING: Histogram range (" << adc1 << ", " << adc2
468  << ") does not include peak at " << radcmax1 << "." << endl;
469  }
470  }
471  delete phr;
472  TH1* phf = new TH1F(hname.c_str(), htitl.c_str(), wadc, adc1, adc2);
473  phf->SetDirectory(0);
474  //phf->Sumw2();
475  Index countLo = 0;
476  Index countHi = 0;
477  Index count = 0;
478  IndexVector fcounts(wadc, 0);
479  for ( Index isam=0; isam<nsam; ++isam ) {
480  AdcIndex val = acd.raw[isam];
481  ++count;
482  if ( val < adc1 ) {
483  ++countLo;
484  } else if ( val >= adc2 ) {
485  ++countHi;
486  } else {
487  if ( keep[isam] ) ++fcounts[val-adc1];
488  }
489  }
490  for ( Index iadc=0; iadc<wadc; ++iadc ) {
491  phf->SetBinContent(iadc+1, fcounts[iadc]);
492  //float err = sqrt(fcounts[iadc]);
493  //if ( err <= 0.0 ) err = 1.0;
494  //phf->SetBinError(iadc+1, err);
495  }
496  float fracLo = count > 0 ? float(countLo)/count : 0.0;
497  float fracHi = count > 0 ? float(countHi)/count : 0.0;
498  phf->SetStats(0);
499  phf->SetLineWidth(2);
500  // Fetch the peak bin and suppress it for the fit if more than 20% (but not
501  // all) the data is in it.
502  // May 2021: We expect the peak bin to hold 20% of the samples if the RMS is near
503  // or below 2.0. Don't drop bin for low RMS and log a warning if bin is dropped
504  // and fit sigm < 2.5.
505  int binmax = phf->GetMaximumBin();
506  double valmax = phf->GetBinContent(binmax);
507  float peakFrac = valmax/phf->Integral();
508  double xcomax = phf->GetBinLowEdge(binmax);
509  double rangeIntegral = phf->Integral(1, phf->GetNbinsX());
510  double peakBinFraction = (rangeIntegral > 0) ? valmax/rangeIntegral : 1.0;
511  bool allBin = peakBinFraction > 0.99;
512  float rawRms = phf->GetRMS();
513  bool isNarrow = rawRms < 2.5;
514  bool dropBin = m_RemoveStickyCode && peakFrac > 0.2 && !allBin && !isNarrow;
515  int nbinsRemoved = 0;
516  if ( dropBin ) {
517  double tmpval = 0.5*(phf->GetBinContent(binmax-1)+phf->GetBinContent(binmax+1));
518  phf->SetBinContent(binmax, tmpval);
519  rangeIntegral = phf->Integral(1, phf->GetNbinsX());
520  ++nbinsRemoved;
521  }
522  double amean = phf->GetMean() + 0.5;
523  double arms = phf->GetRMS();
524  double fitRmsMin = m_tfs.at("FitRmsMin")->eval();
525  double fitRmsMax = m_tfs.at("FitRmsMax")->eval();
526  double ameanWin = fitRmsMax > fitRmsMin ? fitRmsMax : 0.0;
527  bool doFit = peakBinFraction < 0.99 && m_fitOpts.size() > 0;
528  float pedestal = phf->GetMean();
529  //float pedestalRms = 1.0/sqrt(12.0);
530  float pedestalRms = arms;
531  if ( fitRmsMax > fitRmsMin ) {
532  if ( arms < fitRmsMin ) arms = fitRmsMin;
533  if ( arms > fitRmsMax ) arms = fitRmsMax;
534  }
535  float fitChiSquare = 0.0;
536  float fitReducedChiSquare = 0.0;
537  float peakBinExcess = 0.0;
538  if ( doFit ) {
539  // Block Root info message for new Canvas produced in fit.
540  int levelSave = gErrorIgnoreLevel;
541  gErrorIgnoreLevel = 1001;
542  gErrorIgnoreLevel = 2001; // Block warning in Fit
543  // Block non-default (e.g. art) from handling the Root "error".
544  // We switch to the Root default handler while making the call to Print.
545  ErrorHandlerFunc_t pehSave = nullptr;
546  ErrorHandlerFunc_t pehDefault = DefaultErrorHandler;
547  //pehDefault = handleRootError;
548  if ( GetErrorHandler() != pehDefault ) {
549  pehSave = SetErrorHandler(pehDefault);
550  }
551  // Set fit precision. Least-squares only?
552  float fprec = TFitter::GetPrecision();
553  if ( m_FitPrecision > 0.0 ) TFitter::SetPrecision(m_FitPrecision);
554  int fitStat = 99;
555  TF1* pfinit = nullptr;
556  //TF1 fitter("pedgaus", "gaus", adc1, adc2, TF1::EAddToList::kNo);
557  TF1& fitter = *state().pfitter;
558  for ( Name fopt : m_fitOpts ) {
559  fitter.SetParameters(0.1*rangeIntegral, amean, pedestalRms);
560  fitter.SetParLimits(0, 0.01*rangeIntegral, rangeIntegral);
561  if ( ameanWin > 0.0 ) fitter.SetParLimits(1, amean - ameanWin, amean + ameanWin);
562  if ( allBin ) fitter.FixParameter(1, amean); // Fix posn.
563  if ( fitRmsMin < fitRmsMax ) {
564  fitter.SetParLimits(2, fitRmsMin, fitRmsMax);
565  }
566  fitter.SetParError(0, 0.0);
567  if ( m_PlotShowFit >= 2 ) {
568  pfinit = dynamic_cast<TF1*>(fitter.Clone("pedgaus0"));
569  pfinit->SetLineColor(3);
570  pfinit->SetLineStyle(2);
571  }
572  if ( m_LogLevel < 3 ) fopt += "Q";
573  // Root calls error handler but returns 0 if the histo has no data in range
574  // so we check that before calling fitter.
575  fitStat = (phf->Integral() == 0.0) ? 999 : int(phf->Fit(&fitter, fopt.c_str(), "", adc1, adc2));
576  //fopt += " S"; // So we can retrieve fit status
577  //TFitResultPtr pfres = phf->Fit(&fitter, fopt.c_str());
578  //bool haveFitStatus = pfres.Get();
579  //int fitStat = haveFitStatus ? pfres->Status() : 999;
580  if ( fitStat == 0 ) break;
581  }
582  if ( m_FitPrecision > 0.0 ) TFitter::SetPrecision(fprec);
583  if ( pehSave != nullptr ) SetErrorHandler(pehSave);
584  gErrorIgnoreLevel = levelSave;
585  if ( pfinit != nullptr ) {
586  phf->GetListOfFunctions()->AddLast(pfinit, "0");
587  phf->GetListOfFunctions()->Last()->SetBit(TF1::kNotDraw, true);
588  }
589  if ( fitStat ) {
590  Index istat = acd.channelStatus();
591  string sstat = istat == 0 ? "good" : istat == 1 ? "bad" : istat == 2 ? "noisy" : "unknown";
592  cout << myname << "WARNING: Fit status is " << fitStat << " for " << sstat << " channel "
593  << acd.channel() << endl;
594  cout << myname << " Errors[0]: " << fitter.GetParErrors()[0] << endl;
595  //cout << myname << " radcmax1 = " << radcmax1 << endl;
596  //cout << myname << " radcmean = " << radcmean << endl;
597  //cout << myname << " adcmean = " << adcmean << endl;
598  cout << myname << " adcmax = " << adcmax << endl;
599  //cout << myname << " rbinmax1,2: " << rbinmax1 << ", " << rbinmax2 << endl;
600  cout << myname << " peakBinFraction = " << valmax << "/" << rangeIntegral
601  << " = " << peakBinFraction << endl;
602  cout << myname << " allBin = " << allBin << endl;
603  cout << myname << " dropBin = " << dropBin << endl;
604  cout << myname << " amean = " << amean << " +/- " << ameanWin << endl;
605  } else {
606  double valEval = fitter.Eval(xcomax);
607  peakBinExcess = (valmax - valEval)/rangeIntegral;
608  pedestal = fitter.GetParameter(1) - 0.5;
609  pedestalRms = fitter.GetParameter(2);
610  // Chi-square from the fitter.
611  fitChiSquare = fitter.GetChisquare();
612  // Estimate of chi-square/DOF
613  float ibin1 = int(pedestal - 3.0*pedestalRms) - adc1;
614  if ( ibin1 < 1 ) ibin1 = 1;
615  float ibin2 = int(pedestal + 3.0*pedestalRms + 2.0) - adc1;
616  if ( ibin2 > wadc ) ibin2 = wadc;
617  int nbin = 0;
618  double sumsq = 0.0;
619  for ( int ibin=ibin1; ibin<=ibin2; ++ibin ) {
620  float xfun = adc1 + ibin - 0.5;
621  float yfun = fitter.Eval(xfun);
622  if ( yfun < 1.0 ) continue;
623  float yhst = phf->GetBinContent(ibin);
624  float dely = yhst - yfun;
625  float vary = yfun > 1.0 ? yfun : 1.0;
626  sumsq += dely*dely/vary;
627  ++nbin;
628  }
629  float estndof = nbin > 4 ? nbin - 3 : 1;
630  fitReducedChiSquare = sumsq/estndof;
631  // Warn if bin was dropped for a too-narrow distribution.
632  if ( dropBin && pedestalRms < 2.5 ) {
633  int precSave = cout.precision();
634  cout.precision(2);
635  cout << myname << "WARNING: Bin was dropped for channel " << acd.channel()
636  << " with fit sigma=" << fixed << pedestalRms
637  << ", raw RMS=" << fixed << rawRms
638  << " and peak fraction=" << fixed << peakFrac << endl;
639  cout.precision(precSave);
640  }
641  }
642  }
643  if ( dropBin ) phf->SetBinContent(binmax, valmax);
644  res.setHist("pedestal", phf, true);
645  res.setFloat("fitFractionLow", fracLo);
646  res.setFloat("fitFractionHigh", fracHi);
647  res.setFloat("fitPedestal", pedestal);
648  res.setFloat("fitPedestalRms", pedestalRms);
649  res.setFloat("fitChiSquare", fitChiSquare);
650  res.setFloat("fitPeakBinFraction", peakBinFraction);
651  res.setFloat("fitPeakBinExcess", peakBinExcess);
652  res.setFloat("fitChiSquare", fitChiSquare);
653  res.setFloat("fitReducedChiSquare", fitReducedChiSquare);
654  res.setInt("fitChannel", acd.channel());
655  res.setInt("fitNSkip", nskip);
656  res.setInt("fitNBinsRemoved", nbinsRemoved);
657  string rfname = nameReplace(m_RootFileName, acd, false);
658  if ( rfname.size() ) {
659  if ( m_LogLevel >=2 ) cout << myname << "Write histogram " << phf->GetName() << " to " << rfname << endl;
660  TFile* pf = TFile::Open(rfname.c_str(), "UPDATE");
661  TH1* phfCopy = (TH1*) phf->Clone();
662  phfCopy->GetListOfFunctions()->Clear();
663  phfCopy->Write();
664  delete pf;
665  }
666  if ( m_LogLevel >= 3 ) cout << myname << "Exiting..." << endl;
667  return res;
668 }
669 
670 //**********************************************************************
671 
673  if ( pman == nullptr ) return 1;
674  TH1* phf = dm.getHist("pedestal");
675  pman->add(phf, "hist");
676  if ( m_PlotShowFit > 1 ) pman->addHistFun(1);
677  if ( m_PlotShowFit ) pman->addHistFun(0);
678  pman->addVerticalModLines(64);
679  pman->showUnderflow();
680  pman->showOverflow();
681  pman->addAxis();
682  Index istat = acd.channelStatus();
683  string sstat = istat == 0 ? "Good" : istat == 1 ? "Bad" : istat == 2 ? "Noisy" : "No-status";
684  NameVector slabs(3);
685  slabs[0] = sstat + " channel";
686  slabs[1] = "# skipped bins: " + std::to_string(dm.getInt("fitNSkip"));
687  slabs[2] = "# dropped bins: " + std::to_string(dm.getInt("fitNBinsRemoved"));
688  float xlab = 0.13;
689  float ylab = 0.86;
690  float dylab = 0.06;
691  for ( Name slab : slabs ) {
692  TLatex* ptxt = new TLatex(xlab, ylab, slab.c_str());
693  ptxt->SetNDC();
694  ptxt->SetTextFont(42);
695  pman->add(ptxt);
696  ylab -= dylab;
697  }
698  slabs.clear();
699  ostringstream sslab;
700  sslab << "Pedestal: " << std::fixed << std::setprecision(1) << dm.getFloat("fitPedestal");
701  slabs.push_back(sslab.str());
702  sslab.str("");
703  sslab << "Ped RMS: " << std::fixed << std::setprecision(1) << dm.getFloat("fitPedestalRms");
704  slabs.push_back(sslab.str());
705  sslab.str("");
706  //sslab << "Fit #chi^{2}: " << std::fixed << std::setprecision(1) << dm.getFloat("fitChiSquare");
707  //slabs.push_back(sslab.str());
708  //sslab.str("");
709  sslab << "#chi^{2}/DOF: " << std::fixed << std::setprecision(1) << dm.getFloat("fitReducedChiSquare");
710  slabs.push_back(sslab.str());
711  sslab.str("");
712  float frac = dm.getFloat("fitFractionLow");
713  int prec = frac > 0 ? int(-log10(frac)) + 3 : 0;
714  sslab << "f_{lo}: " << std::fixed << std::setprecision(prec) << frac;
715  slabs.push_back(sslab.str());
716  sslab.str("");
717  frac = dm.getFloat("fitFractionHigh");
718  prec = frac > 0 ? int(-log10(frac)) + 3 : 0;
719  sslab << "f_{hi}: " << std::fixed << std::setprecision(prec) << frac;
720  slabs.push_back(sslab.str());
721  xlab = 0.94;
722  ylab = 0.86;
723  for ( Name slab : slabs ) {
724  TLatex* ptxt = new TLatex(xlab, ylab, slab.c_str());
725  ptxt->SetNDC();
726  ptxt->SetTextFont(42);
727  ptxt->SetTextAlign(31);
728  pman->add(ptxt);
729  ylab -= dylab;
730  }
731  return 0;
732 }
733 
734 //**********************************************************************
735 
static QCString name
Definition: declinfo.cpp:673
int fillChannelPad(DataMap &dm, const AdcChannelData &acd, TPadManipulator *pman) const
const DuneEventInfo & getEventInfo() const
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
void setFloat(Name name, float val)
Definition: DataMap.h:133
void msg(const char *fmt,...)
Definition: message.cpp:107
void setGain(float val)
Definition: RunData.h:67
int add(unsigned int ipad, TObject *pobj, std::string sopt="", bool replace=false)
unsigned int Index
DataMap & setStatus(int stat)
Definition: DataMap.h:130
std::string string
Definition: nybbler.cc:12
DataMap beginEvent(const DuneEventInfo &) const override
DataMap updateMap(AdcChannelDataMap &acds) const override
DataMap update(AdcChannelData &acd) const override
std::set< string > NameSet
struct vector vector
int setCanvasSize(int wx, int wy)
void setHist(Name name, TH1 *ph, bool own=false)
Definition: DataMap.h:136
int split(Index nx, Index ny)
DataMap getPedestal(const AdcChannelData &acd) const
virtual Names unsetPars() const =0
unsigned int Index
std::vector< Name > NameVector
int showOverflow(bool show=true)
Q_EXPORT QTSManip setprecision(int p)
Definition: qtextstream.h:343
bool isValid() const
Definition: RunData.h:48
int status() const
Definition: DataMap.h:202
void setIntVector(Name name, const IntVector &val)
Definition: DataMap.h:132
Name nameReplace(Name name, const AdcChannelData &acd, bool isTitle) const
T abs(T value)
AdcSignal pedestalRms
int precision() const
Definition: qtextstream.h:259
static std::string build(const AdcChannelStringTool *ptool, const AdcChannelData &acd, const DataMap &dm, std::string spat)
DataMap view(const AdcChannelData &acd) const override
const AdcChannelStringTool * m_adcStringBuilder
int showUnderflow(bool show=true)
int addAxis(bool flag=true)
void setInt(Name name, int val)
Definition: DataMap.h:131
State & state() const
virtual RunData runData(Index run, Index subRun=0) const =0
static constexpr double ps
Definition: Units.h:99
AdcCountVector raw
AdcPedestalFitter(fhicl::ParameterSet const &ps)
TPadManipulator * man(unsigned int ipad=0)
std::vector< Index > IndexVector
unsigned int AdcIndex
Definition: AdcTypes.h:15
int addVerticalModLines(double xmod, double xoff=0.0, double lenfrac=1.0, int isty=3)
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
Float getFloat(Name name, Float def=0.0) const
Definition: DataMap.h:220
Index channelStatus() const
Channel channel() const
int addHistFun(unsigned int ifun=0)
AdcSignal pedestal
int getInt(Name name, int def=0) const
Definition: DataMap.h:218
virtual Names resetPars() const =0
virtual int unsetParValues()=0
virtual Name name() const
Definition: ParFormula.h:32
std::map< AdcChannel, AdcChannelData > AdcChannelDataMap
TH1 * getHist(Name name, TH1 *def=nullptr) const
Definition: DataMap.h:223
void setShaping(float val)
Definition: RunData.h:68
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
def rebin(a, args)
Definition: arrays.py:2
void setFloatVector(Name name, const FloatVector &val)
Definition: DataMap.h:134
SetStat setFormulaPars(TFormula *form)
Definition: RunData.h:87
int bool
Definition: qglobal.h:345
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
int print(std::string fname, std::string spat="{,}")
static DuneToolManager * instance(std::string fclname="", int dbg=1)
const RunDataTool * m_prdtool
T * getShared(std::string name)
QTextStream & endl(QTextStream &s)
AdcFlagVector flags