Python interface
The pvfmm Python package (in
python/) wraps the
C interface using ctypes, numpy, and mpi4py.
Installation and setup
Build and install the PVFMM library first, then:
cd python && pip install .
If libpvfmm.so is not on the system library search path, point the PVFMM
environment variable at the directory containing it (e.g. the CMake build/
directory or the install prefix’s lib/pvfmm).
mpi4py is optional and imported only when you pass an explicit communicator.
For a single process, or to let the library use MPI_COMM_WORLD, omit the
communicator (comm=None) and no mpi4py install is required. To drive
several ranks, pass an mpi4py communicator and launch through it so that
MPI_Init/MPI_Finalize are handled correctly:
export PVFMM=/path/to/dir-containing-libpvfmm
mpirun -n 2 python -m mpi4py your_program.py
The comm-less default is available for FMMParticleContext; the volume
constructors require an explicit mpi4py communicator.
Precision is selected per object with the dtype argument (numpy.float64,
the default, or numpy.float32); all array arguments must be 1-D contiguous
NumPy arrays of that dtype in [x1 y1 z1 x2 y2 z2 ...] (array-of-structures)
layout.
Note
The classes below have no docstrings yet; this page is the reference.
Signatures correspond to python/src/pvfmm/wrapper.py.
FMMKernel
class FMMKernel(Enum):
LaplacePotential = 0
LaplaceGradient = 1
StokesPressure = 2
StokesVelocity = 3
StokesVelocityGrad = 4
BiotSavartPotential = 5
Mirrors the C PVFMMKernel enum. Source/target dimensions per kernel are
listed in Kernel functions.
FMMBoundaryType
class FMMBoundaryType(Enum):
FreeSpace = 0
PXYZ = 1
PX = 2
PXY = 3
Periodic = 1 # alias for PXYZ
Mirrors the C PVFMMBoundaryType enum
(Boundary conditions); functions taking a periodic
argument also still accept a plain bool (False/True = free space / fully
periodic).
Particle FMM
class FMMParticleContext(box_size, max_points, multipole_order, kernel,
comm=None, dtype=np.float64, boundary=None)
Creates a particle-FMM context (PVFMMCreateContext*). box_size is the
domain length and the period along the periodic directions (<= 0 allowed
only for free space); max_points is the maximum number of points per leaf
node; multipole_order must be positive and even. comm may be an mpi4py
communicator; if omitted (None) the context uses the world communicator
obtained from the library itself (PVFMMGetCommWorld), so mpi4py is not
required for single- or multi-rank runs launched with mpirun. Passing
boundary=FMMBoundaryType.PX (etc.) selects the
boundary conditions explicitly; with boundary=None the sign of box_size
decides (> 0 fully periodic, otherwise free space). The underlying context
is freed when the object is garbage-collected.
FMMParticleContext.evaluate(src_pos, sl_den, dl_den, trg_pos, setup=True) -> np.ndarray
Evaluates the potential at the target points (PVFMMEval*). With
(src_dim, trg_dim) the kernel dimensions from Kernel functions:
sl_den (single-layer density) has src_dim values per source, dl_den
(double-layer density + normal) has src_dim + 3 values per source, and the
returned array has trg_dim values per target; either density may be
None. Pass setup=True whenever source or target positions changed
since the last call; setup=False re-uses the tree when only densities
changed.
Volume FMM
class FMMVolumeContext(multipole_order, chebyshev_degree, kernel, comm, dtype=np.float64)
Builds (or loads from cache — see Precomputed operator files) the
volume-FMM translation operators (PVFMMCreateVolumeFMM*).
FMMVolumeTree.from_function(cheb_deg, data_dim, fn, context, trg_coord, comm,
tol, max_pts, periodic, init_depth) -> FMMVolumeTree
Builds an adaptively refined Chebyshev tree from a source-density callback
(PVFMMCreateVolumeTree*). fn must be a ctypes function pointer with C
signature void fn(const double* coord, long n, double* out, const void* ctx)
(use pvfmm.ffi.double_volume_callback / float_volume_callback, e.g. via
numba.cfunc as in python/examples/example2.py); context is passed
through to the callback as ctx.
FMMVolumeTree.from_coefficients(cheb_deg, data_dim, leaf_coord, fn_coeff,
trg_coord, comm, periodic) -> FMMVolumeTree
Builds the tree from given leaf-node coordinates and Chebyshev coefficients
(PVFMMCreateVolumeTreeFromCoeff*); fn_coeff must have length
N_leaf * data_dim * (cheb_deg+1)(cheb_deg+2)(cheb_deg+3)/6. trg_coord may
be None. In both constructors periodic accepts a bool or an
FMMBoundaryType.
FMMVolumeTree.evaluate(fmm: FMMVolumeContext, loc_size: int) -> np.ndarray
Runs the volume FMM and returns the potential at the target points, an array
of length n_trg * trg_dim for the context’s kernel.
FMMVolumeTree.leaf_count() -> int # number of leaf nodes
FMMVolumeTree.get_leaf_coordinates() -> np.ndarray # leaf corners, 3 per leaf
FMMVolumeTree.get_coefficients() -> np.ndarray # Chebyshev coeffs of the potential
FMMVolumeTree.get_values() -> np.ndarray # potential on Chebyshev nodes
get_coefficients/get_values require that evaluate has been called
(they raise ValueError otherwise).
pvfmm.nodes_to_coeff(N_leaf, cheb_deg, dof, node_val) -> np.ndarray
Converts function values on tensor-product Chebyshev nodes (first kind) to
Chebyshev coefficients (PVFMMNodes2Coeff*) — the usual way to prepare
fn_coeff for from_coefficients.
Examples
python/examples/example1.py— particle FMM (Biot–Savart), timed against a direct O(N²) sum compiled with numba.python/examples/example2.py— volume FMM (Stokes velocity), building the tree both from anumba.cfunccallback and from Chebyshev coefficients.