13 #include "TDirectory.h" 19 #include "TFitResult.h" 28 using std::ostringstream;
49 acd.
metadata[
"fitPedReducedChiSquare"] = res.
getFloat(
"fitReducedChiSquare");
70 : m_LogLevel(ps.
get<
int>(
"LogLevel")),
71 m_AdcRange(ps.
get<
Name>(
"AdcRange")),
73 m_FitPrecision(ps.
get<
float>(
"FitPrecision")),
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")),
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")),
90 const string myname =
"AdcPedestalFitter::ctor: ";
92 string stringBuilder =
"adcStringBuilder";
95 cout << myname <<
"WARNING: AdcChannelStringTool not found: " << stringBuilder <<
endl;
101 Name foptLsq =
"WWB";
103 Name foptLik =
"LWB";
105 if (
m_LogLevel > 0 ) cout << myname <<
"Mean used in place of pedestal fit." <<
endl;
108 if (
m_LogLevel > 0 ) cout << myname <<
"Chi-square fit used for pedestal." <<
endl;
111 if (
m_LogLevel > 0 ) cout << myname <<
"Likelihood fit used for pedestal." <<
endl;
113 if (
m_LogLevel > 0 ) cout << myname <<
"Chi-square/likelihood fit used for pedestal." <<
endl;
117 cout <<
"WARNING: Invalid FitOpt: " <<
m_FitOpt <<
". Not fit will be performed." <<
endl;
126 for (
const auto& itf :
m_tfs ) {
130 string stnam =
"runDataTool";
133 cout << myname <<
"ERROR: RunDataTool " << stnam
134 <<
" not found. Formulas will not be evaluated." <<
endl;
136 cout << myname <<
"RunDataTool retrieved." <<
endl;
139 cout << myname <<
"No formula parameters. RunDataTool is not retrieved." <<
endl;
142 cout << myname <<
"Configuration parameters:" <<
endl;
147 cout << myname <<
" SkipFlags: [";
149 for (
Index flg : m_SkipFlags ) {
150 if ( first ) first =
false;
174 const string myname =
"AdcPedestalFitter::view: ";
183 if ( pman !=
nullptr ) {
185 if (
m_LogLevel >= 3 ) cout << myname <<
"Creating plot " << pfname <<
endl;
198 const string myname =
"AdcPedestalFitter::update: ";
200 if ( res.
status() != 0 )
return res;
204 copyMetadata(res, acd);
212 const string myname =
"AdcPedestalFitter::updateMap: ";
214 Index nPedFitGood = 0;
215 Index nPedFitFail = 0;
216 if (
m_LogLevel >= 2 ) cout << myname <<
"Fitting " << acds.size() <<
" channels." <<
endl;
227 cout << myname <<
"Pad count is " << npad <<
" (" << npady <<
" x " << npadx <<
")" <<
endl;
231 Index nacd = acds.size();
236 string plotFileName =
"";
237 for (
auto& acdPair : acds ) {
240 if (
m_LogLevel >= 3 ) cout << myname <<
" " << iacd <<
": Processing channel " << acd.
channel() <<
endl;
242 if ( npad > 0 && pmantop ==
nullptr ) {
243 if (
m_LogLevel >= 3 ) cout << myname <<
" Creating canvas." <<
endl;
246 if ( npad > 1 ) pmantop->
split(npady, npady);
249 Index ipad = npad == 0 ? 0 : iacd % npad;
253 fitStats[iacd] = tmpres.
status();
254 float fitPedestal = 0.0;
255 float fitPedestalRms = 0.0;
256 if ( tmpres.
status() == 0 ) {
258 fitPedestal = tmpres.
getFloat(
"fitPedestal");
259 fitPedestalRms = tmpres.
getFloat(
"fitPedestalRms");
260 copyMetadata(tmpres, acdMutable);
264 fitPedestals[iacd] = fitPedestal;
265 fitPedestalRmss[iacd] = fitPedestalRms;
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);
277 for (
auto& acdPair : acds ) {
284 cout << myname <<
" # good pedestal fits: " << nPedFitGood <<
endl;
285 cout << myname <<
" # fail pedestal fits: " << nPedFitFail <<
endl;
287 ret.
setInt(
"nPedFitGood", nPedFitGood);
288 ret.
setInt(
"nPedFitFail", nPedFitFail);
299 const string myname =
"AdcPedestalFitter::beginEvent: ";
304 cout << myname <<
"Setting run " << evi.
run <<
endl;
311 msg =
"WARNING: RunData tool not found. Using default parameters.";
315 if ( msg.size() == 0 && ! rdat.
isValid() ) {
316 msg =
"WARNING: RunData not found. Using default parameters.";
319 cout << myname << msg <<
endl;
323 for (
auto& itr :
m_tfs ) {
328 cout <<
"ERROR: Formula " << form.
name() <<
" has unset parameters: [";
331 if ( first ) first =
false;
338 cout <<
"WARNING: Formula " << form.
name() <<
" has reset parameters" <<
endl;
350 if ( pnbl ==
nullptr )
return name;
352 return pnbl->
build(acd, dm, name);
359 const string myname =
"AdcPedestalFitter::getPedestal: ";
366 if (
m_LogLevel >= 2 ) cout << myname <<
"WARNING: Raw data is empty." <<
endl;
372 cout << myname <<
"WARNING: Calling beginEvent to evaluate formulas." <<
endl;
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;
395 if (
m_LogLevel >= 2 ) cout << myname <<
"WARNING: No raw data is selected." <<
endl;
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);
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);
415 for (
Index isam=0; isam<nsam; ++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];
424 for (
Index ibin=0; ibin<nbin; ++ibin ) {
425 phr->SetBinContent(ibin+1, rcounts[ibin]);
427 double wadc =
m_tfs.at(
"AdcFitRange")->eval();
429 cout << myname <<
"INFO: Invalid fit range: " << wadc <<
" < 10 ADC counts" <<
endl;
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;
438 double radcmax1 = phr->GetBinCenter(rbinmax1);
439 double radcmean = phr->GetMean();
440 double radcsum1 = phr->Integral();
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();
449 double adcmean = radcmean;
450 int rbinmax = rbinmax1;
451 if ( radcsum2 > 0.01*radcsum1 ) {
454 if (
abs(rbinmax2-rbinmax1) > 1 ) {
455 rbinmax = (rbinmax1 + rbinmax2)/2;
456 adcmean = phr->GetMean();
459 adcmax = phr->GetBinCenter(rbinmax);
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;
466 if ( radcmax1 < adc1 || radcmax1+1.0 > adc2 ) {
467 cout << myname <<
"WARNING: Histogram range (" << adc1 <<
", " << adc2
468 <<
") does not include peak at " << radcmax1 <<
"." <<
endl;
472 TH1* phf =
new TH1F(hname.c_str(), htitl.c_str(), wadc, adc1, adc2);
473 phf->SetDirectory(0);
479 for (
Index isam=0; isam<nsam; ++isam ) {
484 }
else if ( val >= adc2 ) {
487 if ( keep[isam] ) ++fcounts[val-adc1];
490 for (
Index iadc=0; iadc<wadc; ++iadc ) {
491 phf->SetBinContent(iadc+1, fcounts[iadc]);
496 float fracLo = count > 0 ?
float(countLo)/count : 0.0;
497 float fracHi = count > 0 ?
float(countHi)/count : 0.0;
499 phf->SetLineWidth(2);
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;
515 int nbinsRemoved = 0;
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());
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();
530 float pedestalRms = arms;
531 if ( fitRmsMax > fitRmsMin ) {
532 if ( arms < fitRmsMin ) arms = fitRmsMin;
533 if ( arms > fitRmsMax ) arms = fitRmsMax;
535 float fitChiSquare = 0.0;
536 float fitReducedChiSquare = 0.0;
537 float peakBinExcess = 0.0;
545 ErrorHandlerFunc_t pehSave =
nullptr;
546 ErrorHandlerFunc_t pehDefault = DefaultErrorHandler;
548 if ( GetErrorHandler() != pehDefault ) {
549 pehSave = SetErrorHandler(pehDefault);
552 float fprec = TFitter::GetPrecision();
555 TF1* pfinit =
nullptr;
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);
563 if ( fitRmsMin < fitRmsMax ) {
564 fitter.SetParLimits(2, fitRmsMin, fitRmsMax);
566 fitter.SetParError(0, 0.0);
568 pfinit =
dynamic_cast<TF1*
>(fitter.Clone(
"pedgaus0"));
569 pfinit->SetLineColor(3);
570 pfinit->SetLineStyle(2);
575 fitStat = (phf->Integral() == 0.0) ? 999 :
int(phf->Fit(&fitter, fopt.c_str(),
"", adc1, adc2));
580 if ( fitStat == 0 )
break;
583 if ( pehSave !=
nullptr ) SetErrorHandler(pehSave);
585 if ( pfinit !=
nullptr ) {
586 phf->GetListOfFunctions()->AddLast(pfinit,
"0");
587 phf->GetListOfFunctions()->Last()->SetBit(TF1::kNotDraw,
true);
591 string sstat = istat == 0 ?
"good" : istat == 1 ?
"bad" : istat == 2 ?
"noisy" :
"unknown";
592 cout << myname <<
"WARNING: Fit status is " << fitStat <<
" for " << sstat <<
" channel " 594 cout << myname <<
" Errors[0]: " << fitter.GetParErrors()[0] <<
endl;
598 cout << myname <<
" adcmax = " << adcmax <<
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;
606 double valEval = fitter.Eval(xcomax);
607 peakBinExcess = (valmax - valEval)/rangeIntegral;
608 pedestal = fitter.GetParameter(1) - 0.5;
609 pedestalRms = fitter.GetParameter(2);
611 fitChiSquare = fitter.GetChisquare();
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;
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;
629 float estndof = nbin > 4 ? nbin - 3 : 1;
630 fitReducedChiSquare = sumsq/estndof;
632 if ( dropBin && pedestalRms < 2.5 ) {
633 int precSave = cout.precision();
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;
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);
655 res.
setInt(
"fitNSkip", nskip);
656 res.
setInt(
"fitNBinsRemoved", nbinsRemoved);
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();
673 if ( pman ==
nullptr )
return 1;
674 TH1* phf = dm.
getHist(
"pedestal");
675 pman->
add(phf,
"hist");
683 string sstat = istat == 0 ?
"Good" : istat == 1 ?
"Bad" : istat == 2 ?
"Noisy" :
"No-status";
685 slabs[0] = sstat +
" channel";
691 for (
Name slab : slabs ) {
692 TLatex* ptxt =
new TLatex(xlab, ylab, slab.c_str());
694 ptxt->SetTextFont(42);
701 slabs.push_back(sslab.str());
704 slabs.push_back(sslab.str());
710 slabs.push_back(sslab.str());
712 float frac = dm.
getFloat(
"fitFractionLow");
713 int prec = frac > 0 ?
int(-log10(frac)) + 3 : 0;
715 slabs.push_back(sslab.str());
717 frac = dm.
getFloat(
"fitFractionHigh");
718 prec = frac > 0 ?
int(-log10(frac)) + 3 : 0;
720 slabs.push_back(sslab.str());
723 for (
Name slab : slabs ) {
724 TLatex* ptxt =
new TLatex(xlab, ylab, slab.c_str());
726 ptxt->SetTextFont(42);
727 ptxt->SetTextAlign(31);
int fillChannelPad(DataMap &dm, const AdcChannelData &acd, TPadManipulator *pman) const
const DuneEventInfo & getEventInfo() const
void setFloat(Name name, float val)
void msg(const char *fmt,...)
int add(unsigned int ipad, TObject *pobj, std::string sopt="", bool replace=false)
DataMap & setStatus(int stat)
DataMap beginEvent(const DuneEventInfo &) const override
DataMap updateMap(AdcChannelDataMap &acds) const override
DataMap update(AdcChannelData &acd) const override
int setCanvasSize(int wx, int wy)
void setHist(Name name, TH1 *ph, bool own=false)
int split(Index nx, Index ny)
DataMap getPedestal(const AdcChannelData &acd) const
std::vector< Name > NameVector
int showOverflow(bool show=true)
Q_EXPORT QTSManip setprecision(int p)
void setIntVector(Name name, const IntVector &val)
Name nameReplace(Name name, const AdcChannelData &acd, bool isTitle) const
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)
static constexpr double ps
AdcPedestalFitter(fhicl::ParameterSet const &ps)
TPadManipulator * man(unsigned int ipad=0)
std::vector< Index > IndexVector
int addVerticalModLines(double xmod, double xoff=0.0, double lenfrac=1.0, int isty=3)
Q_EXPORT QTSManip setw(int w)
Float getFloat(Name name, Float def=0.0) const
Index channelStatus() const
int addHistFun(unsigned int ifun=0)
int getInt(Name name, int def=0) const
std::map< AdcChannel, AdcChannelData > AdcChannelDataMap
TH1 * getHist(Name name, TH1 *def=nullptr) const
void setShaping(float val)
auto const & get(AssnsNode< L, R, D > const &r)
void setFloatVector(Name name, const FloatVector &val)
SetStat setFormulaPars(TFormula *form)
std::string to_string(ModuleType const mt)
int print(std::string fname, std::string spat="{,}")
const RunDataTool * m_prdtool
QTextStream & endl(QTextStream &s)