Space-group search: log the refusal the two-merge rule overrides
When the all-observation and Lorentz-filtered search merges disagree, the
higher point group is adopted. The losing arm's answer was dropped, so a
promotion one arm refused on its twin gates (H ratio, added-operator R)
went through with nothing in the output saying a gate had fired - and the
report printed the adopted group's failing H ratio ("2.02 against a bound
of 1.85") as if it were a margin. Seen on an H3 partial twin (5j23),
refused on both twin gates by the all-observation merge and promoted to
R32 by the filtered one.
Now the losing arm's refusal (group and reason), or the fact that it never
confirmed the operators, is logged as a warning and written to the report
(SPACE_GROUP_ARM_OVERRIDE). A bound the adopted group exceeds is printed as
"EXCEEDS its bound - that gate fired and was overridden", for the H ratio
and for the best-operator R. The comment that claimed both arms keep their
vetoes now describes the rule as implemented. The rule itself is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
e715d3999e
commit
7ae1da277a
3 files changed
+50
-6
No files matched your search
+19
-2
@@ -528,9 +528,21 @@ ReportDocument BuildReportDocument(const std::string &output_prefix,
|
||||
// operator and candidate tables that justify it.
|
||||
std::string line = fmt::format(" Point group {} from the intensity correlations",
|
||||
search.point_group_hm);
|
||||
// A bound the adopted group EXCEEDS is a gate that fired and was overridden - the point group
|
||||
// was taken from the other search arm - and must not read as the margin of a pass.
|
||||
if (std::isfinite(search.h_ratio))
|
||||
line += fmt::format(";\n twin-law H ratio {:.2f} against a bound of {:.2f}",
|
||||
search.h_ratio, search.h_ratio_bound);
|
||||
line += search.h_ratio > search.h_ratio_bound
|
||||
? fmt::format(";\n twin-law H ratio {:.2f} EXCEEDS its bound of {:.2f} - that gate fired "
|
||||
"and was overridden", search.h_ratio, search.h_ratio_bound)
|
||||
: fmt::format(";\n twin-law H ratio {:.2f} against a bound of {:.2f}",
|
||||
search.h_ratio, search.h_ratio_bound);
|
||||
// The best-operator R gate is the one that applies once two operators are confirmed, i.e.
|
||||
// above order 2 (the first step out of P1 is judged on the noise floor instead).
|
||||
if (search.point_group_order > 2 && std::isfinite(search.r_over_best)
|
||||
&& search.r_over_best_bound > 0.0 && search.r_over_best > search.r_over_best_bound)
|
||||
line += fmt::format(";\n added-operator R {:.2f}x the best operator EXCEEDS its bound of {:.2f}x - "
|
||||
"that gate fired and was overridden", search.r_over_best,
|
||||
search.r_over_best_bound);
|
||||
line += ".\n The space group follows from the systematic absences.";
|
||||
if (!alts.empty())
|
||||
line += fmt::format("\n These data cannot separate it from {} - both are consistent with"
|
||||
@@ -541,6 +553,11 @@ ReportDocument BuildReportDocument(const std::string &output_prefix,
|
||||
" cannot name. Molecular replacement settles it: one of the two refines and the\n"
|
||||
" other does not - the normal outcome for a chiral group, not a failure of the\n"
|
||||
" run."));
|
||||
if (!result.space_group_arm_override.empty()) {
|
||||
Add(s, KeyText("SPACE_GROUP_ARM_OVERRIDE", result.space_group_arm_override));
|
||||
Add(s, Prose(fmt::format(" The two search merges disagreed and the higher point group was taken:\n {}.",
|
||||
result.space_group_arm_override)));
|
||||
}
|
||||
if (refused)
|
||||
Add(s, Prose(fmt::format(
|
||||
" A promotion to {} was refused: {}.\n"
|
||||
|
||||
+27
-4
@@ -5280,9 +5280,12 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b
|
||||
// rotations are real, because a promotion is refused by the most damning statistic it can
|
||||
// be shown and only one arm has to be starved for that to happen, while the ABSENCES are
|
||||
// always judged on the all-observation merge, which is the only one holding the weak
|
||||
// reflections a systematic absence is made of. Both searches keep their vetoes, so a merohedral twin
|
||||
// stays refused in each (verified on a real twin at the three frame ranges where it
|
||||
// over-promotes: refused in both arms every time).
|
||||
// reflections a systematic absence is made of. The vetoes are NOT kept per arm: a promotion
|
||||
// one arm refused on its twin gates (H ratio, added-operator R) is adopted when the other arm
|
||||
// confirms it, because the higher order wins. That held on one real twin at three frame
|
||||
// ranges, where both arms refused, but an H3 partial twin has been seen refused by the
|
||||
// all-observation arm on both twin gates and promoted to R32 by the filtered one. So the
|
||||
// losing arm's refusal is logged and carried to the report below; the rule is unchanged.
|
||||
if (rsm && rsm->GetSearchMinZeta() > 0.0 && !sg_search.point_group_hm.empty()) {
|
||||
const double zeta = rsm->GetSearchMinZeta();
|
||||
rsm->SetSearchMinZeta(0.0);
|
||||
@@ -5341,10 +5344,29 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b
|
||||
stats_text << " !! " << msg << "\n\n";
|
||||
result.warnings.push_back({PathologyCode::SYMMETRY_AMBIGUITY, msg});
|
||||
}
|
||||
if (order_of(alt) > order_of(sg_search))
|
||||
// The arm whose lower answer is about to be overridden, and why it stopped there. A
|
||||
// refusal by a consistency gate is the case that matters: the higher group is adopted
|
||||
// anyway, and without this nothing in the output says a gate ever fired.
|
||||
const auto overridden = [&](const SearchSpaceGroupResult &lower, const char *lower_name,
|
||||
const char *higher_name) {
|
||||
std::string msg;
|
||||
if (!lower.refused_point_group_hm.empty())
|
||||
msg = fmt::format("the {} merge REFUSED {} ({}); overridden, because the {} merge "
|
||||
"confirmed the higher point group", lower_name,
|
||||
lower.refused_point_group_hm, lower.refused_reason, higher_name);
|
||||
else
|
||||
msg = fmt::format("the {} merge did not confirm the operators of the higher point "
|
||||
"group (no gate refused it); the {} merge did", lower_name,
|
||||
higher_name);
|
||||
logger.Warning("Space-group search: {}", msg);
|
||||
result.space_group_arm_override = msg;
|
||||
};
|
||||
if (order_of(alt) > order_of(sg_search)) {
|
||||
logger.Info("Space-group search: all-observation merge supports {} where the "
|
||||
"Lorentz-filtered one supports {} - taking the higher symmetry",
|
||||
alt.point_group_hm, sg_search.point_group_hm);
|
||||
overridden(sg_search, "Lorentz-filtered", "all-observation");
|
||||
}
|
||||
if (order_of(alt) < order_of(sg_search)) {
|
||||
// The filtered arm found symmetry the all-observation arm did not. Discarding it
|
||||
// was costing real point groups: over the corpus the two arms disagree on eight
|
||||
@@ -5359,6 +5381,7 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b
|
||||
// that found it and the absences are re-judged here, on every observation. That
|
||||
// is what fixed_point_group is for: Stage A still runs and still reports what it
|
||||
// would have refused, only the choice is overridden.
|
||||
overridden(alt, "all-observation", "Lorentz-filtered");
|
||||
sg_opts.fixed_point_group = sg_search.point_group_representative;
|
||||
auto split = SearchSpaceGroup(sm_all.merged, sg_opts);
|
||||
sg_opts.fixed_point_group.reset();
|
||||
|
||||
@@ -334,6 +334,10 @@ struct ProcessResult {
|
||||
// populated only when a search ran (no space group was fixed). The library no longer renders it to
|
||||
// text - the CLI formats it for stdout, the viewer draws it as a table.
|
||||
std::optional<SearchSpaceGroupResult> space_group_search;
|
||||
// When the two search arms (all observations / Lorentz-filtered) disagreed and the higher point
|
||||
// group was taken from one of them: what the other arm said - which gate refused the promotion,
|
||||
// or that it never confirmed the operators. Empty when the arms agreed.
|
||||
std::string space_group_arm_override;
|
||||
|
||||
// ---- Material for the results report (<prefix>_report.txt, see rugnux/ResultReport.h) ----
|
||||
|
||||
|
||||
Reference in new issue
Block a user