ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
P3MFFT.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024-2026 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include "p3m/P3MFFTBackend.hpp"
23
24#include "communication.hpp"
25
27
28#include <utils/Vector.hpp>
29#include <utils/index.hpp>
30
31#include <boost/mpi/communicator.hpp>
32
33#include <heffte.h>
34#include <heffte_backends.h>
35
36#include <algorithm>
37#include <array>
38#include <initializer_list>
39#include <memory>
40
41#if defined(__CUDACC__)
42#include "cuda/utils.cuh"
43#endif
44
45/**
46 * @brief FFT manager.
47 */
48template <typename FloatType, Arch Architecture, class FFTConfig> class P3MFFT {
49public:
50 using OutputType = typename heffte::fft_output<FloatType>::type;
51 using backend =
52 std::conditional_t<Architecture == Arch::CPU, heffte::backend::fftw,
53 heffte::backend::cufft>;
54 template <class T = OutputType>
55 using buffer_container = heffte::fft3d<backend>::template buffer_container<T>;
56
57private:
58 using FFT3D =
59 std::conditional_t<FFTConfig::use_r2c, heffte::fft3d_r2c<backend>,
60 heffte::fft3d<backend>>;
61 using Box = heffte::box3d<>;
62 using stream_type =
63 heffte::backend::device_instance<heffte::tag::gpu>::stream_type;
64
65 /* input box */
66 std::unique_ptr<Box> in_box;
67 /* output box */
68 std::unique_ptr<Box> out_box;
69 /* workspace for the FFT */
71 /* FFT backend */
72 std::unique_ptr<FFT3D> fft3d;
73 std::shared_ptr<boost::mpi::environment> m_mpi_env_lock;
74
75 template <typename T, std::size_t N>
76 static auto to_array(Utils::Vector<T, N> const &vec) {
77 std::array<T, N> res{};
78 std::ranges::copy(vec, res.begin());
79 return res;
80 }
81
82public:
84 fft3d.reset();
85 m_mpi_env_lock.reset();
86 }
87 P3MFFT(stream_type gpu_stream, boost::mpi::communicator comm,
91 Utils::Vector3i const &node_grid) {
92 auto constexpr row_major_order = std::array<int, 3>{2, 1, 0};
93 auto constexpr col_major_order = std::array<int, 3>{0, 1, 2};
94 auto constexpr in_box_order =
95 (FFTConfig::r_space_order == Utils::MemoryOrder::ROW_MAJOR)
98 auto constexpr out_box_order =
99 (FFTConfig::k_space_order == Utils::MemoryOrder::ROW_MAJOR)
102 auto const n_procs = Utils::product(node_grid);
103 auto const high = to_array(global_mesh - Utils::Vector3i::broadcast(1));
104 auto const global_out_box_full = Box({0, 0, 0}, high, out_box_order);
105 auto const global_out_box =
106 FFTConfig::use_r2c ? global_out_box_full.r2c(FFTConfig::r2c_dir)
108 auto best_grid = node_grid;
109 for (auto i : {0u, 1u, 2u}) {
110 if (global_mesh[i] % (2 * n_procs) == 0) {
111 best_grid = {n_procs, 1, 1};
112 break;
113 }
114 }
115 // use optimal output box decomposition based on prime factors
116 auto out_boxes = heffte::split_world(global_out_box, to_array(best_grid));
117 out_box = std::make_unique<Box>(out_boxes[comm.rank()]);
118
119 in_box = std::make_unique<Box>(
120 to_array(rs_local_ld_index),
123
124 // at this stage we can manually adjust some HeFFTe options
125 heffte::plan_options options = heffte::default_options<backend>();
126
127 // use strided 1-D FFT operations
128 // some backends work just as well when the entries of the data are not
129 // contiguous then there is no need to reorder the data in the intermediate
130 // stages which saves time
131 options.use_reorder = true;
132
133 // use point-to-point communications
134 // collaborative all-to-all and individual point-to-point communications are
135 // two alternatives one may be better than the other depending on the
136 // version of MPI, the hardware interconnect, and the problem size
137 options.algorithm = heffte::reshape_algorithm::p2p_plined;
138
139 // in the intermediate steps, the data can be shapes as either 2-D slabs or
140 // 1-D pencils for sufficiently large problem, it is expected that the
141 // pencil decomposition is better but for smaller problems, the slabs may
142 // perform better (depending on hardware and backend)
143 options.use_pencils = true;
144#if defined(__CUDACC__)
145 if constexpr (Architecture == Arch::CUDA) {
146 options.use_gpu_aware = ::communication_environment->is_mpi_gpu_aware();
147 }
148#endif
149#ifdef ESPRESSO_FPE
150 // cuFFT builds device kernels using CUDA-JIT
151 // (https://docs.nvidia.com/cuda/archive/13.1.1/cufft/#plan-initialization-time)
152 // but this operation is not guaranteed to succeed for all mesh sizes,
153 // and in rare cases, it can send the SIGFPE signal
154 auto const trap_pause = (Architecture == Arch::CUDA)
156 : nullptr;
157#endif
158
159 if constexpr (FFTConfig::use_r2c) {
160 fft3d = std::make_unique<FFT3D>(gpu_stream, *in_box, *out_box,
161 FFTConfig::r2c_dir, comm, options);
162 } else {
163 fft3d =
164 std::make_unique<FFT3D>(gpu_stream, *in_box, *out_box, comm, options);
165 }
166 m_workspace = decltype(m_workspace)(fft3d->size_workspace());
167 // MPI communicator is needed to destroy the FFT plans
168 m_mpi_env_lock = ::communication_environment->get_mpi_env();
169 }
170
172 return Utils::Vector3i(out_box->low);
173 }
175 return Utils::Vector3i(out_box->high) + Utils::Vector3i::broadcast(1);
176 }
181 return Utils::Vector3i(in_box->high) + Utils::Vector3i::broadcast(1) -
182 Utils::Vector3i(in_box->low);
183 }
184 void forward(auto &&in, auto &&out) {
185 fft3d->forward(in, out, m_workspace.data());
186 }
187 void backward(auto &&in, auto &&out) {
188 fft3d->backward(in, out, m_workspace.data());
189 }
190};
191
192/**
193 * @brief heFFTe-backed implementation of the P3M FFT interface.
194 *
195 * Thin adapter that exposes @ref P3MFFT through the @ref P3MFFTBackend
196 * virtual interface, so the solver can hold it interchangeably with other
197 * backends. This is the general backend, used for any rank count.
198 */
199template <typename FloatType, class FFTConfig>
200struct P3MFFTHeffte final : public P3MFFTBackend<FloatType, FFTConfig> {
204
205 P3MFFTHeffte(boost::mpi::communicator comm,
209 Utils::Vector3i const &node_grid)
211 node_grid),
212 m_input(static_cast<std::size_t>(Utils::product(rs_local_size()))) {}
213
215 return m_impl.ks_local_ld_index();
216 }
218 return m_impl.ks_local_ur_index();
219 }
221 return m_impl.ks_local_size();
222 }
224 return m_impl.rs_local_size();
225 }
226 RSpaceScalar *forward_input_buffer() override { return m_input.data(); }
227 void forward(RSpaceScalar const *in, ComplexType *out) override {
228 m_impl.forward(in, out);
229 }
231 // heFFTe preserves the input; the non-const parameter is the interface's
232 // contract for backends that cannot (see P3MFFTBackend::backward).
233 m_impl.backward(in, out);
234 }
235
236private:
238 std::vector<RSpaceScalar> m_input;
239};
Vector implementation and trait types for boost qvm interoperability.
FFT manager.
Definition P3MFFT.hpp:48
void backward(auto &&in, auto &&out)
Definition P3MFFT.hpp:187
Utils::Vector3i ks_local_size() const
Definition P3MFFT.hpp:177
void forward(auto &&in, auto &&out)
Definition P3MFFT.hpp:184
Utils::Vector3i ks_local_ur_index() const
Definition P3MFFT.hpp:174
Utils::Vector3i rs_local_size() const
Definition P3MFFT.hpp:180
~P3MFFT()
Definition P3MFFT.hpp:83
typename heffte::fft_output< FloatType >::type OutputType
Definition P3MFFT.hpp:50
heffte::fft3d< backend >::template buffer_container< T > buffer_container
Definition P3MFFT.hpp:55
P3MFFT(stream_type gpu_stream, boost::mpi::communicator comm, Utils::Vector3i const &global_mesh, Utils::Vector3i const &rs_local_ld_index, Utils::Vector3i const &rs_local_ur_index, Utils::Vector3i const &node_grid)
Definition P3MFFT.hpp:87
std::conditional_t< Architecture==Arch::CPU, heffte::backend::fftw, heffte::backend::cufft > backend
Definition P3MFFT.hpp:53
Utils::Vector3i ks_local_ld_index() const
Definition P3MFFT.hpp:171
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value) noexcept
Create a vector that has all entries set to the same value.
Definition Vector.hpp:132
static std::shared_ptr< scoped_pause > make_shared_pause_scoped()
Generate a shared handle to temporarily disable any currently active exception trap for the lifetime ...
Definition fe_trap.cpp:144
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
std::unique_ptr< CommunicationEnvironment > communication_environment
T product(Vector< T, N > const &v)
Definition Vector.hpp:383
VectorXi< 3 > Vector3i
Definition Vector.hpp:202
STL namespace.
Abstract interface for the P3M reciprocal-space FFT.
std::complex< FloatType > ComplexType
FloatType RSpaceScalar
Real-space scalar type.
heFFTe-backed implementation of the P3M FFT interface.
Definition P3MFFT.hpp:200
Utils::Vector3i rs_local_size() const override
Definition P3MFFT.hpp:223
typename Base::RSpaceScalar RSpaceScalar
Definition P3MFFT.hpp:203
Utils::Vector3i ks_local_ld_index() const override
Definition P3MFFT.hpp:214
void forward(RSpaceScalar const *in, ComplexType *out) override
Definition P3MFFT.hpp:227
Utils::Vector3i ks_local_size() const override
Definition P3MFFT.hpp:220
RSpaceScalar * forward_input_buffer() override
Definition P3MFFT.hpp:226
P3MFFTHeffte(boost::mpi::communicator comm, Utils::Vector3i const &global_mesh, Utils::Vector3i const &rs_local_ld_index, Utils::Vector3i const &rs_local_ur_index, Utils::Vector3i const &node_grid)
Definition P3MFFT.hpp:205
Utils::Vector3i ks_local_ur_index() const override
Definition P3MFFT.hpp:217
void backward(ComplexType *in, RSpaceScalar *out) override
Definition P3MFFT.hpp:230
typename Base::ComplexType ComplexType
Definition P3MFFT.hpp:202