diff --git a/image_analysis/scale_merge/SearchSpaceGroup.cpp b/image_analysis/scale_merge/SearchSpaceGroup.cpp index fd03e6fc..fe61e95e 100644 --- a/image_analysis/scale_merge/SearchSpaceGroup.cpp +++ b/image_analysis/scale_merge/SearchSpaceGroup.cpp @@ -640,6 +640,7 @@ SearchSpaceGroupResult SearchSpaceGroup( if (best_pg->representative) result.point_group_hm = best_pg->representative->point_group_hm(); + result.point_group_order = best_pg_order; // Only report a refusal that is actually ABOVE what was adopted. if (refused_order > best_pg_order) { diff --git a/image_analysis/scale_merge/SearchSpaceGroup.h b/image_analysis/scale_merge/SearchSpaceGroup.h index e8b93553..39e0a86d 100644 --- a/image_analysis/scale_merge/SearchSpaceGroup.h +++ b/image_analysis/scale_merge/SearchSpaceGroup.h @@ -219,6 +219,11 @@ struct SearchSpaceGroupResult { std::vector alternatives; std::string point_group_hm; // chosen point group, e.g. "422" + // Order of that point group (its number of rotations). Reported separately because Stage B can + // leave best_space_group unset - no candidate had enough absences to be eligible - while Stage A + // has confirmed the point group perfectly well, and a caller comparing two searches has to see + // the symmetry that was found either way. 0 only when no point group was chosen at all. + int point_group_order = 0; std::vector operator_scores; // Stage A, all distinct operators tested std::vector candidates; // Stage B, ranked diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 4b742832..c95bc3a2 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -1223,13 +1223,13 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b auto sm_all = scale_and_merge("P1, all observations", true); rsm->SetSearchMinZeta(zeta); const auto alt = SearchSpaceGroup(sm_all.merged, sg_opts); - // Point-group order = the number of rotations, which is what sym_ops holds (centering - // lives in cen_ops). Taken from the space group the search chose - a point-group symbol - // like "422" is not a space-group name and cannot be looked up. - const auto order_of = [](const SearchSpaceGroupResult &r) -> size_t { - return r.best_space_group.has_value() - ? r.best_space_group->operations().sym_ops.size() : 0; - }; + // The order of the point group each arm confirmed. Read from the search, not from the + // space group it went on to pick: Stage B leaves best_space_group unset when no + // candidate has enough absences to be eligible, which is common on the filtered arm + // precisely because the filter removes the weak reflections the absences live in. An + // arm that confirmed 422 would then have scored 0 and lost to a P2 arm - a demotion, + // reported as "taking the higher symmetry". + const auto order_of = [](const SearchSpaceGroupResult &r) { return r.point_group_order; }; logger.Info("Space-group search: all-observation merge -> {} (order {}), " "Lorentz-filtered -> {} (order {})", alt.point_group_hm.empty() ? "?" : alt.point_group_hm, order_of(alt),