Source code for irksome.pc
import copy
import numpy
from firedrake import AuxiliaryOperatorPC, derivative
from firedrake.dmhooks import get_appctx
# Oddly, we can't turn pivoting off in scipy?
[docs]
def ldu(A):
m = A.shape[0]
assert m == A.shape[1]
L = numpy.eye(m)
U = numpy.copy(A)
D = numpy.zeros((m, m))
for k in range(m):
for i in range(k+1, m):
alpha = U[i, k] / U[k, k]
U[i, :] -= alpha * U[k, :]
L[i, k] = alpha
assert numpy.allclose(L @ U, A)
for k in range(m):
D[k, k] = U[k, k]
U[k, k:] /= D[k, k]
assert numpy.allclose(L @ D @ U, A)
return L, D, U
[docs]
class IRKAuxiliaryOperatorPC(AuxiliaryOperatorPC):
"""Base class that inherits from Firedrake's AuxiliaryOperatorPC class and
provides the preconditioning bilinear form associated with an auxiliary
Form and/or approximate Butcher matrix (which are provided by subclasses).
"""
[docs]
def getNewForm(self, pc, u0, test):
"""Derived classes can optionally provide an auxiliary Form."""
raise NotImplementedError
[docs]
def getAtilde(self, A):
"""Derived classes produce a typically structured
approximation to A."""
raise NotImplementedError
[docs]
def form(self, pc, test, trial):
"""Implements the interface for AuxiliaryOperatorPC."""
appctx = self.get_appctx(pc)
stepper = appctx["stepper"]
butcher = stepper.butcher_tableau
F = stepper.F
u0 = stepper.u0
bcs = stepper.orig_bcs
v0, = F.arguments()
try:
# use new Form if provided
F, bcs = self.getNewForm(pc, u0, v0)
except NotImplementedError:
pass
try:
# use new ButcherTableau if provided
Atilde = self.getAtilde(butcher.A)
butcher = copy.deepcopy(butcher)
butcher.A = Atilde
except NotImplementedError:
pass
# get stages
ctx = get_appctx(pc.getDM())
w = ctx._x
Fnew, bcnew = stepper.get_form_and_bcs(w, tableau=butcher, F=F)
Jnew = derivative(Fnew, w, du=trial)
return Jnew, bcnew
[docs]
class RanaBase(IRKAuxiliaryOperatorPC):
"""Base class for methods out of Rana, Howle, Long, Meek, & Milestone."""
pass
[docs]
class RanaLD(RanaBase):
"""Implements Rana-type preconditioner using Atilde = LD where A=LDU."""
[docs]
class RanaDU(RanaBase):
"""Implements Rana-type preconditioner using Atilde = DU where A=LDU."""
[docs]
class NystromAuxiliaryOperatorPC(AuxiliaryOperatorPC):
"""Base class that inherits from Firedrake's AuxiliaryOperatorPC class and
provides the preconditioning bilinear form associated with an auxiliary
Form and/or approximate Nystrom matrices (which are provided by subclasses).
"""
[docs]
def getNewForm(self, pc, u0, ut0, test):
"""Derived classes can optionally provide an auxiliary Form."""
raise NotImplementedError
[docs]
def getAtildes(self, A, Abar):
"""Derived classes produce a typically structured
approximation to A and Abar."""
raise NotImplementedError
[docs]
def form(self, pc, test, trial):
"""Implements the interface for AuxiliaryOperatorPC."""
appctx = self.get_appctx(pc)
stepper = appctx["stepper"]
tableau = stepper.tableau
F = stepper.F
bcs = stepper.orig_bcs
u0 = stepper.u0
ut0 = stepper.ut0
v0, = F.arguments()
try:
# use new Form if provided
F, bcs = self.getNewForm(pc, u0, ut0, v0)
except NotImplementedError:
pass
try:
# use new ButcherTableau if provided
Atilde, Abartilde = self.getAtildes(tableau.A, tableau.Abar)
tableau = copy.deepcopy(tableau)
tableau.A = Atilde
tableau.Abar = Abartilde
except NotImplementedError:
pass
# get stages
ctx = get_appctx(pc.getDM())
w = ctx._x
Fnew, bcnew = stepper.get_form_and_bcs(w, tableau=tableau, F=F)
Jnew = derivative(Fnew, w, du=trial)
return Jnew, bcnew
[docs]
class ClinesBase(NystromAuxiliaryOperatorPC):
"""Base class for methods out of Clines/Howle/Long."""
pass
[docs]
class ClinesLD(ClinesBase):
"""Implements Clines-type preconditioner using Atilde = LD where A=LDU."""
[docs]
def getAtildes(self, A, Abar):
L, D, _ = ldu(A)
Atilde = L @ D
try:
Lbar, Dbar, _ = ldu(Abar)
except AssertionError:
raise ValueError(
"ClinesLD preconditioner failed for for this tableau. Please try again with GaussLegendre or RadauIIA methods")
Abartilde = Lbar @ Dbar
return Atilde, Abartilde