Guard degenerate asymptotic-ISa fit on low-multiplicity data

On very-low-multiplicity data (e.g. EP_cs_01-24, mult ~1.4) the merge has too
few symmetry equivalents to measure the asymptotic I/sigma: both the (a, b)
error-model fit and the per-group strong-reflection scatter collapse toward
zero, so 1/error_model_b_asymptotic either explodes to an impossibly high ISa
(tiny positive b) or is left as 0. Real macromolecular data does not exceed
ISa ~50, so clamp the reported asymptote at a generous cap (ISa 100) and treat
anything past it as unmeasured (result.isa undetermined) rather than emitting a
spurious extreme. No-op for all well-measured data (b_asy well above the cap).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-21 23:02:40 +02:00
co-authored by Claude Opus 4.8
parent 81dbf9a385
commit c52886c8ff
@@ -1520,6 +1520,12 @@ RotationScaleMerge::Result RotationScaleMerge::MergeAndStats(int n_groups, bool
if (b_asy <= 0.0) b_asy = asymptote_above(10.0, 50); // relaxed for weak / damaged data
if (b_asy > 0.0) error_model_b_asymptotic = b_asy;
}
// Guard a degenerate low-multiplicity fit: with too few symmetry equivalents both the (a, b) fit and
// the per-group scatter collapse toward zero, and 1/b then reports an impossibly high asymptotic
// I/sigma. Real macromolecular data does not exceed ISa ~50; past a generous cap treat the asymptote
// as unmeasured (result.isa left undetermined) rather than emit a spurious extreme.
constexpr double MIN_ASYMPTOTIC_B = 0.01; // ISa cap 100
if (error_model_b_asymptotic < MIN_ASYMPTOTIC_B) error_model_b_asymptotic = 0.0;
if (error_model_active)
logger.Info("Error model: a={:.3f} b={:.3f} ISa={:.1f} chi2={:.2f}", error_model_a, error_model_b,
error_model_b_asymptotic > 0 ? 1.0 / error_model_b_asymptotic : 0.0, error_model_chi2);