From 8cb1cacadf8341ca963a56e6fb51c19299f1a67d Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 29 Jul 2026 08:27:43 +0200 Subject: [PATCH] rugnux: show the space-group search on rotation data The search runs in pass 1 of the rotation two-pass; pass 2 only reuses the group it decided, so the result the CLI renders carried no search at all and the whole report - operator correlations, the space-group candidate table, the refused higher symmetry - was silently dropped on every rotation dataset. Most costly of all, the "or (indistinguishable from these data)" line never appeared, so an enantiomorphic pair the intensities genuinely cannot separate was reported as a single answer. Carry pass 1's search into the returned result. Also de-duplicate the alternatives when the centred-lattice test swaps the metric-matching candidate into the answer: the group it displaced was left out and the chosen one listed twice ("C2 or P21 or C2"). Co-Authored-By: Claude Opus 5 (1M context) --- rugnux/Rugnux.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 7ebc3be7..4b742832 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -286,6 +286,11 @@ ProcessResult Rugnux::Run(RugnuxObserver *observer) { force_rotation_result_.reset(); } } + // The space group was DECIDED in pass 1 and only reused by pass 2, which therefore has no search + // of its own to report. Carry pass 1's over, or the evidence behind the decision (operator CCs, + // absence counts, the refused higher symmetry) is never shown on the default rotation path. + if (!pass2.space_group_search.has_value()) + pass2.space_group_search = pass1.space_group_search; return pass2; } return RunPipeline(observer, /*write_output=*/true, /*geometry_prepass=*/false); @@ -1351,6 +1356,15 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b // cell we reindex into - otherwise the space group and the written cell disagree. if (chosen.centring_type() == cand.centering) { sg_search = s2; + // Swap the metric-matching candidate into the answer and leave the one it + // displaced among the alternatives, so the reported "or ..." list stays the + // set of groups the data cannot separate, each named once. + if (chosen.number != s2.best_space_group->number) { + sg_search.alternatives.push_back(*s2.best_space_group); + std::erase_if(sg_search.alternatives, [&](const gemmi::SpaceGroup &a) { + return a.number == chosen.number; + }); + } sg_search.best_space_group = chosen; commit_reindex = reindex; commit_cell = cand.conventional.GetUnitCell();