From 56216050bf3889db877cf1eec77911372f9323f3 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 28 Oct 2026 11:01:15 +0100 Subject: [PATCH] RESULT-CHANGING: post-refinement fits the lattice in the fixed space group's setting With -S (or a group taken from --model / -z), ScaleMergeAndSymmetry re-seats the integrated reflections into the fixed group's Bravais setting when the indexed lattice's centring or metric does not carry it - but the rotation geometry post-refinement was then handed the indexer's lattice in the OLD setting beside the re-seated indices. Every Miller index was predicted against the wrong basis: the held-out residual started ~5 orders of magnitude above a de-novo run's, the joint fit used every step and "never settled", the rotation scale ran to its 0.95 bound, the detector geometry (including a ~6 px header beam-centre error) was left at the header, and the end of the sweep was then rejected as radiation damage. The lattice now goes across with the reflections (the same composed change of basis the reflections received), and the fit is parameterised in the class it is now held to. Runs without a fixed group never re-seat before the post-refinement and are unchanged. Measured on a split-domain C2 crystal with a ~6 px header beam-centre error: -S, -S -C and --model -z now commit the post-refinement, move the centre as the de-novo run does, reject no frames and reach ISa ~15 (was ~12.3), matching the de-novo run. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HVeDQqN9qRD57vnShzTC37 --- rugnux/RugnuxScaleMerge.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rugnux/RugnuxScaleMerge.cpp b/rugnux/RugnuxScaleMerge.cpp index 42c41b648..0afb9533d 100644 --- a/rugnux/RugnuxScaleMerge.cpp +++ b/rugnux/RugnuxScaleMerge.cpp @@ -975,13 +975,22 @@ bool Rugnux::ScaleMergeAndSymmetry(PipelineLocals &p) { } } if (result.consensus_cell.has_value()) { - const auto rot = indexer->FinalizeRotationIndexing(); + auto rot = indexer->FinalizeRotationIndexing(); indexer->RethrowIndexerError(); if (rot && rot->axis) { if (geometry_prepass) prepass_result_ = *rot; // full result (lattice+geom+axis), for the supercell fallback PostRefineSettings prs; prs.crystal_system = rot->search_result.system; + // The reflections were re-seated into the fixed space group's setting above, so the + // lattice they are fitted against has to go across with them, in the class it is now + // held to. Left in the indexer's setting, every index was another reflection's: on a + // P-indexed lattice reseated into C2 the held-out residual started 5 orders of magnitude + // above the bare run's, the fit never settled and the header's centre error stayed. + if (end_msg.reindex_matrix) { + rot->lattice = rot->lattice.Multiply(stored_to_final); + prs.crystal_system = end_msg.rotation_lattice_type->crystal_system; + } prs.num_threads = static_cast(config_.nthreads); prs.refine_geometry = true; // Only a pass still at the file's distance can hold it as a hypothesis; a pass