Skip to content

Commit b670d8e

Browse files
committed
Fix self-attenuating RelAct calculations as AD goes to zero.
Previous niave implementation would result in a inf for AD equal to zero, and probably bad values of derivative as it approached; replaced with more well-behaved approach if mu*ad is below a threshold. Also fixup some debug checks.
1 parent 8f92c46 commit b670d8e

File tree

4 files changed

+28
-9
lines changed

4 files changed

+28
-9
lines changed

InterSpec/PeakDists_imp.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ void gauss_exp_integral( const T peak_mean,
374374
const double simple_answer = peak_amplitude * PeakDists::gauss_exp_integral( peak_mean, peak_sigma, skew, lower_energy, upper_energy );
375375
const double diff = fabs(val - simple_answer);
376376
const double frac_diff = diff / std::max(val, simple_answer);
377-
assert( (frac_diff < 1.0E-5) || (diff < 1.0E-8) );
377+
assert( (frac_diff < 1.0E-5) || (diff < 1.0E-7) || (fabs(peak_mean - 0.5*(lower_energy + upper_energy)) > (5.0*peak_sigma)) );
378378
}
379379
#endif
380380

InterSpec/RelActCalc_imp.hpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,26 @@ T eval_physical_model_eqn_imp( const double energy,
253253

254254
assert( areal_density >= 0.0 );
255255

256-
if( (mu >= 0.0) && (areal_density >= 0.0) )
257-
answer *= (1.0 - exp(-mu * areal_density)) / (mu * self_atten->areal_density);
258-
256+
//The simple computation to handel self-attenuation would be:
257+
// answer *= (1.0 - exp(-mu * areal_density)) / (mu * areal_density);
258+
//But if -mu*areal_density is zero, we get NaN, and even as it goes towards zero, we will greatly lose precision
259+
260+
const T epsilon = T(1.0e-8);
261+
const T x = mu * areal_density;
262+
263+
if( x < epsilon )
264+
{
265+
// Use the Taylor series expansion for small x.
266+
// f(x) = 1 - x/2 + x^2/6
267+
answer *= (T(1.0) - 0.5*x + ((x*x) / 6.0)); // + -(x*x*x)/24.0 + ...
268+
}else
269+
{
270+
// For larger x, use the standard formula, but with expm1
271+
// to avoid catastrophic cancellation near zero.
272+
// 1 - exp(-x) = -expm1(-x)
273+
answer *= -expm1(-x) / x;
274+
}//if( (mu*areal_density) < epsilon ) / else
275+
259276
assert( !isnan(answer) && !isinf(answer) );
260277
}//if( self_atten->has_value() )
261278

src/PeakFit.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6412,17 +6412,16 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
64126412
{
64136413
//20250410: I believe `PeakFit::fit_amp_and_offset_imp(...)` should be the better function to use, as it uses SVD
64146414
// but currently leaving the below check in to make sure the re-implementation of this function is correct
6415-
// TODO: remove this check after a while
6415+
#define COMPARE_TO_OLD_FIT_WAY 0
64166416
double * const dummy_channel_counts = nullptr;
6417-
std::vector<double> dummy_amplitudes, dummy_continuum_coeffs, dummy_amplitudes_uncerts, dummy_continuum_coeffs_uncerts;
6418-
#if( !PERFORM_DEVELOPER_CHECKS )
6417+
#if( !COMPARE_TO_OLD_FIT_WAY )
64196418
return PeakFit::fit_amp_and_offset_imp( x, data, nbin, num_polynomial_terms, step_continuum,
64206419
ref_energy, means, sigmas, fixedAmpPeaks, skew_type, skew_parameters,
64216420
amplitudes, continuum_coeffs,
64226421
amplitudes_uncerts, continuum_coeffs_uncerts,
64236422
dummy_channel_counts );
64246423
#else
6425-
6424+
std::vector<double> dummy_amplitudes, dummy_continuum_coeffs, dummy_amplitudes_uncerts, dummy_continuum_coeffs_uncerts;
64266425
const double dummy_chi2 = PeakFit::fit_amp_and_offset_imp( x, data, nbin, num_polynomial_terms, step_continuum,
64276426
ref_energy, means, sigmas, fixedAmpPeaks, skew_type, skew_parameters,
64286427
dummy_amplitudes, dummy_continuum_coeffs,
@@ -6852,7 +6851,7 @@ double fit_amp_and_offset( const float *x, const float *data, const size_t nbin,
68526851
}
68536852

68546853
return chi2;
6855-
#endif // !PERFORM_DEVELOPER_CHECKS )
6854+
#endif // if( COMPARE_TO_OLD_FIT_WAY ) / else
68566855
}//double fit_amp_and_offset(...)
68576856

68586857

src/RelActAutoGuiNuclide.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,9 @@ void RelActAutoGuiNuclide::handleColorChange()
13241324
std::variant<std::monostate, const SandiaDecay::Nuclide *, const SandiaDecay::Element *, const ReactionGamma::Reaction *> RelActAutoGuiNuclide::source() const
13251325
{
13261326
const string nucstr = m_nuclide_edit->text().toUTF8();
1327+
if( nucstr.empty() )
1328+
return std::monostate{};
1329+
13271330
const SandiaDecay::SandiaDecayDataBase * const db = DecayDataBaseServer::database();
13281331
assert( db );
13291332
if( !db )

0 commit comments

Comments
 (0)