jpolyd is a C++17 / Fortran / Python library for Jacobi polynomial approximation on simplices, with a focus on high-order operator construction and hierarchical Poincaré–Steklov (HPS) solvers for elliptic PDEs on simplicial meshes.
The core numerical library supports Jacobi bases on the ctypes wrappers expose the same functionality for validation and higher-level mesh experiments.
The current production solver path is dense and precomputed: local elliptic operators are materialized once, the tau-stabilized leaf least-squares problem is factorized with dense QR, and reusable leaf response maps are retained for subsequent boundary data and source terms. Matrix-free and dense/sparse variants remain available as alternative backends and research paths.
For the underlying simplex Jacobi definitions and notation, see Dunkl & Xu.
Let
denote polynomials of total degree at most
We use the reference simplex in Cartesian coordinates,
The Jacobi parameter vector has length
with componentwise admissibility
Under this convention:
kappa = 0gives the Dirichlet-half / Chebyshev-type simplex weight
kappa = 1/2gives the unweighted simplex measure.
For second-order PDEs, derivative outputs are promoted into the common residual Jacobi family
The variable-coefficient elliptic path currently uses the full trial-degree residual space
The library provides:
-
$D$ -simplex Jacobi basis evaluation in graded total-degree ordering; - multi-index and tail-degree tables;
- tensor-product / collapsed-coordinate simplex quadrature;
- weighted basis evaluation and projection;
- face quadrature and canonical face bases;
- affine reference-to-physical simplex geometry.
Relevant headers include:
include/jbasis.hhinclude/jweight.hhinclude/jquad_tprod.hhinclude/jquad_optim.hhinclude/jgeom.hh
Differentiation changes both polynomial degree and Jacobi parameters. The library therefore separates:
- differentiation operators (
DMat); - Jacobi-family promotion operators (
KMat); - coordinate/Jacobi operators (
JMat).
Known sparse stencils are used when constructing these operators. RefSimplexPrecomp builds and caches the derivative/promotion DAG used by the PDE solvers while retaining dense compatibility maps for validation.
Relevant headers:
include/jdmat.hhinclude/jkmat.hhinclude/jmat.hhinclude/jprecomp.hh
For a coefficient field
using anti-aliased quadrature chosen from the degree of the triple product.
A lifted operator-valued Clenshaw implementation is also retained. It is used by the matrix-free backend and as an algebraic reference for verification.
Relevant header:
include/jmult.hh
The library constructs modal trace and normal-derivative maps on every simplex face, including the face permutations/orientations required by a simplicial mesh.
Relevant headers:
include/jtrace.hhinclude/jflux.hhinclude/jperms.hhinclude/jgeom.hh
The Poisson path solves constant-coefficient problems on affine simplicial meshes with Robin boundary data
For Poisson,
The local PDE residual lies naturally in
Relevant headers:
include/jlaplace.hhinclude/jleaf.hhinclude/jnode.hhinclude/jmerge.hh
The current general elliptic operator is written in non-divergence form,
Coefficient fields are represented elementwise in the residual Jacobi family. Principal, first-order, and zero-order terms are assembled after derivative/promotion into the common residual space.
The current elliptic residual policy is
so
after projection.
Relevant header:
include/jelliptic.hh
Each leaf combines the interior PDE equations with trace penalty rows. With trace map
The dense leaf path factorizes the stacked system once with Householder QR and precomputes reusable response maps:
These maps are then merged hierarchically. Source-transfer maps are retained through the tree so the expensive leaf factorization/materialization can be reused for new source terms and boundary data.
The elliptic tau parameter is interpreted as a base constant and rescaled for the enlarged residual space,
before the usual face-size/degree scaling is applied. The base constant remains user-configurable; Robin data with nonzero
Relevant headers:
include/jleaf.hhinclude/jnode.hhinclude/jmerge.hhinclude/jmesh.hh
The HPS implementation currently exposes several leaf backends.
This is the current main path.
- direct-quadrature multiplication-matrix materialization;
- dense local elliptic operator;
- tau-stabilized dense stacked system;
- one QR factorization per leaf;
- batched construction of
[U_lambda U_f]; - reusable
SandG_fmaps.
A hybrid experimental path retaining a dense interior operator with sparse/CSC trace and flux maps. It was useful for measuring sparsity and memory tradeoffs, but on the current CPU/OpenBLAS target the dense path is generally faster.
An apply-only path using the derivative DAG and lifted Clenshaw multiplication without materializing the full elliptic operator. This is substantially slower for the tested low/moderate-dimensional CPU cases because multiplication is repeated many times inside LSMR, but it remains useful for:
- high-dimensional problems where dense storage becomes prohibitive;
- memory-constrained settings;
- architectures where sparse/apply-only kernels may be more competitive;
- verification against the dense operator.
Builds/uses both representations and checks dense versus matrix-free actions.
The current mesh-level variable-coefficient solver is a non-divergence-form elliptic solver. Its interface algebra uses the existing normal-derivative-style flux map.
The planned next extension is divergence form,
implemented by reusing the non-divergence volume machinery after expanding
and replacing the face flux with the co-normal flux
This will allow correct conservation across interfaces with anisotropic and elementwise discontinuous diffusion tensors while leaving the HPS merge algebra unchanged.
include/ Header-only C++ numerical core
bindings/c_api/include/ C API headers
bindings/c_api/src/ C/C++ wrappers around the template library
bindings/lsmr/ Fortran/C ABI glue for reverse-communication LSMR
third_party/lsmr/ SOL LSMR Fortran sources
python/ Thin ctypes-based Python wrappers
testing/ Python regression, manufactured-solution, and research tests
tex/ Mathematical notes / derivations
src/ C++ regression tests and Jacobi-codec experiments
The numerical-library regression executables in src/ include tests for:
JMat,DMat, andKMatstencil construction/caching;- derivative/promotion DAG compatibility;
- direct-quadrature multiplication matrices versus lifted Clenshaw;
- dense versus matrix-free elliptic actions;
- leaf operator modes;
- Poisson HPS leaf modes;
- thread-safe LSMR reverse communication.
The remaining non-library-test programs in src/ are experimental programs for a Jacobi codec and related transform/quantization/video experiments. They are not part of the PDE solver API and should be treated as research code.
The Python files in python/ are thin wrappers around libjpolyd rather than a separate reimplementation.
Examples include:
jbasis.pyjdmat.pyjkmat.pyjmat.pyjmult.pyjgeom.pyjtrace.pyjflux.pyjlaplace.pyjelliptic.pyjprecomp.pyjhps.py
python/libjpolyd_loader.py loads the shared library from the same installed directory.
The higher-level HPS convergence and mesh experiments under testing/ use these bindings.
The current CMake project requires:
- CMake 3.16 or newer;
- a C++17 compiler;
- C and Fortran compilers;
- OpenBLAS / BLAS;
- LAPACK;
- LAPACKE;
- OpenMP;
- NLopt.
The current top-level CMake configuration also requires OpenCV because the repository still builds the Jacobi-codec experiment targets.
Some experimental executables additionally use SuiteSparse/SPQR.
Python validation scripts generally require:
- Python 3;
- NumPy;
and, depending on the script:
- SciPy;
- SymPy;
- Matplotlib;
- PyMetis.
A normal release build is:
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DJPOLYD_BUILD_CAPI=ON \
-DJPOLYD_ENABLE_TEST=ON
cmake --build build -jThe current CMake configuration writes:
lib/ shared/static libraries
bin/ executables
under the repository root.
Release mode is the default when CMAKE_BUILD_TYPE is not specified.
Detailed elliptic/HPS timing counters can be enabled with:
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DTIMING=ON
cmake --build build -jBy default, the install target places the Python wrappers and libjpolyd into the user's Python site-packages directory:
cmake --install buildThe default is equivalent to:
-DJPOLYD_PY_INSTALL_USER=ON
Set
-DJPOLYD_PY_INSTALL_USER=OFFto target the system site-packages location instead.
After installation, a simple import check is:
python3 - <<'PY'
import jbasis
import jelliptic
import jhps
print("jpolyd Python bindings loaded")
print("Dense backend:", jhps.HpsLeafOperatorMode.DENSE)
PYRun the CMake-registered tests with:
ctest --test-dir build --output-on-failureUseful C++ regression executables include:
./bin/kmat_stencil_test
./bin/dmat_kmat_stencil_cache_test
./bin/test_jmat_stencil_cache
./bin/test_jprecomp_partial_dag_compat
./bin/test_jleaf_dag_elliptic_compat
./bin/test_jelliptic_matrix_free_actions
./bin/test_jmult_quadrature_matrix
./bin/test_jleaf_operator_modes
./bin/test_jhps_poisson_leaf_operator_modes
./bin/test_lsmr_shim_threadsafeThe testing/ directory contains larger Python validation programs, including:
- basis/quadrature checks;
- manufactured-solution tests;
- Poisson Robin convergence;
- single- and multi-simplex trace/flux tests;
- HPS merge-algebra tests;
- arbitrary-mesh HPS convergence studies;
- dense, dense/sparse, and matrix-free elliptic comparisons;
- variable-coefficient non-polynomial convergence tests.
Many of these are research/regression drivers rather than a stable command-line interface.
The current solver stack has been exercised with:
- polynomial manufactured solutions recovering to roundoff;
- smooth non-polynomial manufactured solutions showing spectral convergence on fixed affine simplex meshes;
- full HPS mesh trees in dimensions
$D=1,\ldots,4$ in the current elliptic convergence studies; - dense versus matrix-free operator-action comparisons;
- direct-quadrature multiplication matrices versus lifted Clenshaw;
- multiple leaf operator backends;
- source and boundary response-map reuse;
- tau-stabilized HPS merge residual checks.
The dense QR/direct-quadrature path is the current reference implementation for solver development.
The tex/ directory contains derivations and working notes for the simplex Jacobi and HPS constructions. In particular:
tex/jsimplex.textex/steklov.textex/steklov.pdf
These files are useful references for the operator-valued Jacobi/Clenshaw formulation, trace/Steklov constructions, and solver derivations.
This repository is research software. The current emphasis is:
- preserve mathematically explicit simplex/Jacobi operators;
- validate each operator against manufactured solutions or independent constructions;
- materialize reusable local HPS maps when doing so is faster and memory-feasible;
- keep matrix-free/sparse alternatives available where dimensionality or hardware may favor them;
- separate solver mathematics from experimental optimization paths.
The next solver-development target is divergence-form elliptic support with co-normal flux conservation.
If jpolyd contributes to published research, please cite the software.
The project-wide DOI is 10.5281/zenodo.22137636, which always resolves to the latest archived release.
For reproducible research, please cite the DOI of the specific release used.
The preferred citation metadata is provided in
CITATION.cff.