Skip to content

adam_poisson_mg_object ​

ADAM, multigrid-preconditioned conjugate-gradient Poisson solver on AMR grids (issue #81, M8-P5).

Solves L_h phi = factor (f - mean(f)) on the leaf cells of a 2:1-balanced octree (quadtree in 2-D, null_z), periodic in every active direction, with L_h a composite second-order Laplacian that is symmetric and consistent (issue #81, P5a):

  • between leaves of one level, the 7-point (5-point) stencil;
  • across a 2:1 face, the mimetic mean flux: every fine cell f_k (k = 1..n, n = 2^(d-1)) on a coarse cell C's face gets the same flux (2/3) w (mean_k phi_fk - phi_C), w the fine face weight (area over the fine spacing), and C gets their sum. It is the hybrid mimetic finite-difference flux of the coarse cell seen as a polygon with hanging nodes, its face unknowns eliminated: consistency (every sub-face flux exact for linear phi) forces the coarse cell's sub-face block to rank one (it sees only the mean of the face unknowns), and the elimination gives the mean of the fine cells. Exact for linear phi face by face, so the truncation error stays bounded at the seams (phi second order, the seam face gradient first order); symmetric in the V-weighted form (rows times the cell volume), so the solution map phi = K f has V K symmetric, which exact energy conservation of self-gravity needs. Rejected on the way (#81, P5-0 and P5a): Tomida & Stone's flux matching (consistent, not symmetric: the fallback); its symmetrisation (B + B^T) / 2 (symmetric, inconsistent: O(1/h) truncation, a seam gravity that does not converge); the Galerkin operator P^T A_fine P (symmetric, first order).

The solve is flexible preconditioned conjugate gradients (Notay's FCG(1)) on the composite operator: correctness lives in its matrix-vector product only. The preconditioner is one V-cycle over the level hierarchy: level l holds the leaves at l and a shadow block for every tree node at l that has children (ADAM keeps leaves only); red-black Gauss-Seidel sweeps down and up on the plain level Laplacian, a face to a cell outside the level reading the coarser correction (piecewise constant) on the way up; restriction the sum of the children's residuals, prolongation piecewise constant; the coarsest tree level (every block at the minimum leaf level: the whole domain) coarsened further inside the blocks (issue #84, E5c): each level below it halves the cells per block along every active direction, the same blocks on the same ranks, the plain level Laplacian with the face kinds, the same smoother and transfers, while the cells per block are even and the domain has more than root_cells cells at the level (default: the root solver's root_cells_max, told the growth of the root's transform: on the host 128^3 transform cells, so a periodic root of 128^3 cells and a ghost-Dirichlet one of 64^3; on cuFFT 32^3 cells, #84 E6 and E6b); the last of them, the root (lbot), is solved exactly by the FFT solver (adam_poisson_fft_object%solve_blocks; of the caller's backend type with initialize(coarse=)): on every rank (redundant), from the source gathered by MPI_ALLGATHERV, when it has at most REDUNDANT_ROOT_MAX (32^3) cells, so no rank-0 gather and scatter per V-cycle; a larger root (root_cells above the default) on the FFT solver's distributed path, since every rank transforming it contends for the node's memory (FNL, 4 GPUs, the isolated 128^3 coarsest level: 4.7 -> 6.4 s per solve). A coarsest tree level of at most root_cells cells is its own root, solved as before. Measured (test_poisson_mg --sub, every level down to one cell per block): 1 -> 14 FCG iterations on a uniform 1:2:3-cell box (point smoothing on anisotropic cells), +1 to +13 on AMR (24-47 -> 25-53). Medooza CPU, 3.9 M AMR cells per solve: isolated 50.7 -> 31.2 s at np 1 and 39.9 -> 6.5 s at np 16 (its 258^3 coarsest level and 42 exact solves were 70% of it); periodic 9.2 -> 12.7 s at np 1, even at np 8, 2.6 -> 2.3 s at np 16 (the generic CSR smoother on the base level costs more than one FFT of it on few ranks; a stencil smoother is #84 E6). It stops at tolerance or at the round-off floor of the source, 100 eps max|factor f| / max|factor (f - mean f)|, whichever is larger (a small perturbation of a uniform density is known only to that floor, #81 P5b).

Backend hooks (issue #84, E6a). The FCG iteration and the V-cycle work on vectors allocated once (make_work) through overridable hooks: apply, smooth, the vector operations (vec_*, nopass), vec_update (a vector to or from where the hooks compute) and work_place (the operators and vectors put there after initialize). Here they are the host loops, bitwise those of before; adam_fnl_poisson_mg_object runs them on the device. The right-hand side, the root, the James step and the ghost fill's placement stay on the host.

Distributed and assembled. Every rank gathers the leaf list once (block coordinates, owner, local index), derives the shadow blocks and their owners (the owner of the first leaf below, in the gathered order: the same on every rank), and assembles, from the geometry only, the rows of its own cells: the operator, the ghost fill, the level operators and transfers. Columns are global cell keys; every operator owns a halo-exchange plan (the remote columns it reads, fetched from their owners by MPI_ALLTOALLV). Correct for any rank count. Cell keys carry the level offset by KEY_LEVEL_OFFSET (the levels inside the blocks may be negative).

Domain boundaries (issue #87, P1; per face, issue #84, E1b). Every active axis is periodic (both faces) or bounded, and each face of a bounded axis has a kind (adam_flail_parameters; initialize(..., bc=), by default ghost-Dirichlet on every bounded axis, the #87 behaviour). A boundary face of a leaf cell C (weight w, the face area over the cell spacing h) adds to C's row, and maps its boundary value g onto the right-hand side:

  • FLAIL_BC_DIRICHLET_GHOST, g the value at the centre of the first ghost cell: -w phi_C, w g;
  • FLAIL_BC_DIRICHLET, g the value at the face (phi_ghost = 2 g - phi_C): -2 w phi_C, 2 w g;
  • FLAIL_BC_NEUMANN, g the outward normal derivative at the face (phi_ghost = phi_C + h g): nothing, w h g. So the operator A keeps the homogeneous rows, symmetric, and solve(..., ghost=g) solves A phi = factor V f - B g, B the map of the boundary values onto the boundary rows (apply_b; its transpose apply_bt, the boundary rows onto the faces). The faces are listed per rank (nbnd, bnd_row, bnd_w the weight in B, bnd_kind, bnd_dir the outward axis signed, bnd_x where g lives: the ghost centre or the face centre). Without a Dirichlet face the operator is singular, as on a periodic grid (singular): the solve removes the mean of the right-hand side factor V f - B g (the compatibility condition, exact for compatible data) and of the solution. The V-cycle's levels take the same face kinds, homogeneous, and its coarsest level the FFT solver with them (odd or even extensions; issue #84, E1a); on a uniform grid the two operators coincide and one V-cycle is the exact solve. The two faces of an axis are both periodic or neither, and both ghost-Dirichlet or neither (the FFT solver's scope).

Isolated boundaries (issue #87, P2), a symmetric James step. initialize(..., isolated=.true.): each solve is the zero-ghost solve phi0 = A^-1 factor V f; the screening charge s = B^T phi0 on the ghost cells (extended by zero, phi0 satisfies the infinite operator with the extra source -s there); the ghost values of the free-space solution g = -G s, G the inverse of the V-weighted operator on the infinite coarsest lattice from ghost cell to ghost cell (the lattice Green's function over the coarsest spacing; ghost_green, a zero-padded FFT of the coarsest box widened by the ghost layer, gfft); and the solve with them. The map (A^-1 + A^-1 B G B^T A^-1) factor V is symmetric in the V-weighted form (A and G are), so self-gravity keeps its exact E + W exchange; on a uniform grid it is the discrete free-space solution (the FFT solver's isolated mode), on AMR second order (G misses the refined interior, a truncation-order perturbation). G is exact on the boundary only if every boundary leaf is at the coarsest level (each face then has its own ghost cell of the coarse lattice): fatal otherwise (D-87-2). The textbook James method (the screening charge on the boundary surface, the potential at the ghost centres) is not symmetric (selfgravity/james_proto.py, the P0 prototype).

Scope (fatal otherwise). The face kinds above: without bc every active direction periodic or none (a mixed grid would get a silent zero on its bounded faces), with it the grid's periodicity and bc agree; isolated: 3-D, no periodic direction, no bc, cubic cells, every boundary leaf at the coarsest level; 2:1 balance across faces; fewer than 2^19 cells per direction at the finest level (the cell keys). On output phi holds the leaf solution and its first ghost layer per face: same level, the neighbour; at a domain face, the ghost of its kind, g, 2 g - phi_C or phi_C + h g (g = 0 when none is given); across a 2:1 face, the value that makes the one-sided face difference equal the operator's own face gradient, (mean_f - phi_C) / (1.5 h) (fine side: phi_f - (mean_f - phi_C) / 1.5; coarse side: phi_C + (mean_f - phi_C) / 0.75); deeper ghost layers copy the first.

Source: src/lib/common/adam_poisson_mg_object.F90

Dependencies

Contents ​

Variables ​

NameTypeAttributesDescription
MG_SEAM_GHOST_SCALEreal(kind=R8P)parametercomposite operator's face gradient (clients that invert it, as
CLS_SAMEinteger(kind=I4P)parameterNeighbour position: a leaf of the same level.
CLS_FINERinteger(kind=I4P)parameterNeighbour position: refined (finer leaves).
CLS_COARSERinteger(kind=I4P)parameterNeighbour position: inside a leaf one level coarser.
SPACE_COMPinteger(kind=I4P)parameterVector space: the composite leaf cells (levels are the other spaces;
KEY_LEVEL_OFFSETinteger(kind=I4P)parameterLevel offset in the cell keys (the levels below lmin, E5c).
REDUNDANT_ROOT_MAXinteger(kind=I4P)parameterA root of at most this many cells is solved on every rank;

Derived Types ​

hash_table ​

Open-addressing hash, int64 key (>= 0) -> int32 value (0: absent).

Components ​

NameTypeAttributesDescription
keysinteger(kind=I8P)allocatableKeys (-1: empty).
valsinteger(kind=I4P)allocatableValues.
capinteger(kind=I4P)Capacity (a prime).

dcsr ​

Distributed CSR operator: local rows; columns local (1..nloc) or halo (nloc+1..nloc+nhalo).

Components ​

NameTypeAttributesDescription
nrowinteger(kind=I4P)Rows, local columns, halo columns.
nlocinteger(kind=I4P)Rows, local columns, halo columns.
nhalointeger(kind=I4P)Rows, local columns, halo columns.
rowptrinteger(kind=I4P)allocatableRow pointers [nrow+1].
colinteger(kind=I4P)allocatableColumn slots.
valreal(kind=R8P)allocatableValues.
scountinteger(kind=I4P)allocatableSend counts and displacements per rank.
sdisplinteger(kind=I4P)allocatableSend counts and displacements per rank.
sidxinteger(kind=I4P)allocatableLocal column indices to send.
rcountinteger(kind=I4P)allocatableReceive counts and displacements per rank (halo order).
rdisplinteger(kind=I4P)allocatableReceive counts and displacements per rank (halo order).

rvec ​

A real vector (one per level).

Components ​

NameTypeAttributesDescription
vreal(kind=R8P)allocatableValues.

ivec ​

An integer vector (one per level).

Components ​

NameTypeAttributesDescription
vinteger(kind=I4P)allocatableValues.

triplets ​

Assembly buffer: (row, column key, value).

Components ​

NameTypeAttributesDescription
ninteger(kind=I4P)Entries.
rinteger(kind=I4P)allocatableRows.
kinteger(kind=I8P)allocatableColumn keys.
vreal(kind=R8P)allocatableValues.

poisson_mg_object ​

Multigrid-preconditioned CG Poisson solver on AMR grids.

Inheritance

Components ​

NameTypeAttributesDescription
is_initializedlogicalInitialization status.
nijkinteger(kind=I4P)Cells per block per direction.
ncbinteger(kind=I4P)Cells per block.
ngcinteger(kind=I4P)Ghost cells per side.
ndinteger(kind=I4P)Active directions.
actinteger(kind=I4P)The active directions.
nulllogicalNull directions.
nblk0integer(kind=I4P)Blocks per direction at level 0.
dx0real(kind=R8P)Cell spacing at level 0.
lmininteger(kind=I4P)Leaf levels range.
lmaxinteger(kind=I4P)Leaf levels range.
lbotinteger(kind=I4P)The root level: lmin less the levels inside the blocks (E5c).
root_maxinteger(kind=I4P)Most cells of the root (E5c; the root solver's default).
nrinteger(kind=I4P)Ranks, this rank.
meinteger(kind=I4P)Ranks, this rank.
nleafinteger(kind=I4P)Leaves over the ranks.
leaf_cinteger(kind=I4P)allocatableLeaf block coordinates (i,j,k,level) [4,nleaf].
leaf_ownerinteger(kind=I4P)allocatableOwner rank.
leaf_locinteger(kind=I4P)allocatableLocal block index (the field's) on its owner.
leaf_hashtype(hash_table)Block key -> leaf id.
nnodeinteger(kind=I4P)Nodes.
node_cinteger(kind=I4P)allocatableNode block coordinates (i,j,k,level) [4,nnode].
node_ownerinteger(kind=I4P)allocatableOwner rank.
node_locinteger(kind=I4P)allocatableLocal block index in its level space on its owner.
node_leaflogicalallocatableThe node is a leaf.
node_hashtype(hash_table)Block key -> node id.
nloc_levinteger(kind=I4P)allocatableThis rank's blocks per level [lbot:lmax].
lev_nodeinteger(kind=I4P)allocatableThis rank's level blocks: node id [max blocks, lbot:lmax]
nleaf_locinteger(kind=I4P)This rank's leaves.
leaf_levinteger(kind=I4P)allocatableThis rank's leaf b: its level.
leaf_lev_locinteger(kind=I4P)allocatableThis rank's leaf b: its local index in its level space.
atype(dcsr)The composite operator on the leaves.
gtype(dcsr)Ghost fill: the first ghost layer of the leaves.
g_dstinteger(kind=I4P)allocatableGhost fill destinations (i,j,k,b) [4,rows].
altype(dcsr)allocatableLevel operators [lbot+1:lmax].
eltype(dcsr)allocatableLevel ghost terms from level l-1 [lbot+1:lmax].
rltype(dcsr)allocatableRestriction l -> l-1 [lbot+1:lmax].
pltype(dcsr)allocatableProlongation l-1 -> l [lbot+1:lmax].
diagtype(rvec)allocatableLevel operator diagonals [lbot+1:lmax].
colourtype(rvec)allocatableRed-black colour (0, 1) of the level cells [lbot+1:lmax].
volreal(kind=R8P)allocatableLeaf cell volumes.
bcinteger(kind=I4P)Kind per face [lo/hi, axis] (adam_flail_parameters).
periodiclogicalPeriodic axes (a null axis counts as periodic).
singularlogicalNo Dirichlet face: the operator's kernel is the constants.
eminreal(kind=R8P)Domain lower corner.
nbndinteger(kind=I4P)This rank's boundary faces.
bnd_rowinteger(kind=I4P)allocatableBoundary face: the local leaf cell (row) it bounds.
bnd_wreal(kind=R8P)allocatableBoundary face: its weight in B (see the module).
bnd_xreal(kind=R8P)allocatableBoundary face: where its value lives, ghost or face centre.
bnd_kindinteger(kind=I4P)allocatableBoundary face: its kind.
bnd_dirinteger(kind=I4P)allocatableBoundary face: the outward axis, signed (-3..3).
bnd_gsreal(kind=R8P)allocatableBoundary face: its value's weight in the ghost fill.
g_bndinteger(kind=I4P)allocatableGhost-fill row: its boundary face, 0 for an interior one.
isolatedlogicalFree-space boundaries: the ghost values by the James step.
ncinteger(kind=I4P)Cells per direction at the coarsest level.
bnd_giinteger(kind=I4P)allocatableBoundary face: its ghost cell in the widened coarsest box.
u0real(kind=R8P)allocatableThe last zero-ghost solution (warm start of the first solve).
iterations0integer(kind=I4P)Iterations of the last zero-ghost solve.
fftclass(poisson_fft_object)allocatableThe root solver, on every rank (FFTW, or the caller's backend).
gfftclass(poisson_fft_object)allocatable
tolerancereal(kind=R8P)Relative max-norm residual to stop.
max_iterationsinteger(kind=I4P)FCG iterations at most.
sweepsinteger(kind=I4P)Red-black sweeps per level, down and up.
iterationsinteger(kind=I4P)Iterations of the last solve.
residualreal(kind=R8P)Relative residual of the last solve.
tolerance_usedreal(kind=R8P)Stop tolerance of the last solve (the round-off floor of the
factor_meanreal(kind=R8P)Mean convergence factor per iteration of the last solve.
ureal(kind=R8P)allocatableThe last solution (warm start).
has_guesslogicalu holds a solution of the current grid.
wfreal(kind=R8P)allocatableprevious p and A p (leaf space).
wrreal(kind=R8P)allocatableprevious p and A p (leaf space).
wzreal(kind=R8P)allocatableprevious p and A p (leaf space).
wpreal(kind=R8P)allocatableprevious p and A p (leaf space).
wqreal(kind=R8P)allocatableprevious p and A p (leaf space).
wppreal(kind=R8P)allocatableprevious p and A p (leaf space).
wqpreal(kind=R8P)allocatableprevious p and A p (leaf space).
w1real(kind=R8P)allocatableOnes (leaf space).
wgreal(kind=R8P)allocatableGhost-fill values [g%nrow].
lrtype(rvec)allocatableV-cycle: level residual and correction [lbot:lmax].
letype(rvec)allocatableV-cycle: level residual and correction [lbot:lmax].
lt1type(rvec)allocatableV-cycle: level temporaries [lbot:lmax].
lt2type(rvec)allocatableV-cycle: level temporaries [lbot:lmax].
mlevtype(ivec)allocatablePer level: the level-space and leaf-space cells of the
mleaftype(ivec)allocatablePer level: the level-space and leaf-space cells of the
root_coordsinteger(kind=I4P)allocatableV-cycle: the root blocks [3,blocks].
root_bufreal(kind=R8P)allocatableV-cycle: the root's source and solution (host).
root_outreal(kind=R8P)allocatableV-cycle: the root's source and solution (host).

Type-Bound Procedures ​

NameAttributesDescription
destroypass(self)Destroy the solver.
initializepass(self)Gather the leaves, assemble the operators.
solvepass(self)Solve for phi from one variable of q.
solve_packedpass(self)Solve for phi from the packed interior source.
symmetry_defectpass(self)|x . A y - y . A x| / (|x| |A y|) (verification).
apply_apass(self)y = A x on the leaves (verification).
apply_bpass(self)y = B g: the boundary values onto the boundary rows.
apply_btpass(self)s = B^T x: the boundary rows onto the boundary faces.
applypass(self)y = M x for a distributed operator.
smoothpass(self)Red-black Gauss-Seidel on a level.
vec_fillnopassx(1:n) = a.
vec_copynopassy(1:n) = x(1:n).
vec_lincombnopassw(1:n) = x(1:n) + a y(1:n).
vec_axpynopassy(1:n) = y(1:n) + a x(1:n).
vec_dotnopasssum x y over the local n entries and the ranks.
vec_relmaxnopassmax |r / vol| over the ranks, over fmax.
vec_permutenopassy(iy(i)) = x(ix(i)).
vec_updatenopassA work vector between the host and where the hooks compute.
work_placepass(self)Put (or release) the operators and work vectors where the hooks compute.
assemblepass(self)Finish a distributed operator from triplets.
a_rowpass(self)The row of the composite operator at a cell.
cell_volumepass(self)Cell volume at a level.
classifypass(self)Classify a neighbour position.
comp_valuepass(self)The level-l value of a cell as leaf-cell weights.
dx_ofpass(self)Cell spacing at a level.
face_cellspass(self)The fine cells of a coarse face.
face_weightpass(self)V-weighted face weight (area over distance) at a level.
ghost_greenpass(self)Isolated: g = -G s, the ghost-to-ghost Green's function.
solve_fcgpass(self)The FCG solve with given ghost values (or none).
linpass(self)Linear index of a cell in a leaf block.
make_workpass(self)Allocate the work vectors and the level maps.
lin_ofpass(self)Linear index of a cell in a block at a level.
ncb_ofpass(self)Cells per block at a level.
ncellpass(self)Cells along a direction over the domain at a level.
nijk_ofpass(self)Cells per block per direction at a level.
outsidepass(self)A cell position beyond a domain face.
locatepass(self)Owner and local index of a cell key in a space.
parent3pass(self)Parent cell coordinates.
vcyclepass(self)The preconditioner.
wrappass(self)Periodic wrap of cell coordinates at a level.

Subroutines ​

destroy ​

Destroy the solver.

fortran
subroutine destroy(self)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.

Call graph

initialize ​

Gather the leaves, derive the hierarchy, assemble the operator, the ghost fill and the preconditioner, set up the coarsest-level FFT solver: of the dynamic type of coarse when given (the FNL backend passes its cuFFT solver), the FFTW one otherwise. With isolated (issue #87), also the ghost-to-ghost Green's function of the James step. bc (issue #84, E1b): the kind of every face (see the module); a periodic axis of the grid must be periodic in bc and the other way round. Without it, every bounded axis takes ghost-Dirichlet faces. root_cells (#84 E5c): the levels inside the blocks below lmin stop once the root has at most this many cells (default: the root solver's root_cells_max for the root's transform growth; tests force the levels with a small one, the bench measures others).

fortran
subroutine initialize(self, grid, field, tolerance, max_iterations, coarse, isolated, bc, root_cells)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
gridtype(grid_object)inThe grid.
fieldtype(field_object)inThe field (block coordinates).
tolerancereal(kind=R8P)inoptionalRelative residual to stop.
max_iterationsinteger(kind=I4P)inoptionalFCG iterations at most.
coarseclass(poisson_fft_object)inoptionalMold of the coarsest-level solver.
isolatedlogicalinoptionalFree-space boundaries (James), else as the grid.
bcinteger(kind=I4P)inoptionalKinds per face [lo/hi, axis].
root_cellsinteger(kind=I4P)inoptionalMost cells of the root (default: the backend's).

Call graph

solve ​

Solve A phi = factor V q(iv) - B ghost on the leaves, the mean of the right-hand side removed when the operator is singular (periodic, or no Dirichlet face); phi's ghosts filled (see the module).

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

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_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 V f phi (all ranks).
ghostreal(kind=R8P)inoptionalThe boundary value per face.

Call graph

solve_packed ​

Solve from the packed interior source of this rank's leaves (block-major, i fastest); then the ghost fill. Isolated (issue #87, P2), the James step: the zero-ghost solve phi0 = A^-1 factor V f, the screening charge s = B^T phi0 on the ghost cells, the ghost values of the free-space solution g = -G s (ghost_green), and the solve with them, phi = A^-1 (factor V f - B g): the map is (A^-1 + A^-1 B G B^T A^-1) factor V, symmetric in the V-weighted form since A and G are. Each of the two solves warm-starts from its own last solution.

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

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
fieldtype(field_object)inThe field.
bufreal(kind=R8P)inPacked interior source.
factorreal(kind=R8P)inSource factor.
phireal(kind=R8P)inoutPotential [i,j,k,nb].
energyreal(kind=R8P)outoptionalsum_cells V f phi (all ranks).
ghostreal(kind=R8P)inoptionalThe boundary value per boundary face.

Call graph

solve_fcg ​

Solve from the packed interior source of this rank's leaves (block-major, i fastest): FCG on the operator, preconditioned by the V-cycle, from the previous solution when there is one; then the ghost fill.

fortran
subroutine solve_fcg(self, field, buf, factor, phi, energy, ghost)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
fieldtype(field_object)inThe field.
bufreal(kind=R8P)inPacked interior source.
factorreal(kind=R8P)inSource factor.
phireal(kind=R8P)inoutPotential [i,j,k,nb].
energyreal(kind=R8P)outoptionalsum_cells V f phi (all ranks).
ghostreal(kind=R8P)inoptionalThe boundary value per boundary face.

Call graph

apply_a ​

y = A x on this rank's leaf cells (V-weighted), through the work vectors (where the hooks compute).

fortran
subroutine apply_a(self, x, y)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
xreal(kind=R8P)inLeaf vector.
yreal(kind=R8P)inoutResult.

Call graph

apply_b ​

y = B g on this rank's leaf cells: every boundary face adds its weight times its boundary value to its row (A phi + B g is the operator with the boundary values g).

fortran
subroutine apply_b(self, g, y)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
greal(kind=R8P)inBoundary value per boundary face.
yreal(kind=R8P)inoutResult, a leaf vector.

apply_bt ​

s = B^T x: every boundary face takes its weight times the value of its row.

fortran
subroutine apply_bt(self, x, s)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
xreal(kind=R8P)inLeaf vector.
sreal(kind=R8P)inoutResult, one value per boundary face.

Call graph

apply ​

y = M x: fetch the halo of x from the owners, then the local rows.

fortran
subroutine apply(self, m, x, y)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
mtype(dcsr)inOperator.
xreal(kind=R8P)inLocal column-space vector.
yreal(kind=R8P)inoutResult (rows).

Call graph

vec_fill ​

x(1:n) = a.

fortran
subroutine vec_fill(x, a, n)

Arguments

NameTypeIntentAttributesDescription
xreal(kind=R8P)inoutVector.
areal(kind=R8P)inValue.
ninteger(kind=I4P)inEntries.

Call graph

vec_copy ​

y(1:n) = x(1:n).

fortran
subroutine vec_copy(x, y, n)

Arguments

NameTypeIntentAttributesDescription
xreal(kind=R8P)inSource.
yreal(kind=R8P)inoutDestination.
ninteger(kind=I4P)inEntries.

Call graph

vec_lincomb ​

w(1:n) = x(1:n) + a y(1:n) (w distinct from x and y).

fortran
subroutine vec_lincomb(x, a, y, w, n)

Arguments

NameTypeIntentAttributesDescription
xreal(kind=R8P)inFirst vector.
areal(kind=R8P)inCoefficient.
yreal(kind=R8P)inSecond vector.
wreal(kind=R8P)inoutResult.
ninteger(kind=I4P)inEntries.

Call graph

vec_axpy ​

y(1:n) = y(1:n) + a x(1:n).

fortran
subroutine vec_axpy(a, x, y, n)

Arguments

NameTypeIntentAttributesDescription
areal(kind=R8P)inCoefficient.
xreal(kind=R8P)inVector.
yreal(kind=R8P)inoutUpdated vector.
ninteger(kind=I4P)inEntries.

Call graph

vec_permute ​

y(iy(i)) = x(ix(i)), i = 1..n.

fortran
subroutine vec_permute(x, ix, y, iy, n)

Arguments

NameTypeIntentAttributesDescription
xreal(kind=R8P)inSource.
ixinteger(kind=I4P)inSource entries.
yreal(kind=R8P)inoutDestination.
iyinteger(kind=I4P)inDestination entries.
ninteger(kind=I4P)inEntries.

Call graph

vec_update ​

A work vector to (to_device) or from where the hooks compute: nothing on the host.

fortran
subroutine vec_update(x, to_device)

Arguments

NameTypeIntentAttributesDescription
xreal(kind=R8P)inoutWork vector.
to_devicelogicalinDirection.

Call graph

work_place ​

Put (attach) the operators and the work vectors where the hooks compute, or release them: nothing on the host.

fortran
subroutine work_place(self, attach)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
attachlogicalinPut, or release.

Call graph

assemble ​

Finish a distributed operator: rows sorted; column keys resolved to local slots, or to halo slots grouped by owner; the exchange plan agreed with the owners (they receive the keys and return their local indices).

fortran
subroutine assemble(self, t, nrow, space, m)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
ttype(triplets)inoutTriplets (emptied).
nrowinteger(kind=I4P)inRows.
spaceinteger(kind=I4P)inColumn space.
mtype(dcsr)inoutOperator.

Call graph

a_row ​

The row of the composite operator at cell cc of level lv (V-weighted): same-level faces, and the fine and the coarse side of 2:1 faces (see the module).

fortran
subroutine a_row(self, lv, cc, keys, vals)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.
ccinteger(kind=I4P)inCell coordinates at lv.
keysinteger(kind=I8P)inoutallocatableColumn keys.
valsreal(kind=R8P)inoutallocatableValues.

Call graph

face_cells ​

The keys of the 2^(nd-1) fine cells (level lf) on the coarse face that contains the fine cell fc's face normal to d: fc's normal index, every pair of tangential indices of its coarse parent.

fortran
subroutine face_cells(self, lf, fc, d, keys_f)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lfinteger(kind=I4P)inFine level.
fcinteger(kind=I4P)inA fine cell of the face.
dinteger(kind=I4P)inNormal direction.
keys_finteger(kind=I8P)outallocatableKeys.

Call graph

ghost_green ​

the infinite lattice, from ghost cell to ghost cell (G(n) / H, the unit lattice's Green's function over the coarsest spacing). Rank 0 gathers the charges into the coarsest box widened by the ghost layer (every face has its own ghost cell: a boundary leaf is at the coarsest level), convolves with the padded FFT (gfft, which solves L_H phi = factor f by the kernel H^2 G, so factor = -1 / H^3), and scatters the values back.

fortran
subroutine ghost_green(self, s, g)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
sreal(kind=R8P)inScreening charge per boundary face.
greal(kind=R8P)inoutGhost value per boundary face.

Call graph

comp_value ​

Append w times the level-lv value of cell cc as leaf-cell weights: the leaf itself; the mean of the leaves inside, if refined; the containing coarser leaf, if inside one.

Attributes: recursive

fortran
subroutine comp_value(self, lv, cc, w, keys, wts)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.
ccinteger(kind=I4P)inCell coordinates.
wreal(kind=R8P)inWeight.
keysinteger(kind=I8P)inoutallocatableKeys.
wtsreal(kind=R8P)inoutallocatableWeights.

Call graph

make_work ​

Allocate the work vectors (FCG, ghost fill, the V-cycle's levels and root) and the maps of the leaves into the level spaces (#84 E6a).

fortran
subroutine make_work(self)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.

Call graph

locate ​

Owner rank and local index of a cell key in a space (the composite leaves, or a level).

fortran
subroutine locate(self, space, key, owner, lidx)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
spaceinteger(kind=I4P)inSpace.
keyinteger(kind=I8P)inCell key.
ownerinteger(kind=I4P)outOwner rank.
lidxinteger(kind=I4P)outLocal index on the owner.

Call graph

smooth ​

Red-black Gauss-Seidel sweeps on level lv: A_l e = rhs (the ghost term already in rhs).

fortran
subroutine smooth(self, lv, e, rhs, order)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
lvinteger(kind=I4P)inLevel.
ereal(kind=R8P)inoutCorrection.
rhsreal(kind=R8P)inRight-hand side.
orderinteger(kind=I4P)in0: colour 0 first, 1: colour 1 first.

Call graph

vcycle ​

The preconditioner: z = M r, one V-cycle over the levels (see the module), down to the root (lbot), solved exactly by FFT on every rank (#84 E5c: below lmin the levels coarsen inside the blocks). On the work vectors, through the hooks (#84 E6a); the root goes through the host.

fortran
subroutine vcycle(self, r_leaf, z_leaf)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
r_leafreal(kind=R8P)inLeaf residual (V-weighted).
z_leafreal(kind=R8P)inoutLeaf correction.

Call graph

kdecode ​

Decode a cell key.

Attributes: pure

fortran
subroutine kdecode(key, lv, cc)

Arguments

NameTypeIntentAttributesDescription
keyinteger(kind=I8P)inKey.
lvinteger(kind=I4P)outLevel.
ccinteger(kind=I4P)outCell coordinates.

Call graph

hash_init ​

A table for about n keys (capacity: the first prime above 2 n).

fortran
subroutine hash_init(h, n)

Arguments

NameTypeIntentAttributesDescription
htype(hash_table)inoutTable.
ninteger(kind=I4P)inExpected keys.

Call graph

hash_free ​

Free a table.

fortran
subroutine hash_free(h)

Arguments

NameTypeIntentAttributesDescription
htype(hash_table)inoutTable.

Call graph

hash_put ​

Insert or overwrite (linear probing).

fortran
subroutine hash_put(h, key, val)

Arguments

NameTypeIntentAttributesDescription
htype(hash_table)inoutTable.
keyinteger(kind=I8P)inKey (>= 0).
valinteger(kind=I4P)inValue (> 0).

Call graph

trip_add ​

Append a triplet.

fortran
subroutine trip_add(t, row, key, val)

Arguments

NameTypeIntentAttributesDescription
ttype(triplets)inoutBuffer.
rowinteger(kind=I4P)inRow.
keyinteger(kind=I8P)inColumn key.
valreal(kind=R8P)inValue.

Functions ​

symmetry_defect ​

|x . A y - y . A x| / (|x| |A y|) over the ranks, for two leaf vectors: the operator's symmetry, verified.

Returns: real(kind=R8P)

fortran
function symmetry_defect(self, x, y) result(defect)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inoutThe solver.
xreal(kind=R8P)inFirst vector.
yreal(kind=R8P)inSecond vector.

Call graph

vec_dot ​

sum_i x_i y_i over the local n entries and the ranks.

Returns: real(kind=R8P)

fortran
function vec_dot(x, y, n) result(d)

Arguments

NameTypeIntentAttributesDescription
xreal(kind=R8P)inFirst vector.
yreal(kind=R8P)inSecond vector.
ninteger(kind=I4P)inLocal entries.

Call graph

vec_relmax ​

max |r / vol| over the ranks, over fmax (when positive).

Returns: real(kind=R8P)

fortran
function vec_relmax(r, vol, n, fmax) result(rm)

Arguments

NameTypeIntentAttributesDescription
rreal(kind=R8P)inResidual.
volreal(kind=R8P)inCell volumes.
ninteger(kind=I4P)inLocal entries.
fmaxreal(kind=R8P)inNormalisation.

Call graph

cell_volume ​

Cell volume at level lv (the product over the active directions).

Attributes: pure

Returns: real(kind=R8P)

fortran
function cell_volume(self, lv) result(v)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.

Call graph

classify ​

Classify the level-lv cell position nb3: a leaf of lv, refined, or inside a leaf of lv-1 (fatal otherwise: the grid is not 2:1 balanced across faces).

Returns: integer(kind=I4P)

fortran
function classify(self, lv, nb3) result(cls)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.
nb3integer(kind=I4P)inCell coordinates.

Call graph

dx_of ​

Cell spacing at level lv (null directions keep the level-0 one).

Attributes: pure

Returns: real(kind=R8P)

fortran
function dx_of(self, lv) result(dx)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.

Call graph

face_weight ​

The V-weighted face weight at level lv along d: the face area over the centre distance, V / dx_d^2.

Attributes: pure

Returns: real(kind=R8P)

fortran
function face_weight(self, lv, d) result(w)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.
dinteger(kind=I4P)inDirection.

Call graph

lin ​

Linear index of cell (i,j,k) in a block, i fastest.

Attributes: pure

Returns: integer(kind=I4P)

fortran
function lin(self, ijk) result(l)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
ijkinteger(kind=I4P)inCell (1-based).

Call graph

lin_of ​

Linear index of a cell (1-based) in a block at level lv (nijk_of(lv) cells).

Attributes: pure

Returns: integer(kind=I4P)

fortran
function lin_of(self, lv, ijk) result(l)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.
ijkinteger(kind=I4P)inCell (1-based).

Call graph

ncb_of ​

Cells per block at level lv.

Attributes: pure

Returns: integer(kind=I4P)

fortran
function ncb_of(self, lv) result(n)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.

Call graph

ncell ​

Cells along direction d over the domain at level lv: the blocks at max(lv, lmin) times their cells.

Attributes: pure

Returns: integer(kind=I4P)

fortran
function ncell(self, lv, d) result(n)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.
dinteger(kind=I4P)inDirection.

Call graph

nijk_of ​

Cells per block per direction at level lv: nijk at lmin and above, halved per level below it along the active directions (the levels inside the blocks, #84 E5c).

Attributes: pure

Returns: integer(kind=I4P)

fortran
function nijk_of(self, lv) result(nl)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.

Call graph

parent3 ​

Parent cell coordinates (one level coarser) along the active directions.

Attributes: pure

Returns: integer(kind=I4P)

fortran
function parent3(self, cc) result(pc)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
ccinteger(kind=I4P)inCell coordinates.

Call graph

outside ​

A cell position at level lv beyond a domain face along a bounded active direction (never along a periodic one).

Attributes: pure

Returns: logical

fortran
function outside(self, lv, cc) result(beyond)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.
ccinteger(kind=I4P)inCell coordinates.

Call graph

wrap ​

Periodic wrap of cell coordinates at level lv along the periodic active directions (bounded ones unchanged).

Attributes: pure

Returns: integer(kind=I4P)

fortran
function wrap(self, lv, cc) result(cw)

Arguments

NameTypeIntentAttributesDescription
selfclass(poisson_mg_object)inThe solver.
lvinteger(kind=I4P)inLevel.
ccinteger(kind=I4P)inCell coordinates.

Call graph

gdot ​

sum_i x_i y_i over the local n entries and the ranks.

Returns: real(kind=R8P)

fortran
function gdot(x, y, n) result(s)

Arguments

NameTypeIntentAttributesDescription
xreal(kind=R8P)inFirst vector.
yreal(kind=R8P)inSecond vector.
ninteger(kind=I4P)inLocal entries.

Call graph

bkey ​

Key of a block or cell: (i, j, k, level) packed in 19 + 19 + 19 + 7 bits.

Attributes: pure

Returns: integer(kind=I8P)

fortran
function bkey(c4) result(key)

Arguments

NameTypeIntentAttributesDescription
c4integer(kind=I4P)inCoordinates (i, j, k, level).

Call graph

ckey ​

Key of a cell at level lv.

Attributes: pure

Returns: integer(kind=I8P)

fortran
function ckey(lv, cc) result(key)

Arguments

NameTypeIntentAttributesDescription
lvinteger(kind=I4P)inLevel.
ccinteger(kind=I4P)inCell coordinates.

Call graph

hash_get ​

The value of a key, 0 when absent.

Attributes: pure

Returns: integer(kind=I4P)

fortran
function hash_get(h, key) result(val)

Arguments

NameTypeIntentAttributesDescription
htype(hash_table)inTable.
keyinteger(kind=I8P)inKey.

Call graph