// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include #include "BraggIntegrationEngine.h" #include "../indexing/CUDAMemHelpers.h" // CUDA engine: reproduces BraggIntegrationEngineCPU up to floating-point precision. Each stage is a // kernel with one CUDA block per reflection cooperating over the small window via shared-memory // reductions (the natural mapping for thousands of independent, tiny per-spot integrations). // // Pipeline (profile modes): reset -> mark_mask -> boxsum -> learn_profile -> build_profiles -> fit // (the resolution shell is computed inline, so there is no separate shell pass). BoxSum mode stops // after boxsum (that pass is the BraggIntegrate2D box integrator and the seed of the profile fit). // The preprocessed image already lives on the device (ImagePreprocessorBufferGPU::getGPUBuffer()); // only the per-frame predicted centres are uploaded. class BraggIntegrationEngineGPU : public BraggIntegrationEngine { std::shared_ptr stream; int threads; size_t fit_shared_bytes; size_t capacity = 0; // per-reflection device/host arrays hold at least this many reflections // --- per-reflection device arrays (grown by EnsureCapacity) --- CudaDevicePtr d_px_x, d_px_y, d_d; CudaDevicePtr d_cx, d_cy; CudaDevicePtr d_I, d_sigma, d_bkg, d_obs_x, d_obs_y; CudaDevicePtr d_ok, d_strong, d_has_obs; // --- fixed-size device arrays --- // The learning/fit math is single precision: FP64 is heavily throttled on consumer GPUs and the // extraction is Poisson-noise limited, so float reproduces the double CPU path to ~1e-4. CudaDevicePtr d_mask; // per-pixel r2-disk reflection mask CudaDevicePtr d_shell_grid, d_global_grid; // learned profile accumulators (N_SHELL*GG, GG) CudaDevicePtr d_shell_P, d_global_P; // normalised profiles (empirical mode) CudaDevicePtr d_shell_sigma2, d_global_sigma2; CudaDevicePtr d_shell_n, d_global_n; CudaDevicePtr d_invd2; // [min,max] inv-d^2 as monotonic bit patterns // --- host staging (copied back once per frame) --- std::vector h_px_x, h_px_y, h_d; std::vector h_I, h_sigma, h_bkg, h_obs_x, h_obs_y; std::vector h_ok, h_has_obs; void EnsureCapacity(size_t n); public: BraggIntegrationEngineGPU(const DiffractionExperiment &experiment, std::shared_ptr stream); std::vector Run(const ImagePreprocessorBuffer &image, const std::vector &predicted, size_t npredicted, int64_t image_number) override; };