Loading...
Searching...
No Matches
sycl.cpp
Go to the documentation of this file.
1/**
2 * SYCLGPUFFTGrid — GPUFFTGrid implementation for SYCL/oneAPI.
3 *
4 * Delegates all FFT operations to a composed SerialFFTGrid (FFTW on CPU).
5 * This is the safe initial implementation — identical to the Metal backend
6 * approach. On Intel CPUs, oneMKL internally uses FFTW anyway, so there
7 * is no performance penalty for the CPU fallback path.
8 *
9 * FP64 FFTs delegate directly to SerialFFTGrid.
10 * FP32 FFTs use the upcast-to-FP64 / downcast pattern (same as Metal fallback).
11 *
12 * oneMKL DFT descriptors can be added later as an optimization for native
13 * GPU FFT on Intel Data Center GPUs.
14 */
15
18
19#include <vector>
20
21namespace q3 {
22namespace gpu {
23
24class SYCLGPUFFTGrid : public GPUFFTGrid {
25 public:
26 /**
27 * Construct a SYCL FFT grid backed by the given device.
28 *
29 * All FFT operations are delegated to the internal SerialFFTGrid,
30 * so no SYCL-specific resources are created here.
31 */
33 std::shared_ptr<execution::gpu::device::GPUDeviceBackend> device_backend)
34 : GPUFFTGrid(std::move(device_backend)) {}
35
36 ~SYCLGPUFFTGrid() override = default;
37
38 // ── FFTGrid base interface (delegated to serial_fft_grid_) ───────────
39
40 void init(int dimension_1,
41 int dimension_2,
42 int dimension_3,
43 bool use_measured_planning = false) override {
44 serial_fft_grid_.init(dimension_1, dimension_2, dimension_3, use_measured_planning);
45 }
46
47 [[nodiscard]] int grid_dimension_1() const override {
48 return serial_fft_grid_.grid_dimension_1();
49 }
50 [[nodiscard]] int grid_dimension_2() const override {
51 return serial_fft_grid_.grid_dimension_2();
52 }
53 [[nodiscard]] int grid_dimension_3() const override {
54 return serial_fft_grid_.grid_dimension_3();
55 }
56 [[nodiscard]] int total_grid_points() const override {
57 return serial_fft_grid_.total_grid_points();
58 }
59 [[nodiscard]] int local_grid_points() const override {
60 return serial_fft_grid_.local_grid_points();
61 }
62 [[nodiscard]] int local_offset() const override {
63 return serial_fft_grid_.local_offset();
64 }
65
66 void forward(Complex* data) const override {
67 serial_fft_grid_.forward(data);
68 }
69 void inverse(Complex* data) const override {
70 serial_fft_grid_.inverse(data);
71 }
72 void inverse_raw(Complex* data) const override {
73 serial_fft_grid_.inverse_raw(data);
74 }
75
76 [[nodiscard]] int
77 g_vector_to_fft_grid_index(int miller_1, int miller_2, int miller_3) const override {
78 return serial_fft_grid_.g_vector_to_fft_grid_index(miller_1, miller_2, miller_3);
79 }
80
81 void reduce_g_space(Complex* data, int number_of_elements) const override {
82 serial_fft_grid_.reduce_g_space(data, number_of_elements);
83 }
84
85 Complex* input_buffer() const override {
86 return serial_fft_grid_.input_buffer();
87 }
88 Complex* output_buffer() const override {
89 return serial_fft_grid_.output_buffer();
90 }
91
92 void execute_inverse_raw_on_buffers() const override {
93 serial_fft_grid_.execute_inverse_raw_on_buffers();
94 }
95 void execute_forward_on_buffers() const override {
96 serial_fft_grid_.execute_forward_on_buffers();
97 }
98 void prepare_forward_from_output() const override {
99 serial_fft_grid_.prepare_forward_from_output();
100 }
101
102 // ── FP32 FFT (upcast to FP64 via SerialFFTGrid) ─────────────────────
103
104 /**
105 * Forward FP32 FFT via upcast to FP64 + SerialFFTGrid + downcast.
106 *
107 * This matches the Metal backend fallback path. oneMKL DFT can be
108 * added later for native FP32 GPU FFT on Intel hardware.
109 */
110 void forward_single(ComplexSingle* data) const override {
111 const int grid_points = total_grid_points();
112 std::vector<Complex> temporary_buffer(static_cast<size_t>(grid_points));
113
114 for (int point_index = 0; point_index < grid_points; ++point_index) {
115 temporary_buffer[static_cast<size_t>(point_index)] =
116 Complex(static_cast<double>(data[point_index].real()),
117 static_cast<double>(data[point_index].imag()));
118 }
119
120 serial_fft_grid_.forward(temporary_buffer.data());
121
122 for (int point_index = 0; point_index < grid_points; ++point_index) {
123 data[point_index] = ComplexSingle(
124 static_cast<float>(temporary_buffer[static_cast<size_t>(point_index)].real()),
125 static_cast<float>(temporary_buffer[static_cast<size_t>(point_index)].imag()));
126 }
127 }
128
129 /**
130 * Inverse FP32 FFT (raw, unnormalized) via upcast to FP64 + SerialFFTGrid + downcast.
131 */
132 void inverse_raw_single(ComplexSingle* data) const override {
133 const int grid_points = total_grid_points();
134 std::vector<Complex> temporary_buffer(static_cast<size_t>(grid_points));
135
136 for (int point_index = 0; point_index < grid_points; ++point_index) {
137 temporary_buffer[static_cast<size_t>(point_index)] =
138 Complex(static_cast<double>(data[point_index].real()),
139 static_cast<double>(data[point_index].imag()));
140 }
141
142 serial_fft_grid_.inverse_raw(temporary_buffer.data());
143
144 for (int point_index = 0; point_index < grid_points; ++point_index) {
145 data[point_index] = ComplexSingle(
146 static_cast<float>(temporary_buffer[static_cast<size_t>(point_index)].real()),
147 static_cast<float>(temporary_buffer[static_cast<size_t>(point_index)].imag()));
148 }
149 }
150
151 // ── FP64 FFT (delegate to SerialFFTGrid) ─────────────────────────────
152
153 /**
154 * Forward FP64 FFT delegates to SerialFFTGrid (FFTW).
155 */
156 void forward_transform(Complex* data) const override {
157 serial_fft_grid_.forward(data);
158 }
159
160 /**
161 * Inverse FP64 FFT (raw, unnormalized) delegates to SerialFFTGrid (FFTW).
162 */
163 void inverse_transform(Complex* data) const override {
164 serial_fft_grid_.inverse_raw(data);
165 }
166
167 private:
168 SerialFFTGrid serial_fft_grid_;
169};
170
171std::unique_ptr<GPUFFTGrid>
172create_sycl_gpu_fft_grid(std::shared_ptr<execution::gpu::device::GPUDeviceBackend> device_backend) {
173 return std::make_unique<SYCLGPUFFTGrid>(std::move(device_backend));
174}
175
176} // namespace gpu
177} // namespace q3
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
execution::gpu::device::GPUDeviceBackend & device_backend()
Definition init.hpp:162
void init(int dimension_1, int dimension_2, int dimension_3, bool use_measured_planning=false) override
Definition sycl.cpp:40
int local_grid_points() const override
Definition sycl.cpp:59
int local_offset() const override
Definition sycl.cpp:62
int grid_dimension_2() const override
Definition sycl.cpp:50
void inverse_raw_single(ComplexSingle *data) const override
Definition sycl.cpp:132
SYCLGPUFFTGrid(std::shared_ptr< execution::gpu::device::GPUDeviceBackend > device_backend)
Definition sycl.cpp:32
void inverse_transform(Complex *data) const override
Definition sycl.cpp:163
void execute_forward_on_buffers() const override
Definition sycl.cpp:95
Complex * output_buffer() const override
Definition sycl.cpp:88
int total_grid_points() const override
Definition sycl.cpp:56
Complex * input_buffer() const override
Definition sycl.cpp:85
void forward(Complex *data) const override
Definition sycl.cpp:66
int grid_dimension_1() const override
Definition sycl.cpp:47
void prepare_forward_from_output() const override
Definition sycl.cpp:98
int grid_dimension_3() const override
Definition sycl.cpp:53
~SYCLGPUFFTGrid() override=default
void forward_single(ComplexSingle *data) const override
Definition sycl.cpp:110
void inverse_raw(Complex *data) const override
Definition sycl.cpp:72
void reduce_g_space(Complex *data, int number_of_elements) const override
Definition sycl.cpp:81
void forward_transform(Complex *data) const override
Definition sycl.cpp:156
void execute_inverse_raw_on_buffers() const override
Definition sycl.cpp:92
int g_vector_to_fft_grid_index(int miller_1, int miller_2, int miller_3) const override
Definition sycl.cpp:77
void inverse(Complex *data) const override
Definition sycl.cpp:69
std::unique_ptr< GPUFFTGrid > create_sycl_gpu_fft_grid(std::shared_ptr< execution::gpu::device::GPUDeviceBackend > device_backend)
Definition sycl.cpp:172
std::complex< float > ComplexSingle
std::complex< double > Complex