Decomposition and FFT¶
OpenPFC spectral workflows partition a Domain across MPI ranks and transform
local data through an implementation of the FFT contract. Read the
spectral-stack concept before using the exact
API below.
For uniform bounded axes, see boundary transforms: explicit DCT/DST grids and periodic x/y with bounded z.
Chebyshev Helmholtz solves¶
The rank-local functions in openpfc/kernel/fft/chebyshev.hpp solve
u'' - lambda*u = f on the Lobatto grid of [-1,1]. These are not
uniform-grid DCT/DST Laplacian solves. Boundary slopes are derivatives
with respect to increasing z; an outward Robin slope has positive weight
at +1 and negative weight at -1.
For nonzero lambda, let J integrate a Chebyshev series with integration
constant zero. The solver enforces
a[k] - lambda*(J*J*a)[k] = (J*J*f)[k], k=2,…,N, and two exact
coefficient boundary rows. Both extra modes of the first integral are
retained through the second integration before truncating the equations.
This integral formulation replaces the downward recurrence and its
cancellation between exponentially growing boundary-matching columns.
The finite truncation is an integrated coefficient formulation, not
bitwise the previous tau recurrence or pointwise collocation equations.
Row equilibration, partial pivoting and extended-precision elimination
are internal; the public values remain doubles. No small forcing modes
are discarded. Singular or numerically unresolved boundary systems and
nonfinite data are rejected. Negative lambda remains allowed, but
pure Dirichlet/Neumann resonances at lambda=-(m*pi/2)², m>=1, are
rejected explicitly. General Robin poles are only guarded by the pivot
test, not a condition-number estimate. Near-resonance sensitivity and
insufficient spatial resolution are not cured by this formulation.
Numerical differentiation of a returned high-degree field
can still amplify double-precision sampling roundoff.
Zero lambda retains the existing Poisson integrations, Neumann flux compatibility check and zero-integral gauge. Fourier-Chebyshev callers reuse this solve with lambda plus the periodic squared wavenumbers. The current direct solve uses O(N²) storage and O(N³) worst-case work per bounded line; factorization/plan caching is not provided.
The Chebyshev line transform calls pfc::fft::ComplexLineFFT, an ordinary
unnormalized complex DFT. For a Lobatto series of degree n the even
extension has length 2n. FFTW scaling applies: the backward transform of
the forward transform is length times the input. CudaComplexLineFFT
is the same contract on one rank through cufftPlan1d Z2Z. IHostFFT
and the cuFFT/rocFFT pencil plans remain real-to-complex volume
transforms. rocFFT and a distributed or HeFFTe line DFT are not part of
this step (#141).
pfc::decomposition::Decomposition¶
-
struct Decomposition¶
Global geometry and rank-owned boxes for a rectangular domain.
Geometry is stored by value, independently of the source Domain’s lifetime. The process grid uses x-fastest rank order. No communication is performed by this data type; MPI halo and FFT operations use its layout separately.
The grid is const, but m_domain and m_local_boxes are public mutable data. Treat a published layout as stable while fields, halo plans or FFT plans refer to it; changing these members does not rebuild their dependent state.
Public Functions
-
Decomposition(const Domain &domain, const Int3 &grid)¶
Locally partition domain with a positive, x-fastest process grid.
- Throws:
std::invalid_argument – If the grid is invalid or would make empty boxes.
std::runtime_error – If the splitter violates x-fastest rank ordering. No MPI calls are made. Geometry and boxes are owned by value.
-
Decomposition(const Domain &domain, const Int3 &grid)¶
pfc::fft::IHostFFT¶
-
struct IHostFFT : public pfc::fft::IFFTQueries¶
Host-container FFT (
std::vector/ host Field). Device backends are not this.Subclassed by pfc::fft::LocalFFT
Public Functions
-
virtual void forward(const RealVector &in, ComplexVector &out) = 0¶
Collective, unscaled real-to-complex transform on the plan communicator.
Every rank must call the same transform in the same order with valid local buffers. The output uses get_outbox_bounds(), with x-fastest ordering; its partition can differ from the input box.
- Parameters:
in – Real buffer; must satisfy
in.size() == size_inbox()out – Complex buffer; must satisfy
out.size() == size_outbox()
- Throws:
std::invalid_argument – when either buffer size mismatches the inbox/outbox contract (implementations report expected and actual).
-
virtual void backward(const ComplexVector &in, RealVector &out) = 0¶
Collective complex-to-real transform, scaled by 1/N globally.
N is the product of the full real-grid dimensions (not the local size). This normalization makes backward(forward(x)) recover x to roundoff. All plan ranks must participate in the same transform order.
- Parameters:
in – Complex buffer; must satisfy
in.size() == size_outbox()out – Real buffer; must satisfy
out.size() == size_inbox()
- Throws:
std::invalid_argument – when either buffer size mismatches the outbox/inbox contract (implementations report expected and actual).
-
virtual void forward(const RealVector &in, ComplexVector &out) = 0¶
pfc::fft::CPUFFT¶
-
class CPUFFT : public pfc::fft::FFT_Impl<heffte::backend::fftw>¶