# Helmholtz equation¶

Helmholtz problem in both complex and real modes In the complex mode, the exact solution is a plane wave propagating at an angle theta to the positive x-axis. Chosen for comparison with results from Ihlenburg's book "Finite Element Analysis of Acoustic Scattering" p138-139. In real mode, the Method of Manufactured Solutions is used to produce the exact solution and source term.

```import numpy as np
from dolfinx import (Function, FunctionSpace, UnitSquareMesh, fem,
has_petsc_complex)
from dolfinx.fem.assemble import assemble_scalar
from dolfinx.io import XDMFFile
from mpi4py import MPI
from ufl import FacetNormal, TestFunction, TrialFunction, dx, grad, inner

# wavenumber
k0 = 4 * np.pi

# approximation space polynomial degree
deg = 1

# number of elements in each direction of mesh
n_elem = 128

mesh = UnitSquareMesh(MPI.COMM_WORLD, n_elem, n_elem)
n = FacetNormal(mesh)

# Source amplitude
if has_petsc_complex:
A = 1 + 1j
else:
A = 1

# Test and trial function space
V = FunctionSpace(mesh, ("Lagrange", deg))

# Define variational problem
u = TrialFunction(V)
v = TestFunction(V)
f = Function(V)
f.interpolate(lambda x: A * k0**2 * np.cos(k0 * x) * np.cos(k0 * x))
a = inner(grad(u), grad(v)) * dx - k0**2 * inner(u, v) * dx
L = inner(f, v) * dx

# Compute solution
uh = fem.Function(V)
uh.name = "u"
problem = fem.LinearProblem(a, L, u=uh, petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
problem.solve()

# Save solution in XDMF format (to be viewed in Paraview, for example)
with XDMFFile(MPI.COMM_WORLD, "plane_wave.xdmf", "w", encoding=XDMFFile.Encoding.HDF5) as file:
file.write_mesh(mesh)
file.write_function(uh)
```

Calculate L2 and H1 errors of FEM solution and best approximation. This demonstrates the error bounds given in Ihlenburg. Pollution errors are evident for high wavenumbers.

```# Function space for exact solution - need it to be higher than deg
V_exact = FunctionSpace(mesh, ("Lagrange", deg + 3))
u_exact = Function(V_exact)
u_exact.interpolate(lambda x: A * np.cos(k0 * x) * np.cos(k0 * x))

# H1 errors
diff = uh - u_exact