├── sample ├── neumann.dat ├── elements3.dat ├── dirichlet.dat ├── elements4.dat ├── coordinates.dat ├── u_d.m ├── f.m └── g.m ├── src ├── stima3.m ├── stima4.m ├── show.m ├── heat.m └── fem_50.m ├── square ├── u_d.m ├── g.m ├── f.m └── square.m ├── Gamma ├── f.m ├── u_d.m └── Gamma.m ├── sinusoid ├── dirichlet.dat ├── u_d.m ├── g.m ├── f.m ├── coordinates.dat └── elements3.dat └── README.md /sample/neumann.dat: -------------------------------------------------------------------------------- 1 | 5 6 2 | 6 7 3 | 1 2 4 | 2 3 5 | -------------------------------------------------------------------------------- /sample/elements3.dat: -------------------------------------------------------------------------------- 1 | 2 3 13 2 | 3 4 13 3 | 4 5 15 4 | 5 6 15 5 | -------------------------------------------------------------------------------- /sample/dirichlet.dat: -------------------------------------------------------------------------------- 1 | 3 4 2 | 4 5 3 | 7 8 4 | 8 9 5 | 9 10 6 | 10 11 7 | 11 12 8 | 12 1 9 | -------------------------------------------------------------------------------- /sample/elements4.dat: -------------------------------------------------------------------------------- 1 | 1 2 13 12 2 | 12 13 14 11 3 | 13 4 15 14 4 | 11 14 9 10 5 | 14 15 8 9 6 | 15 6 7 8 7 | -------------------------------------------------------------------------------- /src/stima3.m: -------------------------------------------------------------------------------- 1 | function M = stima3 ( vertices ) 2 | 3 | d = size ( vertices, 2 ); 4 | 5 | G = [ ones(1,d+1); vertices' ] \ [ zeros(1,d); eye(d) ]; 6 | 7 | M = det ( [ ones(1,d+1); vertices' ] ) * G * G' / prod ( 1:d ); 8 | 9 | end 10 | -------------------------------------------------------------------------------- /sample/coordinates.dat: -------------------------------------------------------------------------------- 1 | 0.00 0.00 2 | 1.00 0.00 3 | 1.59 0.00 4 | 2.00 1.00 5 | 3.00 1.41 6 | 3.00 2.00 7 | 3.00 3.00 8 | 2.00 3.00 9 | 1.00 3.00 10 | 0.00 3.00 11 | 0.00 2.00 12 | 0.00 1.00 13 | 1.00 1.00 14 | 1.00 2.00 15 | 2.00 2.00 16 | -------------------------------------------------------------------------------- /src/stima4.m: -------------------------------------------------------------------------------- 1 | function M = stima4 ( vertices ) 2 | 3 | D_Phi = [ vertices(2,:) - vertices(1,:); vertices(4,:) - vertices(1,:) ]'; 4 | 5 | B = inv ( D_Phi' * D_Phi ); 6 | 7 | C1 = [ 2, -2; -2, 2 ] * B(1,1) ... 8 | + [ 3, 0; 0, -3 ] * B(1,2) ... 9 | + [ 2, 1; 1, 2 ] * B(2,2); 10 | 11 | C2 = [ -1, 1; 1, -1 ] * B(1,1) ... 12 | + [ -3, 0; 0, 3 ] * B(1,2) ... 13 | + [ -1, -2; -2, -1 ] * B(2,2); 14 | 15 | M = det ( D_Phi ) * [ C1 C2; C2 C1 ] / 6; 16 | end 17 | -------------------------------------------------------------------------------- /square/u_d.m: -------------------------------------------------------------------------------- 1 | function value = u_d ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% U_D evaluates the Dirichlet boundary conditions. 6 | % 7 | % Discussion: 8 | % 9 | % The user must supply the appropriate routine for a given problem 10 | % 11 | % Parameters: 12 | % 13 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 14 | % 15 | % Output, VALUE(N), contains the value of the Dirichlet boundary 16 | % condition at each point. 17 | % 18 | value = zeros ( size ( u, 1 ), 1 ); 19 | 20 | end 21 | -------------------------------------------------------------------------------- /sample/u_d.m: -------------------------------------------------------------------------------- 1 | function value = u_d ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% U_D evaluates the Dirichlet boundary conditions. 6 | % 7 | % Discussion: 8 | % 9 | % The user must supply the appropriate routine for a given problem 10 | % 11 | % Parameters: 12 | % 13 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 14 | % 15 | % Output, VALUE(N), contains the value of the Dirichlet boundary 16 | % condition at each point. 17 | % 18 | value = zeros ( size ( u, 1 ), 1 ); 19 | 20 | end 21 | 22 | -------------------------------------------------------------------------------- /sample/f.m: -------------------------------------------------------------------------------- 1 | function value = f ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% F evaluates the right hand side of Laplace's equation. 6 | % 7 | % Discussion: 8 | % 9 | % This routine must be changed by the user to reflect a particular problem. 10 | % 11 | % Parameters: 12 | % 13 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 14 | % 15 | % Output, VALUE(N), contains the value of the right hand side of Laplace's 16 | % equation at each of the points. 17 | % 18 | value = ones ( size ( u, 1 ), 1 ); 19 | 20 | end 21 | -------------------------------------------------------------------------------- /Gamma/f.m: -------------------------------------------------------------------------------- 1 | function value = f ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% F evaluates the right hand side of Laplace's equation. 6 | % 7 | % Discussion: 8 | % 9 | % This routine must be changed by the user to reflect a particular problem. 10 | % 11 | % Parameters: 12 | % 13 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 14 | % 15 | % Output, VALUE(N), contains the value of the right hand side of Laplace's 16 | % equation at each of the points. 17 | % 18 | n = size ( u, 1 ); 19 | 20 | value(1:n) = 0; 21 | end 22 | -------------------------------------------------------------------------------- /sinusoid/dirichlet.dat: -------------------------------------------------------------------------------- 1 | 1 2 2 | 2 3 3 | 3 4 4 | 4 5 5 | 5 6 6 | 6 7 7 | 7 8 8 | 8 9 9 | 9 10 10 | 10 11 11 | 11 12 12 | 12 13 13 | 13 26 14 | 26 39 15 | 39 52 16 | 52 65 17 | 65 78 18 | 78 91 19 | 91 104 20 | 104 117 21 | 117 130 22 | 130 143 23 | 143 156 24 | 156 169 25 | 169 168 26 | 168 167 27 | 167 166 28 | 166 165 29 | 165 164 30 | 164 163 31 | 163 162 32 | 162 161 33 | 161 160 34 | 160 159 35 | 159 158 36 | 158 157 37 | 157 144 38 | 144 131 39 | 131 118 40 | 118 105 41 | 105 92 42 | 92 79 43 | 79 66 44 | 66 53 45 | 53 40 46 | 40 27 47 | 27 14 48 | 14 1 49 | -------------------------------------------------------------------------------- /sample/g.m: -------------------------------------------------------------------------------- 1 | function value = g ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% G evaluates the outward normal values assigned at Neumann boundary conditions. 6 | % 7 | % Discussion: 8 | % 9 | % This routine must be changed by the user to reflect a particular problem. 10 | % 11 | % Parameters: 12 | % 13 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 14 | % 15 | % Output, VALUE(N), contains the value of outward normal at each point 16 | % where a Neumann boundary condition is applied. 17 | % 18 | value = zeros ( size ( u, 1 ), 1 ); 19 | 20 | end 21 | -------------------------------------------------------------------------------- /square/g.m: -------------------------------------------------------------------------------- 1 | function value = g ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% G evaluates the outward normal values assigned at Neumann boundary conditions. 6 | % 7 | % Discussion: 8 | % 9 | % This routine must be changed by the user to reflect a particular problem. 10 | % 11 | % Parameters: 12 | % 13 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 14 | % 15 | % Output, VALUE(N), contains the value of outward normal at each point 16 | % where a Neumann boundary condition is applied. 17 | % 18 | value = zeros ( size ( u, 1 ), 1 ); 19 | 20 | end 21 | -------------------------------------------------------------------------------- /sinusoid/u_d.m: -------------------------------------------------------------------------------- 1 | function value = u_d ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% U_D evaluates the Dirichlet boundary conditions. 6 | % 7 | % Discussion: 8 | % 9 | % The user must supply the appropriate routine for a given problem 10 | % 11 | % Modified: 12 | % 13 | % 25 February 2004 14 | % 15 | % Parameters: 16 | % 17 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 18 | % 19 | % Output, VALUE(N), contains the value of the Dirichlet boundary 20 | % condition at each point. 21 | % 22 | value = zeros ( size ( u, 1 ), 1 ); 23 | 24 | return 25 | end 26 | -------------------------------------------------------------------------------- /square/f.m: -------------------------------------------------------------------------------- 1 | function value = f ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% F evaluates the right hand side of Laplace's equation. 6 | % 7 | % Discussion: 8 | % 9 | % This routine must be changed by the user to reflect a particular problem. 10 | % 11 | % Parameters: 12 | % 13 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 14 | % 15 | % Output, VALUE(N), contains the value of the right hand side of Laplace's 16 | % equation at each of the points. 17 | % 18 | n = size ( u, 1 ); 19 | 20 | value(1:n) = 2.0 * pi * pi * sin ( pi * u(1:n,1) ) .* sin ( pi * u(1:n,2) ); 21 | end 22 | -------------------------------------------------------------------------------- /sinusoid/g.m: -------------------------------------------------------------------------------- 1 | function value = g ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% G evaluates the outward normal values assigned at Neumann boundary conditions. 6 | % 7 | % Discussion: 8 | % 9 | % This routine must be changed by the user to reflect a particular problem. 10 | % 11 | % Modified: 12 | % 13 | % 25 February 2004 14 | % 15 | % Parameters: 16 | % 17 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 18 | % 19 | % Output, VALUE(N), contains the value of outward normal at each point 20 | % where a Neumann boundary condition is applied. 21 | % 22 | value = zeros ( size ( u, 1 ), 1 ); 23 | 24 | return 25 | end 26 | -------------------------------------------------------------------------------- /Gamma/u_d.m: -------------------------------------------------------------------------------- 1 | function value = u_d ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% U_D evaluates the Dirichlet boundary conditions. 6 | % 7 | % Discussion: 8 | % 9 | % The user must supply the appropriate routine for a given problem 10 | % 11 | % Parameters: 12 | % 13 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 14 | % 15 | % Output, VALUE(N), contains the value of the Dirichlet boundary 16 | % condition at each point. 17 | % 18 | x = u(:,1); 19 | y = u(:,2); 20 | theta = atan2(y, x); 21 | j = find(theta < 0); 22 | theta(j) = theta(j) + 2*pi; 23 | r = sqrt(x.^2 + y.^2); 24 | value = r.^(2.0/3.0) .* sin(2.0*theta/3.0); 25 | 26 | end 27 | -------------------------------------------------------------------------------- /sinusoid/f.m: -------------------------------------------------------------------------------- 1 | function value = f ( u ) 2 | 3 | %*****************************************************************************80 4 | % 5 | %% F evaluates the right hand side of Laplace's equation. 6 | % 7 | % Discussion: 8 | % 9 | % This routine must be changed by the user to reflect a particular problem. 10 | % 11 | % Modified: 12 | % 13 | % 25 February 2004 14 | % 15 | % Parameters: 16 | % 17 | % Input, real U(N,M), contains the M-dimensional coordinates of N points. 18 | % 19 | % Output, VALUE(N), contains the value of the right hand side of Laplace's 20 | % equation at each of the points. 21 | % 22 | n = size ( u, 1 ); 23 | 24 | value(1:n) = 2.0 * pi * pi * sin ( pi * u(1:n,1) ) .* sin ( pi * u(1:n,2) ); 25 | 26 | return 27 | end 28 | -------------------------------------------------------------------------------- /src/show.m: -------------------------------------------------------------------------------- 1 | function show ( elements3, elements4, coordinates, u ) 2 | % 3 | % Parameters: 4 | % 5 | % Input, integer ELEMENTS3(N3,3), the nodes that make up each triangle. 6 | % 7 | % Input, integer ELEMENTS4(N4,4), the nodes that make up each quadrilateral. 8 | % 9 | % Input, real COORDINATES(N,1:2), the coordinates of each node. 10 | % 11 | % Input, real U(N), the finite element coefficients which represent the solution. 12 | % There is one coefficient associated with each node. 13 | % 14 | hold off 15 | % 16 | % Display the information associated with triangular elements. 17 | % 18 | trisurf ( elements3, coordinates(:,1), coordinates(:,2), u' ); 19 | % 20 | % Retain the previous image, 21 | % and overlay the information associated with quadrilateral elements. 22 | % 23 | hold on 24 | trisurf ( elements4, coordinates(:,1), coordinates(:,2), u', ... 25 | 'EdgeColor', 'interp', 'FaceColor', 'interp' ); 26 | % 27 | % Define the initial viewing angle. 28 | % 29 | view ( -67.5, 30 ); 30 | 31 | title ( 'Solution to the Problem' ) 32 | 33 | % if isempty(elements4) 34 | % figure(2) 35 | % pdecont(coordinates', elements3', u); 36 | % end 37 | end 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2-D FEM code in Matlab 2 | 3 | This is a matlab code for solving poisson equation by FEM on 2-d domains. It is taken from 4 | 5 | **Alberty, Carstensen, Funken: Remarks around 50 lines of Matlab: short finite element implementation** 6 | 7 | * http://link.springer.com/article/10.1023/A:1019155918070 8 | * https://www.math.hu-berlin.de/~cc/cc_homepage/download/1999-AJ_CC_FS-50_Lines_of_Matlab.pdf 9 | 10 | ## Examples 11 | 12 | * sample : This contains the example grid from the paper 13 | * Gamma : Generate grid by running Gamma.m in matlab 14 | * sinusoid : 15 | * square : Generate grid by running square.m in matlab 16 | 17 | ## How to run code in "square" 18 | 19 | ```shell 20 | bash> cd square 21 | ``` 22 | 23 | Start matlab 24 | 25 | ```shell 26 | bash> matlab 27 | ``` 28 | 29 | In matlab, generate mesh 30 | 31 | ```matlab 32 | >> square(30) 33 | >> close all 34 | >> clear all 35 | ``` 36 | 37 | Add path to fem code and run it 38 | 39 | ```matlab 40 | >> addpath(path,'../src') 41 | >> fem_50() 42 | ``` 43 | 44 | ## Running on matlab drive 45 | 46 | Download code 47 | 48 | ```matlab 49 | unzip('https://github.com/cpraveen/fem50/archive/master.zip') 50 | movefile('fem50-master', 'fem50'), addpath(fullfile(cd,'fem50/src')), savepath 51 | ``` 52 | 53 | Run it 54 | 55 | ```matlab 56 | square(30) 57 | fem_50() 58 | ``` 59 | 60 | ## You can avoid matlab 61 | 62 | There is no reason to use matlab which is not a free software. You have better options in Python and Julia. For similar codes as this, see 63 | 64 | 1. Python: https://github.com/cpraveen/fem/tree/master/python/2d 65 | 1. Julia: https://github.com/cpraveen/juliafem 66 | -------------------------------------------------------------------------------- /square/square.m: -------------------------------------------------------------------------------- 1 | function square(n) 2 | 3 | xmin=0;xmax=1; 4 | ymin=0;ymax=1; 5 | nx=n; 6 | ny=n; 7 | x=linspace(xmin,xmax,nx); 8 | y=linspace(ymin,ymax,ny); 9 | c=1; 10 | X=zeros(nx*ny,1); 11 | Y=zeros(nx*ny,1); 12 | for j=1:nx 13 | for k=1:ny 14 | X(c) = x(j); 15 | Y(c) = y(k); 16 | c = c + 1; 17 | end 18 | end 19 | 20 | tri=DelaunayTri([X,Y]); 21 | triplot(tri) 22 | e=tri.edges; % all edges 23 | eb=tri.freeBoundary; % boundary edges 24 | 25 | np = length(X); % no of vertices 26 | nt = size(tri,1); % no of triangles 27 | fprintf(1,'Number of points = %d\n', np); 28 | fprintf(1,'Number of triangles = %d\n', nt); 29 | 30 | n_e = size(e ,1); % no of all edges 31 | n_eb = size(eb,1); % no of boundary edges 32 | 33 | % find neighbouring cell of boundary edges 34 | for j=1:n_eb 35 | nbr = tri.edgeAttachments(eb(j,:)); 36 | nbr = nbr{:}; 37 | dx = X(eb(j,2)) - X(eb(j,1)); 38 | dy = Y(eb(j,2)) - Y(eb(j,1)); 39 | % order vertices so that domain is to left side 40 | v = tri.Triangulation(nbr(1),:); 41 | dx1= sum(X(v))/3 - X(eb(j,1)); 42 | dy1= sum(Y(v))/3 - Y(eb(j,1)); 43 | if(dx1*dy - dx*dy1 > 0) 44 | tmp = eb(j,:); 45 | eb(j,1) = tmp(2); 46 | eb(j,2) = tmp(1); 47 | end 48 | end 49 | 50 | fid=fopen('coordinates.dat','w'); 51 | fprintf(fid,'%24.14e %24.14e\n', tri.X'); 52 | fclose(fid); 53 | 54 | fid=fopen('elements3.dat','w'); 55 | fprintf(fid,'%8d %8d %8d\n', tri.Triangulation'); 56 | fclose(fid); 57 | 58 | fid=fopen('dirichlet.dat','w'); 59 | fprintf(fid,'%8d %8d\n', eb); 60 | fclose(fid); 61 | 62 | %fid=fopen('neumann.dat','w'); 63 | %fprintf(fid,'%8d %8d\n', eb); 64 | %fclose(fid); 65 | -------------------------------------------------------------------------------- /src/heat.m: -------------------------------------------------------------------------------- 1 | function heat ( ) 2 | % 3 | % Read the nodal coordinate data file. 4 | % 5 | load coordinates.dat; 6 | % 7 | % Read the triangular element data file. 8 | % 9 | eval ( 'load elements3.dat;', 'elements3=[];' ); 10 | % 11 | % Read the quadrilateral element data file. 12 | % 13 | eval ( 'load elements4.dat;', 'elements4=[];' ); 14 | % 15 | % Read the Neumann boundary condition data file. 16 | % I THINK the purpose of the EVAL command is to create an empty NEUMANN array 17 | % if no Neumann file is found. 18 | % 19 | eval ( 'load neumann.dat;', 'neumann=[];' ); 20 | % 21 | % Read the Dirichlet boundary condition data file. 22 | % 23 | eval ( 'load dirichlet.dat;', 'dirichlet=[];' ); 24 | 25 | A = sparse ( size(coordinates,1), size(coordinates,1) ); 26 | b = sparse ( size(coordinates,1), 1 ); 27 | % 28 | % Assembly. 29 | % 30 | for j = 1 : size(elements3,1) 31 | A(elements3(j,:),elements3(j,:)) = A(elements3(j,:),elements3(j,:)) ... 32 | + stima3(coordinates(elements3(j,:),:)); 33 | end 34 | 35 | for j = 1 : size(elements4,1) 36 | A(elements4(j,:),elements4(j,:)) = A(elements4(j,:),elements4(j,:)) ... 37 | + stima4(coordinates(elements4(j,:),:)); 38 | end 39 | % 40 | % Volume Forces. 41 | % 42 | for j = 1 : size(elements3,1) 43 | b(elements3(j,:)) = b(elements3(j,:)) ... 44 | + det( [1,1,1; coordinates(elements3(j,:),:)'] ) * ... 45 | f(sum(coordinates(elements3(j,:),:))/3)/6; 46 | end 47 | 48 | for j = 1 : size(elements4,1) 49 | b(elements4(j,:)) = b(elements4(j,:)) ... 50 | + det([1,1,1; coordinates(elements4(j,1:3),:)'] ) * ... 51 | f(sum(coordinates(elements4(j,:),:))/4)/4; 52 | end 53 | % 54 | % Neumann conditions. 55 | % 56 | if ( ~isempty(neumann) ) 57 | for j = 1 : size(neumann,1) 58 | b(neumann(j,:)) = b(neumann(j,:)) + ... 59 | norm(coordinates(neumann(j,1),:) - coordinates(neumann(j,2),:)) * ... 60 | g(sum(coordinates(neumann(j,:),:))/2)/2; 61 | end 62 | end 63 | % 64 | % Determine which nodes are associated with Dirichlet conditions. 65 | % Assign the corresponding entries of U, and adjust the right hand side. 66 | % 67 | u = sparse ( size(coordinates,1), 1 ); 68 | BoundNodes = unique ( dirichlet ); 69 | u(BoundNodes) = u_d ( coordinates(BoundNodes,:) ); 70 | b = b - A * u; 71 | % 72 | % Compute the solution by solving A * U = B for the remaining unknown values of U. 73 | % 74 | FreeNodes = setdiff ( 1:size(coordinates,1), BoundNodes ); 75 | 76 | u(FreeNodes) = A(FreeNodes,FreeNodes) \ b(FreeNodes); 77 | % 78 | % Graphic representation. 79 | % 80 | show ( elements3, elements4, coordinates, full ( u ) ); 81 | 82 | end 83 | -------------------------------------------------------------------------------- /Gamma/Gamma.m: -------------------------------------------------------------------------------- 1 | function Gamma(n) 2 | 3 | X=zeros(n*(2*n-1)+(n-1)*n,1); 4 | Y=zeros(n*(2*n-1)+(n-1)*n,1); 5 | 6 | c=1; 7 | 8 | %------------------------------------------------------------------------------ 9 | % Create boundary edges 10 | %------------------------------------------------------------------------------ 11 | x=linspace(-1,0,n); 12 | for j=1:n 13 | X(c) = x(j); 14 | Y(c) = -1; 15 | c = c + 1; 16 | end 17 | 18 | y=linspace(-1,0,n); 19 | for j=2:n 20 | X(c) = 0; 21 | Y(c) = y(j); 22 | c = c + 1; 23 | end 24 | 25 | x=linspace(0,1,n); 26 | for j=2:n 27 | X(c) = x(j); 28 | Y(c) = 0; 29 | c = c + 1; 30 | end 31 | 32 | y=linspace(0,1,n); 33 | for j=2:n 34 | X(c) = 1; 35 | Y(c) = y(j); 36 | c = c + 1; 37 | end 38 | 39 | x=linspace(1,-1,2*n-1); 40 | for j=2:2*n-1 41 | X(c) = x(j); 42 | Y(c) = 1; 43 | c = c + 1; 44 | end 45 | 46 | y=linspace(1,-1,2*n-1); 47 | for j=2:2*n-2 48 | X(c) = -1; 49 | Y(c) = y(j); 50 | c = c + 1; 51 | end 52 | 53 | bedge = zeros(c-1, 2); 54 | bedge(:,1) = 1:c-1; 55 | bedge(:,2) = 2:c; 56 | bedge(c-1,2)=1; 57 | 58 | figure(1) 59 | plot(X(bedge(:,1)), Y(bedge(:,1)), 'o-') 60 | %------------------------------------------------------------------------------ 61 | % Generate interior points 62 | %------------------------------------------------------------------------------ 63 | 64 | % generate points inside (-1,0) x (-1,+1) 65 | nx=n; 66 | ny=2*n-1; 67 | x=linspace(-1, 0, nx); 68 | y=linspace(-1, 1, ny); 69 | for j=2:nx-1 70 | for k=2:ny-1 71 | X(c) = x(j); 72 | Y(c) = y(k); 73 | c = c + 1; 74 | end 75 | end 76 | 77 | % generate points inside (0,1) x (0,1) 78 | nx=n; 79 | ny=n; 80 | x=linspace(0,1,nx); 81 | y=linspace(0,1,ny); 82 | for j=1:nx-1 83 | for k=2:ny-1 84 | X(c) = x(j); 85 | Y(c) = y(k); 86 | c = c + 1; 87 | end 88 | end 89 | 90 | tri=DelaunayTri([X,Y], bedge); 91 | 92 | % Plot all triangles 93 | figure(2) 94 | triplot(tri) 95 | 96 | % Triangles inside our domain 97 | figure(3) 98 | inside=inOutStatus(tri); 99 | triplot(tri(inside, :), tri.X(:,1), tri.X(:,2)); 100 | 101 | e=tri.edges; % all edges 102 | eb=tri.freeBoundary; % boundary edges 103 | 104 | np = length(X); % no of vertices 105 | nt = size(tri,1); % no of triangles 106 | fprintf(1,'Number of points = %d\n', np); 107 | fprintf(1,'Number of triangles = %d\n', nt); 108 | 109 | n_e = size(e ,1); % no of all edges 110 | n_eb = size(eb,1); % no of boundary edges 111 | 112 | % find neighbouring cell of boundary edges 113 | for j=1:n_eb 114 | nbr = tri.edgeAttachments(eb(j,:)); 115 | nbr = nbr{:}; 116 | dx = X(eb(j,2)) - X(eb(j,1)); 117 | dy = Y(eb(j,2)) - Y(eb(j,1)); 118 | % order vertices 119 | v = tri.Triangulation(nbr(1),:); 120 | dx1= sum(X(v))/3 - X(eb(j,1)); 121 | dy1= sum(Y(v))/3 - Y(eb(j,1)); 122 | if(dx1*dy - dx*dy1 > 0) 123 | tmp = eb(j,:); 124 | eb(j,1) = tmp(2); 125 | eb(j,2) = tmp(1); 126 | end 127 | end 128 | 129 | fid=fopen('coordinates.dat','w'); 130 | fprintf(fid,'%24.14e %24.14e\n', tri.X'); 131 | fclose(fid); 132 | 133 | fid=fopen('elements3.dat','w'); 134 | fprintf(fid,'%8d %8d %8d\n', (tri(inside,:))'); 135 | fclose(fid); 136 | 137 | fid=fopen('dirichlet.dat','w'); 138 | fprintf(fid,'%8d %8d\n', bedge); 139 | fclose(fid); 140 | -------------------------------------------------------------------------------- /sinusoid/coordinates.dat: -------------------------------------------------------------------------------- 1 | 0.0000 0.0000 2 | 0.0833 0.0000 3 | 0.1667 0.0000 4 | 0.2500 0.0000 5 | 0.3333 0.0000 6 | 0.4167 0.0000 7 | 0.5000 0.0000 8 | 0.5833 0.0000 9 | 0.6667 0.0000 10 | 0.7500 0.0000 11 | 0.8333 0.0000 12 | 0.9167 0.0000 13 | 1.0000 0.0000 14 | 0.0000 0.0833 15 | 0.0833 0.0833 16 | 0.1667 0.0833 17 | 0.2500 0.0833 18 | 0.3333 0.0833 19 | 0.4167 0.0833 20 | 0.5000 0.0833 21 | 0.5833 0.0833 22 | 0.6667 0.0833 23 | 0.7500 0.0833 24 | 0.8333 0.0833 25 | 0.9167 0.0833 26 | 1.0000 0.0833 27 | 0.0000 0.1667 28 | 0.0833 0.1667 29 | 0.1667 0.1667 30 | 0.2500 0.1667 31 | 0.3333 0.1667 32 | 0.4167 0.1667 33 | 0.5000 0.1667 34 | 0.5833 0.1667 35 | 0.6667 0.1667 36 | 0.7500 0.1667 37 | 0.8333 0.1667 38 | 0.9167 0.1667 39 | 1.0000 0.1667 40 | 0.0000 0.2500 41 | 0.0833 0.2500 42 | 0.1667 0.2500 43 | 0.2500 0.2500 44 | 0.3333 0.2500 45 | 0.4167 0.2500 46 | 0.5000 0.2500 47 | 0.5833 0.2500 48 | 0.6667 0.2500 49 | 0.7500 0.2500 50 | 0.8333 0.2500 51 | 0.9167 0.2500 52 | 1.0000 0.2500 53 | 0.0000 0.3333 54 | 0.0833 0.3333 55 | 0.1667 0.3333 56 | 0.2500 0.3333 57 | 0.3333 0.3333 58 | 0.4167 0.3333 59 | 0.5000 0.3333 60 | 0.5833 0.3333 61 | 0.6667 0.3333 62 | 0.7500 0.3333 63 | 0.8333 0.3333 64 | 0.9167 0.3333 65 | 1.0000 0.3333 66 | 0.0000 0.4167 67 | 0.0833 0.4167 68 | 0.1667 0.4167 69 | 0.2500 0.4167 70 | 0.3333 0.4167 71 | 0.4167 0.4167 72 | 0.5000 0.4167 73 | 0.5833 0.4167 74 | 0.6667 0.4167 75 | 0.7500 0.4167 76 | 0.8333 0.4167 77 | 0.9167 0.4167 78 | 1.0000 0.4167 79 | 0.0000 0.5000 80 | 0.0833 0.5000 81 | 0.1667 0.5000 82 | 0.2500 0.5000 83 | 0.3333 0.5000 84 | 0.4167 0.5000 85 | 0.5000 0.5000 86 | 0.5833 0.5000 87 | 0.6667 0.5000 88 | 0.7500 0.5000 89 | 0.8333 0.5000 90 | 0.9167 0.5000 91 | 1.0000 0.5000 92 | 0.0000 0.5833 93 | 0.0833 0.5833 94 | 0.1667 0.5833 95 | 0.2500 0.5833 96 | 0.3333 0.5833 97 | 0.4167 0.5833 98 | 0.5000 0.5833 99 | 0.5833 0.5833 100 | 0.6667 0.5833 101 | 0.7500 0.5833 102 | 0.8333 0.5833 103 | 0.9167 0.5833 104 | 1.0000 0.5833 105 | 0.0000 0.6667 106 | 0.0833 0.6667 107 | 0.1667 0.6667 108 | 0.2500 0.6667 109 | 0.3333 0.6667 110 | 0.4167 0.6667 111 | 0.5000 0.6667 112 | 0.5833 0.6667 113 | 0.6667 0.6667 114 | 0.7500 0.6667 115 | 0.8333 0.6667 116 | 0.9167 0.6667 117 | 1.0000 0.6667 118 | 0.0000 0.7500 119 | 0.0833 0.7500 120 | 0.1667 0.7500 121 | 0.2500 0.7500 122 | 0.3333 0.7500 123 | 0.4167 0.7500 124 | 0.5000 0.7500 125 | 0.5833 0.7500 126 | 0.6667 0.7500 127 | 0.7500 0.7500 128 | 0.8333 0.7500 129 | 0.9167 0.7500 130 | 1.0000 0.7500 131 | 0.0000 0.8333 132 | 0.0833 0.8333 133 | 0.1667 0.8333 134 | 0.2500 0.8333 135 | 0.3333 0.8333 136 | 0.4167 0.8333 137 | 0.5000 0.8333 138 | 0.5833 0.8333 139 | 0.6667 0.8333 140 | 0.7500 0.8333 141 | 0.8333 0.8333 142 | 0.9167 0.8333 143 | 1.0000 0.8333 144 | 0.0000 0.9167 145 | 0.0833 0.9167 146 | 0.1667 0.9167 147 | 0.2500 0.9167 148 | 0.3333 0.9167 149 | 0.4167 0.9167 150 | 0.5000 0.9167 151 | 0.5833 0.9167 152 | 0.6667 0.9167 153 | 0.7500 0.9167 154 | 0.8333 0.9167 155 | 0.9167 0.9167 156 | 1.0000 0.9167 157 | 0.0000 1.0000 158 | 0.0833 1.0000 159 | 0.1667 1.0000 160 | 0.2500 1.0000 161 | 0.3333 1.0000 162 | 0.4167 1.0000 163 | 0.5000 1.0000 164 | 0.5833 1.0000 165 | 0.6667 1.0000 166 | 0.7500 1.0000 167 | 0.8333 1.0000 168 | 0.9167 1.0000 169 | 1.0000 1.0000 170 | -------------------------------------------------------------------------------- /src/fem_50.m: -------------------------------------------------------------------------------- 1 | function fem_50 ( ) 2 | %*****************************************************************************80 3 | % 4 | %% FEM_50 applies the finite element method to Laplace's equation. 5 | % 6 | % Discussion: 7 | % 8 | % FEM_50 is a set of MATLAB routines to apply the finite 9 | % element method to solving Laplace's equation in an arbitrary 10 | % region, using about 50 lines of MATLAB code. 11 | % 12 | % FEM_50 is partly a demonstration, to show how little it 13 | % takes to implement the finite element method (at least using 14 | % every possible MATLAB shortcut.) The user supplies datafiles 15 | % that specify the geometry of the region and its arrangement 16 | % into triangular and quadrilateral elements, and the location 17 | % and type of the boundary conditions, which can be any mixture 18 | % of Neumann and Dirichlet. 19 | % 20 | % The unknown state variable U(x,y) is assumed to satisfy 21 | % Laplace's equation: 22 | % -Uxx(x,y) - Uyy(x,y) = F(x,y) in Omega 23 | % with Dirichlet boundary conditions 24 | % U(x,y) = U_D(x,y) on Gamma_D 25 | % and Neumann boundary conditions on the outward normal derivative: 26 | % Un(x,y) = G(x,y) on Gamma_N 27 | % If Gamma designates the boundary of the region Omega, 28 | % then we presume that 29 | % Gamma = Gamma_D + Gamma_N 30 | % but the user is free to determine which boundary conditions to 31 | % apply. Note, however, that the problem will generally be singular 32 | % unless at least one Dirichlet boundary condition is specified. 33 | % 34 | % The code uses piecewise linear basis functions for triangular elements, 35 | % and piecewise isoparametric bilinear basis functions for quadrilateral 36 | % elements. 37 | % 38 | % The user is required to supply a number of data files and MATLAB 39 | % functions that specify the location of nodes, the grouping of nodes 40 | % into elements, the location and value of boundary conditions, and 41 | % the right hand side function in Laplace's equation. Note that the 42 | % fact that the geometry is completely up to the user means that 43 | % just about any two dimensional region can be handled, with arbitrary 44 | % shape, including holes and islands. 45 | % 46 | % Modified: 47 | % 48 | % 29 March 2004 49 | % 50 | % Author: 51 | % 52 | % Jochen Alberty, Carsten Carstensen, Stefan Funken. 53 | % 54 | % Reference: 55 | % 56 | % Jochen Alberty, Carsten Carstensen, Stefan Funken, 57 | % Remarks Around 50 Lines of MATLAB: 58 | % Short Finite Element Implementation, 59 | % Numerical Algorithms, 60 | % Volume 20, pages 117-137, 1999. 61 | % 62 | clear 63 | tic; 64 | 65 | fprintf ( 1, '\n' ); 66 | fprintf ( 1, 'FEM_50:\n' ); 67 | fprintf ( 1, ' MATLAB version:\n' ); 68 | fprintf ( 1, ' A program to demonstrate the finite element method.\n' ); 69 | % 70 | % Read the nodal coordinate data file. 71 | % 72 | load coordinates.dat; 73 | % 74 | % Read the triangular element data file. 75 | % 76 | eval ( 'load elements3.dat;', 'elements3=[];' ); 77 | % 78 | % Read the quadrilateral element data file. 79 | % 80 | eval ( 'load elements4.dat;', 'elements4=[];' ); 81 | % 82 | % Read the Neumann boundary condition data file. 83 | % I THINK the purpose of the EVAL command is to create an empty NEUMANN array 84 | % if no Neumann file is found. 85 | % 86 | eval ( 'load neumann.dat;', 'neumann=[];' ); 87 | % 88 | % Read the Dirichlet boundary condition data file. 89 | % 90 | eval ( 'load dirichlet.dat;', 'dirichlet=[];' ); 91 | 92 | A = sparse ( size(coordinates,1), size(coordinates,1) ); 93 | b = sparse ( size(coordinates,1), 1 ); 94 | % 95 | % Assembly. 96 | % 97 | for j = 1 : size(elements3,1) 98 | A(elements3(j,:),elements3(j,:)) = A(elements3(j,:),elements3(j,:)) ... 99 | + stima3(coordinates(elements3(j,:),:)); 100 | end 101 | 102 | for j = 1 : size(elements4,1) 103 | A(elements4(j,:),elements4(j,:)) = A(elements4(j,:),elements4(j,:)) ... 104 | + stima4(coordinates(elements4(j,:),:)); 105 | end 106 | % 107 | % Volume Forces. 108 | % 109 | for j = 1 : size(elements3,1) 110 | b(elements3(j,:)) = b(elements3(j,:)) ... 111 | + det( [1,1,1; coordinates(elements3(j,:),:)'] ) * ... 112 | f(sum(coordinates(elements3(j,:),:))/3)/6; 113 | end 114 | 115 | for j = 1 : size(elements4,1) 116 | b(elements4(j,:)) = b(elements4(j,:)) ... 117 | + det([1,1,1; coordinates(elements4(j,1:3),:)'] ) * ... 118 | f(sum(coordinates(elements4(j,:),:))/4)/4; 119 | end 120 | % 121 | % Neumann conditions. 122 | % 123 | if ( ~isempty(neumann) ) 124 | for j = 1 : size(neumann,1) 125 | b(neumann(j,:)) = b(neumann(j,:)) + ... 126 | norm(coordinates(neumann(j,1),:) - coordinates(neumann(j,2),:)) * ... 127 | g(sum(coordinates(neumann(j,:),:))/2)/2; 128 | end 129 | end 130 | % 131 | % Determine which nodes are associated with Dirichlet conditions. 132 | % Assign the corresponding entries of U, and adjust the right hand side. 133 | % 134 | u = sparse ( size(coordinates,1), 1 ); 135 | BoundNodes = unique ( dirichlet ); 136 | u(BoundNodes) = u_d ( coordinates(BoundNodes,:) ); 137 | b = b - A * u; 138 | % 139 | % Compute the solution by solving A * U = B for the remaining unknown values of U. 140 | % 141 | FreeNodes = setdiff ( 1:size(coordinates,1), BoundNodes ); 142 | 143 | u(FreeNodes) = A(FreeNodes,FreeNodes) \ b(FreeNodes); 144 | % 145 | % Graphic representation. 146 | % 147 | show ( elements3, elements4, coordinates, full ( u ) ); 148 | % 149 | % Terminate. 150 | % 151 | fprintf ( 1, '\n' ); 152 | fprintf ( 1, 'FEM_50:\n' ); 153 | fprintf ( 1, ' Normal end of execution.\n' ); 154 | 155 | fprintf ( 1, '\n' ); 156 | toc; 157 | 158 | end 159 | -------------------------------------------------------------------------------- /sinusoid/elements3.dat: -------------------------------------------------------------------------------- 1 | 1 2 15 2 | 15 14 1 3 | 2 3 16 4 | 16 15 2 5 | 3 4 17 6 | 17 16 3 7 | 4 5 18 8 | 18 17 4 9 | 5 6 19 10 | 19 18 5 11 | 6 7 20 12 | 20 19 6 13 | 7 8 21 14 | 21 20 7 15 | 8 9 22 16 | 22 21 8 17 | 9 10 23 18 | 23 22 9 19 | 10 11 24 20 | 24 23 10 21 | 11 12 25 22 | 25 24 11 23 | 12 13 26 24 | 26 25 12 25 | 14 15 28 26 | 28 27 14 27 | 15 16 29 28 | 29 28 15 29 | 16 17 30 30 | 30 29 16 31 | 17 18 31 32 | 31 30 17 33 | 18 19 32 34 | 32 31 18 35 | 19 20 33 36 | 33 32 19 37 | 20 21 34 38 | 34 33 20 39 | 21 22 35 40 | 35 34 21 41 | 22 23 36 42 | 36 35 22 43 | 23 24 37 44 | 37 36 23 45 | 24 25 38 46 | 38 37 24 47 | 25 26 39 48 | 39 38 25 49 | 27 28 41 50 | 41 40 27 51 | 28 29 42 52 | 42 41 28 53 | 29 30 43 54 | 43 42 29 55 | 30 31 44 56 | 44 43 30 57 | 31 32 45 58 | 45 44 31 59 | 32 33 46 60 | 46 45 32 61 | 33 34 47 62 | 47 46 33 63 | 34 35 48 64 | 48 47 34 65 | 35 36 49 66 | 49 48 35 67 | 36 37 50 68 | 50 49 36 69 | 37 38 51 70 | 51 50 37 71 | 38 39 52 72 | 52 51 38 73 | 40 41 54 74 | 54 53 40 75 | 41 42 55 76 | 55 54 41 77 | 42 43 56 78 | 56 55 42 79 | 43 44 57 80 | 57 56 43 81 | 44 45 58 82 | 58 57 44 83 | 45 46 59 84 | 59 58 45 85 | 46 47 60 86 | 60 59 46 87 | 47 48 61 88 | 61 60 47 89 | 48 49 62 90 | 62 61 48 91 | 49 50 63 92 | 63 62 49 93 | 50 51 64 94 | 64 63 50 95 | 51 52 65 96 | 65 64 51 97 | 53 54 67 98 | 67 66 53 99 | 54 55 68 100 | 68 67 54 101 | 55 56 69 102 | 69 68 55 103 | 56 57 70 104 | 70 69 56 105 | 57 58 71 106 | 71 70 57 107 | 58 59 72 108 | 72 71 58 109 | 59 60 73 110 | 73 72 59 111 | 60 61 74 112 | 74 73 60 113 | 61 62 75 114 | 75 74 61 115 | 62 63 76 116 | 76 75 62 117 | 63 64 77 118 | 77 76 63 119 | 64 65 78 120 | 78 77 64 121 | 66 67 80 122 | 80 79 66 123 | 67 68 81 124 | 81 80 67 125 | 68 69 82 126 | 82 81 68 127 | 69 70 83 128 | 83 82 69 129 | 70 71 84 130 | 84 83 70 131 | 71 72 85 132 | 85 84 71 133 | 72 73 86 134 | 86 85 72 135 | 73 74 87 136 | 87 86 73 137 | 74 75 88 138 | 88 87 74 139 | 75 76 89 140 | 89 88 75 141 | 76 77 90 142 | 90 89 76 143 | 77 78 91 144 | 91 90 77 145 | 79 80 93 146 | 93 92 79 147 | 80 81 94 148 | 94 93 80 149 | 81 82 95 150 | 95 94 81 151 | 82 83 96 152 | 96 95 82 153 | 83 84 97 154 | 97 96 83 155 | 84 85 98 156 | 98 97 84 157 | 85 86 99 158 | 99 98 85 159 | 86 87 100 160 | 100 99 86 161 | 87 88 101 162 | 101 100 87 163 | 88 89 102 164 | 102 101 88 165 | 89 90 103 166 | 103 102 89 167 | 90 91 104 168 | 104 103 90 169 | 92 93 106 170 | 106 105 92 171 | 93 94 107 172 | 107 106 93 173 | 94 95 108 174 | 108 107 94 175 | 95 96 109 176 | 109 108 95 177 | 96 97 110 178 | 110 109 96 179 | 97 98 111 180 | 111 110 97 181 | 98 99 112 182 | 112 111 98 183 | 99 100 113 184 | 113 112 99 185 | 100 101 114 186 | 114 113 100 187 | 101 102 115 188 | 115 114 101 189 | 102 103 116 190 | 116 115 102 191 | 103 104 117 192 | 117 116 103 193 | 105 106 119 194 | 119 118 105 195 | 106 107 120 196 | 120 119 106 197 | 107 108 121 198 | 121 120 107 199 | 108 109 122 200 | 122 121 108 201 | 109 110 123 202 | 123 122 109 203 | 110 111 124 204 | 124 123 110 205 | 111 112 125 206 | 125 124 111 207 | 112 113 126 208 | 126 125 112 209 | 113 114 127 210 | 127 126 113 211 | 114 115 128 212 | 128 127 114 213 | 115 116 129 214 | 129 128 115 215 | 116 117 130 216 | 130 129 116 217 | 118 119 132 218 | 132 131 118 219 | 119 120 133 220 | 133 132 119 221 | 120 121 134 222 | 134 133 120 223 | 121 122 135 224 | 135 134 121 225 | 122 123 136 226 | 136 135 122 227 | 123 124 137 228 | 137 136 123 229 | 124 125 138 230 | 138 137 124 231 | 125 126 139 232 | 139 138 125 233 | 126 127 140 234 | 140 139 126 235 | 127 128 141 236 | 141 140 127 237 | 128 129 142 238 | 142 141 128 239 | 129 130 143 240 | 143 142 129 241 | 131 132 145 242 | 145 144 131 243 | 132 133 146 244 | 146 145 132 245 | 133 134 147 246 | 147 146 133 247 | 134 135 148 248 | 148 147 134 249 | 135 136 149 250 | 149 148 135 251 | 136 137 150 252 | 150 149 136 253 | 137 138 151 254 | 151 150 137 255 | 138 139 152 256 | 152 151 138 257 | 139 140 153 258 | 153 152 139 259 | 140 141 154 260 | 154 153 140 261 | 141 142 155 262 | 155 154 141 263 | 142 143 156 264 | 156 155 142 265 | 144 145 158 266 | 158 157 144 267 | 145 146 159 268 | 159 158 145 269 | 146 147 160 270 | 160 159 146 271 | 147 148 161 272 | 161 160 147 273 | 148 149 162 274 | 162 161 148 275 | 149 150 163 276 | 163 162 149 277 | 150 151 164 278 | 164 163 150 279 | 151 152 165 280 | 165 164 151 281 | 152 153 166 282 | 166 165 152 283 | 153 154 167 284 | 167 166 153 285 | 154 155 168 286 | 168 167 154 287 | 155 156 169 288 | 169 168 155 289 | --------------------------------------------------------------------------------