|
| 1 | +"""This demo program solves Helmholtz's equation |
| 2 | +
|
| 3 | + - div grad u(x, y) + u(x,y) = f(x, y) |
| 4 | +
|
| 5 | +on the unit square with source f given by |
| 6 | +
|
| 7 | + f(x, y) = (1.0 + 8.0*pi**2)*cos(x[0]*2*pi)*cos(x[1]*2*pi) |
| 8 | +
|
| 9 | +and the analytical solution |
| 10 | +
|
| 11 | + u(x, y) = cos(x[0]*2*pi)*cos(x[1]*2*pi) |
| 12 | +""" |
| 13 | + |
| 14 | +import numpy as np |
| 15 | +import pytest |
| 16 | + |
| 17 | +from firedrake import * |
| 18 | + |
| 19 | + |
| 20 | +def helmholtz(r, quadrilateral=False, degree=1, variant=None, mesh=None): |
| 21 | + # Create mesh and define function space |
| 22 | + if mesh is None: |
| 23 | + mesh = UnitSquareMesh(2 ** r, 2 ** r, quadrilateral=quadrilateral) |
| 24 | + V = FunctionSpace(mesh, "CR", degree, variant=variant) |
| 25 | + |
| 26 | + x, y = SpatialCoordinate(mesh) |
| 27 | + |
| 28 | + # Define variational problem |
| 29 | + u = TrialFunction(V) |
| 30 | + v = TestFunction(V) |
| 31 | + |
| 32 | + uex = cos(x*pi*2)*cos(y*pi*2) |
| 33 | + f = -div(grad(uex)) + uex |
| 34 | + |
| 35 | + a = (inner(grad(u), grad(v)) + inner(u, v))*dx |
| 36 | + L = inner(f, v)*dx(degree=12) |
| 37 | + |
| 38 | + params = {"snes_type": "ksponly", |
| 39 | + "ksp_type": "preonly", |
| 40 | + "pc_type": "lu"} |
| 41 | + |
| 42 | + # Compute solution |
| 43 | + sol = Function(V) |
| 44 | + solve(a == L, sol, solver_parameters=params) |
| 45 | + # Error norm |
| 46 | + return sqrt(assemble(dot(sol - uex, sol - uex) * dx)), sol, uex |
| 47 | + |
| 48 | + |
| 49 | +@pytest.mark.parametrize(('testcase', 'convrate'), |
| 50 | + [((1, (4, 6)), 1.9), |
| 51 | + ((3, (2, 4)), 3.9), |
| 52 | + ((5, (2, 4)), 5.7)]) |
| 53 | +@pytest.mark.parametrize("variant", ("point", "integral")) |
| 54 | +def test_firedrake_helmholtz_scalar_convergence(variant, testcase, convrate): |
| 55 | + degree, (start, end) = testcase |
| 56 | + l2err = np.zeros(end - start) |
| 57 | + for ii in [i + start for i in range(len(l2err))]: |
| 58 | + l2err[ii - start] = helmholtz(ii, degree=degree, variant=variant)[0] |
| 59 | + assert (np.array([np.log2(l2err[i]/l2err[i+1]) for i in range(len(l2err)-1)]) > convrate).all() |
0 commit comments