From 39204e45d53243bc66b781f94a168779aeff9361 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 11 Nov 2026 19:16:03 +0100 Subject: [PATCH] RESULT-CHANGING: rotation indexer writes a primitive hexagonal lattice in its reduced-cell setting again Since LatticeSearch takes the Bravais class from the metric two-folds (LePage) where the 44-character table misses it, a metrically hexagonal cell that the table read as its ortho-hexagonal C cell comes back as hP in LePage's conventional basis - chosen from the strained cell, so one of the twelve equivalent hexagonal settings, and not necessarily the same one in the two passes. Before, the rotation indexer re-expressed that C cell itself, always from the reduced cell (HexagonalConventional). The rotation path is not invariant under that choice. The refinement and indexed-fraction gates measure the miss in fractional Miller units with an identity metric, which for a and b at 120 degrees changes with the setting, and the two-pass quality guard counts h00/0k0/00l rows of each pass's P1 merge, which are not the same rows in two settings. Measured: - six equivalent settings of one hexagonal small-molecule crystal (same binary, basis relabelled by a 622 operation) gave SHELXL R1 0.097-0.144 and a first-pass beam centre spread of 2.4 px; - on a P6122 protein set the refined pass's search merge counted 0 low-order axial reflections against the header pass's 28 in the LePage setting (28 against 28 in the reduced-cell one), the guard reverted to the header distance and the cell came out 0.44 % short (0.06 % before). A primitive hexagonal result is now written with HexagonalConventional of its reduced cell, whichever route named the class; the class itself still comes from LePage, so its gains (cubic F, the other classes, stills) stay. Subset vs the rc185 build (the commit's parent): the nine hexagonal and trigonal rotation sets and the in-house small molecules are back to their rc185 numbers (two hexagonal small-molecule sets SHELXL R1 0.110 -> 0.097 and 0.129 -> 0.116; ISa and cell recovered on 6pb3, 8a1a, 8v4o); the tetragonal small-molecule cuhf2 still differs (ISa 45.6 -> 41.8, not hexagonal). Against rc186 without it, the three F-cubic sets of the subset (3inp, 5epe, 6oel) are unchanged. The setting dependence itself is not fixed here: an invariant miss metric for the hexagonal gates and a setting-independent axial-row count would make the choice irrelevant. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HVeDQsU5a8AJUdJPgWevAK --- image_analysis/rotation_indexer/RotationIndexer.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/image_analysis/rotation_indexer/RotationIndexer.cpp b/image_analysis/rotation_indexer/RotationIndexer.cpp index 6720f93d2..fa6c7e111 100644 --- a/image_analysis/rotation_indexer/RotationIndexer.cpp +++ b/image_analysis/rotation_indexer/RotationIndexer.cpp @@ -333,7 +333,14 @@ void RotationIndexer::RunIndexingLocked() { // promotion of the same kind, so it is not applied here. if (demote_class && ClassImposesLengthEquality(ls.system)) return LatticeSearch(cand, /*dist_tolerance=*/0.0); - if (!IsHexagonalSystem(ls.system) && IsMetricallyHexagonal(ls.primitive_reduced)) { + // A primitive hexagonal lattice is written in ONE setting, the one derived from its reduced + // cell, whichever route named the class. Its twelve equivalent settings are the same + // lattice, but the run is not indifferent to which it gets: the fractional-index gates of + // the refinement and the axial-row count of the two-pass quality guard are not invariant + // under them, so a setting chosen afresh from each pass's strained cell lets the two + // passes differ in setting and the guard compare rows that are not the same rows. + if ((ls.system == gemmi::CrystalSystem::Hexagonal && ls.centering == 'P') + || (!IsHexagonalSystem(ls.system) && IsMetricallyHexagonal(ls.primitive_reduced))) { ls.conventional = HexagonalConventional(ls.primitive_reduced); ls.system = gemmi::CrystalSystem::Hexagonal; ls.centering = 'P';