Source code for numgrids.integration

from __future__ import annotations

import numpy as np
from numpy.typing import NDArray
from scipy.sparse.linalg import inv
from scipy.sparse import csc_matrix, identity, kron

from numgrids.grids import Grid
from numgrids.api import Diff
from numgrids.axes import EquidistantAxis
from numgrids.utils import multi_kron


[docs] class Integral: r"""The integration operator for integrating on a grid. .. math:: \int_V ... dV Integration always runs over the whole grid. """ def __init__(self, grid: Grid) -> None: """Constructor Parameters ---------- grid: Grid The grid on which to integrate. """ self.grid = grid self.D_invs = [] for i, axis in enumerate(self.grid.axes): internal_grid = Grid(axis) D = Diff(internal_grid, 1, 0).as_matrix() D_inv = inv(csc_matrix(D[1:, 1:])) # inv wants a csc_matrix, but findiff returns csr_matrix self.D_invs.append(D_inv) self.eyes = [identity(len(axis)) for axis in self.grid.axes] def __call__(self, f: NDArray) -> float: """ Apply the integration to a meshed function. Parameters ---------- f: numpy.ndarray The meshed function to integrate over. The shape must be compatible with the shape of the grid. Returns ------- The result of the integration (float). """ f_ = f for i, axis in enumerate(self.grid.axes): if isinstance(axis, EquidistantAxis) and axis.periodic: # FFT-spectral integration is much easier and still spectral accuracy! f_ = axis.spacing * np.sum(f_, axis=0) else: f_ = f_[1:, ...] shape = f_.shape f_ = f_.reshape(-1) matrices = [identity(len(axis)) for axis in self.grid.axes] matrices[i] = self.D_invs[i] D_inv_big = multi_kron(*matrices[i:]) f_ = (D_inv_big * f_).reshape(shape)[-1, ...] return f_