0% found this document useful (0 votes)
16 views17 pages

For For

The document outlines a finite element analysis (FEA) procedure for a 2D isotropic linear elastic material, detailing the setup of nodal coordinates, elemental connectivity, and the construction of global stiffness and force matrices. It includes the application of Dirichlet boundary conditions and the computation of displacements, stress, and strain at specified time intervals. The results are visualized through contour plots of displacement at two different time points.

Uploaded by

Tarik Nadeem
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views17 pages

For For

The document outlines a finite element analysis (FEA) procedure for a 2D isotropic linear elastic material, detailing the setup of nodal coordinates, elemental connectivity, and the construction of global stiffness and force matrices. It includes the application of Dirichlet boundary conditions and the computation of displacements, stress, and strain at specified time intervals. The results are visualized through contour plots of displacement at two different time points.

Uploaded by

Tarik Nadeem
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

clc;

clear ;

% size of the body


sz_x = 40; % Length L = 40 mm
sz_y = 30; % Height H = 30 mm

% number of elements
nx = 5; % number of elements in x-dir (along L)
ny = 10; % number of elements in y-dir (along H)

% total number of elements


nelem = nx * ny;

% total number of nodes


nnode = (nx + 1) * (ny + 1); % Total nodes = 6 * 11 = 66

nnode_el = 4; % number of nodes in a 2D quadrilateral element (4 nodes)

% dimensions
ndim = 2; % 2D problem

% size of elements
elx = sz_x / nx; % element size in x-dir (L)
ely = sz_y / ny; % element size in y-dir (H)

% setup global nodal coordinate matrix


gcoord = zeros(nnode, ndim);

% Assign global node numbers and coordinates


for j = 1:(ny + 1) % Loop over rows (y-direction)
for i = 1:(nx + 1) % Loop over columns (x-direction)
gnode = (j - 1) * (nx + 1) + i; % Global node number (row-wise)
gcoord(gnode, 1) = (i - 1) * elx; % x-coordinate
gcoord(gnode, 2) = (j - 1) * ely; % y-coordinate
end
end

% setup elemental connectivity matrix


conn = zeros(nelem, nnode_el);

% Loop through elements and assign global node numbers to local nodes
elem = 0;
for j = 1:ny % Loop over elements in y-direction
for i = 1:nx % Loop over elements in x-direction
elem = elem + 1;
bottom_left = (j - 1) * (nx + 1) + i;
conn(elem, :) = [bottom_left, bottom_left + 1, bottom_left + nx + 2,
bottom_left + nx + 1];
end
end

1
% Number of quadrature points
nquad = 4;

% Isoparametric coordinates of quadrature points and weights (2x2 Gauss


quadrature)
iso_coord = [-1/sqrt(3), -1/sqrt(3);
1/sqrt(3), -1/sqrt(3);
1/sqrt(3), 1/sqrt(3);
-1/sqrt(3), 1/sqrt(3)];

wt = [1, 1, 1, 1]; % Weights for all quadrature points

% global stiffness matrix


ndof = nnode * ndim; % total number of degrees of freedom
kk = zeros(ndof, ndof);

% global force vector


ff = zeros(ndof, 1);
ff1 = zeros(ndof, 1);

% Elastic tensor for 2D isotropic linear elastic material


E = 120 * 1e3; % GPa to MPa
nu = 0.33; % Poisson's ratio
lambda = E * nu / ((1 + nu) * (1 - 2 * nu)); % Lamé constant
mu = E / (2 * (1 + nu)); % Shear modulus

% Elasticity tensor (ndim x ndim x ndim x ndim)


elasticity_tensor = zeros(ndim, ndim, ndim, ndim);
for i = 1:ndim
for j = 1:ndim
for k = 1:ndim
for l = 1:ndim
elasticity_tensor(i,j,k,l) = lambda * (i == j) * (k == l) +
mu * ((i == k) * (j == l) + (i == l) * (j == k));
end
end
end
end

% construction of global stiffness matrix and force vector


for elem = 1:nelem
% elemental stiffness matrix
k = zeros(nnode_el * ndim);
f = zeros(nnode_el * ndim, 1);
f1 = zeros(nnode_el * ndim, 1);

% get global node numbers for this element


gnodes = conn(elem, :);

% Loop over quadrature points


for q = 1:nquad
xi_1 = iso_coord(q, 1);

2
xi_2 = iso_coord(q, 2);

% Initialize the Jacobian matrix


jacob = zeros(ndim, ndim);
sh = zeros(nnode_el, 1); % shape functions
shdxi = zeros(nnode_el, ndim); % shape function derivatives

% Define shape functions


for node_el = 1:nnode_el
switch node_el
case 1
sh(node_el) = 0.25 * (1 - xi_1) * (1 - xi_2); % N1
case 2
sh(node_el) = 0.25 * (1 + xi_1) * (1 - xi_2); % N2
case 3
sh(node_el) = 0.25 * (1 + xi_1) * (1 + xi_2); % N3
case 4
sh(node_el) = 0.25 * (1 - xi_1) * (1 + xi_2); % N4
end

% Shape function derivatives w.r.t. xi_1 and xi_2


dN_dxi1 = [-1, 1, 1, -1]; % dN/dxi_1 values for each node
dN_dxi2 = [-1, -1, 1, 1]; % dN/dxi_2 values for each node

shdxi(node_el, 1) = 0.25 * dN_dxi1(node_el); % dN/dxi_1 for


node_el
shdxi(node_el, 2) = 0.25 * dN_dxi2(node_el); % dN/dxi_2 for
node_el
end

% Build the Jacobian matrix


coord = gcoord(gnodes, :);
for i = 1:ndim
for j = 1:ndim
jacob(i, j) = sum(shdxi(:, j) .* coord(:, i));
end
end

% Determinant and inverse of the Jacobian


detjacob = det(jacob);
invjacob = inv(jacob);

% Element stiffness matrix construction


for a_hat = 1:nnode_el
for i = 1:ndim
row = (a_hat - 1) * ndim + i;

for b_hat = 1:nnode_el


for m = 1:ndim % Change loop index from 'k' to 'm'
col = (b_hat - 1) * ndim + m;

for j = 1:ndim
for l = 1:ndim
k(row, col) = k(row, col) +

3
elasticity_tensor(i,j,m,l) * shdxi(a_hat,j) * invjacob(j,l) * shdxi(b_hat,l)
* wt(q) * detjacob;
end
end
end
end
end
end
% Define time instances
time_25 = 25; % t = 25 seconds
time_50 = 50; % t = 50 seconds

% Traction at t = 25 seconds
traction_25 = [0; 1 * time_25]; % 1 MPa/s * 25s = 25 MPa in y-
direction

% Traction at t = 50 seconds
traction_50 = [0; 1 * time_50]; % 1 MPa/s * 50s = 50 MPa in y-
direction

% Element force vector construction for t = 25 seconds


for a_hat = 1:nnode_el
for i = 1:ndim
row = (a_hat - 1) * ndim + i;
f(row) = f(row) + sh(a_hat) * traction_25(i) * wt(q) *
detjacob; % Use traction_25 for t = 25
end
end

% Element force vector construction for t = 50 seconds


for a_hat = 1:nnode_el
for i = 1:ndim
row = (a_hat - 1) * ndim + i;
f1(row) = f1(row) + sh(a_hat) * traction_50(i) * wt(q) *
detjacob; % Use traction_50 for t = 50
end
end
end

% ASSEMBLY - Add local element matrix to global stiffness matrix


for a_hat = 1:nnode_el
for i = 1:ndim
for b_hat = 1:nnode_el
for m = 1:ndim % Change 'k' to 'm' to avoid conflict
a = gnodes(a_hat); % Global node a
b = gnodes(b_hat); % Global node b
row_global = (a - 1) * ndim + i;
col_global = (b - 1) * ndim + m;
kk(row_global, col_global) = kk(row_global, col_global) +
k((a_hat - 1) * ndim + i, (b_hat - 1) * ndim + m);
end
end
end
end

4
% ASSEMBLY - Add local element force vector to global force vector
for a_hat = 1:nnode_el
for i = 1:ndim
a = gnodes(a_hat); % global node a
row_global = (a - 1) * ndim + i;
ff(row_global) = ff(row_global) + f((a_hat - 1) * ndim + i);
end
end

for a_hat = 1:nnode_el


for i = 1:ndim
a = gnodes(a_hat); % global node a
row_global = (a - 1) * ndim + i;
ff1(row_global) = ff1(row_global) + f1((a_hat - 1) * ndim + i);
end
end
end

% Preallocate based on the number of nodes on the bottom boundary


num_bottom_nodes = nx + 1;
dbcdof = zeros(1, num_bottom_nodes); % Preallocate for Dirichlet DOFs
dbcval = zeros(1, num_bottom_nodes); % Preallocate for Dirichlet values

% Apply u_2 = 0 on bottom boundary (y-direction)


for i = 1:num_bottom_nodes
node = i; % Bottom boundary nodes
dbcdof(i) = 2 * node; % y-direction dof for node
dbcval(i) = 0; % y-displacement is zero
end

% Apply u_1 = 0 on bottom-left corner (leftmost node)


dbcdof = [dbcdof, 1]; % x-direction dof for node 1
dbcval = [dbcval, 0]; % x-displacement is zero

% Apply Dirichlet boundary conditions


for i = 1:length(dbcdof)
kk(dbcdof(i), :) = 0; % Set entire row to 0
kk(:, dbcdof(i)) = 0; % Set entire column to 0
kk(dbcdof(i), dbcdof(i)) = 1; % Set diagonal to 1 (fix the DOF)
ff(dbcdof(i)) = dbcval(i); % Apply the Dirichlet value to the force
vector
ff1(dbcdof(i)) = dbcval(i); % Assuming you have another force vector ff1
end

% Solve for displacement at t = 25 seconds


displacement = kk \ ff;
displacement1 = kk \ ff1;
% size(displacement1)

5
% Extract the displacement magnitude for each node
displacement_magnitude = sqrt(displacement(1:2:end).^2 +
displacement(2:2:end).^2);

% Reshape the displacement magnitude for contour plotting


displacement_field = reshape(displacement_magnitude, [nx + 1, ny + 1])'; %
Transpose it for correct orientation

% Plot contour for displacement at t = 25 seconds


figure;
x_vals = reshape(gcoord(:, 1), [nx + 1, ny + 1])'; % Reshape the x-
coordinates
y_vals = reshape(gcoord(:, 2), [nx + 1, ny + 1])'; % Reshape the y-
coordinates
contourf(x_vals, y_vals, displacement_field);
colorbar;
title('Displacement Contour at t = 25 seconds');
xlabel('X (mm)');
ylabel('Y (mm)');

displacement_magnitude1 = sqrt(displacement1(1:2:end).^2 +
displacement1(2:2:end).^2);
displacement_field1 = reshape(displacement_magnitude1, [nx + 1, ny + 1])'; %
Transpose it for correct orientation

% Plot contour for displacement at t = 50 seconds


figure;
x_vals = reshape(gcoord(:, 1), [nx + 1, ny + 1])'; % Reshape the x-
coordinates
y_vals = reshape(gcoord(:, 2), [nx + 1, ny + 1])'; % Reshape the y-
coordinates
contourf(x_vals, y_vals, displacement_field1);
colorbar;
title('Displacement Contour at t = 50 seconds');
xlabel('X (mm)');
ylabel('Y (mm)');

% Post-processing: stress and strain calculation


gstress = zeros(nelem, ndim, ndim); % global stress matrix
gstrain = zeros(nelem, ndim, ndim); % global strain matrix

for elem = 1:nelem


strain_avg = zeros(ndim, ndim);
stress_avg = zeros(ndim, ndim);

% Loop over quadrature points for stress/strain computation


for q = 1:nquad
xi_1 = iso_coord(q, 1);
xi_2 = iso_coord(q, 2);

% Initialize the Jacobian and displacement gradient


jacob = zeros(ndim, ndim);
disp_grad = zeros(ndim, ndim);

6
% Shape functions and their derivatives
for node_el = 1:nnode_el
switch node_el
case 1
sh(node_el) = 0.25 * (1 - xi_1) * (1 - xi_2);
case 2
sh(node_el) = 0.25 * (1 + xi_1) * (1 - xi_2);
case 3
sh(node_el) = 0.25 * (1 + xi_1) * (1 + xi_2);
case 4
sh(node_el) = 0.25 * (1 - xi_1) * (1 + xi_2);
end

% Define shape function derivatives arrays


dN_dxi1 = [-1, 1, 1, -1]; % Derivatives of N w.r.t xi_1
dN_dxi2 = [-1, -1, 1, 1]; % Derivatives of N w.r.t xi_2

shdxi(node_el, 1) = 0.25 * dN_dxi1(node_el); % dN/dxi_1 for


node_el
shdxi(node_el, 2) = 0.25 * dN_dxi2(node_el); % dN/dxi_2 for
node_el
end

% Build the Jacobian and displacement gradient


coord = gcoord(conn(elem, :), :);
for i = 1:ndim
for j = 1:ndim
jacob(i, j) = sum(shdxi(:, j) .* coord(:, i));
end
end

invjacob = inv(jacob);
detjacob = det(jacob);

% Calculate
the displacement gradient
for a_hat =
1:nnode_el
for i =
1:ndim
for
b_hat = 1:nnode_el
for k = 1:ndim
for p = 1:ndim
for j = 1:ndim
disp_grad(i, j) = disp_grad(i, j) +
invjacob(i, p) * shdxi(a_hat, p) * displacement1((conn(elem, a_hat) - 1) *
ndim + k);
end
end
end
end
end
end

% Strain tensor
strain = 0.5 * (disp_grad + disp_grad');

7
% Stress tensor using Hooke's law: sigma = D * epsilon
stress = zeros(ndim, ndim);
for i = 1:ndim
for j = 1:ndim
for k = 1:ndim
for l = 1:ndim
stress(i, j) = stress(i, j) +
elasticity_tensor(i,j,k,l) * strain(k, l);
end
end
end
end

strain_avg = strain_avg + strain;


stress_avg = stress_avg + stress;
end

strain_avg = strain_avg / nquad;


stress_avg = stress_avg / nquad;

gstress(elem, :, :) = stress_avg;
gstrain(elem, :, :) = strain_avg;
end

% Load vector for plotting


load_25 = sum(ff); % Total load at t = 25 seconds
load_50 = sum(ff1); % Total load at t = 50 seconds

% Displacement magnitudes
displacement_magnitude_25 = sqrt(displacement(1:2:end).^2 +
displacement(2:2:end).^2);
displacement_magnitude_50 = sqrt(displacement1(1:2:end).^2 +
displacement1(2:2:end).^2);

% Create vectors for plotting


displacement_vector = [mean(displacement_magnitude_25),
mean(displacement_magnitude_50)];
load_vector = [load_25, load_50];

% Plot Load vs Displacement


figure;
plot(displacement_vector, load_vector, '-o', 'LineWidth', 2);
xlabel('Displacement (mm)');
ylabel('Load (N)');
title('Load vs. Displacement Curve');
grid on;

% Extract stress and strain components


stress_xx = squeeze(gstress(:, 1, 1)); % Sigma_xx
strain_xx = squeeze(gstrain(:, 1, 1)); % Epsilon_xx

8
% Create unique stress and strain values for plotting
unique_stress = unique(stress_xx);
unique_strain = unique(strain_xx);

% Assuming unique_strain and unique_stress are defined earlier in your code


disp(['Size of unique_strain: ', num2str(length(unique_strain))]);
disp(['Size of unique_stress: ', num2str(length(unique_stress))]);

% Adjusting lengths if they are different


if length(unique_strain) ~= length(unique_stress)
minLength = min(length(unique_strain), length(unique_stress));
unique_strain = unique_strain(1:minLength);
unique_stress = unique_stress(1:minLength);
disp('Adjusted lengths to match.');
end

% Now you can plot


% Assuming unique_strain and unique_stress are defined and match in length
plot(unique_strain, unique_stress, '-o', 'LineWidth', 2);

% Add labels with units


xlabel('Strain (dimensionless)'); % or 'Strain (%)' if you are using
percentage
ylabel('Stress (Pa)'); % or 'Stress (MPa)' if using megapascals

% Optional: Add a title and grid for better visualization


title('Stress vs. Strain');
grid on; % Optional, for better visibility

% Extract stress and strain components for Y direction


stress_yy = squeeze(gstress(:, 2, 2)); % Sigma_yy
strain_yy = squeeze(gstrain(:, 2, 2)); % Epsilon_yy

% Create unique stress and strain values for Y direction for plotting
unique_stress_y = unique(stress_yy);
unique_strain_y = unique(strain_yy);

% Display the sizes of the unique stress and strain arrays


disp(['Size of unique_strain_y: ', num2str(length(unique_strain_y))]);
disp(['Size of unique_stress_y: ', num2str(length(unique_stress_y))]);

% Adjust lengths if they are different (just in case)


if length(unique_strain_y) ~= length(unique_stress_y)
minLength_y = min(length(unique_strain_y), length(unique_stress_y));
unique_strain_y = unique_strain_y(1:minLength_y);
unique_stress_y = unique_stress_y(1:minLength_y);
disp('Adjusted lengths for Y direction to match.');
end

% Now plot for the Y direction


plot(unique_strain_y, unique_stress_y, '-o', 'LineWidth', 2);

9
% Add labels and units
xlabel('Strain (_{yy}) (dimensionless)'); % or 'Strain (%)' if you are using
percentage
ylabel('Stress (_{yy}) (Pa)'); % or 'Stress (MPa)' if using
megapascals

% Optional: Add a title and grid for better visualization


title('Stress vs. Strain for Y Direction');
grid on; % Optional, for better visibility

% Calculate the slope of the stress vs. strain curve


dStrain = diff(unique_strain); % Difference in strain
dStress = diff(unique_stress); % Difference in stress

% Calculate slope (stress/strain)


slope = dStress ./ dStrain;

% Calculate the average strain for plotting the slope


average_strain = (unique_strain(1:end-1) + unique_strain(2:end)) / 2;

% Plot the slope


figure; % Create a new figure
plot(average_strain, slope, '-o', 'LineWidth', 2);
xlabel('Strain (dimensionless)'); % Change to 'Strain (%)' if applicable
ylabel('Slope (dStress/dStrain)'); % This represents the modulus of
elasticity
title('Slope of Stress vs. Strain Curve');
grid on;

% Extract stress and strain components


stress_xx = zeros(nelem, 1); % Sigma_xx
stress_yy = zeros(nelem, 1); % Sigma_yy
strain_xx = zeros(nelem, 1); % Epsilon_xx
strain_yy = zeros(nelem, 1); % Epsilon_yy

for elem = 1:nelem


stress_xx(elem) = gstress(elem, 1, 1); % Get the xx component of stress
stress_yy(elem) = gstress(elem, 2, 2); % Get the yy component of stress

strain_xx(elem) = gstrain(elem, 1, 1); % Get the xx component of strain


strain_yy(elem) = gstrain(elem, 2, 2); % Get the yy component of strain
end
size(stress_xx)
% Reshape stress and strain for contour plotting (matches element count)
stress_xx_field = reshape(stress_xx, [ny, nx])'; % Reshape to match number
of elements
stress_yy_field = reshape(stress_yy, [ny, nx])'; % Reshape to match number
of elements
strain_xx_field = reshape(strain_xx, [ny, nx])'; % Reshape to match number
of elements
strain_yy_field = reshape(strain_yy, [ny, nx])'; % Reshape to match number
of elements

10
size(stress_xx_field);

% Create meshgrid for node coordinates (matches [nx+1, ny+1] nodes)


[x_vals, y_vals] = meshgrid(reshape(gcoord(:, 1), [nx+1, ny+1])', ...
reshape(gcoord(:, 2), [nx+1, ny+1])');
size(x_vals);
size(y_vals);

% % Create contour plot for stress (xx component) at t = 50 seconds


% figure;
% subplot(1, 2, 1);
% contourf(x_vals(1:end-1, 1:end-1), y_vals(1:end-1, 1:end-1),
stress_xx_field);
% colorbar;
% title('Stress Contour (Sigma_xx) at t = 50 seconds');
% xlabel('X (mm)');
% ylabel('Y (mm)');
%
% % Create contour plot for strain (xx component) at t = 50 seconds
% subplot(1, 2, 2);
% contourf(x_vals(1:end-1, 1:end-1), y_vals(1:end-1, 1:end-1),
strain_xx_field);
% colorbar;
% title('Strain Contour (Epsilon_xx) at t = 50 seconds');
% xlabel('X (mm)');
% ylabel('Y (mm)');

disp('Displacement vector:');
disp(displacement);
disp('Stress and strain matrices calculated.');

Warning: Matrix is close to singular or badly scaled. Results may be


inaccurate.
RCOND = 6.662469e-18.
Warning: Matrix is close to singular or badly scaled. Results may be
inaccurate.
RCOND = 6.662469e-18.
Size of unique_strain: 38
Size of unique_stress: 47
Adjusted lengths to match.
Size of unique_strain_y: 44
Size of unique_stress_y: 48
Adjusted lengths for Y direction to match.

ans =

50 1

Displacement vector:
0
0
0

11
0
0
0
0
0
0
0
0
0
0
0.0080
0
0.0080
0
0.0080
0
0.0080
0
0.0080
0
0.0080
0
0.0152
0
0.0152
0
0.0152
0
0.0152
0
0.0152
0
0.0152
0
0.0215
0
0.0215
0
0.0215
0
0.0215
0
0.0215
0
0.0215
0
0.0270
0
0.0270
0
0.0270
0
0.0270
0

12
0.0270
0
0.0270
0
0.0316
0
0.0316
0
0.0316
0
0.0316
0
0.0316
0
0.0316
0
0.0354
0
0.0354
0
0.0354
0
0.0354
0
0.0354
0
0.0354
0
0.0384
0
0.0384
0
0.0384
0
0.0384
0
0.0384
0
0.0384
0
0.0405
0
0.0405
0
0.0405
0
0.0405
0
0.0405
0
0.0405
0
0.0418
0

13
0.0418
0
0.0418
0
0.0418
0
0.0418
0
0.0418
0
0.0422
0
0.0422
0
0.0422
0
0.0422
0
0.0422
0
0.0422

Stress and strain matrices calculated.

14
15
16
Published with MATLAB® R2024b

17

You might also like