Reputation: 937
EDIT: See solution in the full code, following @bgb2's comment.
I'm currently trying to code a Finite Element Analysis to solve a 2D heat conduction problem. For now I'm looking at the steady state system:
where k is the thermal conductivity of the material.
Here is my code. I have verified that the stiffness matrix is correct, so I really think I'm doing something wrong when assigning the boundary conditions before solving for temperature.
Here is my commented code:
%% Input Geometry
% Local node geometry
% 4____3
% | |
% | |
% 1____2
% Global geometry
% 2____3____6(T=10)
% | | |
% | | |
% 1____4____5
% (T=3.5)
% Node 1 is at 3.5 degrees, and node 6 at 10 degrees.
% node global coordinates
node = [ 0 0 ;
0 0.05;
0.05 0.05;
0.05 0 ;
.1 0 ;
.1 0.05];
% element connections, row=element, col=nodes
conn = [1, 4, 3, 2;
4, 5, 6, 3];
%% Material Inputs
k_r = 1.4;
%% Boundary Conditions
T = zeros(6,1);
T(1) = 3.5; % node 1 fixed at 3.5 degrees
T(6) = 10; % node 6 fixed at 10 degrees
isol = [ 2, 3, 4, 5]; % unconstrained dofs,
%% Integration inputs
% Gauss Quadrature Points and weights for 2D quadrilateral elements
% local coordinates
GQ_coord = [-sqrt(1/3) -sqrt(1/3);
sqrt(1/3) -sqrt(1/3);
-sqrt(1/3) sqrt(1/3);
sqrt(1/3) sqrt(1/3)];
% GQ weights
GQ_w = [1 1 1 1];
%% SOLVER
nn = size(node,1); % number of nodes
ndof = nn; % number of dofs in the problem
ne = size(conn,1); % number of elements
K = zeros(ndof, ndof); %global stiffness matrix
f = zeros(ndof,1); % Heat flux vector
for e = 1:ne
n1 = conn(e, 1); % node id for first node in element e
n2 = conn(e, 2); % node id for second node in element e
n3 = conn(e, 3); % node id for first node in element e
n4 = conn(e, 4); % node id for second node in element e
x1 = node(n1,1); y1 = node(n1,2); % x and y coordinates for the 1st node
x2 = node(n2,1); y2 = node(n2,2); % x and y coordinates for the 2nd node
x3 = node(n3,1); y3 = node(n3,2); % x and y coordinates for the 3rd node
x4 = node(n4,1); y4 = node(n4,2); % x and y coordinates for the 4th node
global_coord = [x1, y1; x2, y2; x3 y3; x4 y4];
%Compute Stiffness of element e
ke = Ke(global_coord, GQ_coord, GQ_w, Vx, Vy, k_r)
% locations where ke is to scatter to in the global stiffness matrix
sctr = [ n1, n2 , n3, n4];
%Add ke into global K
K(sctr,sctr) = K(sctr,sctr) + ke;
end
% Accounting for boundary conditions
EDIT following @bg2b's comment
f(2) = -K(1,2) * T(1);
f(3) = -K(6,3) * T(6) + -K(1,3) * T(1);
f(4) = -K(1,4) * T(1) + -K(6,4) * T(6);
f(5) = -K(6,5) * T(6);
% computing temperature
T(isol) = K(isol,isol)\f(isol);
%% FUNCTIONS
% Shape function
% takes local coord
function s = S(ni, coord)
switch ni
case 1
s = 1/4 * (1-coord(1)) * (1-coord(2));
case 4
s = 1/4 * (1+coord(1)) * (1-coord(2));
case 3
s = 1/4 * (1+coord(1)) * (1+coord(2));
case 2
s = 1/4 * (1-coord(1)) * (1+coord(2));
end
end
% Shape function derivative
% takes local coord as an [eta nu] pair
function ds = dS(ni, dim, coord)
switch ni
case 1
if dim == 1
ds = 1/4 * (coord(2)-1);
else
ds = 1/4 * (coord(1)-1);
end
case 4
if dim == 1
ds = 1/4 * (-coord(2)-1);
else
ds = 1/4 * (1-coord(1));
end
case 3
if dim == 1
ds = 1/4 * (coord(2) + 1);
else
ds = 1/4 * (coord(1) + 1);
end
case 2
if dim == 1
ds = 1/4 * (1-coord(2));
else
ds = 1/4 * (-coord(1)-1);
end
end
end
% Computation of the element's Jacobian
function J = Je(global_coord, GQ_coord)
S = [dS(1,1, GQ_coord(1,:)) dS(2,1, GQ_coord(1,:)) dS(3,1, GQ_coord(1,:)) dS(4,1, GQ_coord(1,:));
dS(1,2, GQ_coord(1,:)) dS(2,2, GQ_coord(1,:)) dS(3,2, GQ_coord(1,:)) dS(4,2, GQ_coord(1,:))];
J = S * global_coord;
end
% Computation of the element stifness matrix
function ke = Ke(global_coord, GQ_coord, GQ_w, Vx, Vy, k_r)
J = Je(global_coord, GQ_coord)
ke = zeros(4,4);
Jinv = inv(J);
for i = 1:4
for j = 1:4
ke(i,j) = 0;
for n = 1:4
A = (Jinv(1,1) * dS(i,1, GQ_coord(n,:)) + Jinv(1,2) * dS(i,2, GQ_coord(n,:)));
B = (Jinv(1,1) * dS(j,1, GQ_coord(n,:)) + Jinv(1,2) * dS(j,2, GQ_coord(n,:)));
C = (Jinv(2,1) * dS(i,1, GQ_coord(n,:)) + Jinv(2,2) * dS(i,2, GQ_coord(n,:)));
D = (Jinv(2,1) * dS(j,1, GQ_coord(n,:)) + Jinv(2,2) * dS(j,2, GQ_coord(n,:)));
ke(i,j) = ke(i,j) + k_r * (A*B + C*D) * det(J)*GQ_w(i)*GQ_w(j);
end
end
end
end
To save having to put the code for the stiffness matrix here it is:
K =[ 0.9333 -0.2333 -0.4667 -0.2333 0 0;
-0.2333 0.9333 -0.2333 -0.4667 0 0;
-0.4667 -0.2333 1.8667 -0.4667 -0.4667 -0.2333;
-0.2333 -0.4667 -0.4667 1.8667 -0.2333 -0.4667;
0 0 -0.4667 -0.2333 0.9333 -0.2333;
0 0 -0.2333 -0.4667 -0.2333 0.9333]
So here is the cut down test code for you:
%% Input Geometry
% Local node geometry
% 4____3
% | |
% | |
% 1____2
% Global geometry
% 2____3____6(T=10)
% | | |
% | | |
% 1____4____5
% (T=3.5)
% Node 1 is at 3.5 degrees, and node 6 at 10 degrees.
%% Boundary Conditions
T = zeros(6,1);
T(1) = 3.5; % node 1 fixed at 3.5 degrees
T(6) = 10; % node 6 fixed at 10 degrees
isol = [ 2, 3, 4, 5]; % unconstrained dofs
f = zeros(ndof,1); % Heat flux vector
%global stiffness matrix
K =[ 0.9333 -0.2333 -0.4667 -0.2333 0 0;
-0.2333 0.9333 -0.2333 -0.4667 0 0;
-0.4667 -0.2333 1.8667 -0.4667 -0.4667 -0.2333;
-0.2333 -0.4667 -0.4667 1.8667 -0.2333 -0.4667;
0 0 -0.4667 -0.2333 0.9333 -0.2333;
0 0 -0.2333 -0.4667 -0.2333 0.9333]
% Accounting for boundary conditions
% I THINK THAT'S WHERE I'M GOING WRONG
f(2) = K(2,1) * T(1); % Heat outflow
f(5) = -K(5,6) * T(6); % Heat inflow
% computing temperature
T(isol) = K(isol,isol)\f(isol);
Here is what I obtain, x is the global node index, y is the temperature.
Because the only place for heat to leave the system is node 1 (as far as I can tell) I wouldn't expect to see temperature values below 3.5 degrees.
PS: I know Matlab has a FEM toolbox, but this is really a learning exercise I've set myself.
PS 2: Feel free to leave answers in Python as I am familiar with that language as well
Upvotes: 0
Views: 228