版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/walkandthink/article/details/76400893
在前面一节,我们有了一维的形函数,可以对一维问题进行有限元计算了,这一节我们来看一下二维单元的形函数。
这里先说明一下,二维单元的类型最常用的主要有三角形单元和四边形单元,这两种单元类型各有各的好处。因为在AsFem的网格生成模块中主要考虑二维的矩形区域,所以本章就优先介绍四边形单元中的4点线性单元和9节点二次单元。其他单元的结构非常类似,随便google一下都能找到具体的表达式,就不在多说了。
先回顾下一维情形下的一阶Lagrange插值多项式:
现在我们假设在y(也就是
做一个向量乘法就可以得到二维一阶4节点单元的形函数为:
为了方便,还是用
所以在二维4节点线性单元中,4个节点对应的形函数为:
同理,二维9节点二次单元的形函数就可以由一下公式计算得到:
具体表达式如下:
以上是针对4,9节点取巧的计算方法,真正的形函数推导应该先根据单元的节点数构造出对应的位移模式:
然后带入4个点的(
我们可以画一下对应的形函数曲面,代码如下:
扫描二维码关注公众号,回复:
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变换矩阵就是:
其中
最后,形函数对自然坐标的偏导就可以写为:
这里
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;
}
}