Finite Element Method with Maple
Copyright 2000, Fedderik van der Bos
Author's note: This worksheet is intended for academic use only. It is not for commerical use.
This worksheet computes solutions of linear second order non-symmetric PDE's using a Finite Element Method (FEM). It also uses the NAG library, which greatly reduces the computing time. Most of the algorithms and also the notation are from the book Introduction to Scientific Computing written by B. Lucquin and O. Pironneau, John Wiley & Sons, 1998. The following problem is used (equation 6.1-3 in the book)
in
on
on
With n the normal on the boundary and is the boundary of .
This worksheet demonstrates use of the accompanying Maple package FEMpackge.mws, which may be downloaded by clicking on the "Download Code" column in the Maple Application Center entry for this application.
The FEM-package contains the following procedures.
Solving the Linear System can easily be done by LinearSolve from the LinearAlgebra package.
It uses the following global variables
The following variables have to be defined.
Now we can begin.
Libname has to be redefined in order to be able to use the FEM-package on my PC.
> restart;
> libname:="F:\\Program Files\\Maple Libraries",libname:
> with(plots):
> with(linalg):
> with(FEM);
Warning, the name changecoords has been redefined
Warning, the protected names norm and trace have been redefined and unprotected
>
The usage of Square_Grid, Generate_Hatfunction and Gridplot can be seen in the following section. For the other procedures more data is needed and their usage can been seen in the examples.
Generate Grid and Hatfunctions
Square_Grid and Gridplot
> Square_Grid(5);
> Vertices;
> Triangles;
> Boundary;
> Number_of_Vertices;
> Number_of_Triangles;
> Number_of_Boundary_segments;
> Gridplot();
Generate_Hatfunctions
> Generate_Hatfunctions();
> Hatfunctions[1](x);
> plot3d(Hatfunctions[7](x),x[1]=0..1,x[2]=0..1);
>
Examples
Check from a known function
In this example we make the function solution . Also we define M, u, a0 and a1. f and g are calculated. This is a nice way to see if the program works. As you can see in the example I have chosen the functions are quite random.
Functions
> phi:=x->x[1]^2+sin(2*x[1]*Pi)*x[2]+cos(2*x[2]*Pi)+exp(x[1]*x[2]);
> plot_phi:=plot3d(phi(x),x[1]=0..1,x[2]=0..1,color=blue):
> display(plot_phi,axes=normal);
Interior functions.
> M:=x->matrix(2,2,[1,0,0,1]);
> u:=x->[-x[2],x[1]];
> a0:=x->10*sin(x[1]*Pi/10)*cosh(x[2]*Pi);
Boundary functions, look at the way they are defined.
> phi0:=x->[phi(x),phi(x),phi(x),phi(x)];
> a1:=x->[x[1],x[2],x[1]*x[2],sin(x[2])];
> f:=unapply(-diverge(evalm(M(x)&*grad(phi(x),[x[1],x[2]])),[x[1],x[2]])+innerprod(u(x),grad(phi(x),[x[1],x[2]]))+a0(x)*phi(x),x);
For the calculation of g we need to know the normal.
> N:=[[0,-1],[1,0],[0,1],[-1,0]];
> g:=unapply([seq(evalm(N[k]&*M(x)&*grad(phi(x),[x[1],x[2]]))+a1(x)[k]*phi(x),k=1..4)],x);
Input
> Type_Dirichlet:=[true,false,false,true];
> N:=4;
> Bandwidth:=2*N+1;
> e:=10000;
Grid generation
> Square_Grid(N);
> Generate_Hatfunctions();
Calculation
> Convert_Data_Interior(M,u,a0,f);
> Convert_Data_Boundary(Type_Dirichlet,phi0,a1,g);
Data generated
> M_data;
> U_data;
> A0_data;
> F_data;
> Phi0_data;
> A1_data;
> G_data;
> Linear_System(Type_Dirichlet,Bandwidth,e);
> Matrix_A;
> Vector_F;
> Phi:=convert(LinearAlgebra[LinearSolve](Matrix_A,Vector_F),list);
Plotting
> phi_h:=x->sum(Phi[k]*Hatfunctions[k](x),k=1..Number_of_Vertices);
> plot_phi_h:=plot3d(phi_h(x),x[1]=0..1,x[2]=0..1,color=red,labels=[x,y,z]):
> display({plot_phi_h,plot_phi},axes=normal);
>
Acoustics
This is an nice example from the book (paragraph 1.4). The "+" sign is wrong in the book, it has to be a "-" sign.
Functions
> f:=x->exp(-10*((x[1]-.1)^2+(x[2]-.5)^2));
> g:=x->[0,0,0,0];
> Type_Dirichlet:=[false,false,false,false];
> phi0:=x->0;
> M:=x->matrix(2,2,[1,0,0,1]);
> u:=x->[0,0];
> a0:=x->.8;
> a1:=x->[0,0,0,0];
Input
> N:=5;
> Bandwidth:=2*N+1;
> e:=10000;
Grid generation
We want the grid to look like a concert hall, so the domain [0,1]x[0,1] is transformed.
> Square_Grid(N);
> Trans:=x->[x[1],piecewise(x[1]<=.2,x[2],x[1]<=.8,(.8+x[1])*x[2]+(x[1]-.2),(2.4-x[1])*x[2]+x[1]-.2)];
> VT:=[seq(Trans(Vertices[i]),i=1..Number_of_Vertices)]:
> Vertices:=Array(1..Number_of_Vertices,1..2,VT,datatype=float,readonly);
> Gridplot();
> Generate_Hatfunctions();
Calculation
> Convert_Data_Interior(M,u,a0,f);
> Convert_Data_Boundary(Type_Dirichlet,phi0,a1,g);
> Linear_System(Type_Dirichlet,Bandwidth,e);
> Phi:=convert(LinearAlgebra[LinearSolve](Matrix_A,Vector_F),list);
Plotting
> phi_h:=x->sum(Phi[k]*Hatfunctions[k](x),k=1..Number_of_Vertices);
> plot3d(phi_h(x),x[1]=0..1,x[2]=0..(2.2));
>