Dear FEniCS community,
I am trying to solve a simple Poisson equation in \Omega=(0,1)^2 where the left-hand side is constant and u=0 on \partial\Omega. To compute the convergence rates I solve the same problem in a refined mesh. I was expecting to observe a rate O(h^{k+1}) and O(h^k) for the L2 and H1-errors, respectively. However, for k\geq 2 the rate is stuck at 3 and 2. Am I missing something in the code? or is there a regularity estimate of the solution that have to be considered?.
The MWE is below.
import dolfinx.fem as fem
import dolfinx.fem.petsc
import numpy as np
import ufl
from basix.ufl import element
from dolfinx import mesh, default_scalar_type
from mpi4py import MPI
from ufl import dx, grad, inner
def main(N, k):
msh = mesh.create_unit_square(MPI.COMM_WORLD, N, N, mesh.CellType.triangle)
tdim = msh.topology.dim
fdim = tdim - 1
msh.topology.create_connectivity(fdim, tdim)
Vh = fem.functionspace(msh, element("Lagrange", msh.basix_cell(), k))
msh.topology.create_connectivity(fdim, tdim)
boundary_facets = mesh.exterior_facet_indices(msh.topology)
boundary_dofs = fem.locate_dofs_topological(Vh, fdim, boundary_facets)
bc = fem.dirichletbc(default_scalar_type(0), boundary_dofs, Vh)
# Next, the variational problem is defined:
u = ufl.TrialFunction(Vh)
v = ufl.TestFunction(Vh)
a = inner(grad(u), grad(v)) * dx
L = inner(fem.Constant(msh, default_scalar_type(1)), v) * dx
# +
problem = fem.petsc.LinearProblem(
a, L, bcs=[bc], petsc_options={"ksp_type": "preonly", "pc_type": "lu"}
)
uh_lap = problem.solve()
return uh_lap, Vh, msh
if __name__ == "__main__":
results = []
N = [2 ** (k + 2) for k in range(2, 6)]
degree = 3
hh, rU, rUH1, eU, eUH1 = [], [], [], [], []
rU.append(0.0)
rUH1.append(0.0)
uhlap_fine, Vh_fine, _ = main(160, k=degree + 3)
for nn in N:
uh_lap, Vh, msh = main(nn, degree)
tdim = msh.topology.dim
num_cells = msh.topology.index_map(tdim).size_local + msh.topology.index_map(tdim).num_ghosts
cells = np.arange(num_cells, dtype=np.int32)
hmax = dolfinx.cpp.mesh.h(msh._cpp_object, tdim, cells).max()
V_exact = fem.functionspace(msh, ("Lagrange", degree + 3))
u_exact = fem.Function(V_exact)
interpolation_data = fem.create_interpolation_data(V_exact, Vh_fine, cells)
u_exact.interpolate_nonmatching(uhlap_fine, cells, interpolation_data=interpolation_data)
u_exact.x.scatter_forward()
# H01 errors
diff = uh_lap - u_exact
H1_diff = msh.comm.allreduce(
fem.assemble_scalar(fem.form(inner(grad(diff), grad(diff)) * dx)),
op=MPI.SUM,
)
H1_diff = np.sqrt(H1_diff)
# L2 errors
L2_diff = msh.comm.allreduce(
fem.assemble_scalar(fem.form(inner(diff, diff) * dx)), op=MPI.SUM
)
L2_diff = np.sqrt(L2_diff)
eU.append(L2_diff)
eUH1.append(H1_diff)
nk = N.index(nn)
hh.append(hmax)
if nk > 0:
rU.append(np.log(eU[nk] / eU[nk - 1]) / np.log(hh[nk] / hh[nk - 1]))
rUH1.append(np.log(eUH1[nk] / eUH1[nk - 1]) / np.log(hh[nk] / hh[nk - 1]))
print('L2-rate')
for k in range(len(N)):
print(rU[k])
print('H1-rate')
for k in range(len(N)):
print(rUH1[k])