Source code for irksome.tools

from operator import mul
from functools import reduce
import numpy
from firedrake import Function, FunctionSpace, MixedVectorSpaceBasis, Constant
from ufl.algorithms.analysis import extract_type
from ufl import as_tensor, zero
from ufl import replace as ufl_replace

from irksome.deriv import TimeDerivative


[docs] def get_stage_space(V, num_stages): return reduce(mul, (V for _ in range(num_stages)))
[docs] def getNullspace(V, Vbig, num_stages, nullspace): """ Computes the nullspace for a multi-stage method. :arg V: The :class:`FunctionSpace` on which the original time-dependent PDE is posed. :arg Vbig: The multi-stage :class:`FunctionSpace` for the stage problem :arg num_stages: The number of stages in the RK method :arg nullspace: The nullspace for the original problem. On output, we produce a :class:`MixedVectorSpaceBasis` defining the nullspace for the multistage problem. """ num_fields = len(V) if nullspace is None: nspnew = None else: try: nullspace.sort() except AttributeError: raise AttributeError("Nullspace entries must be of form (idx, VSP), where idx is a non-negative integer") if (nullspace[-1][0] > num_fields) or (nullspace[0][0] < 0): raise ValueError("At least one index for nullspaces is out of range") nspnew = [] nsp_comp = len(nullspace) for i in range(num_stages): count = 0 for j in range(num_fields): if count < nsp_comp and j == nullspace[count][0]: nspnew.append(nullspace[count][1]) count += 1 else: nspnew.append(Vbig.sub(j + num_fields * i)) nspnew = MixedVectorSpaceBasis(Vbig, nspnew) return nspnew
[docs] def replace(e, mapping): """A wrapper for ufl.replace that allows numpy arrays.""" cmapping = {k: as_tensor(v) for k, v in mapping.items()} return ufl_replace(e, cmapping)
# Utility functions that help us refactor
[docs] def AI(A): return (A, numpy.eye(*A.shape, dtype=A.dtype))
[docs] def IA(A): return (numpy.eye(*A.shape, dtype=A.dtype), A)
[docs] def is_ode(f, u): """Given a form defined over a function `u`, checks if (each bit of) u appears under a time derivative.""" derivs = extract_type(f, TimeDerivative) Dtbits = [] for k in derivs: op, = k.ufl_operands Dtbits.extend(op[i] for i in numpy.ndindex(op.ufl_shape)) ubits = [u[i] for i in numpy.ndindex(u.ufl_shape)] return set(Dtbits) == set(ubits)
# Utility class for constants on a mesh
[docs] class MeshConstant(object): def __init__(self, msh): self.msh = msh self.V = FunctionSpace(msh, 'R', 0)
[docs] def Constant(self, val=0.0): return Function(self.V).assign(val)
[docs] def ConstantOrZero(x, MC=None): const = MC.Constant if MC else Constant return zero() if abs(complex(x)) < 1.e-10 else const(x)
vecconst = numpy.vectorize(ConstantOrZero)