58 explicit FFTGridSticks(MPI_Comm communicator) : communicator_(communicator) {
59 MPI_Comm_rank(communicator_, &rank_);
60 MPI_Comm_size(communicator_, &size_);
78 bool use_measured_planning =
false)
override {
79 grid_dimension_1_ = dimension_1;
80 grid_dimension_2_ = dimension_2;
81 grid_dimension_3_ = dimension_3;
82 use_measured_planning_ = use_measured_planning;
83 total_grid_points_ = dimension_1 * dimension_2 * dimension_3;
89 int base = dimension_3 / size_;
90 int remainder = dimension_3 % size_;
91 plane_counts_.assign(
static_cast<std::size_t
>(size_), base);
92 plane_offsets_.assign(
static_cast<std::size_t
>(size_), 0);
93 for (
int rank = 0; rank < size_; ++rank) {
94 if (rank < remainder) {
95 plane_counts_[
static_cast<std::size_t
>(rank)] += 1;
97 plane_offsets_[
static_cast<std::size_t
>(rank)] =
99 : plane_offsets_[
static_cast<std::size_t
>(rank - 1)] +
100 plane_counts_[
static_cast<std::size_t
>(rank - 1)];
102 local_planes_ = plane_counts_[
static_cast<std::size_t
>(rank_)];
103 local_plane_offset_ = plane_offsets_[
static_cast<std::size_t
>(rank_)];
104 local_grid_points_ = local_planes_ * dimension_1 * dimension_2;
106 std::vector<int> all_occupied(
static_cast<std::size_t
>(dimension_1) * dimension_2, 1);
116 partition_.
build(grid_dimension_1_, grid_dimension_2_, stick_weights, size_);
122 sticks_by_rank_.assign(
static_cast<std::size_t
>(size_), {});
123 stick_local_index_.assign(
static_cast<std::size_t
>(grid_dimension_1_) * grid_dimension_2_,
125 for (
int first = 0; first < grid_dimension_1_; ++first) {
126 for (
int second = 0; second < grid_dimension_2_; ++second) {
127 int owner = partition_.
owner_of(first, second);
131 auto& list = sticks_by_rank_[
static_cast<std::size_t
>(owner)];
132 if (owner == rank_) {
133 stick_local_index_[
static_cast<std::size_t
>(first) * grid_dimension_2_ +
134 second] =
static_cast<int>(list.size());
136 list.push_back(first * grid_dimension_2_ + second);
139 local_sticks_ =
static_cast<int>(sticks_by_rank_[
static_cast<std::size_t
>(rank_)].size());
140 local_g_space_points_ = local_sticks_ * grid_dimension_3_;
147 send_counts_.assign(
static_cast<std::size_t
>(size_), 0);
148 recv_counts_.assign(
static_cast<std::size_t
>(size_), 0);
149 send_displacements_.assign(
static_cast<std::size_t
>(size_), 0);
150 recv_displacements_.assign(
static_cast<std::size_t
>(size_), 0);
151 for (
int other = 0; other < size_; ++other) {
152 send_counts_[
static_cast<std::size_t
>(other)] =
153 local_sticks_ * plane_counts_[
static_cast<std::size_t
>(other)];
154 recv_counts_[
static_cast<std::size_t
>(other)] =
155 static_cast<int>(sticks_by_rank_[
static_cast<std::size_t
>(other)].size()) *
158 for (
int other = 1; other < size_; ++other) {
159 send_displacements_[
static_cast<std::size_t
>(other)] =
160 send_displacements_[
static_cast<std::size_t
>(other - 1)] +
161 send_counts_[
static_cast<std::size_t
>(other - 1)];
162 recv_displacements_[
static_cast<std::size_t
>(other)] =
163 recv_displacements_[
static_cast<std::size_t
>(other - 1)] +
164 recv_counts_[
static_cast<std::size_t
>(other - 1)];
166 int transpose_size = 0;
167 for (
int other = 0; other < size_; ++other) {
168 transpose_size = std::max(transpose_size,
169 send_displacements_[
static_cast<std::size_t
>(other)] +
170 send_counts_[
static_cast<std::size_t
>(other)]);
171 transpose_size = std::max(transpose_size,
172 recv_displacements_[
static_cast<std::size_t
>(other)] +
173 recv_counts_[
static_cast<std::size_t
>(other)]);
177 static_cast<std::size_t
>(std::max(local_g_space_points_, local_grid_points_));
178 stick_buffer_.assign(std::max<std::size_t>(larger, 1),
Complex(0.0, 0.0));
179 plane_buffer_.assign(std::max<std::size_t>(larger, 1),
Complex(0.0, 0.0));
180 transpose_buffer_.assign(std::max<std::size_t>(
static_cast<std::size_t
>(transpose_size), 1),
187 return grid_dimension_1_;
190 return grid_dimension_2_;
193 return grid_dimension_3_;
196 return total_grid_points_;
199 return local_grid_points_;
202 return local_g_space_points_;
206 return local_plane_offset_;
210 int points_per_plane = grid_dimension_1_ * grid_dimension_2_;
211 int index_3 = local_plane_offset_ + local_index / points_per_plane;
212 int index_within_plane = local_index % points_per_plane;
213 int index_1 = index_within_plane / grid_dimension_2_;
214 int index_2 = index_within_plane % grid_dimension_2_;
215 return (index_1 * grid_dimension_2_ + index_2) * grid_dimension_3_ + index_3;
219 return grid_dimension_1_;
222 return local_sticks_;
233 const auto& mine = sticks_by_rank_[
static_cast<std::size_t
>(rank_)];
234 for (std::size_t stick = 0; stick < mine.size(); ++stick) {
235 std::memcpy(local_g_space + stick *
static_cast<std::size_t
>(grid_dimension_3_),
236 full_g_space +
static_cast<std::size_t
>(mine[stick]) * grid_dimension_3_,
237 static_cast<std::size_t
>(grid_dimension_3_) *
sizeof(
Complex));
242 const auto& mine = sticks_by_rank_[
static_cast<std::size_t
>(rank_)];
243 for (std::size_t stick = 0; stick < mine.size(); ++stick) {
244 std::memcpy(full_g_space +
static_cast<std::size_t
>(mine[stick]) * grid_dimension_3_,
245 local_g_space + stick *
static_cast<std::size_t
>(grid_dimension_3_),
246 static_cast<std::size_t
>(grid_dimension_3_) *
sizeof(
Complex));
250 [[nodiscard]]
bool owns_stick(
int miller_1,
int miller_2)
const override {
260 stick_local_index_[
static_cast<std::size_t
>(wrapped_1) * grid_dimension_2_ + wrapped_2];
261 if (local_stick < 0) {
264 return local_stick * grid_dimension_3_ + wrapped_3;
270 return stick_buffer_.data();
273 return plane_buffer_.data();
277 sticks_to_planes(stick_buffer_.data(), plane_buffer_.data());
287 planes_to_sticks(plane_buffer_.data(), stick_buffer_.data());
288 std::memcpy(plane_buffer_.data(),
289 stick_buffer_.data(),
290 static_cast<std::size_t
>(local_g_space_points_) *
sizeof(
Complex));
299 std::memcpy(plane_buffer_.data(), data, local_grid_points_ *
sizeof(
Complex));
300 planes_to_sticks(plane_buffer_.data(), stick_buffer_.data());
301 std::memcpy(data, stick_buffer_.data(), local_g_space_points_ *
sizeof(
Complex));
305 std::memcpy(stick_buffer_.data(), data, local_g_space_points_ *
sizeof(
Complex));
306 sticks_to_planes(stick_buffer_.data(), plane_buffer_.data());
307 std::memcpy(data, plane_buffer_.data(), local_grid_points_ *
sizeof(
Complex));
312 Real scale = 1.0 /
static_cast<Real>(total_grid_points_);
313 for (
int index = 0; index < local_grid_points_; ++index) {
314 data[index] *= scale;
320 MPI_IN_PLACE, data, number_of_elements, MPI_C_DOUBLE_COMPLEX, MPI_SUM, communicator_);
333 if (local_sticks_ > 0) {
334 fftw_execute_dft(plan_sticks_inverse_,
335 reinterpret_cast<fftw_complex*
>(sticks),
336 reinterpret_cast<fftw_complex*
>(sticks));
339 Complex* send = transpose_buffer_.data();
340 for (
int other = 0; other < size_; ++other) {
341 int plane_start = plane_offsets_[
static_cast<std::size_t
>(other)];
342 int plane_count = plane_counts_[
static_cast<std::size_t
>(other)];
343 Complex* destination = send + send_displacements_[
static_cast<std::size_t
>(other)];
344 for (
int stick = 0; stick < local_sticks_; ++stick) {
345 std::memcpy(destination +
static_cast<std::size_t
>(stick) * plane_count,
346 sticks +
static_cast<std::size_t
>(stick) * grid_dimension_3_ +
348 static_cast<std::size_t
>(plane_count) *
sizeof(
Complex));
352 std::vector<Complex>& receive = receive_buffer_;
353 receive.resize(std::max<std::size_t>(
354 static_cast<std::size_t
>(recv_displacements_.back() + recv_counts_.back()), 1));
357 send_displacements_.data(),
358 MPI_C_DOUBLE_COMPLEX,
361 recv_displacements_.data(),
362 MPI_C_DOUBLE_COMPLEX,
369 std::fill(planes, planes + local_grid_points_,
Complex(0.0, 0.0));
370 std::size_t plane_stride =
static_cast<std::size_t
>(grid_dimension_1_) * grid_dimension_2_;
371 for (
int other = 0; other < size_; ++other) {
372 const auto& their_sticks = sticks_by_rank_[
static_cast<std::size_t
>(other)];
374 receive.data() + recv_displacements_[
static_cast<std::size_t
>(other)];
375 for (std::size_t stick = 0; stick < their_sticks.size(); ++stick) {
376 int position = their_sticks[stick];
377 for (
int plane = 0; plane < local_planes_; ++plane) {
378 planes[
static_cast<std::size_t
>(plane) * plane_stride + position] =
379 source[stick *
static_cast<std::size_t
>(local_planes_) + plane];
384 if (local_planes_ > 0) {
385 fftw_execute_dft(plan_planes_inverse_,
386 reinterpret_cast<fftw_complex*
>(planes),
387 reinterpret_cast<fftw_complex*
>(planes));
393 if (local_planes_ > 0) {
394 fftw_execute_dft(plan_planes_forward_,
395 reinterpret_cast<fftw_complex*
>(planes),
396 reinterpret_cast<fftw_complex*
>(planes));
404 std::vector<Complex>& send = receive_buffer_;
405 send.resize(std::max<std::size_t>(
406 static_cast<std::size_t
>(recv_displacements_.back() + recv_counts_.back()), 1));
407 std::size_t plane_stride =
static_cast<std::size_t
>(grid_dimension_1_) * grid_dimension_2_;
408 for (
int other = 0; other < size_; ++other) {
409 const auto& their_sticks = sticks_by_rank_[
static_cast<std::size_t
>(other)];
411 send.data() + recv_displacements_[
static_cast<std::size_t
>(other)];
412 for (std::size_t stick = 0; stick < their_sticks.size(); ++stick) {
413 int position = their_sticks[stick];
414 for (
int plane = 0; plane < local_planes_; ++plane) {
415 destination[stick *
static_cast<std::size_t
>(local_planes_) + plane] =
416 planes[
static_cast<std::size_t
>(plane) * plane_stride + position];
421 Complex* receive = transpose_buffer_.data();
422 MPI_Alltoallv(send.data(),
424 recv_displacements_.data(),
425 MPI_C_DOUBLE_COMPLEX,
428 send_displacements_.data(),
429 MPI_C_DOUBLE_COMPLEX,
432 for (
int other = 0; other < size_; ++other) {
433 int plane_start = plane_offsets_[
static_cast<std::size_t
>(other)];
434 int plane_count = plane_counts_[
static_cast<std::size_t
>(other)];
435 const Complex* source = receive + send_displacements_[
static_cast<std::size_t
>(other)];
436 for (
int stick = 0; stick < local_sticks_; ++stick) {
437 std::memcpy(sticks +
static_cast<std::size_t
>(stick) * grid_dimension_3_ +
439 source +
static_cast<std::size_t
>(stick) * plane_count,
440 static_cast<std::size_t
>(plane_count) *
sizeof(
Complex));
444 if (local_sticks_ > 0) {
445 fftw_execute_dft(plan_sticks_forward_,
446 reinterpret_cast<fftw_complex*
>(sticks),
447 reinterpret_cast<fftw_complex*
>(sticks));
453 void create_plans() {
455 unsigned flags = use_measured_planning_ ? FFTW_MEASURE : FFTW_ESTIMATE;
461 if (local_sticks_ > 0) {
462 int length = grid_dimension_3_;
463 auto* buffer =
reinterpret_cast<fftw_complex*
>(stick_buffer_.data());
464 plan_sticks_forward_ = fftw_plan_many_dft(1,
477 plan_sticks_inverse_ = fftw_plan_many_dft(1,
491 if (local_planes_ > 0) {
492 int lengths[2] = {grid_dimension_1_, grid_dimension_2_};
493 int plane_points = grid_dimension_1_ * grid_dimension_2_;
494 auto* buffer =
reinterpret_cast<fftw_complex*
>(plane_buffer_.data());
495 plan_planes_forward_ = fftw_plan_many_dft(2,
508 plan_planes_inverse_ = fftw_plan_many_dft(2,
524 void destroy_plans() {
525 for (fftw_plan* plan : {&plan_sticks_forward_,
526 &plan_sticks_inverse_,
527 &plan_planes_forward_,
528 &plan_planes_inverse_}) {
529 if (*plan !=
nullptr) {
530 fftw_destroy_plan(*plan);
536 MPI_Comm communicator_;
540 int grid_dimension_1_ = 0;
541 int grid_dimension_2_ = 0;
542 int grid_dimension_3_ = 0;
543 int total_grid_points_ = 0;
544 bool use_measured_planning_ =
false;
546 std::vector<int> plane_counts_;
547 std::vector<int> plane_offsets_;
548 int local_planes_ = 0;
549 int local_plane_offset_ = 0;
550 int local_grid_points_ = 0;
552 FFTStickPartition partition_;
553 std::vector<std::vector<int>> sticks_by_rank_;
554 std::vector<int> stick_local_index_;
555 int local_sticks_ = 0;
556 int local_g_space_points_ = 0;
558 std::vector<int> send_counts_, recv_counts_, send_displacements_, recv_displacements_;
560 mutable std::vector<Complex> stick_buffer_;
561 mutable std::vector<Complex> plane_buffer_;
562 mutable std::vector<Complex> transpose_buffer_;
563 mutable std::vector<Complex> receive_buffer_;
565 fftw_plan plan_sticks_forward_ =
nullptr;
566 fftw_plan plan_sticks_inverse_ =
nullptr;
567 fftw_plan plan_planes_forward_ =
nullptr;
568 fftw_plan plan_planes_inverse_ =
nullptr;