Stills keep an overload as a lower bound only where it has pixels at the limit; run-level gate removed

The lower bound counts each saturated pixel at the saturation limit, so it needs one. An observation
overloaded only by pixels unreadable on this frame (a per-frame bad-pixel flag, data value 0) was kept
as a box sum with those pixels counted as zero, which bounds nothing; it now stays overloaded and is
dropped, per observation.

With the stuck pixels masked by the pre-scan, the run-level gate (kept overloads must be enriched
coarser than 4 A) has nothing left to catch: without it every still set gives the gated result
(clipped CCD and Rayonix sets identical to the fourth decimal, photon-counting sets unchanged), so it
is removed with Reflection::overload_kept. A neighbour-brightness test per saturated pixel was tried
and not kept: after the mask it only dropped 9-20% of the Rayonix overloads and worsened R_split on
one set (0.245 -> 0.278).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-10-22 17:27:44 +02:00
1 parent b7e4ea23a3
commit 5905d34cba
5 files changed
+101 -44

No files matched your search

@@ -284,11 +284,14 @@ std::vector<Reflection> BraggIntegrationEngine::Finalize(const std::vector<Refle
// So a still keeps the observation as a lower bound: each saturated pixel counted at the
// saturation limit. (A fit to the unsaturated wings was tried and read lower still: the
// profile learned from unsaturated spots does not describe the wings of a clipped one.)
if (fr.overloaded && keep_overloads) {
// That takes a pixel AT the limit: an observation overloaded only by pixels unreadable on
// this frame has nothing to count at the limit, and counting those pixels as zero is no
// lower bound of anything - it stays overloaded and is dropped. (A pixel stuck at the limit
// is no clipped spot either; the pre-scan masks it, HotPixelFinder.)
if (fr.overloaded && keep_overloads && fr.saturated > 0) {
refl.I = fr.I + static_cast<float>(fr.saturated * (saturation_limit - fr.bkg));
refl.sigma = std::sqrt(fr.var_bkg + std::max(refl.I, 1.0f));
refl.overloaded = false;
refl.overload_kept = true;
++counts.overloads_kept;
}
refl.observed = true;