Adaptive Mesh Refinement

The adaptive mesh refinement (AMR) utilities help determine the resolution required for a given accuracy target. An ErrorEstimator evaluates the local discretisation error on a grid, and the adapt() function iteratively refines axes until the estimated error falls below a prescribed tolerance.

class numgrids.ErrorEstimator(grid: Grid, func: Callable[[Grid], ndarray[tuple[Any, ...], dtype[_ScalarT]]], norm: str = 'max')[source]

Estimate discretization error by comparing grid resolutions.

The estimator evaluates a user-supplied function on the current grid and on a refined version, then computes the difference. This gives a Richardson-extrapolation-style error indicator without requiring an analytical solution.

Parameters:
  • grid (Grid) – The grid on which to estimate error.

  • func (callable) – func(grid) -> NDArray — a function that accepts a Grid and returns an array of shape grid.shape. For analytical functions, use the grid’s meshed coordinates; for PDE solvers, use the grid to build operators.

  • norm (str) – The norm used for the scalar error measure. One of "max" (L-infinity), "l2" (root-mean-square), or "mean" (mean absolute error).

Examples

>>> from numgrids import Grid
>>> from numgrids.axes import ChebyshevAxis
>>> from numgrids.amr import ErrorEstimator
>>> ax = ChebyshevAxis(10, 0, 1)
>>> grid = Grid(ax)
>>> est = ErrorEstimator(grid, lambda g: g.meshed_coords[0] ** 5)
>>> errors = est.per_axis_errors()
property f_current: ndarray[tuple[Any, ...], dtype[_ScalarT]]

The function evaluated on the current grid (cached).

global_error(refinement_factor: float = 2.0) float[source]

Estimate the global discretization error.

Refines all axes by refinement_factor, evaluates the function on the fine grid, interpolates back to the coarse grid, and returns the norm of the difference.

Parameters:

refinement_factor (float) – Factor by which to refine each axis (default 2).

Returns:

Scalar error estimate.

Return type:

float

per_axis_errors(refinement_factor: float = 2.0) dict[int, float][source]

Estimate the error contribution from each axis independently.

For each axis i, creates a grid refined only along axis i, evaluates the function, interpolates back, and computes the difference. Axes with the largest error are the ones that most need additional resolution.

Parameters:

refinement_factor (float) – Factor by which to refine each axis in turn (default 2).

Returns:

Mapping from axis index to scalar error estimate.

Return type:

dict[int, float]

axis_needing_refinement(refinement_factor: float = 2.0) int | None[source]

Return the index of the axis with the largest error.

Parameters:

refinement_factor (float) – Factor by which to test-refine each axis (default 2).

Returns:

Axis index with the largest error contribution, or None if all errors are zero (function is fully resolved).

Return type:

int or None

class numgrids.AdaptationResult(grid: ~numgrids.grids.Grid, f: ~numpy.ndarray[tuple[~typing.Any, ...], ~numpy.dtype[~numpy._typing._array_like._ScalarT]], errors: dict[int, float], global_error: float, iterations: int, converged: bool, history: list[dict] = <factory>)[source]

Container for the result of an adaptive refinement.

grid

The adapted grid.

Type:

Grid

f

The function evaluated on the adapted grid.

Type:

NDArray

errors

Per-axis error estimates on the final grid.

Type:

dict[int, float]

global_error

Global error estimate on the final grid.

Type:

float

iterations

Number of adaptation iterations performed.

Type:

int

converged

Whether the error tolerance was met.

Type:

bool

history

Per-iteration diagnostics (shape, errors, which axes were refined).

Type:

list[dict]

numgrids.adapt(grid: Grid, func: Callable[[Grid], ndarray[tuple[Any, ...], dtype[_ScalarT]]], tol: float = 1e-06, norm: str = 'max', max_iterations: int = 20, max_points_per_axis: int = 1024, refinement_factor: float = 2.0, refine_all: bool = False) AdaptationResult[source]

Iteratively refine a grid per-axis to meet an error tolerance.

At each iteration the axis contributing the most discretization error is refined by refinement_factor. The loop stops when the global error drops below tol, when max_iterations is reached, or when all axes have hit max_points_per_axis.

Parameters:
  • grid (Grid) – The initial grid.

  • func (callable) – func(grid) -> NDArray — evaluates the quantity of interest on any grid.

  • tol (float) – Target error tolerance (default 1e-6).

  • norm (str) – Error norm: "max", "l2", or "mean" (default "max").

  • max_iterations (int) – Maximum number of refinement iterations (default 20).

  • max_points_per_axis (int) – Safety cap on points per axis to prevent runaway refinement (default 1024).

  • refinement_factor (float) – Factor by which to increase axis resolution at each step (default 2).

  • refine_all (bool) – If True, refine all axes whose error exceeds tol / grid.ndims at each step instead of only the worst axis (default False).

Returns:

The adapted grid, function values, error estimates, and diagnostic history.

Return type:

AdaptationResult

Examples

>>> from numgrids import Grid
>>> from numgrids.axes import EquidistantAxis
>>> from numgrids.amr import adapt
>>> grid = Grid(EquidistantAxis(10, 0, 1), EquidistantAxis(10, 0, 1))
>>> result = adapt(
...     grid,
...     lambda g: g.meshed_coords[0] ** 5 + g.meshed_coords[1] ** 2,
...     tol=1e-4,
... )
>>> result.converged
True
numgrids.estimate_error(grid: Grid, func: Callable[[Grid], ndarray[tuple[Any, ...], dtype[_ScalarT]]], norm: str = 'max', refinement_factor: float = 2.0) dict[str, float | dict[int, float]][source]

One-shot error estimation for a function on a grid.

A convenience wrapper around ErrorEstimator for cases where you only need a single error report without running the full adaptation loop.

Parameters:
  • grid (Grid) – The grid on which the function is evaluated.

  • func (callable) – func(grid) -> NDArray.

  • norm (str) – Error norm (default "max").

  • refinement_factor (float) – Factor by which to test-refine (default 2).

Returns:

{"global": float, "per_axis": {0: float, 1: float, ...}}.

Return type:

dict

Examples

>>> from numgrids import Grid
>>> from numgrids.axes import EquidistantAxis
>>> from numgrids.amr import estimate_error
>>> grid = Grid(EquidistantAxis(20, 0, 1))
>>> result = estimate_error(grid, lambda g: g.meshed_coords[0] ** 2)
>>> result["global"]