Anisotropy: say what was measured, and stop crying wolf
Four reporting changes and a restored changelog line. The gate boundaries are unchanged - see below - and no merged number moves: .mtz and .hkl are byte-identical on two crystals, and REPORT_VERSION stays 3 because everything here is an added key or prose. A directional diffraction limit that is really the edge of the measured data was printed as if it were the crystal's. One crystal reported 1.09 / 0.99 / 0.99 A against a 0.994 A cutoff, so two of its three limits were the cutoff. A censored limit now prints with a "<" and sets ANISOTROPY_D_MIN_CENSORED. It fires on 4 of 28 crystals, and on two of those all three limits are censored, which means their reported directional spread was binning noise. The caution about a too-high symmetry assignment fired on every crystal with one deviatoric degree of freedom - every tetragonal, trigonal and hexagonal case, 17 of 38. A caution that fires on 45% of runs is noise. It is now conditional on the signature that actually indicates it, a large symmetry-forbidden signal with a gate that established nothing, and fires on 2 of 38: the crystal already on record as space-group unstable, and one other. The forbidden-direction z is now reported so the reader can see it; its battery median is 6.5. The verdict line quoted deltaB_linear while the headline reported deltaB, and the two differ - deltaB_linear is the larger on 12 of 31 crystals. It now writes out the arithmetic, says which number the gate tests, and says which to act on. The observation count the floor was measured on is reported, and the mmCIF verdict item carries its vocabulary like its neighbours. On the boundaries: they were calibrated against XDS-derived unmerged data, while production measures the floor from rugnux's own observations, and those disagree by 0.12x to 16.2x with 7 of 29 verdicts flipping. Re-measured on production input - by merging each cubic crystal in proper subgroups of its own Laue class, where the true anisotropy is exactly zero and every deltaB that comes back is manufactured - the false-positive rate is 24% at 2.0, 10% at 3.5 and 5% at 5.0. Each sits inside the published band read as its worst-case figure rather than its average. 3.5 maximises power minus false-positive rate across the grid; moving to 4.0 costs a real detection and reduces the false-positive rate by nothing. So the boundaries stay, and the "strong" band at 5.0 is a 5% statement on real data rather than the 0.5% its derivation suggested. The changelog entry for the diagnostic itself was committed with only its first line, having been extracted by a script that took one line of a four-line bullet. Restored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CHMmeM1d489zvNFT7ZMN2P
This commit is contained in:
@@ -309,12 +309,15 @@ void WriteMmcifReflections(const std::vector<MergedReflection> &reflections,
|
||||
if (std::isfinite(an.significance))
|
||||
out << "_reflns.jfjoch_aniso_significance " << Fmt(an.significance, 2)
|
||||
<< " # deltaB(linear) / floor\n";
|
||||
out << "_reflns.jfjoch_aniso_verdict " << AnisotropyVerdictCode(an.verdict) << "\n";
|
||||
out << "_reflns.jfjoch_aniso_verdict " << AnisotropyVerdictCode(an.verdict)
|
||||
<< " # DETECTED / NOT_DETECTED / CANNOT_DETERMINE, at deltaB(linear)/floor > 3.5\n";
|
||||
for (int i = 0; i < 3; ++i)
|
||||
if (std::isfinite(an.d_min_axis[i]))
|
||||
out << "_reflns.jfjoch_aniso_d_min_" << (i + 1) << " "
|
||||
<< Fmt(an.d_min_axis[i], 2)
|
||||
<< " # <I/sigma(I)> = 2 in a 20 deg cone about eigenvector " << (i + 1) << "\n";
|
||||
<< " # <I/sigma(I)> = 2 in a 20 deg cone about eigenvector " << (i + 1)
|
||||
<< (an.d_min_censored[i] ? "; at the edge of the measured data, so a bound" : "")
|
||||
<< "\n";
|
||||
}
|
||||
out << "#\n";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user