bragg_rot_kernel_3d ran one thread for every (h, k, l) of the box on every frame, while the CPU
predictor already skips the l of an (h, k) column whose phi solution cannot lie within the
rocking-curve test's reach (BraggPredictionRot: f(l) = |p0|^2 + 2 S0.p0 bounded by f_max, at
most two intervals of l). The GPU predictor now walks the same l:
- RotationColumnRange.h: the CPU predictor's phi limit and column bound, moved into a
host/device header shared by both, unchanged in arithmetic except that the four divisions
by 2 C*.C* are a product with its reciprocal (each end is widened by a whole index, which
covers the rounding).
- column_range_kernel: the l range of every column, one thread a column, in double; the
column's b and c are evaluated as polynomials in h and k from coefficients set up on the
host, and the blocks are 32 threads, because a consumer card runs double at a small
fraction of the float rate on a unit the warps of a multiprocessor share (a warp per column
with the range on lane 0 was slower than the whole box).
- bragg_rot_kernel_columns: a warp per column, its l spread over the lanes; per (h, k, l) the
same compute_reflections_rot. The output is sorted afterwards (OrderAndSelect), so the
predictions and their order are those of the whole box.
Kernel time on the RTX 5080 (nsys, whole run): 4nwv 1968 -> 415 ms (bragg 374 + ranges 41),
myob 45.5 -> 49.9 ms (small box: the ranges cost more than they save there, ~4 ms a run). On
the Windows laptop bragg_rot_kernel_3d was 9.4 s of 4nwv.
BraggPredictionRotGPU_ColumnRangeKeepsEveryReflection: on 300 random lattices, geometries and
rocking widths the pruned walk predicts bit for bit what the whole box does (the GPU twin of
the CPU test).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4