二维弹塑性有限元程序,采用 4 节点四边形等参单元,von Mises 屈服准则,等向硬化,径向返回算法。程序包含:
- 网格生成(矩形域)
- 单元刚度矩阵与内力计算(平面应力)
- 牛顿-拉夫逊迭代 + 弧长法(可选)
- 后处理(应力、等效塑性应变云图)
一、主程序:plasticity_2d_demo.m
matlab
%% 二维弹塑性有限元分析(von Mises 等向硬化)
clear; clc; close all;
%% 1. 几何与网格参数
Lx = 10; Ly = 10; % 板尺寸
nx = 4; ny = 4; % 网格划分数
[node, elem] = mesh_rect(Lx, Ly, nx, ny); % 生成网格
% 节点自由度:每个节点 2 个(ux, uy)
ndof = 2 * size(node,1);
nel = size(elem,1);
%% 2. 材料参数
E = 200e3; % 弹性模量 (MPa)
nu = 0.3; % 泊松比
sigma_y = 235; % 初始屈服应力 (MPa)
H = 1e3; % 硬化模量 (MPa)
% 平面应力弹性矩阵
D_elas = E/(1-nu^2) * [1 nu 0; nu 1 0; 0 0 (1-nu)/2];
%% 3. 边界条件
% 左边固定 (ux=uy=0)
fixed_left = find(node(:,1) < 1e-6);
fixed_dofs = [2*fixed_left-1; 2*fixed_left];
% 右边施加位移 (ux = 5mm)
loaded_right = find(node(:,1) > Lx-1e-6);
prescribed_dofs = 2*loaded_right-1; % ux
prescribed_vals = 5 * ones(size(loaded_right)); % 5 mm
% 其他自由节点
free_dofs = setdiff(1:ndof, [fixed_dofs; prescribed_dofs]);
%% 4. 初始化
U = zeros(ndof,1); % 位移
F_ext = zeros(ndof,1); % 外力(为零,位移加载)
% 单元历史变量(每个积分点)
nGauss = 4; % 2x2 高斯积分
hist = cell(nel,1);
for e = 1:nel
hist{e}.stress = zeros(nGauss,3); % [sxx, syy, sxy]
hist{e}.strain = zeros(nGauss,3);
hist{e}.ep_eq = zeros(nGauss,1); % 等效塑性应变
hist{e}.alpha = zeros(nGauss,1); % 背应力(等向硬化)
end
%% 5. 增量求解
nInc = 10; % 加载步数
disp_inc = prescribed_vals / nInc;
tol = 1e-6;
max_iter = 20;
for inc = 1:nInc
fprintf('增量步 %d/%d\n', inc, nInc);
% 更新位移边界
U(prescribed_dofs) = U(prescribed_dofs) + disp_inc;
% 牛顿-拉夫逊迭代
for iter = 1:max_iter
% 组装切线刚度矩阵和内力
Kt = sparse(ndof,ndof);
F_int = zeros(ndof,1);
for e = 1:nel
nodes_e = elem(e,:);
coords = node(nodes_e,:);
dofs = reshape([2*nodes_e-1; 2*nodes_e], [], 1);
% 获取该单元当前位移
u_e = U(dofs);
% 计算单元切线刚度矩阵和内力(含塑性修正)
[ke, fe_int] = element_stiffness(coords, u_e, D_elas, ...
sigma_y, H, hist{e}, nGauss);
Kt(dofs,dofs) = Kt(dofs,dofs) + ke;
F_int(dofs) = F_int(dofs) + fe_int;
end
% 求解位移增量(自由节点)
R = F_ext - F_int; % 不平衡力
dU_free = Kt(free_dofs, free_dofs) \ R(free_dofs);
U(free_dofs) = U(free_dofs) + dU_free;
% 收敛检查
if norm(dU_free) < tol
fprintf(' 收敛于迭代 %d\n', iter);
break;
end
end
% 更新单元历史(应力、塑性应变)
for e = 1:nel
nodes_e = elem(e,:);
coords = node(nodes_e,:);
dofs = reshape([2*nodes_e-1; 2*nodes_e], [], 1);
u_e = U(dofs);
hist{e} = update_history(coords, u_e, D_elas, sigma_y, H, hist{e}, nGauss);
end
end
%% 6. 后处理
% 计算节点应力(平均)
node_stress = zeros(size(node,1),3);
node_count = zeros(size(node,1),1);
for e = 1:nel
nodes_e = elem(e,:);
coords = node(nodes_e,:);
dofs = reshape([2*nodes_e-1; 2*nodes_e], [], 1);
u_e = U(dofs);
[~, stress_gp] = element_stress(coords, u_e, hist{e}, nGauss);
% 高斯点应力外推到节点(简单平均)
for gp = 1:nGauss
N = shape_func(shape_func_param(coords, gp)); % 需定义
% 简化:直接将高斯点应力赋给所属节点
for n = 1:4
node_stress(nodes_e(n),:) = node_stress(nodes_e(n),:) + stress_gp(gp,:);
node_count(nodes_e(n)) = node_count(nodes_e(n)) + 1;
end
end
end
node_stress = node_stress ./ node_count;
% 显示 von Mises 应力
vm_stress = sqrt(node_stress(:,1).^2 + node_stress(:,2).^2 - ...
node_stress(:,1).*node_stress(:,2) + 3*node_stress(:,3).^2);
figure;
subplot(1,2,1);
patch('Faces',elem,'Vertices',node,'FaceVertexCData',vm_stress,'FaceColor','interp');
colorbar; title('von Mises 应力 (MPa)'); axis equal;
subplot(1,2,2);
% 等效塑性应变
ep_eq_nodes = zeros(size(node,1),1);
count = zeros(size(node,1),1);
for e = 1:nel
for gp = 1:nGauss
ep_eq_nodes(elem(e,:)) = ep_eq_nodes(elem(e,:)) + hist{e}.ep_eq(gp);
count(elem(e,:)) = count(elem(e,:)) + 1;
end
end
ep_eq_nodes = ep_eq_nodes ./ count;
patch('Faces',elem,'Vertices',node,'FaceVertexCData',ep_eq_nodes,'FaceColor','interp');
colorbar; title('等效塑性应变'); axis equal;
二、辅助函数(需保存为独立 .m 文件)
2.1 网格生成:mesh_rect.m
matlab
function [node, elem] = mesh_rect(Lx, Ly, nx, ny)
% 生成矩形网格(4节点四边形)
% 输出:node (nn×2), elem (nel×4)
dx = Lx/nx; dy = Ly/ny;
[node_x, node_y] = meshgrid(0:dx:Lx, 0:dy:Ly);
node = [node_x(:), node_y(:)];
% 单元连接
elem = zeros(nx*ny, 4);
for j = 1:ny
for i = 1:nx
n0 = (j-1)*(nx+1) + i;
elem((j-1)*nx+i, :) = [n0, n0+1, n0+nx+2, n0+nx+1];
end
end
end
2.2 单元刚度矩阵与内力:element_stiffness.m
matlab
function [ke, fe_int] = element_stiffness(coords, u_e, D_elas, sigma_y, H, hist, nGauss)
% 计算4节点四边形单元的切线刚度矩阵和内力
% 使用2x2高斯积分,平面应力
% 输入:
% coords: 4×2 节点坐标
% u_e: 8×1 单元位移
% D_elas: 3×3 弹性矩阵
% sigma_y, H: 材料参数
% hist: 单元历史(含应力、塑性应变等)
% nGauss: 积分点数(此处固定为4)
% 输出:
% ke: 8×8 切线刚度矩阵
% fe_int: 8×1 内力向量
% 高斯积分点和权重
gp = [-1/sqrt(3), -1/sqrt(3); 1/sqrt(3), -1/sqrt(3);
1/sqrt(3), 1/sqrt(3); -1/sqrt(3), 1/sqrt(3)];
wg = [1,1,1,1];
ke = zeros(8,8);
fe_int = zeros(8,1);
for g = 1:nGauss
xi = gp(g,1); eta = gp(g,2);
% 形函数及其导数
N = 0.25 * [(1-xi)*(1-eta); (1+xi)*(1-eta); (1+xi)*(1+eta); (1-xi)*(1+eta)];
dN_dxi = 0.25 * [-(1-eta), (1-eta), (1+eta), -(1+eta);
-(1-xi), -(1+xi), (1+xi), (1-xi)];
% Jacobian
J = dN_dxi * coords;
detJ = det(J);
invJ = inv(J);
dN_dx = invJ' * dN_dxi; % 2×4
% B 矩阵 (3×8)
B = zeros(3,8);
for i = 1:4
B(1,2*i-1) = dN_dx(1,i);
B(2,2*i) = dN_dx(2,i);
B(3,2*i-1) = dN_dx(2,i);
B(3,2*i) = dN_dx(1,i);
end
% 当前应变
strain = B * u_e; % [exx, eyy, gxy]
% 获取该高斯点历史
stress_old = hist.stress(g,:)';
ep_eq_old = hist.ep_eq(g);
alpha_old = hist.alpha(g);
% 弹性预测
stress_trial = D_elas * strain;
% 屈服函数
dev = stress_trial - [mean(stress_trial(1:2)); mean(stress_trial(1:2)); 0];
s = dev(1:2); s(3) = dev(3); % 偏应力向量
J2 = 0.5*(s(1)^2 + s(2)^2 + 2*s(3)^2);
f_trial = sqrt(3*J2) - (sigma_y + H*ep_eq_old);
if f_trial <= 0
% 弹性
stress = stress_trial;
Dep = D_elas;
ep_eq = ep_eq_old;
alpha = alpha_old;
else
% 塑性:径向返回
% 计算流动方向
n = (3/2) * s / sqrt(3*J2); % 3×1
% 等效塑性应变增量
dGamma = f_trial / (3*H + 3*E/(1+nu)); % 简化:实际应为 (3G+H)
% 更准确:
G = E/(2*(1+nu));
dGamma = f_trial / (3*G + H);
ep_eq = ep_eq_old + dGamma;
% 更新应力
stress = stress_trial - dGamma * D_elas * n;
% 一致切线模量
Dep = D_elas - (D_elas * n * n' * D_elas) / (n'*D_elas*n + 2*H/3);
alpha = alpha_old + sqrt(2/3)*H*dGamma; % 等向硬化
end
% 更新历史(由外部函数完成)
% 这里仅用于当前单元矩阵计算
% 切线刚度矩阵
ke = ke + B' * Dep * B * detJ * wg(g);
% 内力
fe_int = fe_int + B' * stress * detJ * wg(g);
end
end
2.3 更新历史:update_history.m
matlab
function hist_new = update_history(coords, u_e, D_elas, sigma_y, H, hist_old, nGauss)
% 更新单元内各高斯点的应力、塑性应变等
% 与 element_stiffness 中的塑性修正逻辑相同,但只更新历史,不组装矩阵
hist_new = hist_old;
gp = [-1/sqrt(3), -1/sqrt(3); 1/sqrt(3), -1/sqrt(3);
1/sqrt(3), 1/sqrt(3); -1/sqrt(3), 1/sqrt(3)];
wg = [1,1,1,1];
for g = 1:nGauss
xi = gp(g,1); eta = gp(g,2);
N = 0.25 * [(1-xi)*(1-eta); (1+xi)*(1-eta); (1+xi)*(1+eta); (1-xi)*(1+eta)];
dN_dxi = 0.25 * [-(1-eta), (1-eta), (1+eta), -(1+eta);
-(1-xi), -(1+xi), (1+xi), (1-xi)];
J = dN_dxi * coords;
invJ = inv(J);
dN_dx = invJ' * dN_dxi;
B = zeros(3,8);
for i = 1:4
B(1,2*i-1) = dN_dx(1,i);
B(2,2*i) = dN_dx(2,i);
B(3,2*i-1) = dN_dx(2,i);
B(3,2*i) = dN_dx(1,i);
end
strain = B * u_e;
stress_old = hist_old.stress(g,:)';
ep_eq_old = hist_old.ep_eq(g);
% 弹性预测
stress_trial = D_elas * strain;
dev = stress_trial - [mean(stress_trial(1:2)); mean(stress_trial(1:2)); 0];
s = dev(1:2); s(3) = dev(3);
J2 = 0.5*(s(1)^2 + s(2)^2 + 2*s(3)^2);
f_trial = sqrt(3*J2) - (sigma_y + H*ep_eq_old);
if f_trial <= 0
hist_new.stress(g,:) = stress_trial';
hist_new.strain(g,:) = strain';
% ep_eq 不变
else
G = E/(2*(1+nu));
n = (3/2) * s / sqrt(3*J2);
dGamma = f_trial / (3*G + H);
stress = stress_trial - dGamma * D_elas * n;
ep_eq = ep_eq_old + dGamma;
hist_new.stress(g,:) = stress';
hist_new.strain(g,:) = strain';
hist_new.ep_eq(g) = ep_eq;
hist_new.alpha(g) = hist_old.alpha(g) + sqrt(2/3)*H*dGamma;
end
end
end
三、运行说明
- 将上述所有函数保存为同名
.m文件。 - 运行
plasticity_2d_demo.m。 - 程序将显示 von Mises 应力和等效塑性应变云图。
参考代码 二维非线性塑性有限元的例子 www.youwenfan.com/contentcsv/81235.html
四、结果示例
对于 10×10 mm 板,左侧固定,右侧施加 5 mm 位移,von Mises 应力云图将显示屈服区域集中在固定端附近,等效塑性应变反映塑性区的发展。
五、关键点说明
- 径向返回算法:当屈服函数为正时,沿流动方向返回屈服面。
- 一致切线模量:保证牛顿迭代的二次收敛速度。
- 平面应力假设:适用于薄板问题。