\(\DeclareMathOperator{\opdiv}{div}\)
49. Finite Element Error Analysis#
Some lucky accident happens in the analysis for mixed methods for second order problems:
Let \(I_h\) be the Raviart Thomas interpolation operator, and \(P_h\) the \(L_2\)-projection.
We start the error analysis using the discrete \(\inf-\sup\)-stability, as usual for mixed methods:
Now, the famous commuting diagram comes into play:
the interpolation operators commute with the \(\opdiv\)-operator:
The term in the numerator above is
Using the commuting diagram property we get:
Thanks to orthogonality, the second and third term vanish !
Thus, we get the error estimate
Using the triangle inequality for \(\sigma\), we get
The flux error is as good as we can interpolate into the flux space. Since the finite element space for \(u_h\) is of lower order, the error \(u - u_h\) is in general of lower order. But, the filtered error \(\| u_h - P_h u_h \|\) has the better order.
from ngsolve import *
from ngsolve.webgui import Draw
mesh = Mesh(unit_square.GenerateMesh(maxh=0.2))
order=1
Sigma = HDiv(mesh,order=order)
V = L2(mesh, order=order-1)
X = Sigma * V
sigma,u = X.TrialFunction()
tau,v = X.TestFunction()
a = BilinearForm(X)
a += (sigma*tau + div(sigma)*v + div(tau)*u)*dx
a.Assemble()
f = LinearForm(10*v*dx).Assemble()
gfu = GridFunction(X)
gfu.vec.data = a.mat.Inverse() * f.vec
sol_sigma = gfu.components[0]
sol_u = gfu.components[1]
print ("The flux")
Draw (sol_sigma, mesh, "sigma");
The flux
The scalar part of the solution:
Draw (sol_u, mesh, "u");
49.1. Local post-processing#
Since \(\nabla u = \lambda^{-1} \sigma\), we can reconstruct a better approximation \(\widetilde u\) by small, element-wise problems:
This optimization problems can be written as a mixed variational problem:
Find: \(\widetilde u \in P^{k+1,dc}\) and \(p_h \in P^0\):
This requires to solve decoupled problems on every element, what is cheap.
V2 = L2(mesh, order=order+1)
Q2 = L2(mesh, order=0)
X2 = V2*Q2
u2,p2 = X2.TrialFunction()
v2,q2 = X2.TestFunction()
a2 = BilinearForm(X2)
a2 += (grad(u2)*grad(v2) + u2*q2 + v2*p2)*dx
f2 = LinearForm(X2)
f2 += (sol_sigma*grad(v2) + sol_u * q2)*dx
a2.Assemble()
f2.Assemble()
gfu2 = GridFunction(X2)
gfu2.vec.data = a2.mat.Inverse() * f2.vec
Draw(gfu2.components[0], mesh, "upost");