From edc042aadfd2a925372efa81ac46647ab4816d2d Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 27 Aug 2026 16:04:37 +0200 Subject: [PATCH] Reindex into the ASU: follow the change of hand, not the hand landed on ReindexMergedIntoAsu swapped I(+)/I(-) whenever the reindexed index came out on the minus side of its Friedel pair. That is right only for a row that started on the plus side, which is every row when merge_friedel is set - and none of the problem cases. With the mates kept apart, the merge stores the plus mate at +hkl_asu and the minus mate at -hkl_asu (Merge.cpp), while RotationScaleMerge attaches I_plus / I_minus in the plus convention on both rows alike, keying the lookup at plus=true. An alternative-indexing operator is rotation-type, so op(-x) == -op(x) and the two mates always land on opposite sides: testing key.plus alone therefore swaps exactly one row of every pair, whichever way the operator went. The pair ends up self-contradictory, and the mmCIF's pdbx_I_plus / pdbx_I_minus and the F(+)/F(-) columns are swapped on half the rows. Reached by "rugnux -A --model model.pdb" - -A clears MergeFriedel - on a crystal whose indexing ambiguity the model resolves, which is the one path that both keeps the mates apart and reindexes. The swap now fires on was_plus != key.plus. With merge_friedel every row is stored at the ASU representative, so was_plus is always true and this reduces to the previous test; the existing change-of-hand case is unchanged. The test that covered the merge_friedel=false path checked only I, so it passed either way. The new one builds both mates of a pair and asserts they still agree about which intensity is which afterwards - an invariant that holds however the operator moves the hand, so it fails on the old code for either direction. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016L1qig74oYQzfUJJZbbxFh --- .../scale_merge/ReindexAmbiguity.cpp | 11 ++++- tests/ReindexAmbiguityTest.cpp | 48 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/image_analysis/scale_merge/ReindexAmbiguity.cpp b/image_analysis/scale_merge/ReindexAmbiguity.cpp index e72f6ed2..55336cf7 100644 --- a/image_analysis/scale_merge/ReindexAmbiguity.cpp +++ b/image_analysis/scale_merge/ReindexAmbiguity.cpp @@ -78,7 +78,16 @@ std::vector ReindexMergedIntoAsu(const std::vector 0, so the row that was the plus mate of its pair is the minus mate of + // the new one. The intensity now standing at the plus index is the one that was at -hkl before. + CHECK(out[0].I_plus == 90.0f); + CHECK(out[0].I_minus == 110.0f); +}