22. Mixed Methods for the Diffusion equations#
We consider the mixed system
with boundary conditions
22.1. Primal and Dual mixed methods#
22.1.1. Primal mixed method#
Find \(\sigma \in \Sigma := L_2(\Omega)^d\) and \(u \in V := H^1\) s.t. \(u = u_D\) on \(\Gamma_D\) and
22.1.2. Dual mixed method#
Find \(\sigma \in \Sigma := H(\operatorname{div})\) and \(u \in L_2\) s.t. \(\sigma\cdot n = g\) on \(\Gamma_N\) and
22.1.3. Beam-scale:#
Two different formulations for the same equation? We shift regularity between primal and dual spaces
Different choices of spaces for the same biform
22.2. Proving Brezzi conditions#
22.2.1. Primal mixed method:#
\(V = H^1, \Sigma = [L_2]^d\)
\(a(.,.)\) is the inner product in \(\Sigma\), thus (kernel) coercivity holds with constant 1.
LBB condition:
\[ \inf_{u \in H^1} \sup_{\sigma \in [L_2]^d} \frac{(\sigma, \nabla u)_{L_2}}{ \| \sigma \|_{L_2} \| \nabla u \|_{L_2} } \; \underset{\sigma := \nabla u} {=} \; \inf_{u \in H^1} \frac{ \| \nabla u \|} { \| \nabla u \| } = 1 \]The flux is chosen as the gradient of \(u\).
22.2.2. Dual mixed method:#
\(V = L_2, \Sigma = H(\operatorname{div})\), with \(\| \sigma \|_{H(\operatorname{div})}^2 = \| \sigma \|_{L_2}^2 + \| \operatorname{div} \sigma \|_{L_2}^2\).
On \(V_{0h} = \{ \sigma \in \Sigma : \operatorname{div} \sigma = 0 \}\), we have
\[a(\sigma, \sigma) = (\sigma, \sigma)_{L_2} = (\sigma, \sigma)_{L_2} + (\operatorname{div} \sigma, \operatorname{div}\sigma)_{L_2} = \| \sigma \|_{H(\operatorname{div})}^2 \]LBB condition:
Now we have to find a right-inverse to the \(\operatorname{div}\). We can reduce it to solving a Poisson equation:
\[ \sigma := \nabla w \quad \text{with} \quad \Delta w = u \]Then \(\| w \|_{H^1} \preceq \| u \|_{H^-1} \preceq \| u \|_{L_2}\), and thus \(\| \sigma \|_{L_2} = \| \nabla w \|_{L_2} \preceq \| u \|_{L_2}\)
And, \(\operatorname{div} \sigma = \Delta w = u\), and thus also \(\| \operatorname{div} \sigma \|_{L_2} \preceq \| u \|_{L_2}\).
We have found a \(\sigma\) such that
\[ \inf_{u \in V} \sup_{\tau \in \Sigma} \frac{ (\operatorname{div} \tau, u) }{ \| \tau \|_{\Sigma} \| u \|_V } \geq \inf_{u \in V} \frac{ (\operatorname{div} \sigma, u) }{ \| \sigma \|_{\Sigma} \| u \|_V } \succeq \frac { \| u \|_{L_2}^2 } { \| u \|_{L_2}^2 } = 1 \]
22.3. Finite elements for \(H^1\) and \(H(\operatorname{div})\)#
For \(H^1\), we choose piecewise polynomials, which are continuous across elements. Thus, these functions have a weak gradient, which is exactly the element-wise gradient.
For \(H(\operatorname{div})\), we choose vectorial piecewise polynomials, whose normal components are continuous across elements. Thus, these functions have a weak divergence, which is exactly the element-wise divergence (Raviart-Thomas (RT) and Brezzi-Douglas-Marini (BDM) elements).
from ngsolve import *
from ngsolve.webgui import Draw
mesh = Mesh(unit_square.GenerateMesh(maxh=0.25))
fes = H1(mesh, order=1)
gfu = GridFunction(fes, multidim=fes.ndof)
for i in range(fes.ndof):
gfu.vecs[i][i] = 1
Draw (gfu, animate=True, deformation=True, scale=0.3, euler_angles=(-65,0,-170));
fes = HDiv(mesh, order=0) # use RT=True for higher order
gfu = GridFunction(fes, multidim=fes.ndof)
for i in range(fes.ndof):
gfu.vecs[i][i] = 1
Draw (gfu, animate=True, vectors={"grid_size" : 40 }, scale=0.3);
22.4. Proving discrete LBB conditions#
22.4.1. Primal mixed#
Same as continuous one, choose \(\sigma_h = \nabla u_h\).
22.4.2. Dual mixed#
Use a \(H(\operatorname{div})\)-continuous, commuting interpolation operator
where \(\sigma\) is a candidate for the infinite-dimensional LBB condition. Then
22.4.3. Dual mixed method with primal mixed analysis#
Discrete norms:
Candidate for LBB: Given \(u_h \in V_h\), choose \(\sigma_h \in \Sigma_h\) such that
proves the discrete \(\inf-\sup\) condition.
22.5. Super-convergence#
For the dual mixed discretizaton we have
and thus the kernel-inclusion property.
From the discrete \(\inf-\sup\) condition we get:
Using the commuting diagram property we get:
and thus
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()
lhs = sigma*tau*dx + div(sigma)*v*dx + div(tau)*u*dx
rhs = -10*v*dx
gfu = Solve (lhs==rhs)
sol_sigma, sol_u = gfu.components
print ("The flux")
Draw (sol_sigma, mesh);
print ("The scalar")
Draw (sol_u, mesh);
The flux
The scalar
22.6. Local post-processing#
Since \(\lambda \nabla u = \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\):
X2 = L2(mesh, order=order+1) * L2(mesh, order=0)
(ut,p), (vt,q) = X2.TnT()
pp_lhs = (grad(ut)*grad(vt) + ut*q + vt*p)*dx
pp_rhs = (sol_sigma*grad(vt) + sol_u * q)*dx
gfu2 = Solve(pp_lhs==pp_rhs)
Draw(gfu2.components[0], mesh, deformation=True, scale=0.5);
22.7. Hybridization Techniques#
Discretizing an elliptic equation by a primal method leads to a positive definite matrix. Using a mixed method leads to a saddle point problem. This disadvantage can be overcome by the so called hybridization technique:
The idea is as follows: Break the normal-continuity of the RT - space, and reinforce it by another Lagrange parameter. This new Lagrange parameter is a polynomial on every mesh edge (or face, in 3D).
The variational formulation is as follows:
Find: \(\sigma_h \in RT_k^{dc}, u_h \in P^k, \widehat u_h \in P^k(\cup E)\) such that
We used the definition of the jump term \([\![ \tau_n ]\!] = \tau_1 n_1 + \tau_2 n_2\)
This formulation gives the same solution as the mixed formulation, so we don’t need an extra error analysis
The physical meaning of the Lagrange paramter \(\widehat u_h\) is the primal variable, what can be seen by integration by parts of the first equation.
Now, Dirichlet boundary conditions are set by constraining the \(\widehat u\) on the Dirichlet boundary, and Neumann boundary conditions are formulated by \(\int_{\Gamma_N} g \widehat v\). The hybridized formulation is thus similar to a primal method.
The discretization system has the form
The submatrix
is regular and block-diagonal, each block corresponds to an element. Thus it can be cheaply inverted.
If \(u_2\) were known, we could compute the first two variables from \(u_2\):
Plugging this term into the third equation \(B_2 \sigma = 0\), we obtain the system
The matrix on the left hand side is symmetric positive definite. It behaves like a standard system matrix (e.g. for condition number), and standard iterative methods and preconditioners can be used for solution.
The lowest order hybrid method has the same degrees of freedom as the non-conforming \(P^1\) element. Here, the extension to higher order is straight forward.
from ngsolve import *
from ngsolve.webgui import Draw
mesh = Mesh(unit_square.GenerateMesh(maxh=0.2))
order=2
Sigma = Discontinuous (HDiv(mesh, order=order, RT=True))
V = L2(mesh, order=order)
Vhat = FacetFESpace(mesh, order=order, dirichlet="left|bottom")
X = Sigma*V*Vhat
sigma,u,uhat = X.TrialFunction()
tau,v,vhat = X.TestFunction()
n = specialcf.normal(mesh.dim)
a = BilinearForm(X, condense = True)
a += (sigma*tau + div(sigma)*v + div(tau)*u)*dx
a += (-sigma*n*vhat-tau*n*uhat) * dx(element_boundary=True)
c = preconditioners.BDDC(a)
a.Assemble()
f = LinearForm(-v*dx).Assemble()
gfu = GridFunction(X)
f.vec.data += a.harmonic_extension_trans * f.vec
# gfu.vec.data = a.mat.Inverse(X.FreeDofs(True)) * f.vec
from ngsolve.solvers import CG
CG (mat=a.mat, pre=c.mat, rhs=f.vec, sol=gfu.vec,
printrates=True, maxsteps=200)
gfu.vec.data += a.harmonic_extension * gfu.vec
gfu.vec.data += a.inner_solve * f.vec
Draw (gfu.components[0], mesh, "sigma")
Draw (gfu.components[1], mesh, "u");
CG iteration 1, residual = 0.3759129456527738
CG iteration 2, residual = 0.07579218490740629
CG iteration 3, residual = 0.013587579030950514
CG iteration 4, residual = 0.004440234221781763
CG iteration 5, residual = 0.0016170166562519427
CG iteration 6, residual = 0.0006636169222860484
CG iteration 7, residual = 0.00018741441785654082
CG iteration 8, residual = 6.029088620463164e-05
CG iteration 9, residual = 2.077721160522339e-05
CG iteration 10, residual = 6.1533586717709075e-06
CG iteration 11, residual = 2.0768303974751078e-06
CG iteration 12, residual = 5.592765774424091e-07
CG iteration 13, residual = 2.1404260555986382e-07
CG iteration 14, residual = 5.58119308955585e-08
CG iteration 15, residual = 2.1521755208778862e-08
CG iteration 16, residual = 6.3948425814477995e-09
CG iteration 17, residual = 2.257408527935166e-09
CG iteration 18, residual = 7.646470690282326e-10
CG iteration 19, residual = 2.296191954509906e-10
CG iteration 20, residual = 8.967090603271192e-11
CG iteration 21, residual = 2.171142902115537e-11
CG iteration 22, residual = 7.154168881453205e-12
CG iteration 23, residual = 1.8130000866382403e-12
CG iteration 24, residual = 6.554662617875164e-13
CG iteration 25, residual = 1.9067207690099665e-13