Skip to content

adam_poisson_fft_object ​

ADAM, FFT Poisson solver on uniform periodic grids.

Solves L_h phi = factor (f - mean(f)) for a cell field f (one variable of a conservative array q) on a grid whose blocks all sit at one level and whose active directions are all periodic. L_h is the second-order 7-point Laplacian (5-point in 2-D; a null direction contributes nothing). The solve divides each Fourier mode by the eigenvalue of L_h itself, lambda_k = sum_d (2 cos(2 pi k_d / N_d) - 2) / dx_d^2, so the discrete residual of the returned phi is at round-off; the modes with lambda_k = 0 (the mean, and every mode along a null direction) are set to zero.

Data path (issue #81, D-81-2, first version). Every rank packs the interior f of its blocks with their integer block coordinates; MPI_Gatherv brings them to rank 0, which places them by the global cell index, transforms (transform, real-to-complex and back), and MPI_Scattervs every block's phi with all its ghost layers already filled by the periodic wrap of the global solution, so no ghost exchange follows. Correct for any rank count, ranks without blocks included; not scalable (rank 0 holds the whole grid).

Backends. This object transforms with FFTW 3 (-D_FFTW, -lfftw3; FFTW_ESTIMATE plans, deterministic). The FNL twin adam_fnl_poisson_fft_object extends it and overrides make_plans, transform and destroy_plans with cuFFT on the GPU of rank 0. Built without either, initialize stops: "built without an FFT library".

Entry points. solve packs one variable of a host conservative array; solve_packed takes the interior source already packed (block-major, i fastest: what a device kernel produces on FNL). Both can return energy = sum_cells f Phi (computed on rank 0 from the global arrays, broadcast): W = energy dV / 2 is the gravitational energy of self-gravity on a uniform grid.

Isolated boundaries (issue #81, M8-P4), Hockney and Eastwood. initialize(..., isolated=.true.) solves L_h phi = factor f with phi -> 0 at infinity (no mean removed): the source sits in a zero-padded array of m = 2 (n + ngc) cells per direction, and the circular convolution with the lattice Green's function of L_h (adam_lattice_green_library, h^2 G(n)) equals the free-space one on every cell the scatter reads, the ghost layers included, since m exceeds the largest offset, n - 1 + ngc, twice. The kernel's spectrum (khat, real: the kernel is even) is computed once. Inside the domain the discrete residual is that of the kernel, about 1e-11 of the source (scripts/lattice_green.py).

Homogeneous Dirichlet boundaries (issue #87, P1) are for the multigrid's coarsest level only (initialize_blocks(..., dirichlet=.true.)): phi = 0 at the centres of the first ghost layer. The source is extended odd about those centres to m = 2 (n + 1) cells per active direction, and the periodic transform of m cells solves it: the odd extension is the type-I sine transform, exact for the 7-point operator with zero ghosts.

Scope (fatal otherwise). One level for every block, the blocks covering the domain. Periodic: every active direction periodic. Isolated: 3-D, every direction non-periodic, cubic cells (the kernel is the unit lattice's). AMR is the multigrid's (adam_poisson_mg_object), which calls this solver on its coarsest level.

Source: src/lib/common/adam_poisson_fft_object.F90

Dependencies

Contents ​

Variables ​

NameTypeAttributesDescription
PIreal(kind=R8P)parameterPi.

Derived Types ​

poisson_fft_object ​

FFT Poisson solver on uniform periodic grids.

Inheritance

Components ​

NameTypeAttributesDescription
is_initializedlogicalInitialization status.
ninteger(kind=I4P)Global cells per direction.
minteger(kind=I4P)Transform cells per direction: n, or 2 (n + ngc) isolated.
isolatedlogicalIsolated boundaries (zero padding), else periodic.
dirichletlogicalHomogeneous Dirichlet boundaries (odd extension, #87).
ntinteger(kind=I4P)Cells of the periodic transform the eigenvalues refer to: n,
nijkinteger(kind=I4P)Cells per block per direction.
ngcinteger(kind=I4P)Ghost cells per side.
levelinteger(kind=I4P)Level of every block.
dxyzreal(kind=R8P)Cell spacing per direction.
lam1real(kind=R8P)allocatableEigenvalue part along x [0:n(1)/2].
lam2real(kind=R8P)allocatableEigenvalue part along y [0:n(2)-1].
lam3real(kind=R8P)allocatableEigenvalue part along z [0:n(3)-1].
f_globalreal(kind=R8P)allocatableRank 0: the source, then the potential [m(1),m(2),m(3)].
f_sourcereal(kind=R8P)allocatableRank 0: a copy of the source, for the energy.
f_hatcomplex(kind=R8P)allocatableRank 0: the transform [m(1)/2+1,m(2),m(3)].
khatreal(kind=R8P)allocatableRank 0, isolated: the kernel's spectrum over prod(m).
plan_r2ctype(c_ptr)FFTW forward plan (rank 0).
plan_c2rtype(c_ptr)FFTW backward plan (rank 0).

Type-Bound Procedures ​

NameAttributesDescription
destroypass(self)Destroy the solver.
initializepass(self)Check the grid, size the solver, make the plans.
solvepass(self)Solve for phi from one variable of q.
solve_packedpass(self)Solve for phi from the packed interior source.
initialize_blockspass(self)Size the solver from block counts and spacing (no grid, no field).
solve_blockspass(self)Solve from an explicit list of blocks (coordinates and source).
make_kernelpass(self)Rank 0, isolated: the kernel's spectrum.
destroy_planspass(self)Destroy the transform plans.
make_planspass(self)Make the transform plans (rank 0).
transformpass(self)f_global <- factor * L_h^-1 f_global (rank 0).
transform_kernelpass(self)khat <- the spectrum of f_global over prod(m) (rank 0, isolated).

Subroutines ​

destroy ​

Destroy the solver.

fortran
subroutine destroy(self)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.

Call graph

initialize ​

Check the grid (one level, the domain covered, the boundaries), size the solver, make the plans and, isolated, the kernel.

fortran
subroutine initialize(self, grid, field, isolated)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.
gridtype(grid_object)inThe grid.
fieldtype(field_object)inThe field (block coordinates).
isolatedlogicalinoptionalIsolated boundaries (default: periodic).

Call graph

initialize_blocks ​

Size the solver for a uniform grid of nblk blocks per direction, nijk cells each, at level with spacing dxyz, and make the plans (and, isolated, the kernel) on rank 0. No check of a grid: the caller owns the scope (the multigrid's coarsest level calls it directly, issue #81 P5; with dirichlet, issue #87).

fortran
subroutine initialize_blocks(self, nblk, nijk, ngc, dxyz, level, null_xyz, isolated, dirichlet)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.
nblkinteger(kind=I4P)inBlocks per direction.
nijkinteger(kind=I4P)inCells per block per direction.
ngcinteger(kind=I4P)inGhost cells per side (isolated: the padding margin).
dxyzreal(kind=R8P)inCell spacing.
levelinteger(kind=I4P)inLevel of every block.
null_xyzlogicalinNull directions.
isolatedlogicalinIsolated boundaries, else periodic.
dirichletlogicalinoptionalHomogeneous Dirichlet boundaries (default false).

Call graph

solve ​

Solve L_h phi = factor (q(iv) - mean(q(iv))) (periodic) or L_h phi = factor q(iv) with phi -> 0 at infinity (isolated); every ghost layer of phi is filled from the global solution.

fortran
subroutine solve(self, field, q, iv, factor, phi, energy)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.
fieldtype(field_object)inThe field (coordinates).
qreal(kind=R8P)inConservative [nv,i,j,k,nb].
ivinteger(kind=I4P)inVariable of q, the source.
factorreal(kind=R8P)inSource factor (4 pi G).
phireal(kind=R8P)inoutPotential [i,j,k,nb].
energyreal(kind=R8P)outoptionalsum_cells f phi (all ranks).

Call graph

solve_packed ​

Solve L_h phi = factor (f - mean(f)) (periodic) or L_h phi = factor f (isolated) from the packed interior source of this rank's blocks (block-major, i fastest, field%blocks_number * ni * nj * nk values); every ghost layer of phi is filled from the global solution (the periodic wrap, or the padded free-space solution).

fortran
subroutine solve_packed(self, field, buf, factor, phi, energy)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.
fieldtype(field_object)inThe field (block coordinates).
bufreal(kind=R8P)inPacked interior source of this rank.
factorreal(kind=R8P)inSource factor (4 pi G for gravity).
phireal(kind=R8P)inoutPotential [i,j,k,nb].
energyreal(kind=R8P)outoptionalsum_cells f phi (all ranks).

Call graph

solve_blocks ​

The solve on an explicit list of this rank's blocks: their integer coordinates at the solver's level and their packed interior source (block-major, i fastest); out returns each block's potential with gw ghost layers (block-major, i fastest, from 1-gw to n+gw), filled from the global solution. Optionally the energy sum_cells f phi (rank 0 computes it, every rank gets it).

fortran
subroutine solve_blocks(self, nbl, coords, buf, factor, gw, out, energy)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.
nblinteger(kind=I4P)inBlocks of this rank.
coordsinteger(kind=I4P)inBlock coordinates [3,nbl].
bufreal(kind=R8P)inPacked interior source of this rank.
factorreal(kind=R8P)inSource factor (4 pi G for gravity).
gwinteger(kind=I4P)inGhost layers of out.
outreal(kind=R8P)inoutPacked potential, ghosts included.
energyreal(kind=R8P)outoptionalsum_cells f phi (all ranks).

Call graph

make_kernel ​

Rank 0, isolated: place the kernel h^2 G(o) at every offset o, wrapped into (-m/2, m/2] per direction, and keep its spectrum over prod(m) (transform_kernel).

fortran
subroutine make_kernel(self)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.

Call graph

destroy_plans ​

Destroy the FFTW plans.

fortran
subroutine destroy_plans(self)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.

Call graph

make_plans ​

Make the FFTW plans on rank 0's global arrays (FFTW_ESTIMATE: the arrays are not touched, the plans deterministic).

fortran
subroutine make_plans(self)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.

Call graph

transform ​

Rank 0: f_global <- factor * L_h^-1 f_global. Periodic: the modes of zero eigenvalue (the mean) set to zero; isolated: the convolution with the kernel (khat).

fortran
subroutine transform(self, factor)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.
factorreal(kind=R8P)inSource factor.

Call graph

transform_kernel ​

Rank 0, isolated: khat <- FFT(f_global) / prod(m), real (the kernel is even in every direction).

fortran
subroutine transform_kernel(self)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_fft_object)inoutThe solver.

Call graph