rugnux: the two-pass guard says when it has no completeness, instead of printing 0.0%
The guard that judges the post-refined pass against the header-geometry pass reads completeness off
each pass's space-group search merge. That merge does not count possible reflections, so the quotient
is 0.0 on both sides and every de-novo rotation report has been printing
completeness 0.0% vs 0.0%, CC1/2 before corrections 0.994 vs 0.993
as though a comparison had happened. On the 28-dataset in-house battery that is all 28 runs. The
number is not just uninformative, it is a test that did not run: "completeness above 100% means the
cell is wrong" is the guard's wrong-cell arm, and it cannot fire against a constant zero, so only the
CC1/2 arm decides - which is computed on whatever data the pass kept, so a pass that discards a large
part of the sweep can post an equal CC1/2 and win.
Carry a measured flag beside the number. The arm is skipped and the log and PASS_DECISION say
"completeness not measured" where there is nothing to read. No behaviour changes: the arm could not
fire before either. The next commit gives the merge the count so it can.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
* The `rugnux` report gives the twinning statistics measured before the space group was decided, beside the ones measured after.
|
||||
* The `rugnux` report gives the strong-direction diffraction limit, and warns when CC1/2 is not monotone with resolution.
|
||||
* `rugnux` ranks screw axes on the evidence their absences carry, rather than on how many control reflections a candidate happens to have.
|
||||
* The `rugnux` two-pass decision no longer reports a completeness it did not measure.
|
||||
* Twinning is no longer reported when the L-test contradicts it.
|
||||
* The `rugnux` report gives the detector tilt, the measured tilt and the direct beam beside the beam centre, and a post-refined beam centre is judged against the run's own measurement rather than the file's.
|
||||
* `--no-refine-tilt` holds the detector tilt at the value in the file, instead of zeroing it, when the calibration starts from the spots.
|
||||
|
||||
+18
-11
@@ -1612,17 +1612,24 @@ ProcessResult Rugnux::RunAllPasses(RugnuxObserver *observer) {
|
||||
if (!cancelled_ && pass1.has_merge_statistics && pass2.has_merge_statistics) {
|
||||
const double compl1 = pass1.search_merge_completeness;
|
||||
const double compl2 = pass2.search_merge_completeness;
|
||||
const bool compl_measured = pass1.search_merge_completeness_measured
|
||||
&& pass2.search_merge_completeness_measured;
|
||||
// Say so rather than printing a zero that reads as a measurement.
|
||||
const auto compl_text = [&] {
|
||||
return compl_measured ? fmt::format("completeness {:.1f}% vs {:.1f}%", compl2, compl1)
|
||||
: std::string("completeness not measured");
|
||||
};
|
||||
const double cc1 = pass1.search_merge_cc_half;
|
||||
const double cc2 = pass2.search_merge_cc_half;
|
||||
constexpr double MAX_CREDIBLE_COMPLETENESS = 100.5; // rounding headroom, nothing more
|
||||
constexpr double MAX_CC_HALF_LOSS = 0.05;
|
||||
if (pass2.lattice_conflicts_with_fixed_sg
|
||||
|| compl2 > MAX_CREDIBLE_COMPLETENESS || cc2 < cc1 - MAX_CC_HALF_LOSS) {
|
||||
|| (compl_measured && compl2 > MAX_CREDIBLE_COMPLETENESS)
|
||||
|| cc2 < cc1 - MAX_CC_HALF_LOSS) {
|
||||
logger.Warning("Two-pass: the refined pass is worse than the header-geometry pass "
|
||||
"(completeness {:.1f}% vs {:.1f}%, CC1/2 before corrections {:.3f} vs "
|
||||
"{:.3f}) - going back to the header geometry. The refined geometry did "
|
||||
"not help this crystal.",
|
||||
compl2, compl1, cc2, cc1);
|
||||
"({}, CC1/2 before corrections {:.3f} vs {:.3f}) - going back to the "
|
||||
"header geometry. The refined geometry did not help this crystal.",
|
||||
compl_text(), cc2, cc1);
|
||||
// The refined pass has already written the canonical files, so re-run at the header
|
||||
// geometry to replace them - the same remedy the supercell collapse above uses, and it
|
||||
// only costs a pass on a crystal that was going to be wrong otherwise.
|
||||
@@ -1644,15 +1651,14 @@ ProcessResult Rugnux::RunAllPasses(RugnuxObserver *observer) {
|
||||
redo.pass_count = pass2.pass_count + 1;
|
||||
redo.pass_decision = fmt::format(
|
||||
"header geometry re-adopted: the post-refined pass was worse "
|
||||
"(completeness {:.1f}% vs {:.1f}%, CC1/2 before corrections {:.3f} vs {:.3f})",
|
||||
compl2, compl1, cc2, cc1);
|
||||
"({}, CC1/2 before corrections {:.3f} vs {:.3f})",
|
||||
compl_text(), cc2, cc1);
|
||||
return redo;
|
||||
}
|
||||
if (pass2.pass_decision.empty())
|
||||
pass2.pass_decision = fmt::format(
|
||||
"post-refined geometry adopted (completeness {:.1f}% vs {:.1f}%, "
|
||||
"CC1/2 before corrections {:.3f} vs {:.3f})",
|
||||
compl2, compl1, cc2, cc1);
|
||||
"post-refined geometry adopted ({}, CC1/2 before corrections {:.3f} vs {:.3f})",
|
||||
compl_text(), cc2, cc1);
|
||||
}
|
||||
if (pass2.pass_decision.empty())
|
||||
pass2.pass_decision = (prepass_detector_geometry_ || prepass_rotation_scale_)
|
||||
@@ -3490,7 +3496,8 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b
|
||||
// surfaces - where their final merges need not even be in the same group. See RunAllPasses.
|
||||
{
|
||||
const auto &o = sm.statistics.overall;
|
||||
result.search_merge_completeness = o.possible_unique_reflections > 0
|
||||
result.search_merge_completeness_measured = o.possible_unique_reflections > 0;
|
||||
result.search_merge_completeness = result.search_merge_completeness_measured
|
||||
? 100.0 * o.unique_reflections / o.possible_unique_reflections : 0.0;
|
||||
result.search_merge_cc_half = sm.cc_half_before_corrections;
|
||||
}
|
||||
|
||||
@@ -244,6 +244,9 @@ struct ProcessResult {
|
||||
// The final merges of the two passes can be in different groups, where completeness and CC1/2 are
|
||||
// no longer the same measurement; this merge is in the same terms on both sides.
|
||||
double search_merge_completeness = 0.0;
|
||||
// False when the merge had no cell to enumerate possible reflections against, so the guard is told
|
||||
// not to test a number it does not have and the log says so instead of printing a zero.
|
||||
bool search_merge_completeness_measured = false;
|
||||
double search_merge_cc_half = NAN;
|
||||
|
||||
// Per-reflection (I, sigma) of the final merged reflections, for the ISa diagnostic: I/sigma
|
||||
|
||||
Reference in New Issue
Block a user