diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 52d1d535..dc9cb468 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -1529,13 +1529,17 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b double sum = 0.0; for (size_t j = lo; j < hi; ++j) sum += rs[j].second; if (sum / static_cast(hi - lo) < 1.0) { - // Cut the noise-dominated high-res shells, but only when a good low-res region - // exists above the cutoff. If even the lowest-res shell (b == 0) is below the - // threshold - as happens for very weak data whose I/sigma is floored by the - // error model although CC1/2 is still high - there is no clean/noise boundary, - // and cutting here would discard essentially all reflections and leave the - // re-merge with no resolution range. Leave d_min_search at 0 (no cut) instead. - if (b > 0) d_min_search = rs[lo].first; + // Cut the noise-dominated high-res shells. When even the lowest-res shell fails, + // keep that shell alone rather than abandoning the cut. The bound is absolute + // while the merged I/sigma it tests is capped by the merge's own ISa, so a merge + // whose ISa has fallen below 1 cannot satisfy it in ANY shell - and that is + // exactly the merge the search must not be handed whole, since the noise which + // drove ISa down is what the cut exists to remove. Abandoning it feeds back: + // more noise into the search, a weaker operator statistic, and a lost symmetry. + if (b > 0) + d_min_search = rs[lo].first; + else if (per >= 400) + d_min_search = rs[per - 1].first; break; } }