Three more cuts in the bytes the CPU scaling moves per iteration:
- The partials' working copy is ordered with the partials a group mean can take in first - in a
group and not below the partiality floor, ReferenceWeight's fixed tests - group by group in the
CSR's order, and all the others after them. The group means walk only the first part: a partial
they would skip anyway adds nothing to a sum, so no sum changes, and on a fine-sliced sweep about
half of the partials are rocking-curve tails below the floor. The others are read by nothing
during the loop, so their per-iteration corr updates are kept (a few per-frame arrays an
iteration) and applied to them once, in order, when the loop ends.
- ScalingFit holds the four floats the per-frame fit reads (20 bytes, was 32) and the fit works
out 1/sigma^2 and partiality/prescaling_corr from them where it uses them: the same expressions,
so the same doubles.
- The correction surfaces keep their group-ordered reference terms in one copy per frame parity,
so a cross-validation reference pass reads only its own half; a pass over all the terms walks a
group's two halves together in term order, which is the order the single copy had.
Samples in the partial loop on a 3600-frame set (perf, cycles, whole scaling-and-merging step):
group means 29.7k -> 15.1k, per-frame fit 22.4k -> 13.7k, the separate corr update pass 11.9k ->
gone. Wall time on the shared machine (load 26-33) is within its noise of the previous commit.
Validated with the battery against the start of the branch (873880bba), --no-gpu: p.hkl and MTZ
data byte-identical on 4nwv, 8qaw, 9v16, lyso_x06da_ref, cytc_x10sa, myob_x10sa and
yag_x10sa_20keV; the same bytes again at -N 11 on all seven; and on the GPU path the same bytes
on lyso_x06da_ref and 9v16.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4