Source code for firedrake.linear_solver

from firedrake.function import Function
from firedrake.cofunction import Cofunction
from firedrake.matrix import MatrixBase
from firedrake.petsc import PETSc
from pyop2.mpi import internal_comm
from firedrake.variational_solver import LinearVariationalProblem, LinearVariationalSolver

__all__ = ["LinearSolver"]


[docs] class LinearSolver(LinearVariationalSolver): @PETSc.Log.EventDecorator() def __init__(self, A, *, P=None, **kwargs): """A linear solver for assembled systems (Ax = b) with constant A. :arg A: a :class:`~.MatrixBase` (the operator). :arg P: an optional :class:`~.MatrixBase` to construct any preconditioner from; if none is supplied ``A`` is used to construct the preconditioner. :kwarg solver_parameters: (optional) dict of solver parameters. :kwarg nullspace: an optional :class:`~.VectorSpaceBasis` (or :class:`~.MixedVectorSpaceBasis` spanning the null space of the operator. :kwarg transpose_nullspace: as for the nullspace, but used to make the right hand side consistent. :kwarg near_nullspace: as for the nullspace, but used to set the near nullpace. :kwarg options_prefix: an optional prefix used to distinguish PETSc options. If not provided a unique prefix will be created. Use this option if you want to pass options to the solver from the command line in addition to through the ``solver_parameters`` dict. :kwarg pre_apply_bcs: If `True`, the bcs are applied before the solve. Otherwise, the bcs are included as part of the linear system. .. note:: Any boundary conditions for this solve *must* have been applied when assembling the operator. """ if not isinstance(A, MatrixBase): raise TypeError("Provided operator is a '%s', not a MatrixBase" % type(A).__name__) if P is not None and not isinstance(P, MatrixBase): raise TypeError("Provided preconditioner is a '%s', not a MatrixBase" % type(P).__name__) test, trial = A.arguments() self.x = Function(trial.function_space()) self.b = Cofunction(test.function_space().dual()) problem = LinearVariationalProblem(A, self.b, self.x, aP=P, form_compiler_parameters=A.form_compiler_parameters, constant_jacobian=True) super().__init__(problem, **kwargs) self.A = A self.comm = A.comm self._comm = internal_comm(self.comm, self) self.P = P if P is not None else A self.ksp = self.snes.ksp
[docs] @PETSc.Log.EventDecorator() def solve(self, x, b): """Solve the linear system with RHS ``b`` and store the solution in ``x``. Parameters ---------- x : firedrake.function.Function A Function to place the solution to the linear system in. b : firedrake.cofunction.Cofunction A Cofunction with the right-hand side of the linear system. """ if not isinstance(x, Function): raise TypeError(f"Provided solution is a '{type(x).__name__}', not a Function") if not isinstance(b, Cofunction): raise TypeError(f"Provided RHS is a '{type(b).__name__}', not a Cofunction") # When solving `Ax = b`, with A: V x U -> R, or equivalently A: V -> U*, # we need to make sure that x and b belong to V and U*, respectively. if x.function_space() != self.x.function_space(): raise ValueError(f"x must be a Function in {self.x.function_space()}.") if b.function_space() != self.b.function_space(): raise ValueError(f"b must be a Cofunction in {self.b.function_space()}.") self.x.assign(x) self.b.assign(b) super().solve() x.assign(self.x)