Commit Graph
2 Commits
Author SHA1 Message Date
leonarski_f 6326c8b301 beam centre: the capture's transforms run on the GPU, and the CPU stays the fallback
BeamCenterFFTScore is split the way the FFT indexer is: an engine interface with a cuFFT
implementation and an fftw3f one, chosen by whether CUDA is compiled in, a device is visible
and the card has room for the image. Everything that decides anything - the preparation, the
masked Pearson, the shortlist and the margins - is shared, so the engines can differ only in
how the four convolutions are computed, and the parity test compares two shortlists rather
than two answers.

The whole-detector transform was the entire added cost of the capture (4-15 s a run on CPU,
all of it the transforms). On the device it is milliseconds, so the composition is now
cheaper than the walk it replaced rather than dearer - which is what makes 2x2 binning, the
other way out, unnecessary: full resolution is affordable and the binned capture was measured
to pick a neighbouring peak on one dataset of 51.

Device discipline, because the card is shared with the run's own analysis workers: the four
convolution surfaces are brought back to the host and combined there, so the device holds
only one real buffer and three spectra; the spectrum of the image is reused for its square;
plans and buffers are created inside the call that needs them and freed when it returns; and
an image that would not fit is scored on the CPU instead.

Tests, none of which need a GPU or a dataset: the autoconvolution identity (an exactly
symmetric image is recovered at integer and half-pixel centres, scoring exactly 1), shift
equivariance, the four convolutions against brute force, the no-variance overlap that
VARIANCE_FLOOR exists for, the smooth pad, GPU against CPU, and the composition - a walk
seeded at the capture where the walk alone declines, the fallback to the capture alone at
BEAM_CENTER_CAPTURE_SIGMA_PXL, and the beam stop being blanked out of the scored image.
2026-09-13 07:37:05 +02:00
leonarski_fandClaude Opus 5 1d1d7fd686 rugnux: whole-detector FFT beam-centre capture, measured on every run, consumed by none
The centrosymmetry score of the pre-scan projection is a self-convolution, so one FFT set
scores every candidate centre on the detector at half-pixel spacing - the cost is O(N log N)
and independent of how far the header centre is from the truth, where every existing search
pays per pixel of error. BeamCenterFFT computes the 2D point-inversion score (a background
measurement, the physics FindBeamCenterFromBackground fits locally) and the two 1D line-mirror
scores (for the along-spindle coordinate this is exact Friedel physics, sharp exactly where
the indexing count is blind), and returns a non-maximum-suppressed shortlist plus a
peak-to-runner-up margin per surface - a shortlist and a margin, never a centre: measured on
17 datasets the surface can be locally flat (~25 px), and the margin is what says so.

Measured on the gross-header cases that motivate it (offline, float64 reference): a header
351 px wrong is captured at rank 1 within 1.0 px from 30 frames, and still from a 30 deg
wedge; two 73 px placeholder headers at rank 1 within 0.5 px; a dataset whose header is
~170 px wrong but which no centre can index is flagged by the lowest margin of the set
(0.8 %) instead of being answered confidently. Capture survives 30-120 deg wedges on all
four sets tried (union of 8 candidates within 6 px everywhere).

Numerics: fftwf (the tree's FFTW is single precision) with the valid-pixel mean subtracted
before the transform - the masked Pearson is exactly invariant under a global shift, and the
subtraction removes the large-term cancellation - and the per-element combination done in
double. Against the float64 numpy reference the shortlist positions are identical and the
margins agree to 3e-6 absolute on the two controls whose margins are 0.3 %. An overlap with
no image variance (a mirrored empty region) carries no evidence and minted r values of 4-274
in float64 as much as float32; such centres are now not scored (VARIANCE_FLOOR).

Wired report-only into the pre-scan next to the background estimate: one log line with the
strongest candidates, the margins and the wall time. Nothing consumes it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GxZqDiFP3KqriBhNdcR56
2026-09-13 07:37:04 +02:00