30class MPIFFTGrid :
public FFTGrid {
32 explicit MPIFFTGrid(MPI_Comm communicator) : communicator_(communicator) {}
34 ~MPIFFTGrid()
override {
36 MPI_Finalized(&finalized);
41 fftw_destroy_plan(plan_forward_);
43 fftw_destroy_plan(plan_inverse_);
44 if (plan_forward_batched_)
45 fftw_destroy_plan(plan_forward_batched_);
46 if (plan_inverse_batched_)
47 fftw_destroy_plan(plan_inverse_batched_);
51 MPIFFTGrid(
const MPIFFTGrid&) =
delete;
52 MPIFFTGrid& operator=(
const MPIFFTGrid&) =
delete;
53 MPIFFTGrid(MPIFFTGrid&&) =
default;
54 MPIFFTGrid& operator=(MPIFFTGrid&&) =
default;
56 void init(
int dimension_1,
59 bool use_measured_planning =
false)
override {
60 grid_dimension_1_ = dimension_1;
61 grid_dimension_2_ = dimension_2;
62 grid_dimension_3_ = dimension_3;
63 total_grid_points_ = dimension_1 * dimension_2 * dimension_3;
65 ptrdiff_t local_n1, local_offset;
66 ptrdiff_t alloc_local = fftw_mpi_local_size_3d(
67 dimension_1, dimension_2, dimension_3, communicator_, &local_n1, &local_offset);
69 local_dimension_1_ =
static_cast<int>(local_n1);
70 local_offset_ =
static_cast<int>(local_offset);
71 local_grid_points_ = local_dimension_1_ * dimension_2 * dimension_3;
73 data_.resize(
static_cast<std::size_t
>(alloc_local));
75 unsigned int planning_flags = use_measured_planning ? FFTW_MEASURE : FFTW_ESTIMATE;
77 plan_forward_ = fftw_mpi_plan_dft_3d(dimension_1,
80 reinterpret_cast<fftw_complex*
>(data_.data()),
81 reinterpret_cast<fftw_complex*
>(data_.data()),
86 plan_inverse_ = fftw_mpi_plan_dft_3d(dimension_1,
89 reinterpret_cast<fftw_complex*
>(data_.data()),
90 reinterpret_cast<fftw_complex*
>(data_.data()),
96 [[nodiscard]]
int grid_dimension_1()
const override {
97 return grid_dimension_1_;
99 [[nodiscard]]
int grid_dimension_2()
const override {
100 return grid_dimension_2_;
102 [[nodiscard]]
int grid_dimension_3()
const override {
103 return grid_dimension_3_;
106 [[nodiscard]]
int total_grid_points()
const override {
107 return total_grid_points_;
110 [[nodiscard]]
int local_grid_points()
const override {
111 return local_grid_points_;
115 [[nodiscard]]
bool co_locates_mirrors()
const override {
119 [[nodiscard]]
int local_offset()
const override {
120 return local_offset_;
123 void reduce_g_space(Complex* data,
int number_of_elements)
const override {
124 execution::sum_complex_in_place(data, number_of_elements, communicator_);
127 Complex* input_buffer()
const override {
131 Complex* output_buffer()
const override {
136 void execute_inverse_raw_on_buffers()
const override {
137 ProfilingCounters::instance().fft_call_count++;
138 fftw_execute(plan_inverse_);
141 void execute_forward_on_buffers()
const override {
142 ProfilingCounters::instance().fft_call_count++;
143 fftw_execute(plan_forward_);
146 void prepare_forward_from_output()
const override {
150 void forward(Complex* data)
const override {
151 ProfilingCounters::instance().fft_call_count++;
152 std::copy(data, data + local_grid_points_, data_.begin());
153 fftw_execute(plan_forward_);
154 std::copy(data_.begin(), data_.begin() + local_grid_points_, data);
157 void inverse(Complex* data)
const override {
158 ProfilingCounters::instance().fft_call_count++;
159 std::copy(data, data + local_grid_points_, data_.begin());
160 fftw_execute(plan_inverse_);
162 Real inverse_total_points = 1.0 / total_grid_points_;
163 for (
int point_index = 0; point_index < local_grid_points_; point_index++) {
164 data[point_index] = data_[point_index] * inverse_total_points;
168 void inverse_raw(Complex* data)
const override {
169 ProfilingCounters::instance().fft_call_count++;
170 std::copy(data, data + local_grid_points_, data_.begin());
171 fftw_execute(plan_inverse_);
172 std::copy(data_.begin(), data_.begin() + local_grid_points_, data);
176 g_vector_to_fft_grid_index(
int miller_1,
int miller_2,
int miller_3)
const override {
177 int wrapped_index_1 = (miller_1 >= 0) ? miller_1 : miller_1 + grid_dimension_1_;
178 int wrapped_index_2 = (miller_2 >= 0) ? miller_2 : miller_2 + grid_dimension_2_;
179 int wrapped_index_3 = (miller_3 >= 0) ? miller_3 : miller_3 + grid_dimension_3_;
181 if (wrapped_index_1 < local_offset_ ||
182 wrapped_index_1 >= local_offset_ + local_dimension_1_) {
186 int local_i1 = wrapped_index_1 - local_offset_;
187 return (local_i1 * grid_dimension_2_ + wrapped_index_2) * grid_dimension_3_ +
195 int initialized_batched_plan_size()
const override {
196 return batched_count_;
210 void initialize_batched_plans(
int batch_size,
211 bool use_measured_planning =
false)
const override {
212 if (grid_dimension_1_ == 0) {
217 if (plan_forward_batched_) {
218 fftw_destroy_plan(plan_forward_batched_);
219 plan_forward_batched_ =
nullptr;
221 if (plan_inverse_batched_) {
222 fftw_destroy_plan(plan_inverse_batched_);
223 plan_inverse_batched_ =
nullptr;
226 batched_count_ = batch_size;
229 ptrdiff_t local_n1_batched, local_offset_batched;
230 const ptrdiff_t batched_dimensions[3] = {
231 grid_dimension_1_, grid_dimension_2_, grid_dimension_3_};
232 ptrdiff_t alloc_local_batched = fftw_mpi_local_size_many(3,
234 static_cast<ptrdiff_t
>(batch_size),
235 FFTW_MPI_DEFAULT_BLOCK,
238 &local_offset_batched);
240 data_batched_.resize(
static_cast<std::size_t
>(alloc_local_batched));
242 unsigned int planning_flags = use_measured_planning ? FFTW_MEASURE : FFTW_ESTIMATE;
244 ptrdiff_t dimensions[3] = {grid_dimension_1_, grid_dimension_2_, grid_dimension_3_};
246 plan_forward_batched_ =
247 fftw_mpi_plan_many_dft(3,
249 static_cast<ptrdiff_t
>(batch_size),
250 FFTW_MPI_DEFAULT_BLOCK,
251 FFTW_MPI_DEFAULT_BLOCK,
252 reinterpret_cast<fftw_complex*
>(data_batched_.data()),
253 reinterpret_cast<fftw_complex*
>(data_batched_.data()),
258 plan_inverse_batched_ =
259 fftw_mpi_plan_many_dft(3,
261 static_cast<ptrdiff_t
>(batch_size),
262 FFTW_MPI_DEFAULT_BLOCK,
263 FFTW_MPI_DEFAULT_BLOCK,
264 reinterpret_cast<fftw_complex*
>(data_batched_.data()),
265 reinterpret_cast<fftw_complex*
>(data_batched_.data()),
281 void forward_batched(Complex* data,
int batch_size)
const override {
282 if (!plan_forward_batched_ || batch_size != batched_count_) {
283 FFTGrid::forward_batched(data, batch_size);
286 ProfilingCounters::instance().fft_call_count += batch_size;
292 const int local_points = local_grid_points_;
293 std::fill(data_batched_.begin(),
294 data_batched_.begin() +
static_cast<std::size_t
>(local_points) * batch_size,
296 for (
int transform_index = 0; transform_index < batch_size; ++transform_index) {
297 const Complex* source = data + transform_index * local_points;
298 for (
int point_index = 0; point_index < local_points; ++point_index) {
299 data_batched_[point_index * batch_size + transform_index] = source[point_index];
303 fftw_execute(plan_forward_batched_);
306 for (
int transform_index = 0; transform_index < batch_size; ++transform_index) {
307 Complex* destination = data + transform_index * local_points;
308 for (
int point_index = 0; point_index < local_points; ++point_index) {
309 destination[point_index] =
310 data_batched_[point_index * batch_size + transform_index];
325 void inverse_raw_batched(Complex* data,
int batch_size)
const override {
326 if (!plan_inverse_batched_ || batch_size != batched_count_) {
327 FFTGrid::inverse_raw_batched(data, batch_size);
330 ProfilingCounters::instance().fft_call_count += batch_size;
333 const int local_points = local_grid_points_;
334 std::fill(data_batched_.begin(),
335 data_batched_.begin() +
static_cast<std::size_t
>(local_points) * batch_size,
337 for (
int transform_index = 0; transform_index < batch_size; ++transform_index) {
338 const Complex* source = data + transform_index * local_points;
339 for (
int point_index = 0; point_index < local_points; ++point_index) {
340 data_batched_[point_index * batch_size + transform_index] = source[point_index];
344 fftw_execute(plan_inverse_batched_);
347 for (
int transform_index = 0; transform_index < batch_size; ++transform_index) {
348 Complex* destination = data + transform_index * local_points;
349 for (
int point_index = 0; point_index < local_points; ++point_index) {
350 destination[point_index] =
351 data_batched_[point_index * batch_size + transform_index];
357 MPI_Comm communicator_;
358 int grid_dimension_1_{}, grid_dimension_2_{}, grid_dimension_3_{};
359 int total_grid_points_{};
360 int local_dimension_1_{}, local_offset_{}, local_grid_points_{};
361 fftw_plan plan_forward_{
nullptr};
362 fftw_plan plan_inverse_{
nullptr};
363 mutable std::vector<Complex> data_;
366 mutable fftw_plan plan_forward_batched_{
nullptr};
367 mutable fftw_plan plan_inverse_batched_{
nullptr};
368 mutable int batched_count_{0};
369 mutable std::vector<Complex> data_batched_;
void init(const std::string &log_file="")
std::complex< double > Complex