20#include <cuda_runtime.h>
33void check_cufft_error(cufftResult result,
const char* operation) {
34 if (result != CUFFT_SUCCESS) {
35 throw std::runtime_error(std::string(
"CudaGPUFFTGrid: ") + operation +
36 " failed with result " + std::to_string(
static_cast<int>(result)));
51 std::shared_ptr<execution::gpu::device::GPUDeviceBackend>
device_backend)
55 if (plan_fp64_ != 0) {
56 cufftDestroy(plan_fp64_);
58 if (plan_fp32_ != 0) {
59 cufftDestroy(plan_fp32_);
61 if (device_buffer_fp32_ !=
nullptr) {
62 cudaFree(device_buffer_fp32_);
64 if (device_buffer_fp64_ !=
nullptr) {
65 cudaFree(device_buffer_fp64_);
67 if (plan_fp32_batch_ != 0) {
68 cufftDestroy(plan_fp32_batch_);
70 if (device_buffer_fp32_batch_ !=
nullptr) {
71 cudaFree(device_buffer_fp32_batch_);
73 if (plan_fp64_batch_ != 0) {
74 cufftDestroy(plan_fp64_batch_);
76 if (device_buffer_fp64_batch_ !=
nullptr) {
77 cudaFree(device_buffer_fp64_batch_);
86 bool use_measured_planning =
false)
override {
88 serial_fft_grid_.
init(dimension_1, dimension_2, dimension_3, use_measured_planning);
92 cufftPlan3d(&plan_fp64_, dimension_1, dimension_2, dimension_3, CUFFT_Z2Z),
97 cufftPlan3d(&plan_fp32_, dimension_1, dimension_2, dimension_3, CUFFT_C2C),
103 const size_t buffer_size_fp32 =
104 static_cast<size_t>(total_grid_points_cached_) *
sizeof(cufftComplex);
105 cudaMalloc(&device_buffer_fp32_, buffer_size_fp32);
107 const size_t buffer_size_fp64 =
108 static_cast<size_t>(total_grid_points_cached_) *
sizeof(cufftDoubleComplex);
109 cudaMalloc(&device_buffer_fp64_, buffer_size_fp64);
132 serial_fft_grid_.
forward(data);
135 serial_fft_grid_.
inverse(data);
176 const size_t buffer_size =
177 static_cast<size_t>(total_grid_points_cached_) *
sizeof(cufftComplex);
178 cudaMemcpy(device_buffer_fp32_, data, buffer_size, cudaMemcpyDefault);
181 cufftExecC2C(plan_fp32_, device_buffer_fp32_, device_buffer_fp32_, CUFFT_FORWARD),
182 "cufftExecC2C forward");
184 cudaMemcpy(data, device_buffer_fp32_, buffer_size, cudaMemcpyDefault);
194 const size_t buffer_size =
195 static_cast<size_t>(total_grid_points_cached_) *
sizeof(cufftComplex);
196 cudaMemcpy(device_buffer_fp32_, data, buffer_size, cudaMemcpyDefault);
199 cufftExecC2C(plan_fp32_, device_buffer_fp32_, device_buffer_fp32_, CUFFT_INVERSE),
200 "cufftExecC2C inverse");
202 cudaMemcpy(data, device_buffer_fp32_, buffer_size, cudaMemcpyDefault);
214 const size_t buffer_size =
215 static_cast<size_t>(total_grid_points_cached_) *
sizeof(cufftDoubleComplex);
216 cudaMemcpy(device_buffer_fp64_, data, buffer_size, cudaMemcpyDefault);
219 cufftExecZ2Z(plan_fp64_, device_buffer_fp64_, device_buffer_fp64_, CUFFT_FORWARD),
220 "cufftExecZ2Z forward");
222 cudaMemcpy(data, device_buffer_fp64_, buffer_size, cudaMemcpyDefault);
232 const size_t buffer_size =
233 static_cast<size_t>(total_grid_points_cached_) *
sizeof(cufftDoubleComplex);
234 cudaMemcpy(device_buffer_fp64_, data, buffer_size, cudaMemcpyDefault);
237 cufftExecZ2Z(plan_fp64_, device_buffer_fp64_, device_buffer_fp64_, CUFFT_INVERSE),
238 "cufftExecZ2Z inverse");
240 cudaMemcpy(data, device_buffer_fp64_, buffer_size, cudaMemcpyDefault);
258 ensure_batch_resources(batch_size);
260 const size_t buffer_size =
261 static_cast<size_t>(total_grid_points_cached_) * batch_size *
sizeof(cufftComplex);
262 cudaMemcpy(device_buffer_fp32_batch_, data, buffer_size, cudaMemcpyDefault);
264 check_cufft_error(cufftExecC2C(plan_fp32_batch_,
265 device_buffer_fp32_batch_,
266 device_buffer_fp32_batch_,
268 "cufftExecC2C batched forward");
270 cudaMemcpy(data, device_buffer_fp32_batch_, buffer_size, cudaMemcpyDefault);
280 ensure_batch_resources(batch_size);
282 const size_t buffer_size =
283 static_cast<size_t>(total_grid_points_cached_) * batch_size *
sizeof(cufftComplex);
284 cudaMemcpy(device_buffer_fp32_batch_, data, buffer_size, cudaMemcpyDefault);
286 check_cufft_error(cufftExecC2C(plan_fp32_batch_,
287 device_buffer_fp32_batch_,
288 device_buffer_fp32_batch_,
290 "cufftExecC2C batched inverse");
292 cudaMemcpy(data, device_buffer_fp32_batch_, buffer_size, cudaMemcpyDefault);
303 ensure_batch_resources_fp64(batch_size);
305 const size_t buffer_size =
static_cast<size_t>(total_grid_points_cached_) * batch_size *
306 sizeof(cufftDoubleComplex);
307 cudaMemcpy(device_buffer_fp64_batch_, data, buffer_size, cudaMemcpyDefault);
309 check_cufft_error(cufftExecZ2Z(plan_fp64_batch_,
310 device_buffer_fp64_batch_,
311 device_buffer_fp64_batch_,
313 "cufftExecZ2Z batched forward");
315 cudaMemcpy(data, device_buffer_fp64_batch_, buffer_size, cudaMemcpyDefault);
324 ensure_batch_resources_fp64(batch_size);
326 const size_t buffer_size =
static_cast<size_t>(total_grid_points_cached_) * batch_size *
327 sizeof(cufftDoubleComplex);
328 cudaMemcpy(device_buffer_fp64_batch_, data, buffer_size, cudaMemcpyDefault);
330 check_cufft_error(cufftExecZ2Z(plan_fp64_batch_,
331 device_buffer_fp64_batch_,
332 device_buffer_fp64_batch_,
334 "cufftExecZ2Z batched inverse");
336 cudaMemcpy(data, device_buffer_fp64_batch_, buffer_size, cudaMemcpyDefault);
341 cufftHandle plan_fp64_ = 0;
342 cufftHandle plan_fp32_ = 0;
345 cufftComplex* device_buffer_fp32_ =
nullptr;
346 cufftDoubleComplex* device_buffer_fp64_ =
nullptr;
347 int total_grid_points_cached_ = 0;
350 mutable cufftHandle plan_fp32_batch_ = 0;
351 mutable cufftComplex* device_buffer_fp32_batch_ =
nullptr;
352 mutable int current_fp32_batch_size_ = 0;
355 mutable cufftHandle plan_fp64_batch_ = 0;
356 mutable cufftDoubleComplex* device_buffer_fp64_batch_ =
nullptr;
357 mutable int current_fp64_batch_size_ = 0;
362 void ensure_batch_resources(
int batch_size)
const {
363 if (batch_size == current_fp32_batch_size_) {
367 if (plan_fp32_batch_ != 0) {
368 cufftDestroy(plan_fp32_batch_);
369 plan_fp32_batch_ = 0;
371 if (device_buffer_fp32_batch_ !=
nullptr) {
372 cudaFree(device_buffer_fp32_batch_);
373 device_buffer_fp32_batch_ =
nullptr;
379 int distance = total_grid_points_cached_;
381 check_cufft_error(cufftPlanMany(&plan_fp32_batch_,
392 "cufftPlanMany FP32 batch");
394 const size_t buffer_size =
395 static_cast<size_t>(total_grid_points_cached_) * batch_size *
sizeof(cufftComplex);
396 cudaMalloc(&device_buffer_fp32_batch_, buffer_size);
398 current_fp32_batch_size_ = batch_size;
404 void ensure_batch_resources_fp64(
int batch_size)
const {
405 if (batch_size == current_fp64_batch_size_) {
409 if (plan_fp64_batch_ != 0) {
410 cufftDestroy(plan_fp64_batch_);
411 plan_fp64_batch_ = 0;
413 if (device_buffer_fp64_batch_ !=
nullptr) {
414 cudaFree(device_buffer_fp64_batch_);
415 device_buffer_fp64_batch_ =
nullptr;
421 int distance = total_grid_points_cached_;
423 check_cufft_error(cufftPlanMany(&plan_fp64_batch_,
434 "cufftPlanMany FP64 batch");
436 const size_t buffer_size =
static_cast<size_t>(total_grid_points_cached_) * batch_size *
437 sizeof(cufftDoubleComplex);
438 cudaMalloc(&device_buffer_fp64_batch_, buffer_size);
440 current_fp64_batch_size_ = batch_size;
444std::unique_ptr<GPUFFTGrid>
446 return std::make_unique<CudaGPUFFTGrid>(std::move(device_backend));
void inverse(Complex *data) const override
int local_grid_points() const override
int local_offset() const override
void forward(Complex *data) const override
void execute_forward_on_buffers() const override
void reduce_g_space(Complex *, int) const override
int grid_dimension_3() const override
int grid_dimension_1() const override
void init(int dimension_1, int dimension_2, int dimension_3, bool use_measured_planning=false) override
void inverse_raw(Complex *data) const override
Complex * output_buffer() const override
Complex * input_buffer() const override
void execute_inverse_raw_on_buffers() const override
int total_grid_points() const override
int grid_dimension_2() const override
int g_vector_to_fft_grid_index(int miller_1, int miller_2, int miller_3) const override
void prepare_forward_from_output() const override
void reduce_g_space(Complex *data, int number_of_elements) const override
void inverse_transform(Complex *data) const override
int grid_dimension_2() const override
void inverse_raw_single(ComplexSingle *data) const override
int grid_dimension_3() const override
void forward_single_batch(ComplexSingle *data, int batch_size) const override
void forward(Complex *data) const override
void execute_inverse_raw_on_buffers() const override
~CudaGPUFFTGrid() override
void forward_transform(Complex *data) const override
void inverse(Complex *data) const override
void forward_transform_batch(Complex *data, int batch_size) const override
void init(int dimension_1, int dimension_2, int dimension_3, bool use_measured_planning=false) override
void prepare_forward_from_output() const override
void execute_forward_on_buffers() const override
void forward_single(ComplexSingle *data) const override
Complex * input_buffer() const override
CudaGPUFFTGrid(std::shared_ptr< execution::gpu::device::GPUDeviceBackend > device_backend)
int g_vector_to_fft_grid_index(int miller_1, int miller_2, int miller_3) const override
int local_grid_points() const override
void inverse_transform_batch(Complex *data, int batch_size) const override
Complex * output_buffer() const override
void inverse_raw(Complex *data) const override
int local_offset() const override
int total_grid_points() const override
int grid_dimension_1() const override
void inverse_raw_single_batch(ComplexSingle *data, int batch_size) const override
execution::gpu::device::GPUDeviceBackend & device_backend()
std::unique_ptr< GPUFFTGrid > create_cuda_gpu_fft_grid(std::shared_ptr< execution::gpu::device::GPUDeviceBackend > device_backend)
std::complex< float > ComplexSingle
std::complex< double > Complex