From da74197dea7fae0f9bae5a6ec2b233e7eea47fe2 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 31 Jul 2026 11:51:08 +0200 Subject: [PATCH] Stills partiality: an unmeasurable CC is not a reason to adopt the refined tilt The "keep what the crystal came in with" gate required std::isfinite(cc) before it would reject, so a refined model whose CC could not be measured at all was adopted. ImageReferenceCC returns NaN when fewer than 20 reflections clear the partiality cut - which is exactly what a refinement that collapsed the partialities produces, since the cut is on the partialities it just rewrote. The gate therefore failed open on precisely the crystals it exists to catch, and wrote the NaN into image_scale_cc, on which --min-image-cc then drops the image from the merge, the error model and the statistics. Treat a CC that cannot be measured as worse than one that can, so the crystal is put back exactly as it arrived. Co-Authored-By: Claude Opus 5 (1M context) --- image_analysis/scale_merge/StillsPartialityRefine.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/image_analysis/scale_merge/StillsPartialityRefine.cpp b/image_analysis/scale_merge/StillsPartialityRefine.cpp index 1df3787c..f01bae07 100644 --- a/image_analysis/scale_merge/StillsPartialityRefine.cpp +++ b/image_analysis/scale_merge/StillsPartialityRefine.cpp @@ -326,8 +326,11 @@ double StillsPartialityRefine::RefineOne(IntegrationOutcome &outcome, // Adopt the refined model only if it correlates with the reference at least as well as the model it // replaces. Rejecting puts the crystal back exactly as it arrived, which is the same state a - // crystal with too few reflections to fit ends in. - if (cc_before.has_value() && std::isfinite(*cc_before) && std::isfinite(cc) && cc < *cc_before) { + // crystal with too few reflections to fit ends in. A CC that cannot be measured at all counts as + // worse, not as no opinion: ImageReferenceCC returns NaN when too few reflections clear the + // partiality cut, which is precisely what a refinement that collapsed the partialities produces - + // and adopting it would leave image_scale_cc NaN, on which --min-image-cc drops the image outright. + if (cc_before.has_value() && std::isfinite(*cc_before) && !(std::isfinite(cc) && cc >= *cc_before)) { for (size_t i = 0; i < outcome.reflections.size(); ++i) { outcome.reflections[i].partiality = before[i].first; outcome.reflections[i].image_scale_corr = before[i].second;