40using cplx = std::complex<double>;
43 return n > 0 && (n & (n - 1)) == 0;
53 std::vector<cplx> out(
static_cast<std::size_t
>(n));
54 const double s = inv ? 1.0 : -1.0;
55 for (
int k = 0; k < n; ++k) {
57 for (
int j = 0; j < n; ++j) {
58 const double ang = s * 2.0 * std::numbers::pi * (
static_cast<double>(k) * j / n);
59 acc += a[j] *
cplx(std::cos(ang), std::sin(ang));
61 out[
static_cast<std::size_t
>(k)] = inv ? acc /
static_cast<double>(n) : acc;
63 for (
int i = 0; i < n; ++i)
64 a[i] = out[
static_cast<std::size_t
>(i)];
75 for (
int i = 1, j = 0; i < n; ++i) {
77 for (; j & bit; bit >>= 1)
81 std::swap(a[i], a[j]);
83 for (
int len = 2; len <= n; len <<= 1) {
84 const double ang = 2.0 * std::numbers::pi / len * (inv ? 1.0 : -1.0);
85 const cplx wl(std::cos(ang), std::sin(ang));
86 for (
int i = 0; i < n; i += len) {
88 for (
int k = 0; k < len / 2; ++k) {
89 const cplx u = a[i + k], v = a[i + k + len / 2] * w;
91 a[i + k + len / 2] = u - v;
97 for (
int i = 0; i < n; ++i)
109 PoissonFFT(
int Nx,
int Ny,
double Lx,
double Ly,
bool spectral =
false)
118 spectral_(spectral) {}
121 int nx()
const {
return Nx_; }
126 void solve(
const std::vector<double>& rho_local, std::vector<double>& phi_local) {
127 std::vector<cplx> A(
static_cast<std::size_t
>(nyl_) * Nx_);
128 for (std::size_t t = 0; t < A.size(); ++t)
129 A[t] =
cplx(rho_local[t], 0.0);
130 for (
int jl = 0; jl < nyl_; ++jl)
131 fft1d(&A[
static_cast<std::size_t
>(jl) * Nx_], Nx_,
false);
133 std::vector<cplx> B(
static_cast<std::size_t
>(nxl_) * Ny_);
135 for (
int il = 0; il < nxl_; ++il)
136 fft1d(&B[
static_cast<std::size_t
>(il) * Ny_], Ny_,
false);
138 for (
int il = 0; il < nxl_; ++il) {
139 const int kx = rank_ * nxl_ + il;
140 const int kxs = (kx < (Nx_ + 1) / 2) ? kx : kx - Nx_;
141 const double wx = 2.0 * std::numbers::pi * kxs / (Nx_ * dx_);
143 spectral_ ? -(wx * wx)
144 : (2.0 * std::cos(2.0 * std::numbers::pi * kx / Nx_) - 2.0) / (dx_ * dx_);
145 for (
int ky = 0; ky < Ny_; ++ky) {
146 const int kys = (ky < (Ny_ + 1) / 2) ? ky : ky - Ny_;
147 const double wy = 2.0 * std::numbers::pi * kys / (Ny_ * dy_);
149 spectral_ ? -(wy * wy)
150 : (2.0 * std::cos(2.0 * std::numbers::pi * ky / Ny_) - 2.0) / (dy_ * dy_);
151 const double lam = lx + ly;
152 cplx& v = B[
static_cast<std::size_t
>(il) * Ny_ + ky];
153 v = (std::abs(lam) < 1e-14) ?
cplx(0.0, 0.0) : v / lam;
157 for (
int il = 0; il < nxl_; ++il)
158 fft1d(&B[
static_cast<std::size_t
>(il) * Ny_], Ny_,
true);
160 for (
int jl = 0; jl < nyl_; ++jl)
161 fft1d(&A[
static_cast<std::size_t
>(jl) * Nx_], Nx_,
true);
163 phi_local.resize(A.size());
164 for (std::size_t t = 0; t < A.size(); ++t)
165 phi_local[t] = A[t].real();
170 void transpose_fwd(
const std::vector<cplx>& A, std::vector<cplx>& B) {
171 const int blk = nyl_ * nxl_;
172 std::vector<cplx> send(
static_cast<std::size_t
>(np_) * blk), recv(send.size());
173 for (
int s = 0; s < np_; ++s)
174 for (
int jl = 0; jl < nyl_; ++jl)
175 for (
int il = 0; il < nxl_; ++il)
176 send[
static_cast<std::size_t
>(s) * blk +
static_cast<std::size_t
>(jl) * nxl_ + il] =
177 A[
static_cast<std::size_t
>(jl) * Nx_ +
static_cast<std::size_t
>(s) * nxl_ + il];
178 alltoall(send, recv, blk);
179 for (
int q = 0; q < np_; ++q)
180 for (
int jl = 0; jl < nyl_; ++jl)
181 for (
int il = 0; il < nxl_; ++il)
182 B[
static_cast<std::size_t
>(il) * Ny_ +
static_cast<std::size_t
>(q) * nyl_ + jl] =
183 recv[
static_cast<std::size_t
>(q) * blk +
static_cast<std::size_t
>(jl) * nxl_ + il];
187 void transpose_bwd(
const std::vector<cplx>& B, std::vector<cplx>& A) {
188 const int blk = nxl_ * nyl_;
189 std::vector<cplx> send(
static_cast<std::size_t
>(np_) * blk), recv(send.size());
190 for (
int s = 0; s < np_; ++s)
191 for (
int il = 0; il < nxl_; ++il)
192 for (
int jl = 0; jl < nyl_; ++jl)
193 send[
static_cast<std::size_t
>(s) * blk +
static_cast<std::size_t
>(il) * nyl_ + jl] =
194 B[
static_cast<std::size_t
>(il) * Ny_ +
static_cast<std::size_t
>(s) * nyl_ + jl];
195 alltoall(send, recv, blk);
196 for (
int q = 0; q < np_; ++q)
197 for (
int il = 0; il < nxl_; ++il)
198 for (
int jl = 0; jl < nyl_; ++jl)
199 A[
static_cast<std::size_t
>(jl) * Nx_ +
static_cast<std::size_t
>(q) * nxl_ + il] =
200 recv[
static_cast<std::size_t
>(q) * blk +
static_cast<std::size_t
>(il) * nyl_ + jl];
204 void alltoall(
const std::vector<cplx>& send, std::vector<cplx>& recv,
int blk) {
210 MPI_Alltoall(send.data(), 2 * blk, MPI_DOUBLE, recv.data(), 2 * blk, MPI_DOUBLE,
217 int Nx_, Ny_, np_, rank_, nyl_, nxl_;
219 bool spectral_ =
false;
Definition poisson_fft.hpp:101
void solve(const std::vector< double > &rho_local, std::vector< double > &phi_local)
Definition poisson_fft.hpp:126
PoissonFFT(int Nx, int Ny, double Lx, double Ly, bool spectral=false)
spectral: false (default) = DISCRETE 5-point stencil eigenvalue (consistent with the transport gradie...
Definition poisson_fft.hpp:109
int nx() const
Definition poisson_fft.hpp:121
int ny_local() const
Definition poisson_fft.hpp:120
int y_begin() const
Definition poisson_fft.hpp:122
Parallel seam: minimal MPI abstraction (rank/size + collectives) with serial fallback.
Definition amr_hierarchy.hpp:29
std::complex< double > cplx
Definition poisson_fft.hpp:40
void dft1d_direct(cplx *a, int n, bool inv)
Definition poisson_fft.hpp:52
int n_ranks()
Definition comm.hpp:139
bool is_pow2(int n)
Definition poisson_fft.hpp:42
void fft1d(cplx *a, int n, bool inv)
Definition poisson_fft.hpp:70
int my_rank()
Definition comm.hpp:136