Tests and markers#
The suite is deliberately tiered: a pull request should not wait on numerics that take hours, and an expensive accuracy check should not be silently skipped just because it is expensive. Validation Matrix records what each tier currently covers; this page is how to run them.
Tiers#
Tier |
Command |
Runs in |
|---|---|---|
Smoke and regression |
|
Pull-request CI and |
Long-run |
|
Developer or dedicated runs |
Full accuracy |
|
|
There is no benchmark tier any more: the drivers that produced timing, cache and parameter-sweep evidence are no longer in the tree, and what a measurement of this library has to record is Benchmarks and reproducibility.
The commands above assume UV_PROJECT_ENVIRONMENT points at the conda
environment, as in
Installation; without it uv run uses the
project’s own .venv, which has no OpenCL runtime.
uv run pytest -q # default suite
uv run pytest --longrun # include long-running checks
uv run pytest --full-accuracy # include the high-cost accuracy markers
uv run pytest -m 'not slow' # skip the wall-clock hogs
Targeted checks worth running after any environment change:
uv run pytest -q test/test_import.py
uv run pytest -q test/test_public_surface.py
uv run pytest -q test/test_duffy_tanh_sinh.py
Markers and options#
test/conftest.py owns everything the whole suite relies on, and registers its
markers in pytest_configure so they work regardless of which configuration
file pytest picks up.
full_accuracyHigh-cost derivative and direct-reference accuracy tests, and the volume FMM convergence, PDE-residual and split-versus-nonsplit regressions. Skipped unless
--full-accuracyis passed, so a plainpytestrun neither pays for them nor pretends to have run them.slowLabels, but does not skip, the handful of tests that dominate the wall clock.
-m 'not slow'gives a quick run.--longrunEnables the larger table-generation and quadrature cases, through the
longrunfixture.
The ctx_factory fixture is re-exported from pyopencl.tools and parametrizes
OpenCL-using tests over the available platforms, so set PYOPENCL_TEST (see
Device selection) to pin which one. conftest.py
also carries the xfail policy for OpenCL platforms known to crash, a
session-scoped table_2d_order1 near-field table shared by every test that
needs it, and end-of-session cleanup of stray table caches.
The device of the tests that build their own context#
Some tests do not take the ctx_factory fixture. The volume FMM regressions,
the full-accuracy sweeps, the direct references of test_windowed_rke.py, the
manufactured batched Duffy checks and the batched FMMLib stage tests need
double precision whatever platform the fixture was pinned to, and the
near-field tables built by the session-scoped table_2d_order1 and by
test_nearfield_potential_table.py want one queue, not one per platform. They
get their device from test/_opencl_test_utils.py, which reads
PYOPENCL_CTX, not PYOPENCL_TEST:
With
PYOPENCL_CTXset, they run on exactly the device it selects, CPU or GPU. The fp64 tests skip only if that device lacks fp64. A selector that matches no device, or several such asportable:0,1, is an error, not a skip.Without it, the fp64 tests take the first fp64 GPU, and the first fp64 CPU when there is none. This default never picks the
Intel(R) OpenCLplatform, whichconftest.pymarks as crashing on these paths; select it explicitly to run there anyway. The table builds keep the rule they always had: the first device of the first platform other than that one, and the first device of that one only when no other platform has a device.
So set both variables to the same device, as Device selection does, and the whole suite runs where you pointed it.
Until 2026-09 the eleven manufactured checks of
test_duffy_batched_manufactured.py skipped on any device but a GPU, so they
ran in no CI job. On a CPU they take seconds, so they run in the default suite
rather than the full-accuracy tier.
A CPU runs the whole full-accuracy tier, but in a different cost class from a
GPU. On the PoCL CPU of a CI Full runner it took 90 minutes, 57 of them in
the two 3D split-versus-nonsplit tests of test_volume_fmm.py.
VOLUMENTIAL_FULL_ACCURACY_REDUCED=1 runs those two at multipole order 16
instead of 24 and without their source-derivative pair, and CI Full sets it.
In two runs at that size they took 21 and 14 minutes and the tier 55 and 38.
Each of the three runs had a runner with a different CPU; the 55-minute one
ran the rest of the tier about as fast as the 90-minute one. The docstring of
_split_3d_full_accuracy_size says why neither change loosens the comparison.
Leave the variable unset for the full size, on a GPU or whenever a change
touches the 3D split.
VOLUMENTIAL_FULL_ACCURACY_REDUCED=1 uv run pytest -m full_accuracy --full-accuracy
Configuration#
The pytest configuration is [tool.pytest.ini_options] in pyproject.toml,
and it is the only one. Do not add a pytest.ini: pytest reads that file
first, and whenever both exist it ignores the pyproject.toml table (the run
header says so, as WARNING: ignoring pytest config in pyproject.toml!).
Examples as tests#
Four examples run in a reduced configuration on a pull request targeting
main — laplace2d.py, laplace2d_adaptive.py, helmholtz2d.py and
helmholtz3d.py. On a stacked pull request nothing runs at all; see
CI and the review bots.
VOLUMENTIAL_EXAMPLE_SMOKE=1 python examples/laplace2d.py
Smoke mode drops the quadrature order, level count and multipole order and uses a separate table cache file, so it finishes in seconds. An example that stops working in smoke mode is a broken example.
The other maintained examples — laplace3d.py, poisson3d.py and
branched_flow_helmholtz2d.py — run at full settings in CI Full, which has
no pull_request trigger. Nothing gates them on a pull request, so run the one
you touched yourself.
Those three smoke examples are now the whole of the Examples (Smoke) job. It
used to run five benchmark drivers’ smoke modes beside them; the drivers left
the tree, and the job’s benchmark lines left with them.