8#include "TFitResultPtr.h"
9#include "TVirtualFitter.h"
24template<
typename T> T
Sqr(T in) {
return in*in;}
34 {
"tag", {JSON::value_t::string, 1,
true,
true}},
35 {
"enabled", {JSON::value_t::boolean, 1,
true,
true}},
36 {
"LGMode", {JSON::value_t::number_unsigned, 1,
false,
true}},
37 {
"Nsample", {JSON::value_t::number_integer, 1,
false,
true}},
38 {
"FADCFreqMHz", {JSON::value_t::number_integer, 1,
false,
true}},
39 {
"preSampleIdx", {JSON::value_t::number_integer, 1,
true,
true}},
40 {
"nominalPedestal", {JSON::value_t::number_integer, 1,
false,
true}},
41 {
"fitFunction", {JSON::value_t::string, 1,
true,
true}},
42 {
"fitParameterSet", {JSON::value_t::string, 1,
false,
false}},
43 {
"peakSample", {JSON::value_t::number_integer, 1,
true,
true}},
44 {
"peakTolerance", {JSON::value_t::number_integer, 1,
true,
false}},
45 {
"quietFits", {JSON::value_t::boolean, 1,
false,
false}},
46 {
"2ndDerivThreshHG", {JSON::value_t::number_integer, 1,
true,
true}},
47 {
"2ndDerivThreshLG", {JSON::value_t::number_integer, 1,
true,
true}},
48 {
"2ndDerivStep", {JSON::value_t::number_integer, 1,
false,
false}},
49 {
"HGOverflowADC", {JSON::value_t::number_integer, 1,
true,
true}},
50 {
"HGUnderflowADC", {JSON::value_t::number_integer, 1,
true,
true}},
51 {
"LGOverflowADC", {JSON::value_t::number_integer, 1,
true,
true}},
52 {
"nominalT0HG", {JSON::value_t::number_float, 1,
true,
true}},
53 {
"nominalT0LG", {JSON::value_t::number_float, 1,
true,
true}},
54 {
"nominalTau1", {JSON::value_t::number_float, 1,
true,
false}},
55 {
"nominalTau2", {JSON::value_t::number_float, 1,
true,
false}},
56 {
"fixTau1", {JSON::value_t::boolean, 1,
true,
false}},
57 {
"fixTau2", {JSON::value_t::boolean, 1,
true,
false}},
58 {
"nominalTau1HG", {JSON::value_t::number_float, 1,
true,
false}},
59 {
"nominalTau2HG", {JSON::value_t::number_float, 1,
true,
false}},
60 {
"fixTau1HG", {JSON::value_t::boolean, 1,
true,
false}},
61 {
"fixTau2HG", {JSON::value_t::boolean, 1,
true,
false}},
62 {
"nominalTau1LG", {JSON::value_t::number_float, 1,
true,
false}},
63 {
"nominalTau2LG", {JSON::value_t::number_float, 1,
true,
false}},
64 {
"fixTau1LG", {JSON::value_t::boolean, 1,
true,
false}},
65 {
"fixTau2LG", {JSON::value_t::boolean, 1,
true,
false}},
66 {
"T0CutsHG", {JSON::value_t::array, 2,
true,
true}},
67 {
"T0CutsLG", {JSON::value_t::array, 2,
true,
true}},
68 {
"chisqDivAmpCutHG", {JSON::value_t::number_float, 1,
true,
true}},
69 {
"chisqDivAmpCutLG", {JSON::value_t::number_float, 1,
true,
true}},
70 {
"chisqDivAmpScaleHG", {JSON::value_t::number_float, 1,
true,
true}},
71 {
"chisqDivAmpScaleLG", {JSON::value_t::number_float, 1,
true,
true}},
72 {
"chisqDivAmpOffsetHG", {JSON::value_t::number_float, 1,
true,
true}},
73 {
"chisqDivAmpOffsetLG", {JSON::value_t::number_float, 1,
true,
true}},
74 {
"chisqDivAmpPowerHG", {JSON::value_t::number_float, 1,
true,
true}},
75 {
"chisqDivAmpPowerLG", {JSON::value_t::number_float, 1,
true,
true}},
76 {
"gainFactorHG", {JSON::value_t::number_float, 1,
true,
true}},
77 {
"gainFactorLG", {JSON::value_t::number_float, 1,
true,
true}},
78 {
"noiseSigmaHG", {JSON::value_t::number_float, 1,
true,
true}},
79 {
"noiseSigmaLG", {JSON::value_t::number_float, 1,
true,
true}},
80 {
"perSampleNoiseSigmaHG", {JSON::value_t::array, -1,
true,
true}},
81 {
"perSampleNoiseSigmaLG", {JSON::value_t::array, -1,
true,
true}},
82 {
"enableRepass", {JSON::value_t::boolean, 1,
false,
false}},
83 {
"Repass2ndDerivThreshHG", {JSON::value_t::number_integer, 1,
true,
true}},
84 {
"Repass2ndDerivThreshLG", {JSON::value_t::number_integer, 1,
true,
true}},
85 {
"fitAmpMinMaxHG", {JSON::value_t::array, 2,
true,
false}},
86 {
"fitAmpMinMaxLG", {JSON::value_t::array, 2,
true,
false}},
87 {
"ampMinSignifHGLG", {JSON::value_t::array, 2,
true,
false}},
88 {
"enablePreExclusion", {JSON::value_t::array, 3,
false,
false}},
89 {
"enablePostExclusion", {JSON::value_t::array, 3,
false,
false}},
90 {
"enableUnderflowExclusionHG", {JSON::value_t::array, 2,
true,
false}},
91 {
"enableUnderflowExclusionLG", {JSON::value_t::array, 2,
true,
false}},
92 {
"enablePrePulseDetection", {JSON::value_t::boolean, 1,
false,
false}},
93 {
"enablePostPulseDetection", {JSON::value_t::boolean, 1,
false,
false}},
94 {
"enableTimingCorrection", {JSON::value_t::array, 3,
false,
false}},
95 {
"timeCorrCoeffHG", {JSON::value_t::array, 6,
true,
false}},
96 {
"timeCorrCoeffLG", {JSON::value_t::array, 6,
true,
false}},
97 {
"enableADCNLCorrection", {JSON::value_t::array, 3,
false,
false}},
98 {
"ADCNLCorrCoeffs", {JSON::value_t::array, 0,
true,
false}},
99 {
"enableNLCorrection", {JSON::value_t::array, 2,
false,
false}},
100 {
"HGNLCorrCoeffs", {JSON::value_t::array, 5,
true,
false}},
101 {
"LGNLCorrCoeffs", {JSON::value_t::array, 5,
true,
false}},
102 {
"useDelayed", {JSON::value_t::boolean, 1,
false,
false}},
103 {
"delayDeltaT", {JSON::value_t::number_float, 1,
true,
false}},
104 {
"delayDefaultPedestalShift", {JSON::value_t::number_float, 1,
true,
false}},
105 {
"fitTimeMax", {JSON::value_t::number_float, 1,
true,
false}}
126 double chiSquare = 0;
128 float delayBaselineAdjust = par[0];
132 for (
int isample = 0; isample < nSamples; isample++) {
142 double pull = (histValue - funcVal) / histError;
145 chiSquare += pull * pull;
150 for (
int isample = 0; isample < nSamples; isample++) {
152 double histError = std::max(
s_delayedFitHist->GetBinError(isample + 1), 1.0);
159 double pull = (histValue - funcVal) / histError;
162 chiSquare += pull * pull;
170 const std::string& fitFunction,
int peak2ndDerivMinSample,
171 float peak2ndDerivMinThreshHG,
float peak2ndDerivMinThreshLG) :
183 m_tmin = -deltaTSample / 2;
188 std::string histName =
"ZDCFitHist" + tag;
189 std::string histNameLGRefit =
"ZDCFitHist" + tag +
"_LGRefit";
210 (*m_msgFunc_p)(
ZDCMsg::Debug,
"ConfigFromJSON produced result: "+ resultString2);
221 std::string histName =
"ZDCFitHist" +
m_tag;
222 std::string histNameLGRefit =
"ZDCFitHist" +
m_tag +
"_LGRefit";
247 std::string delayedHGName = std::string(
m_fitHist->GetName()) +
"delayed";
248 std::string delayedLGName = std::string(
m_fitHistLGRefit->GetName()) +
"delayed";
565 std::ostringstream ostrm;
566 ostrm <<
"ZDCPulseAnalyzer::SetTauT0Values:: fixTau1 = " << fixTau1 <<
", fixTau2 = " << fixTau2 <<
", nominalTau1 = "
577 (*m_msgFunc_p)(
ZDCMsg::Error, (
"ZDCPulseAnalyzer::SetFitTimeMax:: invalid FitTimeMax: " + std::to_string(tmax)));
594 float deltaT0MinHG,
float deltaT0MaxHG,
595 float deltaT0MinLG,
float deltaT0MaxLG)
617 float deltaT0MinLG,
float deltaT0MaxLG)
627 float chisqDivAmpCutLG,
float chisqDivAmpScaleLG,
float chisqDivAmpOffsetLG,
float chisqDivAmpPowerLG)
641 const std::vector<double>& parsHG,
642 const std::vector<double>& parsLG)
649 std::string timeResHGName =
"TimeResFuncHG_" +
m_tag;
650 std::string timeResLGName =
"TimeResFuncLG_" +
m_tag;
652 TF1* funcHG_p =
new TF1(timeResHGName.c_str(), TF1String.c_str(), 0,
m_HGOverflowADC);
653 TF1* funcLG_p =
new TF1(timeResLGName.c_str(), TF1String.c_str(), 0,
m_LGOverflowADC);
655 if (parsHG.size() !=
static_cast<unsigned int>(funcHG_p->GetNpar()) ||
656 parsLG.size() !=
static_cast<unsigned int>(funcLG_p->GetNpar())) {
661 funcHG_p->SetParameters(&parsHG[0]);
662 funcLG_p->SetParameters(&parsLG[0]);
676 auto getXmin=[](
const TH1 * pH){
677 return pH->GetXaxis()->GetXmin();
679 auto getXmax=[](
const TH1 * pH){
680 return pH->GetXaxis()->GetXmax();
682 auto xmin= getXmin(correHistHG.get());
683 auto xmax= getXmax(correHistHG.get());
684 if (std::abs(
xmin+0.5) > 1e-3 || std::abs(
xmax - 4095.5) > 1e-3) {
685 (*m_msgFunc_p)(
ZDCMsg::Error,
"ZDCPulseAnalyzer::enableFADCCorrections:: invalid high gain correction histogram range: xmin, xmax = " +
686 std::to_string(
xmin ) +
", " + std::to_string(
xmax) );
691 xmin= getXmin(correHistLG.get());
692 xmax= getXmax(correHistLG.get());
693 if (std::abs(
xmin+0.5) > 1e-3 ||
694 std::abs(
xmax - 4095.5) > 1e-3) {
695 (*m_msgFunc_p)(
ZDCMsg::Error,
"ZDCPulseAnalyzer::enableFADCCorrections:: invalid low gain correction histogram range: xmin, xmax = " +
696 std::to_string(
xmin) +
", " + std::to_string(
xmax) );
722 std::vector<float> pulls(
m_Nsample, -100);
725 const TF1* fit_p =
static_cast<const TF1*
>(dataHist_p->GetListOfFunctions()->Last());
727 for (
size_t ibin = 0; ibin <
m_Nsample ; ibin++) {
728 float t = dataHist_p->GetBinCenter(ibin + 1);
729 float fitVal = fit_p->Eval(t);
730 float histVal = dataHist_p->GetBinContent(ibin + 1);
731 float histErr = dataHist_p->GetBinError(ibin + 1);
732 float pull = (histVal - fitVal)/histErr;
742 double amplCorrFactor = 1;
748 amplCorrFactor *= fadcCorr;
760 float invNLCorr = 1.0;
774 amplCorrFactor /= invNLCorr;
777 return amplCorrFactor;
782 float prePulseTMin = 0;
785 std::string tagHG =
m_tag +
"HG";
786 std::string tagLG =
m_tag +
"LG";
928 (*m_msgFunc_p)(
ZDCMsg::Fatal,
"ZDCPulseAnalyzer::LoadAndAnalyzeData:: Wrong LoadAndAnalyzeData called -- expecting both delayed and undelayed samples");
952 const std::vector<float>& ADCSamplesHGDelayed,
const std::vector<float>& ADCSamplesLGDelayed)
955 (*m_msgFunc_p)(
ZDCMsg::Fatal,
"ZDCPulseAnalyzer::LoadAndAnalyzeData:: Wrong LoadAndAnalyzeData called -- expecting only undelayed samples");
982 for (
size_t isample = 0; isample <
m_Nsample; isample++) {
983 float ADCHG = ADCSamplesHG[isample];
984 float ADCLG = ADCSamplesLG[isample];
1025 bool doDump = (*m_msgFunc_p)(
ZDCMsg::Verbose,
"Dumping all samples before subtraction: ");
1027 std::ostringstream dumpStringHG;
1028 dumpStringHG <<
"HG: ";
1030 dumpStringHG << std::setw(4) << val <<
" ";
1038 std::ostringstream dumpStringLG;
1039 dumpStringLG <<
"LG: " << std::setw(4) << std::setfill(
' ');
1041 dumpStringLG << std::setw(4) << val <<
" ";
1055 for (
size_t isample = 0; isample <
m_NSamplesAna; isample++) {
1230 float deriv2ndThreshHG = 0;
1231 float deriv2ndThreshLG = 0;
1252 (
float chisq,
float amp,
unsigned int fitNDoF,
float& ratio)->
bool
1256 if (amp < 1e-6)
return true;
1257 ratio = chisq /(offset + scale* (std::pow(amp/1000, power)));
1258 if (chisq/fitNDoF > 2 && ratio > cut)
return false;
1301 (
float chisq,
float amp,
unsigned int fitNDoF,
float& ratio)->
bool
1305 if (amp < 1e-6)
return true;
1306 ratio = chisq /(offset + scale*(std::pow(amp/1000, power)));
1307 if (chisq/
float(fitNDoF) > 2 && ratio > cut)
return false;
1360 const std::vector<float>& samples,
1361 const std::vector<float>& samplesNoise,
1362 const std::vector<bool>& useSample,
1363 float peak2ndDerivMinThresh,
1364 const std::vector<float>& t0CorrParams,
1366 float minT0Corr,
float maxT0Corr
1379 bool haveFirst =
false;
1380 unsigned int lastUsed = 0;
1382 for (
unsigned int sample = preSampleIdx; sample < nSamples; sample++) {
1383 if (useSample[sample]) {
1439 std::ostringstream baselineMsg;
1440 baselineMsg <<
"Delayed samples baseline correction = " <<
m_baselineCorr << std::endl;
1446 for (
size_t isample = 0; isample < nSamples; isample++) {
1492 if ((deltaLeft2 > 0 || deltaLeft > 0) && (deltaRight2 > 0 || deltaRight > 0)) {
1509 if ((deltaLeft2 > 0 || deltaLeft > 0) && (deltaRight2 > 0 || deltaRight > 0)) {
1561 if (derivPresampleSig < -5) {
1567 if (!useSample[isample])
continue;
1586 float maxPrepulseSig = 0;
1587 unsigned int maxPrepulseSample = 0;
1589 for (
int isample = loopStart; isample <= loopLimit; isample++) {
1590 if (!useSample[isample])
continue;
1604 if (prePulseSig > maxPrepulseSig) {
1605 maxPrepulseSig = prePulseSig;
1606 maxPrepulseSample = isample;
1637 if (!useSample[isample] || !useSample[isample +1])
continue;
1655 std::ostringstream
msg;
1656 msg <<
"ZDCPulseAnalyzer for " <<
m_tag <<
" Found a post pulse at sample " << isample
1657 <<
" deriv = " << deriv <<
", derivErr = " << derivErr
1658 <<
" deriv2nd = " << deriv2nd <<
", deriv2ndErr = " << deriv2nd;
1682 std::ostringstream ostrm;
1699 float correction = 0;
1701 for (
unsigned int ipow = 0; ipow < t0CorrParams.size(); ipow++) {
1702 correction += t0CorrParams[ipow]*std::pow(t0CorrFact,
double(ipow));
1720 double timeResolution = 0;
1732 if (failFixedCut)
m_badT0 =
true;
1752 const std::vector<bool>& useSamples)
1761 for (
unsigned int idx = 0; idx < samplesLG.size(); idx++) {
1764 if (useSamples[idx]) {
1778 TH1* hist_p =
nullptr;
1783 float ampInitial, fitAmpMin, fitAmpMax, t0Initial;
1804 if (ampInitial < fitAmpMin) ampInitial = fitAmpMin * 1.5;
1811 fitWrapper = preExpfitWrapper;
1816 fitWrapper = preFitWrapper;
1831 fitWrapper->
Initialize(ampInitial, t0Initial, fitAmpMin, fitAmpMax);
1850 int fitStatus = result_ptr;
1856 if (fitStatus != 0 && result_ptr->Edm() > 0.001)
1866 if ((
int) constrFitResult_ptr != 0) {
1876 if ((
int) unconstrFitResult_ptr != 0) {
1883 if ((
int) constrFit2Result_ptr != 0) {
1890 result_ptr = constrFit2Result_ptr;
1894 result_ptr = unconstrFitResult_ptr;
1904 hist_p->GetListOfFunctions()->Clear();
1907 std::string name = func->GetName();
1909 TF1* copyFunc =
static_cast<TF1*
>(func->Clone((name +
"_copy").c_str()));
1910 hist_p->GetListOfFunctions()->Add(copyFunc);
1954 for (
size_t ipar = 0; ipar < numPars; ipar++) {
1973 TH1* hist_p =
nullptr, *delayedHist_p =
nullptr;
1985 float fitAmpMin, fitAmpMax, t0Initial, ampInitial;
2001 if (ampInitial < fitAmpMin) ampInitial = fitAmpMin * 1.5;
2026 fitWrapper->
Initialize(ampInitial, t0Initial, fitAmpMin, fitAmpMax);
2031 TFitter* theFitter =
nullptr;
2055 size_t numFitPar = theFitter->GetNumberTotalParameters();
2057 theFitter->GetMinuit()->fISW[4] = -1;
2062 theFitter->GetMinuit()->fISW[4] = -1;
2065 theFitter->GetMinuit()->mnexcm(
"SET NOWarnings",
nullptr,0,ierr);
2067 else theFitter->GetMinuit()->fISW[4] = 0;
2072 theFitter->SetParameter(0,
"delayBaselineAdjust", 0, 0.01, -100, 100);
2073 theFitter->ReleaseParameter(0);
2076 theFitter->SetParameter(0,
"delayBaselineAdjust", 0, 0.01, -100, 100);
2077 theFitter->FixParameter(0);
2081 double arglist[100];
2084 int status = theFitter->ExecuteCommand(
"MIGRAD", arglist, 2);
2086 double fitAmp = theFitter->GetParameter(1);
2090 double chi2, edm, errdef;
2093 theFitter->GetStats(
chi2, edm, errdef, nvpar, nparx);
2098 if (status || fitAmp < fitAmpMin * 1.01 || edm > 0.01){
2103 theFitter->SetParameter(0,
"delayBaselineAdjust", 0, 0.01, -100, 100);
2104 theFitter->FixParameter(0);
2108 if (fitAmp < fitAmpMin * 1.01) {
2114 fitWrapper->
Initialize(ampInitial, t0Initial, fitAmpMin, fitAmpMax);
2118 status = theFitter->ExecuteCommand(
"MIGRAD", arglist, 2);
2123 theFitter->ReleaseParameter(0);
2131 theFitter->ReleaseParameter(0);
2132 status = theFitter->ExecuteCommand(
"MIGRAD", arglist, 2);
2137 theFitter->SetParameter(0,
"delayBaselineAdjust", 0, 0.01, -100, 100);
2138 theFitter->FixParameter(0);
2139 status = theFitter->ExecuteCommand(
"MIGRAD", arglist, 2);
2147 fitAmp = theFitter->GetParameter(1);
2151 if (fitAmp < fitAmpMin * 1.01) {
2162 if (!
m_quietFits) theFitter->GetMinuit()->fISW[4] = -1;
2164 std::vector<double> funcParams(numFitPar - 1);
2165 std::vector<double> funcParamErrs(numFitPar - 1);
2173 for (
size_t ipar = 1; ipar < numFitPar; ipar++) {
2174 funcParams[ipar - 1] = theFitter->GetParameter(ipar);
2175 funcParamErrs[ipar - 1] = theFitter->GetParError(ipar);
2183 theFitter->GetStats(
chi2, edm, errdef, nvpar, nparx);
2203 theFitter->ExecuteCommand(
"Cal1fcn", arglist, 1);
2238 for (
size_t ipar = 0; ipar < numPars; ipar++) {
2256 for (
int ipar = 0; ipar < func->GetNpar(); ipar++) {
2257 double parLimitLow, parLimitHigh;
2259 func->GetParLimits(ipar, parLimitLow, parLimitHigh);
2262 "ZDCPulseAnalyzer name=" + std::string(func->GetName())
2263 +
" ipar=" + std::to_string(ipar)
2264 +
" parLimitLow=" + std::to_string(parLimitLow)
2265 +
" parLimitHigh="+ std::to_string(parLimitHigh)
2269 if (std::abs(parLimitHigh - parLimitLow) > (1e-6)*std::abs(parLimitLow)) {
2270 double value = func->GetParameter(ipar);
2271 if (value >= parLimitHigh) {
2272 value = parLimitHigh * 0.9;
2274 else if (value <= parLimitLow) {
2275 value = parLimitLow + 0.1*std::abs(parLimitLow);
2277 func->SetParameter(ipar, value);
2284 TVirtualFitter::SetDefaultFitter(
"Minuit");
2286 size_t nFitParams = func->GetNpar() + 1;
2287 std::unique_ptr<TFitter> fitter = std::make_unique<TFitter>(nFitParams);
2289 fitter->GetMinuit()->fISW[4] = -1;
2290 fitter->SetParameter(0,
"delayBaselineAdjust", 0, 0.01, -100, 100);
2292 for (
size_t ipar = 0; ipar < nFitParams - 1; ipar++) {
2293 double parLimitLow, parLimitHigh;
2295 func->GetParLimits(ipar, parLimitLow, parLimitHigh);
2296 if (std::abs(parLimitHigh - parLimitLow) < (1e-6)*std::abs(parLimitLow)) {
2297 double value = func->GetParameter(ipar);
2298 double lowLim = std::min(value * 0.99, value * 1.01);
2299 double highLim = std::max(value * 0.99, value * 1.01);
2301 fitter->SetParameter(ipar + 1, func->GetParName(ipar), func->GetParameter(ipar), 0.01, lowLim, highLim);
2302 fitter->FixParameter(ipar + 1);
2305 double value = func->GetParameter(ipar);
2306 if (value >= parLimitHigh) value = parLimitHigh * 0.99;
2307 else if (value <= parLimitLow) value = parLimitLow * 1.01;
2309 double step = std::min((parLimitHigh - parLimitLow)/100., (value - parLimitLow)/100.);
2311 fitter->SetParameter(ipar + 1, func->GetParName(ipar), value, step, parLimitLow, parLimitHigh);
2322 double parLimitLow, parLimitHigh;
2325 func_p->GetParLimits(1, parLimitLow, parLimitHigh);
2327 fitter->SetParameter(2, func_p->GetParName(1), func_p->GetParameter(1), 0.01, parLimitLow, parLimitHigh);
2332 func_p->GetParLimits(parIndex, parLimitLow, parLimitHigh);
2333 fitter->SetParameter(parIndex + 1, func_p->GetParName(parIndex), func_p->GetParameter(parIndex), 0.01, parLimitLow, parLimitHigh);
2344 (*m_msgFunc_p)(
ZDCMsg::Info, (
"using delayed samples with delta T = " + std::to_string(
m_delayedDeltaT) +
", and pedestalDiff == " +
2348 std::ostringstream message1;
2349 message1 <<
"samplesSub ";
2350 for (
size_t sample = 0; sample <
m_samplesSub.size(); sample++) {
2351 message1 <<
", [" << sample <<
"] = " <<
m_samplesSub[sample];
2355 std::ostringstream message3;
2356 message3 <<
"samplesDeriv2nd ";
2367 std::string message =
"Dump of TF1: " + std::string(func->GetName());
2368 bool continueDump = (*m_msgFunc_p)(
ZDCMsg::Verbose, std::move(message));
2369 if (!continueDump)
return;
2371 unsigned int npar = func->GetNpar();
2372 for (
unsigned int ipar = 0; ipar < npar; ipar++) {
2373 std::ostringstream msgstr;
2375 double parMin = 0, parMax = 0;
2376 func->GetParLimits(ipar, parMin, parMax);
2378 msgstr <<
"Parameter " << ipar <<
", value = " << func->GetParameter(ipar) <<
", error = "
2379 << func->GetParError(ipar) <<
", min = " << parMin <<
", max = " << parMax;
2386 std::ostringstream ostrStream;
2387 (*m_msgFunc_p)(
ZDCMsg::Info, (
"\n ZDCPulserAnalyzer:: ======================================================================="));
2388 (*m_msgFunc_p)(
ZDCMsg::Info, (
"ZDCPulserAnalyzer:: settings for instance: " +
m_tag));
2390 ostrStream <<
"Nsample = " <<
m_Nsample <<
" at frequency " <<
m_freqMHz <<
" MHz, preSample index = "
2393 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2396 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2399 ostrStream <<
"Using per-sample noise sigmas for high gain, values = ";
2401 ostrStream <<
"end";
2402 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2406 ostrStream <<
"Using per-sample noise sigmas for low gain, values = ";
2408 ostrStream <<
"end";
2409 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2415 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2418 ostrStream <<
"using delayed samples with delta T = " <<
m_delayedDeltaT <<
", and default pedestalDiff == "
2420 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2432 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2436 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2441 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2445 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2449 (*m_msgFunc_p)(
ZDCMsg::Info,
"Pre-pulse and negative exponential pulse checking disabled");
2452 (*m_msgFunc_p)(
ZDCMsg::Info,
"Post-pulse checking disabled");
2456 ostrStream <<
"Pre-exclusion enabled for up to " <<
m_maxSamplesPreExcl <<
", samples with ADC threshold HG = "
2458 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2461 ostrStream <<
"Post-exclusion enabled for up to " <<
m_maxSamplesPostExcl <<
", samples with ADC threshold HG = "
2463 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2469 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2474 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2477 ostrStream <<
"Minimum significance cuts applied: HG min. sig. = " <<
m_sigMinHG <<
", LG min. sig. " <<
m_sigMinLG;
2478 (*m_msgFunc_p)(
ZDCMsg::Info, ostrStream.str()); ostrStream.str(
""); ostrStream.clear();
2485 unsigned int statusMask = 0;
2522 TH1* hist_p =
nullptr, *delayedHist_p =
nullptr;
2532 std::shared_ptr<TGraphErrors> theGraph = std::make_shared<TGraphErrors>(TGraphErrors(2 *
m_Nsample));
2535 for (
int ipt = 0; ipt < hist_p->GetNbinsX(); ipt++) {
2536 theGraph->SetPoint(npts, hist_p->GetBinCenter(ipt + 1), hist_p->GetBinContent(ipt + 1));
2537 theGraph->SetPointError(npts++, 0, hist_p->GetBinError(ipt + 1));
2540 for (
int iDelayPt = 0; iDelayPt < delayedHist_p->GetNbinsX(); iDelayPt++) {
2541 theGraph->SetPoint(npts, delayedHist_p->GetBinCenter(iDelayPt + 1), delayedHist_p->GetBinContent(iDelayPt + 1) -
m_delayedBaselineShift);
2542 theGraph->SetPointError(npts++, 0, delayedHist_p->GetBinError(iDelayPt + 1));
2545 TF1* func_p =
static_cast<TF1*
>(hist_p->GetListOfFunctions()->Last());
2547 theGraph->GetListOfFunctions()->Add(
new TF1(*func_p));
2548 hist_p->GetListOfFunctions()->SetOwner (
false);
2551 theGraph->SetName(( std::string(hist_p->GetName()) +
"combinaed").c_str());
2553 theGraph->SetMarkerStyle(20);
2554 theGraph->SetMarkerColor(1);
2567 std::shared_ptr<TGraphErrors> theGraph = std::make_shared<TGraphErrors>(TGraphErrors(
m_Nsample));
2570 for (
int ipt = 0; ipt < hist_p->GetNbinsX(); ipt++) {
2571 theGraph->SetPoint(npts, hist_p->GetBinCenter(ipt + 1), hist_p->GetBinContent(ipt + 1));
2572 theGraph->SetPointError(npts++, 0, hist_p->GetBinError(ipt + 1));
2575 TF1* func_p =
static_cast<TF1*
>(hist_p->GetListOfFunctions()->Last());
2576 theGraph->GetListOfFunctions()->Add(func_p);
2577 theGraph->SetName(( std::string(hist_p->GetName()) +
"not_combinaed").c_str());
2579 theGraph->SetMarkerStyle(20);
2580 theGraph->SetMarkerColor(1);
2588 unsigned int nSamples = inputData.size();
2592 unsigned int vecSize = 2*(step - 1) + nSamples - step - 1;
2593 std::vector<float> results(vecSize, 0);
2597 unsigned int fillIdx = step - 1;
2599 for (
unsigned int sample = 0; sample < nSamples - step; sample++) {
2600 int deriv = inputData[sample + step] - inputData[sample];
2601 results.at(fillIdx++) = deriv;
2609 unsigned int nSamples = inputData.size();
2614 unsigned int vecSize = 2*step + nSamples - step - 1;
2615 std::vector<float> results(vecSize, 0);
2617 unsigned int fillIndex = step;
2618 for (
unsigned int sample = step; sample < nSamples - step; sample++) {
2619 auto deriv2nd = inputData[sample + step] + inputData[sample - step] - 2*inputData[sample];
2620 results.at(fillIndex++) = deriv2nd;
2626std::pair<std::vector<float>, std::vector<float>>
2629 unsigned int nSamples = inputData.size();
2634 unsigned int vecSize = 2*step + nSamples - step - 1;
2635 std::vector<float> results(vecSize, 0);
2636 std::vector<float> resultsErr(vecSize, 0);
2638 unsigned int fillIndex = step;
2639 for (
unsigned int sample = step; sample < nSamples - step; sample++) {
2640 float deriv2nd = inputData[sample + step] + inputData[sample - step] - 2*inputData[sample];
2641 float deriv2ndErr = std::sqrt(
Sqr(inputNoise[sample + step]) +
Sqr(inputNoise[sample - step]) + 2*
Sqr(inputNoise[sample]));
2643 results[fillIndex] = deriv2nd;
2644 resultsErr[fillIndex++] = deriv2ndErr;
2647 return {results, resultsErr};
2665 const unsigned int nsamples = samples.size();
2673 float minScore = 1.0e9;
2674 unsigned int minIndex = 0;
2676 for (
unsigned int idx = 2; idx < nsamples - 1; idx++) {
2677 float deriv = derivVec[idx];
2678 float prevDeriv = derivVec[idx - 1];
2680 float derivDiff = deriv - prevDeriv;
2682 float deriv2nd = deriv2ndVec[idx];
2683 if (idx > nsamples - 2) deriv2nd = deriv2ndVec[idx - 1];
2688 float score = (deriv*deriv + 2*derivDiff*derivDiff +
2689 0.5*deriv2nd*deriv2nd);
2691 if (score < minScore) {
2702 if (minIndex<2 or (minIndex+1) >=nsamples){
2703 throw std::out_of_range(
"minIndex out of range in ZDCPulseAnalyzer::obtainDelayedBaselineCorr");
2705 float sample0 = samples[minIndex - 2];
2706 float sample1 = samples[minIndex - 1];
2707 float sample2 = samples[minIndex];
2708 float sample3 = samples[minIndex + 1];
2712 float baselineCorr = (0.5 * (sample1 - sample0 + sample3 - sample2) -
2713 0.25 * (sample3 - sample1 + sample2 - sample0));
2715 if (minIndex % 2 != 0) baselineCorr =-baselineCorr;
2717 return baselineCorr;
2723 std::string resultString =
"success";
2726 auto iter = config.find(key);
2727 if (iter != config.end()) {
2731 auto jsonType = iter.value().type();
2732 auto paramType = std::get<0>(descr);
2733 if (jsonType != paramType) {
2735 resultString =
"Bad type for parameter " + key +
", type in JSON = " + std::to_string((
unsigned int) jsonType) ;
2739 size_t paramSize = std::get<1>(descr);
2740 size_t jsonSize = iter.value().size();
2741 if (jsonSize != paramSize) {
2743 resultString =
"Bad length for parameter " + key +
", length in JSON = " + std::to_string(jsonSize) ;
2748 bool required = std::get<2>(descr);
2751 resultString =
"Missing required parameter " + key;
2761 for (
auto [key, value] : config.items()) {
2770 resultString =
"Unknown parameter, key = " + key;
2776 return {result, resultString};
2782 std::string resultString =
"success";
2784 for (
auto [key, value] : config.items()) {
2788 if (key ==
"Nsample")
m_Nsample = value;
2789 else if (key ==
"tag")
m_tag = value;
2790 else if (key ==
"LGMode")
m_LGMode = value;
2791 else if (key ==
"Nsample")
m_Nsample = value;
2794 else if (key ==
"FADCFreqMHz")
m_freqMHz = value;
2795 else if (key ==
"nominalPedestal")
m_pedestal = value;
2797 else if (key ==
"fitParameterSet") {
2798 if (value.size() < 2) {
2817 else if (key ==
"nominalTau1") {
2821 else if (key ==
"nominalTau2") {
2825 else if (key ==
"fixTau1") {
2829 else if (key ==
"fixTau2") {
2841 else if (key ==
"T0CutsHG") {
2845 else if (key ==
"T0CutsLG") {
2862 else if (key ==
"perSampleNoiseSigmaHG") {
2866 else if (key ==
"perSampleNoiseSigmaLG") {
2875 else if (key ==
"fitTimeMax") {
2881 else if (key ==
"fitAmpMinMaxHG") {
2885 else if (key ==
"fitAmpMinMaxLG") {
2889 else if (key ==
"quietFits") {
2892 else if (key ==
"enablePreExclusion") {
2898 else if (key ==
"enablePostExclusion") {
2904 else if (key ==
"enableUnderflowExclusionHG") {
2909 else if (key ==
"enableUnderflowExclusionLG") {
2914 else if (key ==
"enablePrePulseDetection") {
2917 else if (key ==
"enablePostPulseDetection") {
2920 else if (key ==
"ampMinSignifHGLG") {
2925 else if (key ==
"enableFADCCorrections") {
2926 auto fileNameJson = value[
"filename"];
2927 auto doPerSampleCorrJson = value[
"doPerSampleCorr"];
2929 if (fileNameJson.is_null() || doPerSampleCorrJson.is_null()) {
2931 resultString =
"failure processing enableFADCCorrections object";
2939 else if(key ==
"useDelayed"){
2946 else if (key ==
"enableTimingCorrection") {
2951 else if(key ==
"timeCorrCoeffHG"){
2952 for(
int i = 0;
auto coeff:value){
2957 else if(key ==
"timeCorrCoeffLG"){
2958 for(
int i = 0;
auto coeff:value){
2963 else if(key ==
"enableNLCorrection"){
2972 else if(key ==
"HGNLCorrCoeffs"){
2973 std::string HGParamsStr =
"HG coefficients = ";
2974 for (
auto coeff : value) {
2980 else if(key ==
"LGNLCorrCoeffs"){
2981 std::string LGParamsStr =
"LG coefficients = ";
2982 for(
auto coeff:value){
2990 resultString =
"unprocessed parameter";
2995 return {result, resultString};
virtual float GetTau1() const =0
void Initialize(float initialAmp, float initialT0, float ampMin, float ampMax)
virtual float GetBkgdMaxFraction() const =0
virtual TF1 * GetWrapperTF1RawPtr() const
virtual std::shared_ptr< TF1 > GetWrapperTF1()
virtual float GetAmpError() const =0
virtual float GetTime() const =0
virtual float GetShapeParameter(size_t index) const =0
virtual float GetTau2() const =0
virtual float GetAmplitude() const =0
virtual unsigned int GetNumShapeParameters() const =0
std::map< std::string, JSONParamDescr > JSONParamList
virtual float GetExpAmp() const =0
virtual void SetInitialExpPulse(float expamp)=0
virtual float GetPreAmp() const =0
virtual float GetPreT0() const =0
virtual float GetPostT0() const =0
virtual void SetInitialPrePulse(float amp, float t0, float expamp, bool fixPrePulseToZero)=0
virtual float GetPostAmp() const =0
std::vector< bool > m_useSampleHG
std::shared_ptr< TGraphErrors > GetCombinedGraph(bool forceLG=false)
static TF1 * s_combinedFitFunc
float m_initialPrePulseAmp
std::unique_ptr< const TF1 > m_timeResFuncHG_p
void dumpTF1(const TF1 *) const
float m_chisqDivAmpScaleHG
float m_chisqDivAmpOffsetLG
std::unique_ptr< TFitter > m_prePulseCombinedFitter
bool underflowExclusion() const
float m_initialPostPulseT0
unsigned int m_timeCutMode
std::unique_ptr< const TH1 > m_FADCCorrLG
size_t m_peak2ndDerivMinTolerance
std::vector< float > m_fitPulls
size_t m_peak2ndDerivMinSample
std::vector< float > m_setPerSampleNoiseHG
std::unique_ptr< ZDCFitWrapper > m_defaultFitWrapperLG
bool ScanAndSubtractSamples()
void dumpConfiguration() const
std::vector< float > m_nonLinCorrParamsLG
bool excludeEarlyLG() const
float m_peak2ndDerivMinThreshHG
bool m_havePerSampleNoiseLG
std::vector< float > m_samplesNoiseLGRefit
static std::vector< float > s_pullValues
std::unique_ptr< const TF1 > m_timeResFuncLG_p
static TH1 * s_undelayedFitHist
std::pair< bool, std::string > ConfigFromJSON(const JSON &config)
static std::vector< float > calculate2ndDerivative(const std::vector< float > &inputData, unsigned int step)
std::string m_fitFunction
unsigned int m_preSampleIdx
std::vector< float > m_LGT0CorrParams
std::vector< float > m_samplesLGRefit
std::vector< float > m_samplesNoise
void SetTauT0Values(bool fixTau1, bool fixTau2, float tau1, float tau2, float t0HG, float t0LG)
bool fitMinimumAmplitude() const
float m_chisqDivAmpPowerLG
const TH1 * GetHistogramPtr(bool refitLG=false)
float m_peak2ndDerivMinRepassLG
void SetGainFactorsHGLG(float gainFactorHG, float gainFactorLG)
int m_lastHGOverFlowSample
unsigned int m_preExclLGADCThresh
std::unique_ptr< ZDCFitWrapper > m_defaultFitWrapperHG
unsigned int m_prePulseDelta
void enablePostPulseCheck(unsigned int postPulseSampleDelta, float postPulseDerivMinSig, float postPulseAbsDer2ndMinSig, float minMainDer2ndRatio)
unsigned int m_postExclLGADCThresh
std::vector< float > m_shapeParameters
unsigned int m_NSamplesAna
bool DoAnalysis(bool repass)
void setMinimumSignificance(float sigMinHG, float sigMinLG)
static std::unique_ptr< TFitter > MakeCombinedFitter(TF1 *func)
std::unique_ptr< TH1 > m_delayedHistLGRefit
float m_delayedBaselineShift
unsigned int m_timingCorrMode
float m_chisqDivAmpScaleLG
std::vector< float > m_sampleNoiseLG
unsigned int m_maxSampleEvt
int m_firstHGOverFlowSample
unsigned int m_maxSamplesPreExcl
std::vector< float > m_setPerSampleNoiseLG
std::vector< float > m_ADCSamplesLG
unsigned int m_underFlowExclSamplesPreLG
float m_postPulseMainMinDer2ndRatio
std::unique_ptr< ZDCPreExpFitWrapper > m_preExpFitWrapperHG
static float s_combinedFitTMin
std::vector< float > m_nonLinCorrParamsHG
std::unique_ptr< ZDCPreExpFitWrapper > m_preExpFitWrapperLG
ZDCPulseAnalyzer(ZDCMsg::MessageFunctionPtr msgFunc_p, const std::string &tag, int Nsample, float deltaTSample, size_t preSampleIdx, int pedestal, const std::string &fitFunction, int peak2ndDerivMinSample, float peak2DerivMinThreshHG, float peak2DerivMinThreshLG)
unsigned int m_underFlowExclSamplesPostHG
unsigned int m_maxSamplesPostExcl
void SetADCOverUnderflowValues(int HGOverflowADC, int HGUnderflowADC, int LGOverflowADC)
float m_chisqDivAmpPowerHG
std::vector< float > m_ADCSamplesHGSub
void UpdateFitterTimeLimits(TFitter *fitter, ZDCFitWrapper *wrapper, bool prePulse)
static float obtainDelayedBaselineCorr(const std::vector< float > &samples)
void prepareLGRefit(const std::vector< float > &samplesLG, const std::vector< float > &samplesNoise, const std::vector< bool > &useSamples)
double getAmplitudeCorrection(bool highGain)
float m_peak2ndDerivMinRepassHG
unsigned int m_underFlowExclSamplesPreHG
float m_peak2ndDerivMinThreshLG
float m_postPulseAbsDer2ndMinSig
void enableRepass(float peak2ndDerivMinRepassHG, float peak2ndDerivMinRepassLG)
void enableDelayed(float deltaT, float pedestalShift, bool fixedBaseline=false)
void DoFit(bool refitLG=false)
std::vector< float > m_ADCSamplesLGSub
bool m_enableUnderflowExclHG
float m_delayedPedestalDiff
std::vector< float > m_samplesSub
void SetFitTimeMax(float tmax)
std::unique_ptr< ZDCPrePulseFitWrapper > m_prePulseFitWrapperLG
static float s_combinedFitTMax
std::vector< bool > m_useSampleLG
void reset(bool reanalyze=false)
unsigned int m_underFlowExclSamplesPostLG
unsigned int m_postPulseDelta
std::vector< float > m_ADCSamplesHG
void checkTF1Limits(TF1 *func)
bool AnalyzeData(size_t nSamples, size_t preSample, const std::vector< float > &samples, const std::vector< float > &samplesNoise, const std::vector< bool > &useSamples, float peak2ndDerivMinThresh, const std::vector< float > &toCorrParams, ChisqCutLambdatype chisqCutLambda, float minT0Corr, float maxT0Corr)
void SetTimeCuts(float deltaT0MinHG, float deltaT0MaxHG, float deltaT0MinLG, float deltaT0MaxLG)
bool m_underflowExclusion
std::vector< float > m_sampleNoiseHG
std::vector< float > GetFitPulls(bool forceLG=false) const
bool armSumInclude() const
void SetCutValues(float chisqDivAmpCutHG, float chisqDivAmpCutLG, float deltaT0MinHG, float deltaT0MaxHG, float deltaT0MinLG, float deltaT0MaxLG)
std::vector< float > m_HGT0CorrParams
void SetChisqCuts(float chisqDivAmpCutHG, float chisqDivAmpScaleHG, float chisqDivAmpOffsetHG, float chisqDivAmpPowerHG, float chisqDivAmpCutLG, float chisqDivAmpScaleLG, float chisqDivAmpOffsetLG, float chisqDivAmpPowerLG)
std::unique_ptr< TH1 > m_fitHistLGRefit
std::unique_ptr< TH1 > m_delayedHist
std::shared_ptr< TGraphErrors > GetGraph(bool forceLG=false)
unsigned int m_preExclHGADCThresh
static TH1 * s_delayedFitHist
std::unique_ptr< TH1 > m_fitHist
std::unique_ptr< TFitter > m_defaultCombinedFitter
unsigned int m_minSampleEvt
std::vector< float > m_ADCSSampNoiseLG
bool PSHGOverUnderflow() const
unsigned int GetStatusMask() const
float m_nonLinCorrRefScale
std::string m_fitParameterSetHG
bool LoadAndAnalyzeData(const std::vector< float > &ADCSamplesHG, const std::vector< float > &ADCSamplesLG)
void enableTimeSigCut(bool AND, float sigCut, const std::string &TF1String, const std::vector< double > &parsHG, const std::vector< double > &parsLG)
static void CombinedPulsesFCN(int &numParam, double *, double &f, double *par, int flag)
bool m_havePerSampleNoiseHG
bool m_enableUnderflowExclLG
unsigned int m_postExclHGADCThresh
std::unique_ptr< ZDCPrePulseFitWrapper > m_prePulseFitWrapperHG
bool m_haveFADCCorrections
void SetFitMinMaxAmp(float minAmpHG, float minAmpLG, float maxAmpHG, float maxAmpLG)
static std::vector< float > calculateDerivative(const std::vector< float > &inputData, unsigned int step)
float m_chisqDivAmpOffsetHG
std::unique_ptr< const TH1 > m_FADCCorrHG
std::vector< float > m_samplesDeriv2ndErr
float m_postPulseDerivMinSig
ZDCMsg::MessageFunctionPtr m_msgFunc_p
void FillHistogram(bool refitLG)
std::vector< float >::const_iterator SampleCIter
std::vector< float > m_ADCSSampNoiseHG
float m_initialPrePulseT0
static const ZDCJSONConfig::JSONParamList JSONConfigParams
std::vector< float > m_samplesDeriv2nd
std::pair< bool, std::string > ValidateJSONConfig(const JSON &config)
void DoFitCombined(bool refitLG=false)
std::string m_fadcCorrFileName
std::string m_fitParameterSetLG
bool excludeLateLG() const
std::function< bool(float, float, float, float &)> ChisqCutLambdatype
void enableFADCCorrections(bool correctPerSample, std::unique_ptr< const TH1 > &correHistHG, std::unique_ptr< const TH1 > &correHistLG)
double chi2(TH1 *h0, TH1 *h1)
std::shared_ptr< MessageFunction > MessageFunctionPtr
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP