Source code for firedrake.preconditioners.covariance
import petsctools
from firedrake.petsc import PETSc
from firedrake.function import Function
[docs]
class CovariancePC(petsctools.PCBase):
r"""
A python PC context for a covariance operator.
Will apply either the action or inverse of the covariance,
whichever is the opposite of the Mat operator.
.. math::
B: V^{*} \to V
B^{-1}: V \to V^{*}
Available options:
* ``-pc_use_amat`` - use Amat to apply the covariance operator.
See Also
--------
~firedrake.adjoint.covariance_operator.CovarianceOperatorBase
~firedrake.adjoint.covariance_operator.AutoregressiveCovariance
~firedrake.adjoint.covariance_operator.CovarianceMatCtx
~firedrake.adjoint.covariance_operator.CovarianceMat
"""
needs_python_pmat = True
prefix = "covariance"
[docs]
def initialize(self, pc):
from firedrake.adjoint.covariance_operator import CovarianceMatCtx
A, P = pc.getOperators()
use_amat_prefix = self.parent_prefix + "pc_use_amat"
self.use_amat = PETSc.Options().getBool(use_amat_prefix, False)
mat = (A if self.use_amat else P).getPythonContext()
if not isinstance(mat, CovarianceMatCtx):
raise TypeError(
"CovariancePC needs a CovarianceMatCtx")
covariance = mat.covariance
self.covariance = covariance
self.mat = mat
V = covariance.function_space()
primal = Function(V)
dual = Function(V.dual())
# PC does the opposite of the Mat
if mat.operation == CovarianceMatCtx.Operation.ACTION:
self.operation = CovarianceMatCtx.Operation.INVERSE
self.x = primal
self.y = dual
self._apply_op = covariance.apply_inverse
elif mat.operation == CovarianceMatCtx.Operation.INVERSE:
self.operation = CovarianceMatCtx.Operation.ACTION
self.x = dual
self.y = primal
self._apply_op = covariance.apply_action
[docs]
def apply(self, pc, x, y):
"""Apply the action or inverse of the covariance operator
to x, putting the result in y.
y is not guaranteed to be zero on entry.
Parameters
----------
pc : PETSc.PC
The PETSc preconditioner that self is the python context of.
x : PETSc.Vec
The vector acted on by the pc.
y : PETSc.Vec
The result of the pc application.
"""
with self.x.dat.vec_wo as xvec:
x.copy(result=xvec)
self._apply_op(self.x, tensor=self.y)
with self.y.dat.vec_ro as yvec:
yvec.copy(result=y)
[docs]
def update(self, pc):
pass
[docs]
def view(self, pc, viewer=None):
"""View object. Method usually called by PETSc with e.g. -ksp_view.
"""
from firedrake.adjoint.covariance_operator import (
CovarianceMatCtx, AutoregressiveCovariance)
if viewer is None:
return
if viewer.getType() != PETSc.Viewer.Type.ASCII:
return
viewer.printfASCII(f" firedrake covariance operator preconditioner: {type(self).__name__}\n")
viewer.printfASCII(f" Applying the {str(self.operation)} of the covariance operator {type(self.covariance).__name__}\n")
if self.use_amat:
viewer.printfASCII(" using Amat matrix\n")
if (type(self.covariance) is AutoregressiveCovariance) and (self.covariance.iterations > 0):
if viewer.getFormat() == PETSc.Viewer.Format.ASCII_INFO_DETAIL:
if self.operation == CovarianceMatCtx.Operation.ACTION:
viewer.printfASCII(" Information for the diffusion solver for applying the action:\n")
ksp = self.covariance.solver.snes.ksp
elif self.operation == CovarianceMatCtx.Operation.INVERSE:
viewer.printfASCII(" Information for the mass solver for applying the inverse:\n")
ksp = self.covariance.mass_solver.snes.ksp
viewer.pushASCIITab()
ksp.view(viewer)
viewer.popASCIITab()
else:
prefix = pc.getOptionsPrefix() or ""
viewer.printfASCII(f" Use -{prefix}ksp_view ::ascii_info_detail to display information for diffusion or mass solver.\n")