diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 2c584ec46..cd6f7929e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -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. diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 2fa789964..3bdbfde8b 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -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; } diff --git a/rugnux/Rugnux.h b/rugnux/Rugnux.h index dc15d680d..e41bafc0e 100644 --- a/rugnux/Rugnux.h +++ b/rugnux/Rugnux.h @@ -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