WIP: doubled-cell rise must end at a quarter of the lattice's intensity

On strong data a class at one or two percent of the lattice rises significantly (0.009 to 0.059 at 4
standard errors on a ci-tier triclinic crystal, which was then adopted doubled and failed), and a half
cell missing a few percent of its intensity still describes the crystal. The doubled deposition ends
at 0.35-0.40, those classes at 0.06.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EizBKhTqrAYago9KJG3dA3
This commit is contained in:
2026-10-10 14:14:10 +02:00
co-authored by Claude Opus 5.5
parent 57543845c0
commit 7580256ac7
3 changed files with 16 additions and 6 deletions
+3 -2
View File
@@ -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
+10 -4
View File
@@ -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;
}
+3
View File
@@ -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]") {