diff --git a/firedrake/solving.py b/firedrake/solving.py index 8a86ac96b1..62c32c1a7a 100644 --- a/firedrake/solving.py +++ b/firedrake/solving.py @@ -382,7 +382,17 @@ def _assemble(f, tensor=None, bcs=None): """ - kernels = compile_form(f, "form") + # We stash the form and kernels on the tensor if we reassemble for an + # existing tensor, to save having to compile the form again if identical + # Note that forms override == to construct an equation, so we have to + # explicitly test for object identity + if getattr(tensor, "_form", None) is f and hasattr(tensor, "_kernels"): + kernels = tensor._kernels + else: + kernels = compile_form(f, "form") + if tensor: + tensor._form = f + tensor._kernels = kernels fd = f.form_data() diff --git a/tests/regression/test_assemble.py b/tests/regression/test_assemble.py index 8cac2b4e7a..0ca9e191bb 100644 --- a/tests/regression/test_assemble.py +++ b/tests/regression/test_assemble.py @@ -66,6 +66,29 @@ def test_zero_form(M, f, one): assert isinstance(zero_form, float) assert abs(zero_form - 0.5 * np.prod(f.shape())) < 1.0e-12 + +def test_assemble_with_tensor(cg1): + v = TestFunction(cg1) + L = v*dx + f = Function(cg1) + # Assemble a form into f + f = assemble(L, f) + # Assemble a different form into f + f = assemble(Constant(2)*L, f) + # Make sure we get the result of the last assembly + assert np.allclose(f.dat.data, 2*assemble(L).dat.data, rtol=1e-14) + + +def test_assemble_mat_with_tensor(dg0): + u = TestFunction(dg0) + v = TrialFunction(dg0) + a = u*v*dx + M = assemble(a) + # Assemble a different form into M + M = assemble(Constant(2)*a, M) + # Make sure we get the result of the last assembly + assert np.allclose(M.M.values, 2*assemble(a).M.values, rtol=1e-14) + if __name__ == '__main__': import os pytest.main(os.path.abspath(__file__))