Skip to content

Commit

Permalink
DIRK-IMEX and VFS (#110)
Browse files Browse the repository at this point in the history
Wrap values in float to fix an error updating problems in vector function spaces
  • Loading branch information
ScottMacLachlan authored Jan 29, 2025
1 parent bfd9468 commit 3ba45c3
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 6 deletions.
10 changes: 5 additions & 5 deletions irksome/imex.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,11 +493,11 @@ def advance(self):
for j in range(i):
ksplit = ks[j].subfunctions
for gbit, kbit in zip(g.subfunctions, ksplit):
gbit += dtc * AA[i, j] * kbit
gbit += dtc * float(AA[i, j]) * kbit
for j in range(i+1):
k_hat_split = k_hat_s[j].subfunctions
for gbit, k_hat_bit in zip(g.subfunctions, k_hat_split):
gbit += dtc * A_hat[i, j] * k_hat_bit
gbit += dtc * float(A_hat[i, j]) * k_hat_bit

# Solve for current stage
for j in range(i):
Expand All @@ -522,7 +522,7 @@ def advance(self):
for ghatbit, gbit in zip(ghat.subfunctions, g.subfunctions):
ghatbit.assign(gbit)
for ghatbit, kbit in zip(ghat.subfunctions, ks[i].subfunctions):
ghatbit += dtc * AA[i, i] * kbit
ghatbit += dtc * float(AA[i, i]) * kbit

self._finalize()
self.num_steps += 1
Expand All @@ -549,11 +549,11 @@ def _finalize_general(self):
# Final solution update
for i in range(ns):
for u0bit, kbit in zip(u0.subfunctions, ks[i].subfunctions):
u0bit += dtc * BB[i] * kbit
u0bit += dtc * float(BB[i]) * kbit

for i in range(ns+1):
for u0bit, k_hat_bit in zip(u0.subfunctions, k_hat_s[i].subfunctions):
u0bit += dtc * B_hat[i] * k_hat_bit
u0bit += dtc * float(B_hat[i]) * k_hat_bit

# Last part of advance for the general case, where last explicit stage is not used
def _finalize_no_last_explicit(self):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_dirk.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,4 @@ def test_stokes_bcs(butcher_tableau, bctype):
stepper.advance()
stepperdirk.advance()
t.assign(float(t) + float(dt))
assert errornorm(u_dirk, u) < 1.e-7
assert errornorm(u_dirk, u) < 2.e-7
51 changes: 51 additions & 0 deletions tests/test_imex.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,54 @@ def test_1d_heat_dirichletbc(imp_stages, exp_stages, order):
assert errornorm(uexact, u) / norm(uexact) < 10.0 ** -3
assert isclose(u.at(x0), u_0)
assert isclose(u.at(x1), u_1)


def vecconvdiff_neumannbc(butcher_tableau, order, N):
msh = UnitIntervalMesh(N)
V = VectorFunctionSpace(msh, "CG", order, dim=2)
MC = MeshConstant(msh)
dt = MC.Constant(0.1 / N)
t = MC.Constant(0.0)
(x,) = SpatialCoordinate(msh)

# Choose uexact so rhs is nonzero
uexact = as_vector([cos(pi*x)*exp(-t), cos(2*pi*x)*exp(-2*t)])
rhs = expand_derivatives(diff(uexact, t)) - div(grad(uexact)) + uexact.dx(0)
u = Function(V)
u.interpolate(uexact)

v = TestFunction(V)
F = (
inner(Dt(u), v) * dx
+ inner(grad(u), grad(v)) * dx
- inner(rhs, v) * dx
)
Fexp = inner(u.dx(0), v)*dx

luparams = {"mat_type": "aij", "ksp_type": "preonly", "pc_type": "lu"}

stepper = TimeStepper(
F, butcher_tableau, t, dt, u, Fexp=Fexp,
solver_parameters=luparams, mass_parameters=luparams,
stage_type="dirkimex"
)

t_end = 0.1
while float(t) < t_end:
if float(t) + float(dt) > t_end:
dt.assign(t_end - float(t))
stepper.advance()
t.assign(float(t) + float(dt))

return (errornorm(uexact, u) / norm(uexact))


@pytest.mark.parametrize("imp_stages, exp_stages, order",
[(1, 1, 1), (2, 3, 2)])
def test_1d_vecconvdiff_neumannbc(imp_stages, exp_stages, order):
bt = DIRK_IMEX(imp_stages, exp_stages, order)
errs = np.array([vecconvdiff_neumannbc(bt, order, 10*2**p) for p in [3, 4]])
print(errs)
conv = np.log2(errs[0]/errs[1])
print(conv)
assert conv > order-0.4

0 comments on commit 3ba45c3

Please sign in to comment.