Source code for thetis.assembledschur

from firedrake import *
from petsc4py import PETSc


[docs] class AssembledSchurPC(PCBase): """ Preconditioner for the Schur complement The preconditioner matrix is assembled by explicitly matrix multiplying :math:`A10*Minv*A10`. Here: - :math:`A01`, :math:`A10` are the assembled sub-blocks of the saddle point system. The form of this system needs to be supplied in the :code:`appctx` argument to the solver as :code:`appctx['a']`. - :math:`Minv` is the inverse of the mass-matrix which is assembled as :code:`assemble(Tensor(v*u*dx).inv)`, i.e. the element-wise inverse, where :math:`v` and :math:`u` are the test and trial of the :math:`A00` block. This gives the exact inverse of the mass matrix for a DG discretisation. """
[docs] def initialize(self, pc): _, P = pc.getOperators() ctx = P.getPythonContext() a = ctx.appctx['a'] options_prefix = pc.getOptionsPrefix() test, trial = a.arguments() W = test.function_space() V, Q = W.subfunctions v = TestFunction(V) u = TrialFunction(V) mass = dot(v, u)*dx self.A00_inv = assemble(Tensor(mass).inv, mat_type='aij').M.handle self.A10_A00_inv = None self.schur = None self.schur_plus = None fs = dict(formmanipulation.split_form(a)) self.a01 = fs[(0, 1)] self.a10 = fs[(1, 0)] self.a11 = fs[(1, 1)] self.A01 = None self.A10 = None self.A11 = None self.ksp = PETSc.KSP().create() self.ksp.setOptionsPrefix(options_prefix + 'schur_') self.ksp.setFromOptions() self.update(pc)
[docs] def update(self, pc): self.A01 = assemble(self.a01, tensor=self.A01) self.A10 = assemble(self.a10, tensor=self.A10) self.A11 = assemble(self.a11, tensor=self.A11) A01 = self.A01.M.handle A10 = self.A10.M.handle A11 = self.A11.M.handle self.A10_A00_inv = A10.matMult(self.A00_inv, self.A10_A00_inv, 2.0) self.schur = self.A10_A00_inv.matMult(A01, self.schur, 2.0) if self.schur_plus is None: self.schur_plus = self.schur.duplicate(copy=True) self.schur_plus.aypx(-1.0, A11, PETSc.Mat.Structure.DIFFERENT_NONZERO_PATTERN) else: self.schur_plus = self.schur.copy(self.schur_plus, PETSc.Mat.Structure.DIFFERENT_NONZERO_PATTERN) self.schur_plus.aypx(-1.0, A11, PETSc.Mat.Structure.SAME_NONZERO_PATTERN) self.ksp.setOperators(self.schur_plus)
[docs] def apply(self, pc, X, Y): self.ksp.solve(X, Y) r = self.ksp.getConvergedReason() if r < 0: raise RuntimeError("LinearSolver failed to converge after %d iterations with reason: %s", self.ksp.getIterationNumber(), solving_utils.KSPReasons[r])
[docs] def view(self, pc, viewer=None): super(AssembledSchurPC, self).view(pc, viewer) if viewer is None: return if viewer.getType() != PETSc.Viewer.Type.ASCII: return viewer.pushASCIITab() viewer.printfASCII("Solves assembled Schur system D - C M.inv C^T\n") self.ksp.view(viewer) viewer.popASCIITab()
[docs] def applyTranspose(self, pc, X, Y): raise NotImplementedError("applyTranspose not implemented for AssembledSchurPC")