FEM 代码中的单轴拉伸解不均匀

计算科学 有限元 matlab 固体力学
2021-12-20 05:49:20

我被困在这里很久了。我写了一个玩具 Matlab FEM 代码。我想运行以下模拟。

假设我们有一个立方体,我们将它沿轴划分为子立方体,然后每个子立方体被划分为 5 个四面体元素。立方体沿轴分别分为节点。所以网格中有个节点。网格中的每个节点都可以用x,y,zx,y,znx,ny,nznx×ny×nznode(i,j,k)

边界条件

  • 立方体的平面固定了 DOF,立方体的平面固定 DOF,立方体的平面固定了 DOF。xoyzxozyyozx

  • 立方体的顶部平面施加了均匀的压力(拉伸)。

所以立方体处于单轴(拉伸)应力下。

问题

坐标的节点沿z轴的位移应该相等。那就是zuz(x,y,const)=const

但是,我的代码没有给我这个解决方案。我不知道这是我的代码的错误还是它们不相等的事实。

主要代码

实际上,我已经用一些书中的例子检查了代码。我已经检查了元素矩阵和矩阵组合。我的代码可以通过标准书籍获得相同的解决方案。也许我的加载有问题。但我找不到线索。

完整的代码和检查可以在这个存储库中找到

clc
clear
close all

num_x_node=4;
num_y_node=4;
num_z_node=4;

x_range=10;
y_range=10;
z_range=10;

grid= CubeDomainTetGrid(num_x_node, num_y_node, num_z_node, x_range, y_range, z_range);
node_coordinate_table=grid.nodeCoordinateTable();
element_node_table=grid.elementNodeTable();

dof_per_node=3;
num_node = grid.numNode();
num_dof = num_node * dof_per_node;

is_constrain = zeros(num_dof,1);

load_value = zeros(num_dof,1);
is_load = zeros(num_dof,1);

% assemble global stiffness matrix
element_stiffness_matrix_array = calculateElementStiffnessMatrixArray(node_coordinate_table, element_node_table);
K = assembleGlobalMatrix(node_coordinate_table, element_node_table, dof_per_node, element_stiffness_matrix_array);

%% constrain
% all node at x-y plane is fix z dof to zero
for i=1:1:num_x_node
    for j=1:1:num_y_node
        for k=1
            node_index = grid.nodeIndex(i,j,k);
            for dof_index = 3
                dof_global_index = (node_index - 1) * dof_per_node + dof_index;
                is_constrain(dof_global_index)=1;
            end
        end
    end
end
% all node at y-z plane is fix x dof to zero
for i=1:1:1
    for j=1:1:num_y_node
        for k=1:1:num_z_node
            node_index = grid.nodeIndex(i,j,k);
            for dof_index = 1
                dof_global_index = (node_index - 1) * dof_per_node + dof_index;
                is_constrain(dof_global_index)=1;
            end
        end
    end
end
% all node at x-z plane is fix y dof to zero
for i=1:1:num_x_node
    for j=1
        for k=1:1:num_z_node
            node_index = grid.nodeIndex(i,j,k);
            for dof_index = 2
                dof_global_index = (node_index - 1) * dof_per_node + dof_index;
                is_constrain(dof_global_index)=1;
            end
        end
    end
end
clear node_index;
clear dof_index;
clear dof_global_index;

%% load
% node(:,:,num_z_node) is apply pressure
pressure = 6;

% tranvers cell on surface and accumulate pressure
% the face see from top like
% the node force can be calulate by accumulate each small triangle
%  A y
%  |
%  |---> x
%  
%  -------------
%  |\  |\  |\  |
%  | \ | \ | \ |
%  |  \|  \|  \|     
%  -------------
%  |\  |\  |\  |
%  | \ | \ | \ |
%  |  \|  \|  \|
%  -------------
%
%      1   2
%      -----
%      |\  |
%      | \ |
%      |  \|
%      -----
%      3   4

for i=1:1:num_x_node-1
    for j=1:1:num_y_node-1
        % calculate force on each sub cube's top surface
        dx= x_range / (num_x_node - 1);
        dy= y_range / (num_y_node - 1);
        area_triangle= dx*dy/2;
        force_on_triangle=area_triangle*pressure;
        num_node_per_triangle = 3;
        f_on_node = force_on_triangle/num_node_per_triangle;
        node_1=grid.nodeIndex(i,j+1,num_z_node);
        node_2=grid.nodeIndex(i+1,j+1,num_z_node);
        node_3=grid.nodeIndex(i,j,num_z_node);
        node_4=grid.nodeIndex(i+1,j,num_z_node);
        % lower triangle
        for node_index = [node_1 node_3 node_4]
            dof_index = 3;
            dof_global_index = (node_index - 1) * dof_per_node + dof_index;
            load_value(dof_global_index)=load_value(dof_global_index)+f_on_node;
        end
        % upper triangle
        for node_index = [node_1 node_2 node_4]
            dof_index = 3;
            dof_global_index = (node_index - 1) * dof_per_node + dof_index;
            load_value(dof_global_index)=load_value(dof_global_index)+f_on_node;
        end
        clear node_1 node_2 node_3 node_4
    end
end

%% apply constrain to global stiffness matrix
P=load_value;
for i=1:1:num_dof
    if is_constrain(i)
        K(i,:)=0;
        K(:,i)=0;
        K(i,i)=1;
        P(i)=0;
    end
end

%% solution
U=K\P;

displacement=(reshape(U,dof_per_node,num_node))';
new_node_coordinate_table=node_coordinate_table+displacement*1e8;

figure
hold on
plotTetGrid(node_coordinate_table,element_node_table);
scatter3(new_node_coordinate_table(:,1),new_node_coordinate_table(:,2),new_node_coordinate_table(:,3));
axis equal

x_displacement=zeros(num_node,1);
y_displacement=zeros(num_node,1);
z_displacement=zeros(num_node,1);
for i=1:1:num_node
    x_displacement(i) = U((i - 1)*dof_per_node + 1);
    y_displacement(i) = U((i - 1)*dof_per_node + 2);
    z_displacement(i) = U((i - 1)*dof_per_node + 3);
end
figure
plot(z_displacement);
xlabel('node index');
ylabel('z displacement');
```
2个回答

这个特定的网格没有为这个问题提供正确的、均匀的位移解决方案的原因是它是“不合格的”。具体来说,在模型中两个立方体的交点处,穿过该面的两个单元边不相互对齐,而是相互交叉。

下图显示了不合格网格中的典型面。元素 1 和 2 位于该面的​​一侧,而元素 3 和 4 位于另一侧。考虑面(元素)1 内部的任意位置。该点的位移是通过对节点 1、3 和 4 处的值进行插值来计算的。假设面(元素)3 也包含该位置。在这个面上,该位置的位移是从节点 1、2 和 3 插值的。由于单元节点处的位移通常是任意的,因此在选定位置插值的位移将不相同。这就是为什么网格被称为不合格的原因。

在此处输入图像描述

我附上了这部分的 abaqus 模型,其中网格在这个面上符合。请注意,此模型在每个立方体中包含六个四面体,总共十二个。该模型的节点位移完全一致,并且σzz在所有元素中都等于施加的压力。

*node, nset=all_nodes
  1,                0,                0,                0
  2,                0,               10,                0
  3,               10,                0,                0
  4,               10,               10,                0
  5,                0,                0,               10
  6,                0,               10,               10
  7,               10,                0,               10
  8,               10,               10,               10
  9,                0,                0,               20
 10,                0,               10,               20
 11,               10,                0,               20
 12,               10,               10,               20
*element, type=c3d4, elset=all_elements
  1,   7,  10,  11,   8
  2,  12,  11,  10,   8
  3,   6,   3,   2,   4
  4,   6,   7,   3,   4
  5,   7,  10,   9,  11
  6,   6,  10,   7,   8
  7,   6,   8,   7,   4
  8,   2,   5,   1,   3
  9,   6,   5,   2,   3
 10,   6,   7,   5,   3
 11,   6,   9,   5,   7
 12,   6,  10,   9,   7
*material, name=the_mat
*elastic
         100.,  .3
*solid section, elset=all_elements, material=the_mat
1.0
*nset,nset=x0
1,2,5,6,9,10,
*nset,nset=y0
1,3,5,7,9,11,
*nset,nset=z0
1,2,3,4,
*nset,nset=top 
9,10,11,12,
*surface, TYPE=CUTTING SURFACE, DEFINITION=COORDINATES, name=top_surf
0.,0.,20.,   0.,0.,1.
all_elements
*Boundary
x0, 1, 1
y0, 2,2
z0, 3, 3
*Step, name=Step-1, nlgeom=NO
*Static
1., 1., 1e-05, 1.
*Dsload
**Surf-1, P, -1.
top_surf,P,-1.
*node print
u
*el print
S
*End Step

下图显示了 z 位移的等高线图,可以看出,它在 x 和 y 方向上是均匀的。

在此处输入图像描述

好吧,我的代码中没有与 FEM 相关的错误。如果网格不好,似乎会出现差异。我用 Abaqus 软件检查了我的代码。元素矩阵和元素向量都是相同的。

我可以使用 Abaqus 和我的代码获得相同的解决方案。位移不是恒定的。

  • 工作条件

在此处输入图像描述

  • 结果

在此处输入图像描述

可以看出位移z这个网格得到的结果是不均匀的。

以下 Abaqus 输入文件可用于重现解决方案。

*Heading
** Job name: Job-test Model name: Job_my
** Generated by: Abaqus/CAE 2016
*Preprint, echo=NO, model=NO, history=NO, contact=NO
**
** PARTS
**
*Part, name=PART-1
*Node
      1,           0.,           0.,           0.
      2,           0.,          10.,           0.
      3,          10.,           0.,           0.
      4,          10.,          10.,           0.
      5,           0.,           0.,          10.
      6,           0.,          10.,          10.
      7,          10.,           0.,          10.
      8,          10.,          10.,          10.
      9,           0.,           0.,          20.
     10,           0.,          10.,          20.
     11,          10.,           0.,          20.
     12,          10.,          10.,          20.
*Element, type=C3D4
 1,  1,  3,  4,  7
 2,  1,  4,  2,  6
 3,  7,  5,  6,  1
 4,  7,  6,  8,  4
 5,  1,  7,  4,  6
 6,  5,  7,  8, 11
 7,  5,  8,  6, 10
 8, 11,  9, 10,  5
 9, 11, 10, 12,  8
10,  5, 11,  8, 10
*Elset, elset=Set-1, generate
  1,  10,   1
** Section: Section-1
*Solid Section, elset=Set-1, material=MATERIAL-1
,
*End Part
**  
**
** ASSEMBLY
**
*Assembly, name=Assembly
**  
*Instance, name=PART-1-1, part=PART-1
*End Instance
**  
*Nset, nset=Set-1, instance=PART-1-1, generate
 1,  4,  1
*Nset, nset=Set-2, instance=PART-1-1, generate
  1,  11,   2
*Nset, nset=Set-3, instance=PART-1-1
  1,  2,  5,  6,  9, 10
*Elset, elset=_Surf-1_S1, internal, instance=PART-1-1
 8, 9
*Surface, type=ELEMENT, name=Surf-1
_Surf-1_S1, S1
*End Assembly
** 
** MATERIALS
** 
*Material, name=MATERIAL-1
*Elastic
100.,0.
** 
** BOUNDARY CONDITIONS
** 
** Name: BC-1 Type: Displacement/Rotation
*Boundary
Set-1, 3, 3
** Name: BC-2 Type: Displacement/Rotation
*Boundary
Set-2, 2, 2
** Name: BC-3 Type: Displacement/Rotation
*Boundary
Set-3, 1, 1
** ----------------------------------------------------------------
** 
** STEP: Step-1
** 
*Step, name=Step-1, nlgeom=NO
*Static
1., 1., 1e-05, 1.
** 
** LOADS
** 
** Name: Load-1   Type: Pressure
*Dsload
Surf-1, P, -1.
** 
** OUTPUT REQUESTS
** 
*Restart, write, frequency=0
** 
** FIELD OUTPUT: F-Output-1
** 
*Output, field, variable=PRESELECT
** 
** HISTORY OUTPUT: H-Output-1
** 
*Output, history, variable=PRESELECT
*End Step

我从这门课程中学到的是,如果可能发生奇怪的错误,我们可以使用商业软件进行比较。