jfjoch_broker: Faster live Rugnux analysis, with the GPU indexers prepared at the start of a collection and kept between collections; Rugnux no longer writes .ccp4 maps (the map coefficients are in <prefix>_maps.mtz).
* jfjoch_broker: Faster live Rugnux analysis, with the GPU indexers prepared at the start of a collection and kept between collections; Rugnux no longer writes `.ccp4` maps (the map coefficients are in `<prefix>_maps.mtz`).
A model validation no longer writes <prefix>_2fofc.ccp4, _fofc.ccp4 and _anom.ccp4 (nor their _mr
twins); <prefix>_maps.mtz, which Coot and PyMOL open as maps, is what is written. With the files
goes everything that only existed for them: ModelMaps keeps the coefficients alone, the
keep_map_grids switch is gone from the validation schedule and the rugnux config, and the
mFo-DFc map is no longer transformed to real space at all (nothing read it). The 2mFo-DFc and
anomalous maps are still made, for the mean atom density and the anomalous-site read-out.
The anomalous difference map is now in no output file: _maps.mtz carries no anomalous columns.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
With two or more GPUs StartCentreSpeculation joins the pre-scan's beam-centre capture; that join
used to come before the file centre's schemes were indexed, so on the live server (capture 2.1 s)
the file centre and the short-axis pass waited for it. The file centre's indexing now runs on its
own thread while alongside() runs, and the short-axis pass is started before the centre
speculation. Each indexer reads only what it was fed, so the results are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
PrepareImage copied the finite pixels and ran two nth_element over them (18 M pixels on a 16M
detector, ~200 ms single-threaded). Two counting passes over the float bits (upper, then lower
16 bits of an order-preserving key) give the same k-th values in ~55 ms without the copy. Values
are identical; only the sign of a zero picked as a quantile may differ, which the clipping maps
to the same prepared image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
The probe reports only the lattice and indexing rate on the first 60 degrees and decides nothing
for the run. Its beam-centre capture and second first pass at the measured centre loaded the GPUs
beside the main run's pre-scan for a centre nobody reads.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
WarmUpModelValidation runs one throwaway validation of the uploaded model against its own
calculated intensities on a background thread (holding a GPUWorkBeside), so kernels, cuFFT
kernels and contexts on every card the null's replicates use are loaded before the collection's
validation. ValidateAgainstModel waits for a warm-up still running, so a real validation never
shares the cards with it and computes what it computes without one (test
ModelValidation_WarmUpChangesNothing; CLI run with and without warm-up: identical p.mtz,
p_maps.mtz, report and validation lines). The broker logs the warm-up's time at upload, which
measures the first-use cost on the machine directly (local RTX 5080: 0.88 s first, 0.78 s second).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
jfjoch_broker opened no FFTPlanReuse, so every cuFFT plan of a live run was made on first use and
destroyed after it, and every pass (first pass, measured-centre arm, short-axis pool, pass 2) built
its GPU FFT indexers afresh. Now:
- FFTIndexerReuse: while one lives, a pool worker borrows a kept GPU FFT indexer of its card and
construction settings instead of building one, and gives it back when it ends or is released.
- The rugnux receiver holds an FFTIndexerReuse and an FFTPlanReuse for the broker's lifetime.
- At START, beside the run (which is waiting for its first frames), WarmUpRugnuxLiveGPU builds on
every card the first-pass and short-axis indexers and the beam-centre capture's plan pair.
The CLI opens no FFTIndexerReuse and is unchanged. Results identical: CLI p.hkl md5 equal on two
sets (CLI and --simulate-live --fast-live); broker replay, 3 collections each, MTZ data identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
The rugnux live thread, its lattice probe and the process-wide ParallelFor pool were lowered to nice 10
while a collection ran (and the pool raised back afterwards where the process had the right to). That
is removed: the analysis runs at the broker's priority, and WorkerPool::SetNice with the thread-id
bookkeeping it needed goes with it.
Measured on a workstation (model validation, 10 rigid bodies, under 32 busy threads at nice 0): nice 10
made the host-sync-heavy GPU work 4-15x slower (6.5 s at nice 0 vs 24.7 s at nice 10 with blocking
sync); on the server the post-collection tail ran at nice 10 though the forward threads are idle then.
Results unchanged (p.hkl md5 identical, simulated live).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
Validation reads of the final merge only its French-Wilson amplitudes, which the analyses
made last, from the anisotropy tensor. That tensor is a fit to the merged intensities alone
(the unmerged observations only give its error bar), so AnisotropyPriorHKL computes it from
the merge without the rest of the analysis, bit for bit what AnisotropyTensorHKL of the full
analysis gives (test). The first ValidateAgainstModel now runs from the start of the analyses
on a copy of the merge given those same amplitudes, on the caller's card (get_gpu), with its
log held and replayed where it was printed before; nothing it decides is acted on earlier.
The model's preparation (census wait, indexer pool, GPU hold, merge engine release) moves
with it.
Measured, --simulate-live 10 --fast-live, 4axt model, RTX 5080, analyses + validation steps:
strong lysozyme 0.91 -> 0.63 s, reference lysozyme 1.02 -> 0.66 s (validation beside the
analyses 0.60-0.62 s vs 0.39-0.45 s alone, CPU shared; analyses 0.53 -> 0.62 s). The
analyses were 80% waiting for the anisotropy (0.43 of 0.53 s), so starting on the full
analysis' tensor would have gained ~0.1 s. p.hkl, p_maps.mtz identical, p.mtz data identical,
all validation numbers identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
.ccp4maps (the map coefficients are in<prefix>_maps.mtz).