Linear shape function, mass matrix, and element volume

In unsteady CFD problem, under certain time integration scheme, L2 inner product of shape functions gives what so called mass matrix, i.e. the matrix with its entries in the form , where
is shape function. When shape function is linear, there is a better way to demonstrate
is proportional to local element volume (area) than trivially plugging in and calculating or using Gaussian integral. Assume in 2D triangular element ABC whose area is
, and
stands for the shape function whose unit value is reached at A, B, C correspondingly.

If we interpret local mass entry over element ABC shown above as the mass of a piece of wood splinter in the shape of tetrahedron A1-A-B-C, where
is the thickness function on the element, while
is the density function, then it’s not difficult to see that
, because they are both the mass of tetrahedron with the same volume and density distribution from bottom (A1-A-B or B1-A-B) to top (C). The next step is to show that the mass of tetrahedron C1-A-B-C (
) is the half of the total mass of the prism A1-B1-C1-A-B-C with the same density distribution. The argument is based on linearity, which allows us to assign a single parameter for above integrals. Set this single coordinate
as the line parameter from C to line A-B, i.e.
on AB,
at C. Then, for mass of prism and tetrahedron, we both have
mass
where gives the area for cross section parallel to A1-A-B-B1 at
.
is the thickness of ABC, while
is the density distribution. We have
,
and for prism,
for tetrahedron. Then we have
which proves
Since is nothing but the sum of the mass of three tetrahedrons, which is the mass of the prism. This sum is then
. Using
, finally we have
Note: for 3D tetrahedron element, linear shape function gives similar relation, in this case, above ratio over the volume of a tetrahedron would be 1/10 and 1/20:

What’s the difference?
Today I was asked for a one-sentence comment of the difference between finite difference method and finite element method. What I came up was:
In finite difference method we approximate the differential expression, or the partial derivative, while in finite element method we approximate the space in which the solution lies.
Hopefully this shed some light on the issue.
Saddle point problem in Navier-Stokes equation
It is well known that the the optimization problem
is equal to solving a linear operator equation
provided that is symmetric and positive definite. Here
which is a Hilbert space, and
while
is a bilinear operator.
This is a very general problem considered widely in many areas. However, in the real world, some further condition are to be applied on the space where lies on. If this is described as constraint equation
then we are dealing with constraint optimization problem ,to which Lagrange multiplier is usually the first one can come up. We then try to solve the stationary point of Lagrangian
Now supposing we set , using stationary point condition on above equation, we arrive at
where is replaced by
indicating the parallel unknown as
in the problem. The stationary point nature of this solution gives the name of saddle point problem, whose general case is
So, putting a constraint to a minimization problem, one try to solve a saddle problem instead of a simple linear system with SPD matrix.
For a linear system, one can always decompose it in to the form of
and this is the most general form of saddle problem.
For incompressible Navier-Stokes equation, we have (without mentioning the boundary conditions)
Following -scheme by Glowinski, one has the time discretized plan as:
then
then
The first and last step in above scheme are to solve Stokes problem like
Multiply on both sides of the first equation, by using Green’s formula, we can see it is just the saddle point problem, with
as
and
as
:
Here pressure acts as Lagrange multiplier, and the Lagrangian is
where is the seminorm on
and
is in
.
Jacobi method demo
Code below is to solve the static version of the equation in previous FDM code demo, with B.C. changed as homogeneous. The Jacobi method is used to replace the LAPACK solver which gives inexact method. The exact solution is
Using initial guess as
one can see that most of the computing cost is spent on smoothing lowest mode.
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <fstream>
//#include <vector>
//#include <sunperf.h>
using namespace std;
//typedef std::vector<float> fvector_s;
//Maximum of an array.
float max(float a[], int n) {
float v = a[0];
for (int i=1; i<n; i++) {
if (a[i] > v) {
v = a[i];
}
}
return v;
}
int main ()
{
int n=500;
float tmp, b[n], a_d[n], a_u[n-1], a_l[n-1], \
tol=1.e-7, x0[n], x1[n], x2[n], error=1.;
float h=1./(n+1), pi=3.1416;
int count=0;
//initializing a
for(int i=0; i<n; ++i){
a_d[i]=2.0;
}
for(int i=0; i<n-1; i++){
a_l[i]=-1.;
a_u[i]=-1.;
}
//initializaing b[]
for(int i=0; i<n; ++i){
b[i]=h*h;
}
//initial guess
for(int i=0; i<n; ++i){
x0[i]=sin(2*pi*h*(i+1))+0.5*sin(10*pi*h*(i+1))+\
0.3*sin(20*pi*h*(i+1))+0.1*sin(40*pi*h*(i+1));
x1[i]=x0[i];
}
ofstream outfile;
outfile.open("jac.out");
do{
count+=1;
for(int i=0; i<n; ++i){
if(i==0)
x2[i]=(b[i]-a_u[i]*x1[i+1])/a_d[i];
else if(i==n-1)
x2[i]=(b[i]-a_l[i-1]*x1[i-1])/a_d[i];
else
x2[i]=(b[i]-a_u[i]*x1[i+1]-a_l[i-1]*x1[i-1])/a_d[i];
}
for(int i=0; i<n; i++){
x1[i]=x2[i]-x1[i];
}
error=max(x1, n)/max(x0, n);
for(int i=0; i<n; i++){
x1[i]=fabs(x2[i]-(-(i*h)*(i*h)/2+i*h/2));
}
outfile << count << "\t" << error << endl;
for(int i=0; i<n; ++i){
x1[i]=x2[i];
}
}while(error>tol);
cout << "Number of iterations:" << count << endl;
for(int i=0; i<n; i++){
outfile << count << "\t" << x2[i] << endl;
}
outfile.close();
return 0;
}
A sample of toy FDM code
Solving equation
Time integration is full implicit, and during each time step Newton’s method is employed.
PROGRAM MAIN
!--------------------------------------------------
!Implicit time evolution of equation
!u_t-u''=f(x,u)
!f(x,u)=-2+r*(sin(u)-sin(x^2)),r=2
!--------------------------------------------------
! t=time points
! dt=time step
! h=neighboring nodes distance
! u=unknown
! x=node location
! n=No. of unknowns
!USE SUNPERF
IMPLICIT NONE
INTEGER(4) :: n
REAL(4) :: elapse,time(2),etime
REAL(8) :: t=0,dt=0.1
REAL(8) :: h
REAL(8),ALLOCATABLE :: u(:),x(:)
INTEGER(4) :: count,i
n=50
h=1/(DBLE(n)+1.)
ALLOCATE (x(n),u(n))
x=(/(i*h,i=1,n)/)
u=(/((i*h)**0.5,i=1,n)/)
OPEN(UNIT=100,FILE='data',STATUS='UNKNOWN',ACTION='&
&WRITE')
DO i=1,n
WRITE(100,*) t,x(i),u(i)
END DO
DO WHILE (t<1.0)
CALL newton(n,h,dt,u,x)
t=t+dt
DO i=1,n
WRITE(100,*) t,x(i),u(i)
END DO END DO CLOSE(UNIT=100)
elapse=etime(time)
WRITE(*,*) 'elapsed:',elapse
END PROGRAM MAIN
!--------------------------------------------------
SUBROUTINE newton(n,h,dt,u,x)
IMPLICIT NONE
INTEGER(4),INTENT(IN) :: n
REAL(8),INTENT(IN) :: x(n),h,dt
REAL(8),INTENT(INOUT) :: u(n)
REAL(8) :: r=2,c(n),error,b(n,1),b0(n,1),a(2,n)
REAL(8) :: alpha=1.0,beta=-1.0
INTEGER(4) :: info,i,iter
c=u*h*h/dt
iter=0
error=1
DO WHILE (error>1.e-13)
iter=iter+1
a(1,:)=-1
a(2,:)=2+h*h/dt
b(:,1)=(-2+r*(SIN(u)-SIN(x*x)))*h*h+c
b(n,1)=b(n,1)+1
CALL DSBMV('u',n,1,alpha,a,2,u,1,beta,b,1)
b=-b
a(2,:)=a(2,:)-r*COS(u)*h*h
CALL DGTSV(n,1,a(1,2:),a(2,:),a(1,2:),b,n,info)
error=MAXVAL(ABS(b))
u=u+b(:,1)
END DO
WRITE(*,*) 'INFO',info,'Number of iterations:',iter
END SUBROUTINE newton
!--------------------------------------------------
Output would be like:
% f95 -dalign implicit_newton.f95 -xlic_lib=sunperf % a.out INFO 0 Number of iterations: 4 INFO 0 Number of iterations: 4 INFO 0 Number of iterations: 4 INFO 0 Number of iterations: 4 INFO 0 Number of iterations: 4 INFO 0 Number of iterations: 3 INFO 0 Number of iterations: 3 INFO 0 Number of iterations: 3 INFO 0 Number of iterations: 3 INFO 0 Number of iterations: 3 elapsed: 0.061407
Of course the exact solution is . Here is time evolution plot of the numerical solution.


leave a comment