Fortran interface
The Fortran interface is provided as an include file,
include/pvfmm.f90,
containing bind(C) interface blocks for dedicated Fortran entry points in
libpvfmm (lower-case symbols with a trailing underscore, e.g.
pvfmmcreatecontextd_). Include it in your program and link with -lpvfmm:
program main
use iso_c_binding
implicit none
include 'mpif.h'
include 'pvfmm.f90'
! ...
end program
All functions come in double-precision (D suffix, real(c_double)) and
single-precision (F suffix, real(c_float)) variants; only the D variants
are listed below. Opaque handles are type(c_ptr). Communicators are passed
as plain integer Fortran MPI handles (e.g. MPI_COMM_WORLD from mpif.h).
See Using the C and Fortran interfaces for complete programs.
The kernel constants (PVFMMLaplacePotential, PVFMMLaplaceGradient,
PVFMMStokesPressure, PVFMMStokesVelocity, PVFMMStokesVelocityGrad,
PVFMMBiotSavartPotential) mirror the C PVFMMKernel enum, and the boundary
constants (PVFMMBoundaryFreeSpace, PVFMMBoundaryPXYZ, PVFMMBoundaryPX,
PVFMMBoundaryPXY, alias PVFMMBoundaryPeriodic) mirror PVFMMBoundaryType
— see Boundary conditions.
Particle FMM
subroutine PVFMMCreateContextD(fmm_ctx, box_size, points_per_leaf, &
multipole_order, kernel, bndry, comm)
type(c_ptr), intent(out) :: fmm_ctx ! FMM context
real(c_double), intent(in) :: box_size ! domain length; period along periodic directions
integer(c_int32_t), intent(in) :: points_per_leaf ! max points per leaf node
integer(c_int32_t), intent(in) :: multipole_order ! accuracy (positive, even)
integer(c_int32_t), intent(in) :: kernel ! PVFMMKernel value
integer(c_int32_t), intent(in) :: bndry ! PVFMMBoundary* constant
integer(c_int), intent(in) :: comm ! MPI communicator
subroutine PVFMMEvalD(Xs, Vs, Ns, Xt, Vt, Nt, fmm_ctx, setup)
real(c_double), intent(in) :: Xs(*) ! source positions [x1 y1 z1 ...]
real(c_double), intent(in) :: Vs(*) ! single-layer source densities
integer(c_int64_t), intent(in) :: Ns ! number of sources
real(c_double), intent(in) :: Xt(*) ! target positions
real(c_double), intent(out) :: Vt(*) ! target values
integer(c_int64_t), intent(in) :: Nt ! number of targets
type(c_ptr), intent(inout) :: fmm_ctx ! FMM context
integer(c_int32_t), intent(in) :: setup ! 1 if Xs or Xt changed, else 0
Note
The Fortran PVFMMEval differs from the C PVFMMEvalD: the argument order is
sources → targets → context → setup, and there is no double-layer density
argument (single-layer sources only).
subroutine PVFMMDestroyContextD(fmm_ctx)
type(c_ptr), intent(inout) :: fmm_ctx ! set to NULL on return
Volume FMM
The volume subroutines mirror the C interface one-to-one (same argument meanings, with the created handle returned through the first argument):
! Build/load FMM translation operators.
subroutine PVFMMCreateVolumeFMMD(fmm, m, q, kernel, comm)
! Adaptive Chebyshev tree from a function callback.
subroutine PVFMMCreateVolumeTreeD(tree, cheb_deg, data_dim, fn_ptr, &
trg_coord, n_trg, comm, tol, max_pts, &
periodic, init_depth)
! Chebyshev tree from given leaf nodes and coefficients.
subroutine PVFMMCreateVolumeTreeFromCoeffD(tree, n_nodes, cheb_deg, data_dim, &
node_coord, fn_coeff, trg_coord, &
n_trg, comm, periodic)
! Run the FMM; trg_val receives the potential at the target points.
subroutine PVFMMEvaluateVolumeFMMD(trg_val, tree, fmm, loc_size)
! Tree data access.
subroutine PVFMMGetLeafCountD(Nleaf, tree)
subroutine PVFMMGetLeafCoordD(node_coord, tree)
subroutine PVFMMGetPotentialCoeffD(coeff, tree)
! Chebyshev basis conversions.
subroutine PVFMMCoeff2NodesD(node_val, Nleaf, ChebDeg, dof, coeff)
subroutine PVFMMNodes2CoeffD(coeff, Nleaf, ChebDeg, dof, node_val)
! Cleanup (handles are set to NULL).
subroutine PVFMMDestroyVolumeTreeD(tree)
subroutine PVFMMDestroyVolumeFMMD(fmm)
The source-density callback passed to PVFMMCreateVolumeTreeD has the
interface
subroutine fn_ptr(coord, n, val) bind(C)
real(c_double), intent(in) :: coord(n*3) ! evaluation points [x1 y1 z1 ...]
integer(c_int64_t) :: n ! number of points
real(c_double), intent(out) :: val(*) ! n*data_dim output values
end subroutine
Note
Unlike the C callback, the Fortran callback receives no user context pointer,
and periodic is passed as integer(c_int32_t) — one of the
PVFMMBoundary* constants (0/1 keep the old free-space/periodic meaning).