diff --git a/irksome/imex.py b/irksome/imex.py index 74bce7d..44ca11a 100644 --- a/irksome/imex.py +++ b/irksome/imex.py @@ -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): @@ -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 @@ -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): diff --git a/tests/test_dirk.py b/tests/test_dirk.py index af82e80..6947d7f 100644 --- a/tests/test_dirk.py +++ b/tests/test_dirk.py @@ -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 diff --git a/tests/test_imex.py b/tests/test_imex.py index 3d3faa7..4d0a98e 100644 --- a/tests/test_imex.py +++ b/tests/test_imex.py @@ -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