Build Packages / Create release (push) Successful in 17s
Build Packages / build:viewer:macos-arm64:nocuda (push) Successful in 3m22s
Build Packages / build:rugnux:macos-arm64:nocuda (push) Successful in 2m37s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 9m33s
Build Packages / build:rugnux:linux-x86_64:cuda (push) Successful in 10m39s
Build Packages / build:viewer:linux-x86_64:nocuda (push) Successful in 11m4s
Build Packages / build:viewer:linux-x86_64:cuda (push) Successful in 13m19s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 17m37s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 18m49s
Build Packages / build:viewer:windows-x86_64:nocuda (push) Successful in 19m10s
Build Packages / build:viewer:windows-x86_64:cuda (push) Successful in 24m26s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m31s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 18m54s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 20m45s
Build Packages / Generate python client (push) Successful in 37s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 20m20s
Build Packages / Build documentation (push) Successful in 1m32s
Build Packages / build:rugnux:windows-x86_64:cuda (push) Successful in 14m37s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 21m6s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 19m49s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 20m29s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 17m2s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 14m27s
Build Packages / Unit tests (push) Successful in 1h18m12s
* Rugnux: Performance improvements on GPU and CPU (more of the pre-scan and of scaling on the GPU, faster CPU spot finding and crystal refinement), with unchanged results. * Rugnux: More robust processing - patches of persistently hot pixels are masked, an inconsistent merge triggers a retry at the measured beam centre, and builds targeting different CPU levels give the same results. * Rugnux: Improved scaling and merging - reflections with an overloaded pixel are dropped, as in XDS, sparse rotation sweeps are scaled more reliably, and French-Wilson amplitudes use an anisotropic Wilson prior. * Rugnux: Improved space-group determination - glide planes in groups without a centre of symmetry, screw axes from short or weak axial rows kept when a higher group is adopted, and more reliable decisions on twinned and pseudo-symmetric crystals. * Rugnux: Improved small-molecule processing - spots that grow wider than the integration disk and split spots are integrated over their measured footprint, sparse lattices are integrated on every frame, and the `.hkl` file holds unmerged scaled reflections (SHELX HKLF 4). * Rugnux: Reads Rigaku d*TREK SMV images (Saturn CCD), including detector 2theta and encoded pixel overflows; home-source (rotating-anode) datasets were added to the validation battery. * jfjoch_viewer: Fixed processing failing at the end with "Wrong JPEG library version" on Linux; the merge window shows the space group with proper subscripts and a checklist of crystal pathologies. Reviewed-on: #84 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
73 lines
3.3 KiB
C++
73 lines
3.3 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "../../common/CompressedImage.h"
|
|
#include "../image_preprocessing/BSLZ4DecoderGPU.h"
|
|
#include "../indexing/CUDAMemHelpers.h"
|
|
#include "ShadowMaskGPU.h"
|
|
|
|
// The beam-stop projection accumulated on the device: only the compressed chunk crosses PCIe, and
|
|
// both the decode and the per-pixel maximum / sum / count run on the GPU. The projection comes back
|
|
// once, when the mask is read.
|
|
//
|
|
// This accumulates the RAW STORED COUNTS, with the pixel type's sentinel skipped, exactly as the
|
|
// host ShadowFinder does - NOT the preprocessed image. The two are not the same thing and the
|
|
// shadow is defined on the raw one. Sums and counts are integers, so the device result is identical
|
|
// to the host's rather than merely close.
|
|
//
|
|
// Only bitshuffle+LZ4 images are handled; anything else is left to the host path.
|
|
class ShadowAccumulatorGPU {
|
|
const size_t npixels;
|
|
std::shared_ptr<CudaStream> stream;
|
|
std::unique_ptr<BSLZ4DecoderGPU> decoder;
|
|
|
|
// Frames are decoded into a batch and folded into the projection together. The fold reads and
|
|
// writes 20 bytes per pixel whatever the batch holds, so doing it once per frame would spend
|
|
// most of the bandwidth on the accumulator rather than on the data. Four is where that stops
|
|
// mattering - the fold is then a few percent of the phase - and every frame beyond it is a
|
|
// further full frame of device memory, which costs more in cudaMalloc (device-synchronizing)
|
|
// than it saves.
|
|
static constexpr int BATCH = 4;
|
|
CudaDevicePtr<uint8_t> raw; // BATCH decoded frames, still in their stored type
|
|
CudaDevicePtr<int64_t> gpu_max;
|
|
CudaDevicePtr<int64_t> gpu_sum;
|
|
CudaDevicePtr<uint32_t> gpu_count;
|
|
size_t frame_bytes = 0; // stride of one frame within `raw`
|
|
size_t raw_capacity = 0; // bytes actually allocated for `raw`
|
|
int pending = 0; // frames decoded but not yet folded in
|
|
CompressedImageMode pending_mode = CompressedImageMode::Uint32;
|
|
uint32_t frames = 0;
|
|
int blocks = 0;
|
|
|
|
void EnsureRawCapacity(size_t bytes_per_frame);
|
|
void FoldPending();
|
|
|
|
public:
|
|
explicit ShadowAccumulatorGPU(size_t npixels);
|
|
|
|
// True when this image can be decoded and accumulated on the device.
|
|
static bool Supports(const CompressedImage &image);
|
|
|
|
// Decode and accumulate one frame. Throws if the image is not one this can take (ask Supports
|
|
// first) or if the chunk does not decode.
|
|
void Add(const CompressedImage &image);
|
|
|
|
[[nodiscard]] uint32_t GetFrameCount() const { return frames; }
|
|
|
|
// The beam-stop mask and the mean projection, made where the projection is (ShadowMaskGPU.h), so
|
|
// that it does not have to come back at all.
|
|
std::vector<uint32_t> Mask(const ShadowMaskSetup &setup, const std::vector<uint32_t> &pixel_mask);
|
|
std::vector<float> MeanProjection(const std::vector<uint32_t> &pixel_mask);
|
|
|
|
// Bring the projection back to the host, folding in whatever the last batch still holds. Cheap
|
|
// to call once; it moves 20 bytes per pixel.
|
|
void Download(std::vector<int64_t> &max_value, std::vector<int64_t> &sum_value,
|
|
std::vector<uint32_t> &valid_count);
|
|
};
|