Quadratic Element for Poisson Equation in 3D
This example is to show the rate of convergence of the linear finite element approximation of the Poisson equation on the unit square:
\[- \Delta u = f \; \hbox{in } (0,1)^3\]for the following boundary conditions
- Non-empty Dirichlet boundary condition: $u=g_D \hbox{ on }\Gamma_D, \nabla u\cdot n=g_N \hbox{ on }\Gamma_N.$
- Pure Neumann boundary condition: $\nabla u\cdot n=g_N \hbox{ on } \partial \Omega$.
- Robin boundary condition: $g_R u + \nabla u\cdot n=g_N \hbox{ on }\partial \Omega$.
References:
- Quick Introduction to Finite Element Methods
- Introduction to Finite Element Methods
- Progamming of Finite Element Methods
Subroutines:
- Poisson3P2
- cubePoissonP2
- femPoisson3
- Poisson3P2femrate
The method is implemented in Poisson3P2 subroutine and tested in cubePoissonP2. Together with other elements (P1, P2,Q1,WG), femPoisson3 provides a concise interface to solve Poisson equation. The P2 element is tested in Poisson3P2femrate. This doc is based on Poisson3P2femrate.
P2 Quadratic Element
For the quadratic element on a tetrahedron, the local basis functions can be written in terms of barycentric coordinates. The 10 dofs is displayed below. The first 4 are associated to the vertices and 6 to the middle points of 6 edges.
Given a mesh, the required data structure can be constructured by
[elem2dof,edge,bdDof] = dof3P2(elem)
Local indexing
The tetrahedron consists of four vertices indexed as [1 2 3 4]. Each tetrahedron contains four faces and six edges. They can be indexed as
locFace = [2 3 4; 1 4 3; 1 2 4; 1 3 2];
locEdge = [1 2; 1 3; 1 4; 2 3; 2 4; 3 4];
In locFace, the i-th face is opposite to the i-th vertices and the orientation is induced from the tetrahedronthus this is called opposite indexing. In locEdge, it is the lexicographic indexing which is induced from the lexicographic ordering of the six edges.
node = [1,0,0; 0,1,0; 0,0,0; 0,0,1];
elem = [1 2 3 4];
locEdge = [1 2; 1 3; 1 4; 2 3; 2 4; 3 4];
showmesh3(node,elem);
view(-14,12);
findnode3(node);
findedgedof3(node,locEdge);

Boundary dof
When implement boundary conditions, we need to find the d.o.f associated to boundary faces. For example, for Neumann boundary conditions, it can be found by
bdFace2dof = [elem2dof(bdFlag(:,1) == 2,[2,3,4,10,9,8]); ...
elem2dof(bdFlag(:,2) == 2,[1,4,3,10,6,7]); ...
elem2dof(bdFlag(:,3) == 2,[1,2,4,9,7,5]); ...
elem2dof(bdFlag(:,4) == 2,[1,3,2,8,5,6])];
A local basis
The 10 Lagrange-type bases functions are denoted by $\phi_i, i=1:10$. In barycentric coordinates, they are
\[\phi_1 = \lambda_1(2\lambda_1 -1),\quad \nabla \phi_1 = \nabla \lambda_1(4\lambda_1-1),\] \[\phi_2 = \lambda_2(2\lambda_2 -1),\quad \nabla \phi_2 = \nabla \lambda_2(4\lambda_2-1),\] \[\phi_3 = \lambda_3(2\lambda_3 -1),\quad \nabla \phi_3 = \nabla \lambda_3(4\lambda_3-1),\] \[\phi_4 = \lambda_4(2\lambda_4 -1),\quad \nabla \phi_4 = \nabla \lambda_4(4\lambda_4-1),\] \[\phi_5 = 4\lambda_1\lambda_2,\quad \nabla\phi_5 = 4\left (\lambda_1\nabla \lambda_2 + \lambda_2\nabla \lambda_1\right )\; ,\] \[\phi_6 = 4\lambda _1\lambda_3,\quad \nabla\phi_6 = 4\left (\lambda_1\nabla \lambda_3 + \lambda_3\nabla \lambda_1\right )\; ,\] \[\phi_7 = 4\lambda _1\lambda_4,\quad \nabla\phi_7 = 4\left (\lambda_1\nabla \lambda_4 + \lambda_4\nabla\lambda_1\right )\; .\] \[\phi_8 = 4\lambda _2\lambda_3,\quad \nabla\phi_8 = 4\left (\lambda_2\nabla \lambda_3 + \lambda_3\nabla \lambda_2\right )\; ,\] \[\phi_9 = 4\lambda _2\lambda_4,\quad \nabla\phi_9 = 4\left (\lambda_2\nabla \lambda_4 + \lambda_4\nabla \lambda_2\right )\; ,\] \[\phi_{10} = 4\lambda _3\lambda_4,\quad \nabla\phi_{10} = 4\left (\lambda_3\nabla \lambda_4 + \lambda_4\nabla \lambda_3\right )\; .\]When transfer to the reference triangle formed by $(0,0,0),(1,0,0),(0,1,0),(0,0,1)$, the local bases in x-y-z coordinate can be obtained by substituting
\[\lambda _1 = x, \quad \lambda _2 = y, \quad \lambda _3 = z, \quad \lambda_4 = 1-x-y-z.\]Unlike 2-D case, to apply uniform refinement to obtain a fine mesh with good mesh quality, a different ordering of the inital mesh, which may violate the positive ordering, should be used. See 3 D Red Refinement.
Mixed boundary condition
%% Setting
[node,elem] = cubemesh([0,1,0,1,0,1],1/3);
mesh = struct('node',node,'elem',elem);
option.maxIt = 4;
option.elemType = 'P2';
option.printlevel = 1;
option.plotflag = 1;
%% Non-empty Dirichlet boundary condition.
fprintf('Mixed boundary conditions. \n');
% pde = polydata3;
pde = sincosdata3;
mesh.bdFlag = setboundary3(node,elem,'Dirichlet','~(x==0)','Neumann','x==0');
femPoisson3(mesh,pde,option);
Mixed boundary conditions.
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 3600, #nnz: 70718, smoothing: (1,1), iter: 12, err = 2.83e-09, time = 0.13 s
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 30752, #nnz: 659134, smoothing: (1,1), iter: 12, err = 3.80e-09, time = 0.38 s
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 254016, #nnz: 5674430, smoothing: (1,1), iter: 12, err = 3.57e-09, time = 2.2 s
Table: Error
#Dof h ||u-u_h|| ||Du-Du_h|| ||DuI-Du_h|| ||uI-u_h||_{max}
729 2.500e-01 5.00700e-03 1.32387e-01 5.25032e-02 1.21275e-02
4913 1.250e-01 6.03477e-04 3.52893e-02 9.25606e-03 1.61600e-03
35937 6.250e-02 7.43413e-05 9.04712e-03 1.42917e-03 2.02649e-04
274625 3.125e-02 9.26851e-06 2.28115e-03 2.17441e-04 2.52582e-05
Table: CPU time
#Dof Assemble Solve Error Mesh
729 1.10e-01 2.00e-02 1.20e-01 1.00e-02
4913 1.90e-01 1.30e-01 1.00e-01 1.00e-02
35937 8.80e-01 3.80e-01 3.90e-01 7.00e-02
274625 6.22e+00 2.17e+00 3.01e+00 0.00e+00


Pure Neumann boundary condition
When pure Neumann boundary condition is posed, i.e., $-\Delta u =f$ in $\Omega$ and $\nabla u\cdot n=g_N$ on $\partial \Omega$, the data should be consisitent in the sense that $\int_{\Omega} f \, dx + \int_{\partial \Omega} g \, ds = 0$. The solution is unique up to a constant. A post-process is applied such that the constraint $\int_{\Omega}u_h dx = 0$ is imposed.
%% Pure Neumann boundary condition.
fprintf('Pure Neumann boundary condition. \n');
pde = sincosdata3Neumann;
option.plotflag = 0;
mesh.bdFlag = setboundary3(node,elem,'Neumann');
femPoisson3(mesh,pde,option);
Pure Neumann boundary condition.
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 729, #nnz: 13921, smoothing: (1,1), iter: 11, err = 8.36e-09, time = 0.06 s
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 4913, #nnz: 103105, smoothing: (1,1), iter: 12, err = 3.57e-09, time = 0.07 s
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 35937, #nnz: 792961, smoothing: (1,1), iter: 12, err = 3.77e-09, time = 0.35 s
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 274625, #nnz: 6218497, smoothing: (1,1), iter: 12, err = 4.84e-09, time = 2.2 s
Table: Error
#Dof h ||u-u_h|| ||Du-Du_h|| ||DuI-Du_h|| ||uI-u_h||_{max}
729 2.500e-01 4.33972e-03 1.06671e-01 1.11359e-01 2.69023e-02
4913 1.250e-01 5.63932e-04 3.20352e-02 2.08121e-02 5.72678e-03
35937 6.250e-02 7.20239e-05 8.63820e-03 3.68308e-03 8.55523e-04
274625 3.125e-02 9.12740e-06 2.22998e-03 6.44578e-04 1.14993e-04
Table: CPU time
#Dof Assemble Solve Error Mesh
729 1.00e-01 6.00e-02 4.00e-02 1.00e-02
4913 1.60e-01 7.00e-02 9.00e-02 2.00e-02
35937 8.10e-01 3.50e-01 4.20e-01 7.00e-02
274625 5.80e+00 2.21e+00 2.78e+00 0.00e+00

Robin boundary condition
%% Robin boundary condition.
fprintf('Robin boundary condition. \n');
pde = sincosRobindata3;
mesh.bdFlag = setboundary3(node,elem,'Robin');
femPoisson3(mesh,pde,option);
Robin boundary condition.
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 4913, #nnz: 105409, smoothing: (1,1), iter: 12, err = 2.66e-09, time = 0.05 s
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 35937, #nnz: 802177, smoothing: (1,1), iter: 12, err = 4.68e-09, time = 0.35 s
Multigrid V-cycle Preconditioner with Conjugate Gradient Method
#dof: 274625, #nnz: 6255361, smoothing: (1,1), iter: 12, err = 8.75e-09, time = 2.4 s
Table: Error
#Dof h ||u-u_h|| ||Du-Du_h|| ||DuI-Du_h|| ||uI-u_h||_{max}
729 2.500e-01 4.44278e-03 1.19113e-01 8.29341e-02 4.13848e-02
4913 1.250e-01 5.66084e-04 3.35620e-02 1.48538e-02 3.95143e-03
35937 6.250e-02 7.20911e-05 8.82519e-03 2.51203e-03 3.51203e-04
274625 3.125e-02 9.13225e-06 2.25306e-03 4.25087e-04 4.30278e-05
Table: CPU time
#Dof Assemble Solve Error Mesh
729 7.00e-02 1.00e-02 3.00e-02 0.00e+00
4913 1.60e-01 5.00e-02 9.00e-02 2.00e-02
35937 8.30e-01 3.50e-01 3.80e-01 7.00e-02
274625 6.04e+00 2.36e+00 2.94e+00 0.00e+00

Conclusion
The optimal rate of convergence of the H1-norm (2nd order) and L2-norm (3rd order) is observed. Superconvergence between discrete functions $| \nabla u_I - \nabla u_h |$ is only 2.5 order.
For Neumann problem, the maximum norm is only 2.6 not optimal.
MGCG converges uniformly in all cases.
Comments