Per-frame scale choice: an error model counts as resolved when the bootstrap bounds ISa

The choice between the partials-scaled and fulls-alone per-frame scale read an
error model as resolved only when the bin fit's b was two standard errors clear
of zero. The bin fit reads a b too small for its 16 bins to measure exactly as
it reads one that failed, so a merge that got better - a sweep whose dead second
half had been removed, its ISa bounded on both sides by the bootstrap over the
reflections - was taken for a failed scale, and the fulls-alone arm, with nothing
resolved either, won by default. Resolved is now either test saying so.

On the rc181 battery logs this flips no arm decision; it only skips running the
fulls arm where partials were chosen anyway. One private set moves to the
fulls-alone arm, now resolved by the bootstrap (ISa up, merging statistics equal).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UqXYdL4qBGYRiSXSGXfCLu
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-11-04 21:53:52 +01:00
1 parent 3beb19f09f
commit ce2d2280fd
2 files changed
+12 -4

No files matched your search

@@ -6407,8 +6407,9 @@ RotationScaleMerge::Result RotationScaleMerge::MergeAndStats(int n_groups, bool
// What the report prints of ISa: the interval of b^2 by a bootstrap over the reflections of the
// pool the reported fit was handed. The two-SE test above reads its error off how far the 16 bins
// miss the two-term line, which does not shrink with more data, so on a full sweep it can refuse a
// b that every resampling of the reflections reproduces. Report-only - nothing below reads it -
// and only where there is a fit to resample: b measured, a off its clamp, the final statistics.
// b that every resampling of the reflections reproduces. The report prints it, and the choice of
// the per-frame scale (ErrorModelResolved) reads it; only where there is a fit to resample: b
// measured, a off its clamp, the final statistics.
sub("isa bootstrap");
if (full_stats && error_model_active && chi2_pool && !error_model_b_unmeasured && !error_model_a_at_bound) {
// 50 replicates of at most 100k samples each, one per thread: 0.2-0.5 s a merge on 8 threads.
@@ -7123,8 +7124,14 @@ namespace {
// rocking events per frame the partials' scale read ISa 10.5 against 8.7 from the fulls alone, and
// SHELXL R1 0.105 against 0.062 - the partiality-model error the partial scale takes up is shared by
// symmetry mates measured at the same rocking geometry, so their agreement cannot see it.
//
// Resolved is either test saying so: the bin fit's b two standard errors clear of zero, or the
// bootstrap over the reflections bounding ISa from above. The bin fit alone reads a b too small for
// its 16 bins to measure exactly as it reads one that failed, so a merge that got BETTER - a sweep
// whose dead second half had been removed, its ISa bounded on both sides by the bootstrap - was
// taken for a failed scale, and the fulls-alone arm, with nothing resolved either, won by default.
bool ErrorModelResolved(const RotationScaleMerge::Result &r) {
return r.isa_resolved && std::isfinite(r.isa) && r.isa > 0.0;
return (r.isa_resolved || std::isfinite(r.isa_high)) && std::isfinite(r.isa) && r.isa > 0.0;
}
bool PartialScalingWins(const RotationScaleMerge::Result &with, const RotationScaleMerge::Result &without,
@@ -114,7 +114,8 @@ public:
bool isa_resolved = true;
// The 95% interval of `isa` by a bootstrap over the reflections, which is what the report prints;
// isa_high is infinite where b's interval reaches zero (ISa >= isa_low), both NaN where there was
// no fit to resample. Report-only.
// no fit to resample. A finite isa_high also counts as resolved where the per-frame scale is chosen
// (ErrorModelResolved).
double isa_low = std::numeric_limits<double>::quiet_NaN();
double isa_high = std::numeric_limits<double>::quiet_NaN();
double error_model_a = 0.0; // XDS convention: sigma^2 = a*(sigma0^2 + b*I^2)