From 24ac1a90fc797a560ee5dbb96a541cfbe56e6838 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Aug 2026 22:20:43 +0200 Subject: [PATCH] rugnux: name every space group the data cannot separate in the summary The search already knows when several groups share an absence pattern - it scores them identically, marks them all in the candidate table and prints "Best space group: I23 or I213 (indistinguishable from these data)". The one-line summary then dropped that and reported only the representative, so the run's headline answer claimed a decision the diffraction had not made. Carry the alternatives through to the summary. It already has them: ProcessResult holds the whole SearchSpaceGroupResult. Space group: I23 (No. 197) or I213 (No. 199) - indistinguishable from these data Some of these pairs are enantiomorphs (P4_1 vs P4_3), where the choice needs phasing or anomalous signal. Others are not, and are worth naming because they surprise: I23 vs I2_13 and I222 vs I2_12_12_1 differ only by a screw whose condition h00: h=2n is ALREADY implied by the I-centering condition h+k+l=2n, so the screw has no observable signature at all. Checked over 35936 reflections with gemmi, the two absence patterns are identical - not nearly, but exactly. Of the 65 chiral space groups, 13 classes are indistinguishable this way, the largest being the four-way P3_112 / P3_121 / P3_212 / P3_221. The representative stays the lowest space-group number, which is why a cubic insulin comes out I23 where the deposited convention is I2_13. That choice is a convention and the summary now says so instead of implying it was measured. Co-Authored-By: Claude Opus 5 (1M context) --- rugnux/rugnux_cli.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/rugnux/rugnux_cli.cpp b/rugnux/rugnux_cli.cpp index 5b87e72c..3693c421 100644 --- a/rugnux/rugnux_cli.cpp +++ b/rugnux/rugnux_cli.cpp @@ -1742,8 +1742,20 @@ static int RunRugnux(int argc, char **argv) { if (result.space_group_number.has_value() && anything_indexed) { const gemmi::SpaceGroup *sg = gemmi::find_spacegroup_by_number( static_cast(result.space_group_number.value())); - std::cout << fmt::format("Space group: {} (No. {})", sg ? sg->short_name() : "?", - result.space_group_number.value()) << std::endl; + std::string line = fmt::format("Space group: {} (No. {})", sg ? sg->short_name() : "?", + result.space_group_number.value()); + // Name every group the data cannot separate, not just the representative. Some pairs share + // their whole absence pattern - an enantiomorphic pair (P4_1 vs P4_3), or I23 vs I2_13 and + // I222 vs I2_12_12_1, where the screw condition h00: h=2n is already implied by the + // I-centering - so the choice among them is a convention, not a measurement. The search + // reports the representative as the lowest space-group number; saying so here keeps the + // summary from claiming a decision the diffraction did not make. + if (result.space_group_search.has_value()) + for (const auto &alt : result.space_group_search->alternatives) + line += fmt::format(" or {} (No. {})", alt.short_name(), alt.number); + if (result.space_group_search.has_value() && !result.space_group_search->alternatives.empty()) + line += " - indistinguishable from these data"; + std::cout << line << std::endl; } if (result.consensus_cell.has_value() && anything_indexed) { const auto &c = result.consensus_cell.value();