Commit Graph
3 Commits
Author SHA1 Message Date
leonarski_fandClaude Opus 4.8 fbebc0d56e rugnux: run decay + absorption surfaces on the GPU and enable by default
The decay/absorption correction surfaces previously forced the CPU 3D
combine (absorption needs each full's predicted detector position, which
the GPU SoA did not carry), so they could not be default-on without losing
the fast GPU path. Put them on the GPU:

- carry px/py (peak partial) through the GPU combine and download them with
  the fulls (GetFullsPxPy);
- add SetFullsCorr to re-upload the host-corrected corr to the resident
  fulls before the merge.

The surfaces themselves stay as cheap host fits on the downloaded fulls;
only px/py download + corr upload are added (~two O(n_fulls) transfers).
Measured +2% wall-time on lyso_ref (9.7 -> 9.9 s), and the GPU-combine and
CPU-combine (--dump-observations) paths give identical results.

Enable by default via a single master toggle ScalingSettings::
CorrectionSurfaces (default true; decoupled from the stills-only -B, which
is rejected for rotation again). Both surfaces are cross-validated, so they
no-op where their systematic is absent - safe to leave on. Off-switch wired
through the rugnux CLI (--no-scaling-corrections; --absorption removed) and
the viewer (a "Correction surfaces" checkbox). Documented in docs/RUGNUX.md.

Battery (24 rotation crystals), default-on vs --no-scaling-corrections:
EcwtCQ066S +2.4 ISa, lyso_ref +0.5 (and R-free 0.194 -> 0.185, better than
XDS); every other crystal within run-to-run noise; corrections skip (CV /
dB-floor) wherever there is no signal. lyso_ref anomalous S/Cl peaks are
already ~45% above XDS's - the ISa gap is metric convention, not data.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 10:56:39 +02:00
leonarski_fandClaude Opus 4.8 bab52a8077 rugnux: optional decay + absorption correction surfaces for rotation scaling
Build Packages / build:viewer-tgz:cpu (push) Successful in 7m49s
Build Packages / build:viewer-tgz:cuda (push) Successful in 8m34s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m20s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m25s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m22s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m44s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m10s
Build Packages / build:windows:nocuda (push) Successful in 17m56s
Build Packages / build:windows:cuda (push) Successful in 20m2s
Build Packages / build:rpm (rocky8) (push) Successful in 11m26s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 12m38s
Build Packages / XDS test (durin plugin) (push) Successful in 7m38s
Build Packages / Generate python client (push) Successful in 33s
Build Packages / Build documentation (push) Successful in 1m5s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2404) (push) Successful in 12m36s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m46s
Build Packages / build:rpm (rocky9) (push) Successful in 13m23s
Build Packages / DIALS test (push) Successful in 14m16s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m42s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 8m52s
Build Packages / Unit tests (push) Successful in 1h14m38s
Build Packages / Unit tests (pull_request) Successful in 58m48s
Build Packages / build:windows:nocuda (pull_request) Successful in 10m11s
Build Packages / build:viewer-tgz:cpu (pull_request) Successful in 6m29s
Build Packages / build:viewer-tgz:cuda (pull_request) Successful in 7m14s
Build Packages / build:rpm (rocky8_nocuda) (pull_request) Successful in 9m56s
Build Packages / build:rpm (rocky9_nocuda) (pull_request) Successful in 11m7s
Build Packages / build:rpm (ubuntu2204_nocuda) (pull_request) Successful in 10m51s
Build Packages / build:rpm (ubuntu2404_nocuda) (pull_request) Successful in 9m23s
Build Packages / build:rpm (rocky8_sls9) (pull_request) Successful in 11m13s
Build Packages / build:rpm (rocky9_sls9) (pull_request) Successful in 11m22s
Build Packages / build:rpm (rocky8) (pull_request) Successful in 11m30s
Build Packages / build:rpm (rocky9) (pull_request) Successful in 12m25s
Build Packages / build:rpm (ubuntu2204) (pull_request) Successful in 10m51s
Build Packages / build:rpm (ubuntu2404) (pull_request) Successful in 11m33s
Build Packages / DIALS test (pull_request) Successful in 12m9s
Build Packages / XDS test (durin plugin) (pull_request) Successful in 7m59s
Build Packages / XDS test (JFJoch plugin) (pull_request) Successful in 6m58s
Build Packages / XDS test (neggia plugin) (pull_request) Successful in 6m8s
Build Packages / Generate python client (pull_request) Successful in 17s
Build Packages / Build documentation (pull_request) Successful in 50s
Build Packages / Create release (pull_request) Skipped
Build Packages / build:windows:cuda (pull_request) Successful in 12m40s
After scale-fulls, RotationScaleMerge can now fit two optional
multiplicative corrections on the combined fulls (both off by default,
rotation only):

- -B (decay): a global Debye-Waller relative-B rate for radiation damage,
  ln(Iref/Iobs) = 2 (dB/dn)(n - nbar) s^2, folded into the per-full scale.
  Engages only above a physical floor (total relative-B > 2 A^2), so it is
  a no-op on low-dose data. (-B was previously rejected for rotation.)
- --absorption[=iter]: a smooth factor over the diffracted-beam direction
  in the goniometer frame (predicted detector position de-rotated by the
  spindle, so a crystal-frame direction is sampled at many angles). Wires
  the existing ScalingSettings::absorption_iter scaffold. Negligible at
  hard X-rays; matters at low energy. On lyso_ref it is ISa-neutral (+0.5)
  but drops R-free 0.219 -> 0.212 against the deposited model: a smooth
  absorption error cancels among symmetry mates (small ISa effect) yet
  still biases the intensities (real R-free effect).

Both are CROSS-VALIDATED: the surface is fit on even frames and applied
only if it improves the held-out odd-frame equivalent agreement by a clear
margin (and vice versa), so a fit to noise where the systematic is absent
does not generalize and is discarded - the correction never adds scatter.
Battery: EcwtCQ066S +2.4 ISa, lyso_ref R-free win, others neutral.

Also fixes a latent bug this exposed: the GPU->host corr download before
the CPU 3D-combine was gated on --dump-observations only, so any other
forced-CPU-combine path (the new -B/--absorption) read a stale host corr
and mis-scaled every full. The download condition now matches the
CPU-combine condition.

Predicted detector position (px, py) is carried on the combined fulls for
the absorption surface (CPU combine only; unused by the GPU SoA path).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 10:14:00 +02:00
leonarski_fandClaude Opus 4.8 f737424bdf rugnux: move rugnux_cli.cpp from tools/ to rugnux/
The offline analysis CLI belongs next to its Rugnux library. Move the source and
the ADD_EXECUTABLE(rugnux ...) target (plus the Windows wingetopt link) into
rugnux/CMakeLists.txt; the ../reader, ../common, ../image_analysis includes are
unchanged (both dirs sit one level under the root) and ../rugnux/Rugnux.h becomes
a local Rugnux.h. rugnux/ is added before tools/ in every build config, so
viewer-only and Windows packages still get the CLI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 22:39:12 +02:00