From e123755c7dbf20633fede3545e42b65a6a4ec7cf Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Jul 2026 10:54:53 +0200 Subject: [PATCH] rugnux: carry the point-group promotion into the second pass The two-pass rotation run reinstates pass-1's space group for pass 2's merge, so pass 2 skips the search block entirely - and with it the flag that records that the Laue class was CHOSEN by the search rather than given. The canonical output therefore printed the plain "no twinning: the Laue class is holohedral, so no merohedral twin law exists", which is exactly the circular conclusion the flag was added to replace; only the throwaway _01 output carried the caveat. The text is written per pass, inside RunPipeline, so the flag has to travel with prepass_merge_sg_ rather than being patched onto the returned result. Co-Authored-By: Claude Opus 5 (1M context) --- rugnux/Rugnux.cpp | 6 +++++- rugnux/Rugnux.h | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 5f7e48e6..9342d875 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -235,6 +235,7 @@ ProcessResult Rugnux::Run(RugnuxObserver *observer) { force_rotation_result_.reset(); prepass_sg_reindexed_ = false; prepass_merge_sg_.reset(); + prepass_promoted_point_group_ = false; logger.Info("Rotation two-pass geometry post-refinement: first pass (header geometry) -> {}_01_*", base_prefix); @@ -258,6 +259,7 @@ ProcessResult Rugnux::Run(RugnuxObserver *observer) { // setting the de-novo primitive frame does not share, which is left to re-search. experiment_.SpaceGroupNumber(std::nullopt); prepass_merge_sg_ = prepass_sg_reindexed_ ? std::nullopt : pass1.space_group_number; + prepass_promoted_point_group_ = pass1.twinning.laue_class_was_chosen_by_promotion; logger.Info("Rotation two-pass geometry post-refinement: second pass (refined geometry, canonical) -> {}_*", base_prefix); @@ -1206,7 +1208,9 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b // True when the point group below was chosen BY THE SEARCH (rather than given by the user) and is // above triclinic - i.e. a promotion was made, which is what makes a later "the Laue class is // holohedral so there is no twin law" conclusion circular. - bool promoted_point_group = false; + // Pass 2 reuses pass-1's group instead of searching, so the promotion it needs to report was + // made there; a first / single pass has no carried-over group and decides this below. + bool promoted_point_group = prepass_merge_sg_.has_value() && prepass_promoted_point_group_; if (!experiment_.GetGemmiSpaceGroup().has_value()) { SearchSpaceGroupOptions sg_opts; sg_opts.merge_friedel = experiment_.GetScalingSettings().GetMergeFriedel(); diff --git a/rugnux/Rugnux.h b/rugnux/Rugnux.h index ddee7b78..196862a1 100644 --- a/rugnux/Rugnux.h +++ b/rugnux/Rugnux.h @@ -179,6 +179,12 @@ class Rugnux { // the second pass, and for a reindex-derived group (left to re-search). std::optional prepass_merge_sg_; + // Whether the group in prepass_merge_sg_ was PROMOTED by pass-1's search rather than given. Pass 2 + // reuses the group without searching, so it cannot work this out for itself - and without it the + // canonical output reports "the Laue class is holohedral, so no twin law exists" about a Laue class + // the search chose, which is the circular claim that reasoning exists to flag. + bool prepass_promoted_point_group_ = false; + // Stills global geometry-refinement first pass (config_.refine_geometry): index a spread sample of // frames, bundle-adjust the shared beam/distance/cell from the strongest ones, and apply the result // to experiment_ so the main pass re-indexes with it. No-op (leaves experiment_ unchanged) if it