@@ -76,6 +76,15 @@ using namespace std;
7676
7777using SpecUtils::Measurement;
7878
79+ // 20240911: The minimum uncertainty allowed for a gamma spectrum channel.
80+ // Background subtracted spectra can end up with tiny bins, like 0.0007,
81+ // which if we take its uncertainty to be its sqrt, a single bin like this will
82+ // totally mess up the whole ROI. So we'll impose a minimum uncertainty on
83+ // each channel.
84+ // However, if a spectrum is scaled, and not Poisson errored, this will totally
85+ // mess things up (even though it wouldnt be right in the first place).
86+ #define MIN_CHANNEL_UNCERT 1.0
87+
7988template <class T >
8089bool matrix_invert ( const boost::numeric::ublas::matrix<T>& input,
8190 boost::numeric::ublas::matrix<T> &inverse )
@@ -1774,7 +1783,7 @@ double chi2_for_region( const PeakShrdVec &peaks,
17741783 const double ncontinuum = continuum->offset_integral (xbinlow, xbinup, data);
17751784
17761785 const double npeak = gauss_counts[i];
1777- const double uncert = ndata > 0.0 ? sqrt (ndata) : 1.0 ;
1786+ const double uncert = ndata > MIN_CHANNEL_UNCERT ? sqrt (ndata) : 1.0 ;
17781787 const double chi = (ndata-ncontinuum-npeak)/uncert;
17791788
17801789 chi2 += chi*chi;
@@ -1803,7 +1812,7 @@ double chi2_for_region( const PeakShrdVec &peaks,
18031812 {
18041813 const double peakarea = i->second ;
18051814 const double ndata = data->gamma_channel_content ( i->first );
1806- const double uncert = ndata > 0.0 ? sqrt (ndata) : 1.0 ;
1815+ const double uncert = ndata > MIN_CHANNEL_UNCERT ? sqrt (ndata) : 1.0 ;
18071816 const double chi = (ndata-peakarea)/uncert;
18081817 chi2 += chi*chi;
18091818 }// for( int bin = minbin; bin <= maxbin; ++bin )
@@ -2069,7 +2078,7 @@ double evaluate_chi2dof_for_range( const std::vector<PeakDef> &peaks,
20692078 if ( y_pred < 0.0 )
20702079 y_pred = 0.0 ;
20712080
2072- const double uncert = (y > 0 . 0f ? sqrt (y) : 1.0 );
2081+ const double uncert = (y > MIN_CHANNEL_UNCERT ? sqrt (y) : 1.0 );
20732082 chi2 += std::pow ( (y_pred - y) / uncert, 2.0 );
20742083 }// for( int bin = 0; bin < nbin; ++bin )
20752084
@@ -3702,7 +3711,7 @@ bool check_lowres_single_peak_fit( const std::shared_ptr<const PeakDef> peak,
37023711 const double x = dataH->gamma_channel_lower ( channel );
37033712 const double y = dataH->gamma_channel_content ( channel );
37043713 const double y_pred = poly_coeffs[0 ] + poly_coeffs[1 ]*x;
3705- const double uncert = (y > 0 . 0f ? std::sqrt (y) : 1.0 );
3714+ const double uncert = (y > MIN_CHANNEL_UNCERT ? std::sqrt (y) : 1.0 );
37063715 const double thichi2 = std::pow ( (y_pred - y) / uncert, 2.0 );
37073716
37083717 linechi2 += thichi2;
@@ -4101,7 +4110,7 @@ PeakRejectionStatus check_lowres_multi_peak_fit( const vector<std::shared_ptr<co
41014110 const double x = dataH->gamma_channel_lower ( channel );
41024111 const double y = dataH->gamma_channel_content ( channel );
41034112 const double y_pred = poly_coeffs[0 ] + poly_coeffs[1 ]*x;
4104- const double uncert = (y > 0 . 0f ? sqrt (y) : 1.0 );
4113+ const double uncert = (y > MIN_CHANNEL_UNCERT ? sqrt (y) : 1.0 );
41054114 linechi2 += std::pow ( (y_pred - y) / uncert, 2.0 );
41064115 }// for( int bin = 0; bin < nbin; ++bin )
41074116
@@ -4624,7 +4633,7 @@ bool check_highres_single_peak_fit( const std::shared_ptr<const PeakDef> peak,
46244633 const double x = dataH->gamma_channel_lower ( channel );
46254634 const double y = dataH->gamma_channel_content ( channel );
46264635 const double y_pred = poly_coeffs[0 ] + poly_coeffs[1 ]*x;
4627- const double uncert = (y > 0 . 0f ? std::sqrt (y) : 1.0 );
4636+ const double uncert = (y > MIN_CHANNEL_UNCERT ? std::sqrt (y) : 1.0 );
46284637 const double thichi2 = std::pow ( (y_pred - y) / uncert, 2.0 );
46294638
46304639 linechi2 += thichi2;
@@ -6262,7 +6271,7 @@ double fit_to_polynomial( const float *x, const float *data, const size_t nbin,
62626271
62636272 for ( size_t row = 0 ; row < nbin; ++row )
62646273 {
6265- const double uncert = (data[row] > 0.0 ? sqrt ( data[row] ) : 1.0 );
6274+ const double uncert = (data[row] > MIN_CHANNEL_UNCERT ? sqrt ( data[row] ) : 1.0 );
62666275 b (row) = (data[row] > 0.0 ? sqrt ( data[row] ) : 0.0 );
62676276 for ( int col = 0 ; col < poly_terms; ++col )
62686277 A (row,col) = std::pow ( double (x[row]), double (col)) / uncert;
@@ -6292,7 +6301,7 @@ double fit_to_polynomial( const float *x, const float *data, const size_t nbin,
62926301 double y_pred = 0.0 ;
62936302 for ( int i = 0 ; i < poly_terms; ++i )
62946303 y_pred += a (i) * std::pow ( double (x[bin]), double (i) );
6295- const double uncert = (data[bin] > 0.0 ? sqrt ( data[bin] ) : 1.0 );
6304+ const double uncert = (data[bin] > MIN_CHANNEL_UNCERT ? sqrt ( data[bin] ) : 1.0 );
62966305 chi2 += std::pow ( (y_pred - data[bin]) / uncert, 2.0 );
62976306 }// for( int bin = 0; bin < nbin; ++bin )
62986307
@@ -6375,16 +6384,15 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
63756384 // cerr << "{" << means[i] << ", " << sigmas[i] << "}, ";
63766385 // cerr << endl << endl;
63776386
6378- double step_roi_data_sum = 0.0 , step_cumulative_data = 0.0 ;
6387+ double roi_data_sum = 0.0 , step_cumulative_data = 0.0 ;
63796388
63806389 const double roi_lower = x[0 ];
63816390 const double roi_upper = x[nbin];
6382- if ( step_continuum )
6383- {
6384- for ( size_t row = 0 ; row < nbin; ++row )
6385- step_roi_data_sum += data[row];
6386- }
63876391
6392+ for ( size_t row = 0 ; row < nbin; ++row )
6393+ roi_data_sum += std::max ( data[row], 0 .0f );
6394+
6395+ const double avrg_data_val = roi_data_sum / nbin;
63886396
63896397 // For the RelACtAuto calcs, there can easily be 100 peaks, so for this case we'll calculate
63906398 // their contribution multithreaded.
@@ -6447,7 +6455,14 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
64476455 const double x1_rel = x1 - ref_energy;
64486456
64496457 // const double uncert = (dataval > 0.0 ? sqrt(dataval) : 1.0);
6450- double uncert = (dataval > 0.0 ? sqrt (dataval) : 1.0 );
6458+ // If we are background subtracting a spectrum, we can end up with bins with really
6459+ // small values, like 0.0007, which, even one of would mess the whole fit up if
6460+ // we take its uncertainty to be its square-root, so in this case we will, fairly arbitrarily
6461+ // we want to use an uncert of 1.
6462+ // However, there are also highly scaled spectra, whose all values are really small, so
6463+ // in this case we want to do something more reasonable.
6464+ // TODO: evaluate these choices of thresholds and tradeoffs, more better
6465+ double uncert = (dataval > MIN_CHANNEL_UNCERT ? sqrt (dataval) : 1.0 );
64516466
64526467 if ( step_continuum )
64536468 step_cumulative_data += dataval;
@@ -6511,13 +6526,13 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
65116526 {
65126527 // This logic mirrors that of PeakContinuum::offset_integral(...), and code
65136528 // If you change it in one place - change it in here, below, and in offset_integral.
6514- const double frac_data = (step_cumulative_data - 0.5 *data[row]) / step_roi_data_sum ;
6529+ const double frac_data = (step_cumulative_data - 0.5 *data[row]) / roi_data_sum ;
65156530 const double contribution = frac_data * (x1 - x0);
65166531
65176532 A (row,col) = contribution / uncert;
65186533 }else if ( step_continuum && (num_polynomial_terms == 4 ) )
65196534 {
6520- const double frac_data = (step_cumulative_data - 0.5 *data[row]) / step_roi_data_sum ;
6535+ const double frac_data = (step_cumulative_data - 0.5 *data[row]) / roi_data_sum ;
65216536
65226537 double contrib = 0.0 ;
65236538 switch ( col )
@@ -6577,7 +6592,7 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
65776592 for ( size_t channel = 0 ; channel < nbin; ++channel )
65786593 {
65796594 const double dataval = data[channel];
6580- const double uncert = (dataval > 0.0 ? sqrt (dataval) : 1.0 );
6595+ const double uncert = (dataval > MIN_CHANNEL_UNCERT ? sqrt (dataval) : 1.0 );
65816596 A (channel,npoly + i) = peak_areas[channel] / uncert;
65826597 }// for( size_t channel = 0; channel < nbin; ++channel )
65836598 }// for( size_t i = 0; i < npeaks; ++i )
@@ -6733,7 +6748,7 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
67336748 {
67346749 // This logic mirrors that of PeakContinuum::offset_integral(...) and above code in this
67356750 // function that defines the matrix, see above for comments
6736- const double frac_data = (step_cumulative_data - 0.5 *data[bin]) / step_roi_data_sum ;
6751+ const double frac_data = (step_cumulative_data - 0.5 *data[bin]) / roi_data_sum ;
67376752 const double contribution = frac_data * (x1 - x0);
67386753
67396754 y_pred += a (col)*contribution;
@@ -6742,7 +6757,7 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
67426757 // This logic mirrors that of PeakContinuum::offset_integral(...) and above code in this
67436758 // function that defines the matrix, see above for comments
67446759
6745- const double frac_data = (step_cumulative_data - 0.5 *data[bin]) / step_roi_data_sum ;
6760+ const double frac_data = (step_cumulative_data - 0.5 *data[bin]) / roi_data_sum ;
67466761
67476762 double contrib = 0.0 ;
67486763 switch ( col )
@@ -6774,7 +6789,7 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
67746789 y_pred += fixedAmpPeaks[i].gauss_integral ( x0, x1 );
67756790
67766791 // cerr << "bin " << bin << " predicted " << y_pred << " data=" << data[bin] << endl;
6777- const double uncert = (data[bin] > 0.0 ? sqrt ( data[bin] ) : 1.0 );
6792+ const double uncert = (data[bin] > MIN_CHANNEL_UNCERT ? sqrt ( data[bin] ) : 1.0 );
67786793 chi2 += std::pow ( (y_pred - data[bin]) / uncert, 2.0 );
67796794 }// for( int bin = 0; bin < nbin; ++bin )
67806795
@@ -8412,7 +8427,7 @@ std::vector<PeakDef> search_for_peaks( const std::shared_ptr<const Measurement>
84128427 y_pred += continuum_coeffs[col] * (1.0 /exp) * (pow (x1cont,exp) - pow (x0cont,exp));
84138428 }// for( int order = 0; order < maxorder; ++order )
84148429
8415- const double uncert = (data[bin] > 0.0 ? sqrt ( data[bin] ) : 1.0 );
8430+ const double uncert = (data[bin] > MIN_CHANNEL_UNCERT ? sqrt ( data[bin] ) : 1.0 );
84168431
84178432 if ( y_pred < 0.0 )
84188433 y_pred = 0.0 ;
0 commit comments