diff --git a/docs/HDF5.md b/docs/HDF5.md index 2d095956..e75db39c 100644 --- a/docs/HDF5.md +++ b/docs/HDF5.md @@ -93,7 +93,7 @@ bitshuffle + Zstd; signed integer image datasets use `INTx_MIN` as the HDF5 fill ### Reprocessing output: `_process.h5` -The offline reprocessing tool [`rugnux`](TOOLS.md) (`tools/rugnux_cli.cpp`) re-runs the +The offline reprocessing tool [`rugnux`](TOOLS.md) (`rugnux/rugnux_cli.cpp`) re-runs the full analysis pipeline (spot finding, indexing, refinement, integration, scaling) on an existing dataset and writes its results to a master file named **`_process.h5`**. This file uses the **integrated** format, but instead of copying the images its `/entry/data/data` is a *virtual diff --git a/image_analysis/bragg_prediction/BraggPrediction.h b/image_analysis/bragg_prediction/BraggPrediction.h index f71948dd..e9b9dfb6 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.h +++ b/image_analysis/bragg_prediction/BraggPrediction.h @@ -33,17 +33,18 @@ struct BraggPredictionSettings { class BraggPrediction { protected: - // Not const: the buffer grows to fit a frame that predicts more than it currently holds. + // Not const: on the GPU path the buffer grows to fit a frame that predicts more than it holds. int max_reflections; std::vector reflections; - // A frame that predicts more than the buffer holds keeps an ARBITRARY subset of them: the GPU - // kernels claim slots with an atomicAdd, so which ones survive depends on block scheduling and - // changes from run to run. Say so, once per predictor, rather than let it pass silently - it is - // not a small effect (measured: a 3% run-to-run spread in the number of merged reflections, and - // every frame of that dataset overflowed). // Make room for `count` reflections. Overridden where device buffers have to follow. Called only // when a frame predicted more than the current capacity, so a run pays for it a handful of times. + // + // NOTE: only the GPU Calc overrides call this. BraggPrediction::Calc and BraggPredictionRot::Calc + // stop filling at max_reflections instead, silently - and because that cap is applied inside the + // h/k/l walk, before the resolution test, what survives is the low-|h| block rather than the + // reflections nearest the Ewald sphere. A cell large enough to overflow 20000 therefore yields + // different merged reflections on a CPU-only build than on a GPU one. virtual void GrowCapacity(int count); // Deterministically cap Calc's output at kPredictionOutput: if more were predicted, keep the ones @@ -54,8 +55,9 @@ public: // The prediction buffer holds up to kPredictionCapacity reflections so a strong lattice does not // overflow it. Calc returns at most kPredictionOutput, the number that flows downstream and is serialized - kept low so the // per-image reflection list stays within the frame transport headroom. - // Starting size only: the buffer GROWS to whatever a frame actually predicts (GrowCapacity), so a - // large cell is never truncated here. It used to be a hard cap, and overflowing it was both lossy + // Starting size. On the GPU path the buffer grows to whatever a frame actually predicts + // (GrowCapacity), so a large cell is not truncated there; the CPU path still caps at this value, + // see the note on GrowCapacity. It used to be a hard cap on both, and overflowing it was lossy // and NON-DETERMINISTIC - the GPU kernels claim slots with an atomicAdd, so which reflections // survived depended on block scheduling and changed between runs of the same command. static constexpr int kPredictionCapacity = 20000;