diff --git a/docs/RUGNUX_REPORT.md b/docs/RUGNUX_REPORT.md index 74166f671..bfe6f1c9d 100644 --- a/docs/RUGNUX_REPORT.md +++ b/docs/RUGNUX_REPORT.md @@ -619,8 +619,9 @@ under the `SUPERCELL_POSSIBLE` flag, and the summary's `Supercell` line carries **Both cells merged.** Where the class stands clear of the six empty ones out to the limit (in at least three shells measured above its noise, at more than twice the strongest of them in standard errors) and -grows significantly with resolution - the half cell holds at low resolution and not at high, the shape of -a pseudo-translation breaking down - the run integrates and merges the doubled cell as well, on the same +grows significantly with resolution to a quarter of the lattice's intensity or more in the finest shell +both are measured in - the half cell holds at low resolution and not at high, the shape of a +pseudo-translation breaking down - the run integrates and merges the doubled cell as well, on the same orientation and geometry, and decides with both merges in hand. The size of the class does not decide it - crystals deposited in the half cell carry classes as strong as one deposited in the doubled cell. The doubled cell is the answer only where, in the doubled merge, one translation - half a cell plus a diff --git a/rugnux/RugnuxPasses.cpp b/rugnux/RugnuxPasses.cpp index 0b16e0b6f..c2e229fbf 100644 --- a/rugnux/RugnuxPasses.cpp +++ b/rugnux/RugnuxPasses.cpp @@ -1446,7 +1446,13 @@ bool DoubledCellWorthMerging(const ProcessResult::SupercellClass &sc) { std::string DoubledCellRises(const ProcessResult::SupercellClass &sc) { // From the coarsest shell to the finest one both are measured in, the class has to grow by three - // standard errors of the difference: a significant rise, not a size. + // standard errors of the difference, and end at a quarter of the lattice's intensity or more. The + // rise alone is not enough: on strong data a class at one or two percent of the lattice rises + // significantly (measured: 0.009 to 0.059 at 4 standard errors on a triclinic crystal, and 0.000 to + // 0.060 on a cubic one), and a half cell missing a few percent of the intensity still describes the + // crystal. The quarter sits far from both sides: the doubled deposition ends at 0.35-0.40, those two + // at 0.06. + constexpr double DOUBLED_CELL_OUTER_EXCESS = 0.25; if (sc.trend.empty() || !DoubledCellShellMeasured(sc.trend.front())) return {}; const auto &low = sc.trend.front(); @@ -1455,7 +1461,7 @@ std::string DoubledCellRises(const ProcessResult::SupercellClass &sc) { if (DoubledCellShellMeasured(sh)) outer = &sh; const double se = std::hypot(low.excess / low.z, outer->excess / outer->z); - if (outer == &low || outer->excess - low.excess < 3.0 * se) + if (outer == &low || outer->excess - low.excess < 3.0 * se || outer->excess < DOUBLED_CELL_OUTER_EXCESS) return {}; return fmt::format("the added class grows from {:.3f} of the lattice's intensity at {:.0f}-{:.0f} A to {:.3f} at " "{:.1f}-{:.1f} A ({:.0f} standard errors): the half cell holds at low resolution and not at high", @@ -1616,8 +1622,8 @@ ProcessResult Rugnux::DoubledCellHypothesis(RugnuxObserver *observer, ProcessRes const std::string rises = DoubledCellRises(sc); if (rises.empty()) { logger.Info("Doubled-cell hypothesis: the half-integer class {} {} {} stands clear of the other classes but " - "does not grow significantly with resolution, so the half cell describes the crystal as well " - "at high resolution as at low - not merged", sc.h, sc.k, sc.l); + "does not grow with resolution to a quarter of the lattice's intensity, so the half cell describes " + "the crystal at high resolution too - not merged", sc.h, sc.k, sc.l); return half; } diff --git a/tests/RugnuxTest.cpp b/tests/RugnuxTest.cpp index 7e7dbdaff..f8292f749 100644 --- a/tests/RugnuxTest.cpp +++ b/tests/RugnuxTest.cpp @@ -380,6 +380,9 @@ TEST_CASE("DoubledCellDecision", "[process]") { // A class no stronger than the null: nothing. const auto null_class = trend({{0.01, 4, 20}, {0.02, 5, 10}, {0.03, 2, 5}, {0.05, 1, 2}}); CHECK(!DoubledCellWorthMerging(null_class)); + // A class that rises significantly but stays a few percent of the lattice: the half cell holds. + const auto small = trend({{0.009, 40, 500}, {0.014, 60, 300}, {0.016, 90, 170}, {0.03, 60, 50}, {0.06, 40, 2}}); + CHECK(DoubledCellRises(small).empty()); } TEST_CASE("FitDoubledClassTranslation", "[process]") {