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();
const DuneEventInfo & getEventInfo() const
void setFloat(Name name, float val)
DataMap & setStatus(int stat)
DataMap beginEvent(const DuneEventInfo &) const override
ChannelGroupService::Name Name
void setHist(Name name, TH1 *ph, bool own=false)
Name nameReplace(Name name, const AdcChannelData &acd, bool isTitle) const
void setInt(Name name, int val)
Index channelStatus() const
QTextStream & endl(QTextStream &s)