有限元笔记4-二维单元形函数(2D-4,9Node)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/walkandthink/article/details/76400893

在前面一节,我们有了一维的形函数,可以对一维问题进行有限元计算了,这一节我们来看一下二维单元的形函数。

这里先说明一下,二维单元的类型最常用的主要有三角形单元和四边形单元,这两种单元类型各有各的好处。因为在AsFem的网格生成模块中主要考虑二维的矩形区域,所以本章就优先介绍四边形单元中的4点线性单元和9节点二次单元。其他单元的结构非常类似,随便google一下都能找到具体的表达式,就不在多说了。

先回顾下一维情形下的一阶Lagrange插值多项式:

N1=1ξ2,N2=1+ξ2

现在我们假设在y(也就是 η )方向也有一个一阶的Lagrange插值多项式:
M1=1η2,M2=1+η2

做一个向量乘法就可以得到二维一阶4节点单元的形函数为:
[M2M1][N1N2]=[M2N1M1N1M2N2M1N2]

为了方便,还是用 N 来表示形函数,注意去上面符号的区别。

所以在二维4节点线性单元中,4个节点对应的形函数为:

N1=1η21ξ2=(1η)(1ξ)4

N2=1η21+ξ2=(1η)(1+ξ)4

N3=1+η21+ξ2=(1+η)(1+ξ)4

N4=1+η21ξ2=(1+η)(1ξ)4

同理,二维9节点二次单元的形函数就可以由一下公式计算得到:

N9node=M3M2M1[N1N2N3]

Nij=M3N1M2N1M1N1M3N2M2N2M1N2M3N3M2N3M1N3

具体表达式如下:
N1=η(η1)2ξ(ξ1)2=14η(η1)ξ(ξ1)

N2=η(η1)2ξ(ξ+1)2=14η(η1)ξ(ξ+1)

N3=η(η+1)2ξ(ξ+1)2=14η(η+1)ξ(ξ+1)

N4=η(η+1)2ξ(ξ1)2=14η(η+1)ξ(ξ1)

N5=η(η1)2(1+ξ)(1ξ)=12η(η1)(1ξ2)

N6=(1+η)(1η)ξ(1+ξ)2=12(1η2)ξ(1+ξ)

N7=η(η+1)2(1+ξ)(1ξ)=12η(η+1)(1ξ2)

N8=(1+η)(1η)ξ(1ξ)2=12(1η2)ξ(1ξ)

N9=(1+η)(1η)(1+ξ)(1ξ)=(1η2)(1ξ2)

以上是针对4,9节点取巧的计算方法,真正的形函数推导应该先根据单元的节点数构造出对应的位移模式:

u=α1+α2x+α3y+α4xy

然后带入4个点的( ξi , ηj )值来求解 u=Aα 方程得到 A ,进而得到各个点对应的形函数。

我们可以画一下对应的形函数曲面,代码如下:

扫描二维码关注公众号,回复: 5460080 查看本文章

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
from mpl_toolkits.mplot3d import Axes3D

xi=np.linspace(-1.0,1.0,100)
eta=np.linspace(-1.0,1.0,100)

Xi,Eta=np.meshgrid(xi,eta)
N1=Eta*(1-Eta*Eta)*(1-Xi*Xi)
#N1=(1-Eta*Eta)*Xi*(1+Xi)/2.0

fig=plt.figure(1)
ax=fig.gca(projection='3d')
surf=ax.plot_surface(Xi,Eta,N1,cmap=cm.coolwarm,linewidth=0, antialiased=False)

# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
plt.title('$N_{9}$ of 2D-9Node element')
plt.xlim([-1.0,1.0])
plt.ylim([-1.0,1.0])
plt.xlabel("$\\xi$")
plt.ylabel('$\eta$')
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.savefig('N9-9Node.png',dpi=500)
plt.show()

结果如下:

这里写图片描述

这里写图片描述

这里写图片描述

同上一节一样,有了形函数后我们还需要知道其对自然坐标的导数才能计算 Δ 等算符,计算也很简单,做一下二维情形的Jacobian变换就可以了。
比如:

Ni(ξ,η)x=Niξξx+Niηηx

Ni(ξ,η)y=Niξξy+Niηηy

写成矩阵形式:
NixNix=ξxξyηxηyNiξNiη

这是数学上最直观的表达,但是在程序中,为了方便计算我们反过来做:
Niξ=Nixxξ+Niyyξ

Niη=Nixxη+Niyyη

其矩阵形式为:
NiξNiη=xξxηyξyηNixNix

Jacobian变换矩阵就是:
J=xξxηyξyη

其中
xξ=i=1nNiξxi,xη=i=1nNiηxi

yξ=i=1nNiξyi,yη=i=1nNiηyi

最后,形函数对自然坐标的偏导就可以写为:
NixNiy=J1NiξNiη

这里 J1 为Jacobian矩阵的逆矩阵。

AsFem对应的计算代码如下:

void Shp2D(const int &nDims,const double &xi,const double &eta,const MatrixXd &Coords, MatrixXd &shp, double &DetJac)
{
    int nNodes;
    int i, j;
    double dxdxi, dydxi, dzdxi;
    double dxdeta, dydeta, dzdeta;
    double temp;

    nNodes = int(Coords.rows());


    if (nDims<2||nDims>3)
    {
        cout << "Wrong dimension!!!" << endl;
        abort();
    }

    if (nNodes<3 || nNodes>16)
    {
        cout << "Wrong nodes on current element!!!" << endl;
        cout<<"AsFem only support 2D-4,8,9 nodes element!!!"<<endl;
        abort();
    }

    MatrixXd Jac(2,2);
    Matrix2d XJac;
    shp.setZero();

    if(nNodes==4)
    {
        // 2D-4Nodes rectangle element
        shp(0,0)=(1.0-xi)*(1.0-eta)/4.0;
        shp(1,0)=(1.0+xi)*(1.0-eta)/4.0;
        shp(2,0)=(1.0+xi)*(1.0+eta)/4.0;
        shp(3,0)=(1.0-xi)*(1.0+eta)/4.0;

        shp(0,1)= (eta-1.0)/4.0;
        shp(0,2)= (xi -1.0)/4.0;

        shp(1,1)= (1.0-eta)/4.0;
        shp(1,2)=-(1.0+xi )/4.0;

        shp(2,1)= (1.0+eta)/4.0;
        shp(2,2)= (1.0+xi )/4.0;

        shp(3,1)=-(1.0+eta)/4.0;
        shp(3,2)= (1.0-xi )/4.0;
    }
    else if(nNodes==8)
    {
        // 2D-8Nodes rectangle element
        // Go to AsFem for details
    }
    else if(nNodes==9)
    {
        // 2D-9Nodes rectangle element
        shp(0,0)=(xi*xi-xi )*(eta*eta-eta)/4.0;
        shp(1,0)=(xi*xi+xi )*(eta*eta-eta)/4.0;
        shp(2,0)=(xi*xi+xi )*(eta*eta+eta)/4.0;
        shp(3,0)=(xi*xi-xi )*(eta*eta+eta)/4.0;
        shp(4,0)=(1.0-xi*xi)*(eta*eta-eta)/2.0;
        shp(5,0)=(xi*xi+xi )*(1.0-eta*eta)/2.0;
        shp(6,0)=(1.0-xi*xi)*(eta*eta+eta)/2.0;
        shp(7,0)=(xi*xi-xi )*(1.0-eta*eta)/2.0;
        shp(8,0)=(1.0-xi*xi)*(1.0-eta*eta);

        shp(0,1)=(2.0*xi-1.0)*(eta*eta-eta)/4.0;
        shp(0,2)=(xi*xi-xi  )*(2.0*eta-1.0)/4.0;

        shp(1,1)=(2.0*xi+1.0)*(eta*eta-eta)/4.0;
        shp(1,2)=(xi*xi+xi  )*(2.0*eta-1.0)/4.0;

        // Go to AsFem for details
    }


    // compute jacob transform matrix
    if(nDims==2)
    {
        dxdxi=0.0;dxdeta=0.0;
        dydxi=0.0;dydeta=0.0;
        for(i=0;i<nNodes;i++)
        {
            dxdxi+=Coords(i,0)*shp(i,1);
            dxdeta+=Coords(i,0)*shp(i,2);

            dydxi+=Coords(i,1)*shp(i,1);
            dydeta+=Coords(i,1)*shp(i,2);
        }
        Jac(0,0)=dxdxi;Jac(0,1)=dydxi;
        Jac(1,0)=dxdeta;Jac(1,1)=dydeta;

        DetJac=Jac(0,0)*Jac(1,1)-Jac(0,1)*Jac(1,0);
        if(DetJac==0.0)
        {
            cout<<"Singular element!!!"<<endl;
            abort();
        }
        XJac=Jac.inverse();
    }
    else if(nDims==3)
    {
        // Go to AsFem for details
    }

    for(i=0;i<nNodes;i++)
    {
        temp=XJac(0,0)*shp(i,1)+XJac(0,1)*shp(i,2);
        shp(i,2)=XJac(1,0)*shp(i,1)+XJac(1,1)*shp(i,2);
        shp(i,1)=temp;
    }
}

猜你喜欢

转载自blog.csdn.net/walkandthink/article/details/76400893