首页/文章/ 详情

一种圆柱滚子轴承简化有限元模型的快速建模方法

8月前浏览1033

简介


 

目前,传动系统仍然处于持续开发和快速迭代的阶段,以满足未来对更大载荷、更长使用寿命以及降低噪音和重量的需求。为了有效地实现这些目标,采用诸如有限元方法(FEM)等计算机辅助工程(CAE)技术,是较为常见的手段。

可靠的有限元分析依赖于对传动系统在运行过程中承受的载荷有深入了解,同时必须正确模拟这些载荷对传统系统的影响。由于轴承在传动系统中起到传递载荷的作用,因此轴承是分析传动系统时必须考虑的关键部件。

尽管建立具有实体滚子和考虑接触行为的轴承精细有限元模型完全可行,但对于包含多个轴承的传动系统,或是具有大量滚子的大型轴承,从计算成本的角度来看,采用这种方式并非最佳选择。这是因为,对于球形滚子或圆柱形滚子,滚子与滚道之间的弹性接触可近似为点接触或线接触。由于接触面积相比于轴承的尺寸非常小,为了准确模拟滚子与滚道之间的接触行为,必须采用非常细密的网格来划分,这将严重增加计算成本。

在开展传动系统的有限元分析时,如果关注区域并非轴承本身,而是与轴承相关的结构。此时,如果能够建立复杂度适中、数值稳定、经过充分测试和验证的简化轴承模型,使得简化轴承模型能够提供正确的结构整体刚度以及载荷分布,预计可以获得足够准确的计算结果,并节约计算成本。

为此,本研究将针对圆柱滚子轴承,讨论其简化有限元模型的建模方法,并基于Abaqus二次开发,给出一种快速建模方法,能够根据有限的参数快速生成模型,以进一步提高建模效率。

圆柱滚子轴承简化有限元模型建模方法


 

   

   

   

模型分类

目前,在建立圆柱滚子轴承的简化有限元模型时,普遍的做法为采用实体单元建立轴承的外圈和内圈,并通过具有非线性刚度的弹簧来代替滚子。这种简化建模方式的优点为可以较好地反映轴承外圈和内圈的刚度,通过调整弹簧的布置方式和刚度,可以获得与真实轴承接近的载荷-变形行为。

根据弹簧布置方式的不同,上述简化模型可以分为如图1所示的两类模型。在图中,左侧的轴承模型可以称为分布载荷(Distributed Load)模型,右侧的轴承模型可以称为离散载荷(Discrete Load)模型。

两类简化轴承模型

在分布载荷模型中,外圈滚道和内圈滚道的所有节点均通过弹簧单元连接;而在离散载荷模型中,只有滚子所在区域的节点通过弹簧连接。对于分布载荷模型,当轴承承受载荷作用时,载荷将会被均匀地分配到内圈和外圈上,从而获得更平滑的应力分布,但这也意味着此类模型无法研究滚子和滚道之间的作用载荷。对于离散载荷模型,由于只有滚子所在区域的节点采用弹簧连接,因此相比之下更接近真实轴承的承载情况,并且能够获得外载作用下滚子和滚道之间的作用载荷的分布特性。

对于圆柱滚子轴承,由于滚子与滚道之间的接触行为可以近似为线接触,因此对于每一个滚子,外圈和内圈滚道沿轴向方向上的节点均通过一排弹簧单元连接,如图2所示。通过布置多个弹簧,可以反映单个滚子在轴向方向的载荷分布情况。

单个滚子的节点连接示意图


   

   

   

弹簧非线性刚度计算

在上述简化轴承模型中,弹簧刚度可以通过滚子的载荷-变形行为计算得到。由于随着滚子承受的载荷增大,滚子与滚道之间的接触面积也会随之增大。因此,即使是线弹性模型,滚子的载荷-变形行为也是非线性的。大量的研究人员通过开展试验或仿真,得到对于单个滚子与滚道之间的载荷-变形关系可采用如下所示的表达式近似描述:

 

式中,Q为滚子载荷,δ为变形量,K为载荷-变形系数,n为一个指数,对于滚子轴承可近似取值为1.1。

由于内圈和外圈均会产生变形,因此内圈滚道相对外圈滚道的总的径向变形量δtot可表示为:

 

式中,δiδo分别为内圈和外圈的变形量。

由于滚子受到内圈和外圈的作用力而处于平衡状态,因此有:

 

则对于一个与内圈和外圈滚道同时接触的滚子,其载荷-变形关系可表示为:

 

式中,Kn可表示为

 

式中,KiKo分别为内圈和外圈的载荷-变形系数。载荷-变形系数取决于滚子的有效长度L,也同样受到滚子直径D的影响。因此,滚子-滚道的载荷-变形可写为如下所示的一般形式:

 

式中,L0D0δ0用于对参数进行归一化,当参数以毫米表示时,其取值均为1。n1n2n3为常数,基于部分文献的研究成果,其取值如表1所示。

计算滚子-滚道接触的载荷-变形系数使用的常数

需要说明的是,只有滚道与滚子处于受压状态时,滚道与滚子才会处于接触状态;如果滚道与滚子处于受拉状态时,则滚道将与滚子脱开。这意味着,代表滚子的弹簧只能受压,而不能受拉。上述载荷-变形行为可以通过将弹簧处于拉伸状态时的刚度设置为零来实现,此时弹簧的载荷-变形行为如3所示。在图中,左侧的载荷-变形曲线代表轴承的游隙为零时的情况,右侧的载荷-变形曲线代表轴承的游隙不为零时的情况。此时,可以通过将左侧的载荷-变形曲线向左侧偏移游隙值来获得。其基本原理为当代表滚子的弹簧受压时,当弹簧产生的压缩量小于游隙时,弹簧不会受到载荷的作用;只有当变形量超过游隙值后,弹簧才会承受载荷的作用。此外,对于圆柱滚子轴承,在沿着滚子的轴向方向上,滚子边缘的接触应力将大于滚子中心的接触应力。为了获得较为均匀的接触应力分布,圆柱滚子表现为沿着轴向方向上滚子直径发生改变。对于单个滚子中沿轴向方向上的弹簧,通过调整每个弹簧所代表的轴承游隙值,可以考虑滚子直径的变化。

非线性弹簧的载荷-变形行为

此外,从图3中可以看到,当弹簧受拉时,弹簧的刚度值并不为零,而是具有一个非常微小的刚度值。通过该方法,可以消除轴承内圈变形时的刚体 位移,从而避免在静力分析时出现收敛性问题。需要特别说明的是,在定义非线性弹簧的载荷-变形行为时,需要在较宽的变形范围内定义。这是因为,对于超出数据定义范围内的变形量,有限元软件Abaqus并不会对数据进行线性外推处理,而是假设载荷保持不变,这可能会带来收敛性问题。

另一个需要特别说明的问题为非线性弹簧刚度的标定。这是因为采用上述理论公式计算得到的弹簧刚度包含了滚道的变形。由于有限元模型中已经通过建立内圈和外圈的实体模型考虑了滚道的变形,因此直接使用理论公式计算的刚度会带来额外的误差。此外,由于弹簧是直接通过连接外圈和内圈滚道的节点创建的,而真实的滚子与滚道在变形时存在一定的接触面积,因此同样会存在误差。一些研究人员通过计算滚子与滚道的接触宽度,在接触区域创建一层非常薄的单元层来考虑真实的接触面积。然而,这种方法 会引入长宽比差异较大的单元,同样可能会带来一定的收敛性问题。综上所述,为了获得接近真实轴承的载荷-变形行为,弹簧的刚度应该略大于理论计算值。一种较为可行的方法为通过建立包含单个实体滚子的轴承有限元模型或试验的方式来获得真实轴承的载荷-变形行为,并基于该载荷-变形行为来标定弹簧的刚度。由于本文仅讨论圆柱滚子轴承简化有限元模型的建模方法,因此仍使用理论公式计算得到的弹簧刚度。关于简化轴承有限元模型中弹簧刚度对于轴承滚子载荷分布以及周围结构的影响,仍有待进一步研究。

圆柱滚子轴承简化有限元模型快速建模方法


 

对于圆柱滚子轴承,通过将滚子所在部位的外圈和内圈节点采用具有非线性刚度的弹簧单元依次连接,即可建立圆柱滚子轴承简化有限元模型。然而,对于具有较多滚子数量的轴承结构,如果采用手动连接的方式,建模过程将非常繁琐。为此,本文基于有限元软件Abaqus的二次开发功能,通过批量建立非线性弹簧单元,提出一种圆柱滚子轴承简化有限元模型的快速建模方法。

该方法的基本原理为将外圈滚道和内圈滚道的所有表面节点分别定义两个节点集。通过定义变量来指定两个节点集的名称,如变量Outer_Ring_Node_Set_Name和变量Inner_Ring_Node_Set_Name,可以编写脚本获得两个节点集中所有节点对应的节点编号以及坐标值。然后,通过指定轴承滚子的数量和第一个轴承滚子所在位置(指定滚子中心位置的X和Y坐标,假定轴承轴向为Z轴),脚本程序将会依照节点的极坐标值确定所有轴承滚子对应区域的外圈和内圈滚道表面节点,并依照滚子的编号存放在不同的节点集中。例如,对于第一个滚子,其所在区域的外圈滚道表面节点将会存放在节点集Outer_Ring_Roller1_Node_Set中,内圈滚道表面节点将会存放在节点集Inner_Ring_Roller1_Node_Set中。其余滚子的节点集名称可以依次类推。

在建立每个滚子所在区域节点的节点集后,通过将单个滚子的外圈节点集中的全部节点与内圈节点集中的全部节点通过弹簧单元连接即可建立单个滚子的弹簧单元。需要指出的是,由于节点集中的节点并非沿着轴向顺序排列,因此需要首先判断节点的连接顺序。本文给出的解决方法为首先获取节点集中节点的轴向坐标(Z坐标)按从小到大的顺序排列时,其在节点集中的索引值(即节点对象在节点集对象中的排列顺序,如第一个节点的索引值为0)。然后,根据该索引值来连接外圈和内圈节点,即可确保节点连接顺序无误。

在通过节点集中节点的索引值获得待连接的节点后,只需在两个节点之间创建弹簧单元即可。需要说明的是,对于有限元软件Abaqus,在图形界面中创建的单元仅支持恒定弹簧刚度,如果需要创建非线性刚度的弹簧单元,则必须手动修改inp文件。并且,修改之后的inp文件只能直接进行求解,如果再次导入到Abaqus中,则弹簧的非线性刚度将会失效。此外,由于需要修改inp文件,因此这种方法不利于基于Abaqus二次开发进行交互处理。

为此,本文采用连接器单元来创建具有非线性刚度的弹簧。有限元软件Abaqus提供的连接器单元支持创建各种复杂的连接关系,如铰接、衬套、万向节等。在创建类似于弹簧的连接器单元时,需要在Interaction模块中将连接器截面(Connector Section)指定为轴向(Axial),如图4所示。

具有弹簧变形行为的连接器单元

由该截面定义的连接器单元仅有轴向自由度,而轴向方向由连接器单元两个端点构成的矢量来定义。由于该单元没有额外的转动自由度,因此该单元在本质上可以认为是Abaqus中的桁架(Truss)单元。两者的区别为桁架单元的变形由弹性模量E定义,而这里的连接器单元的变形行为由连接器的刚度定义。

在连接器截面的定义菜单中继续点击Continue即可定义连接器的变形行为。在定义时,选择行为选项(Behavior Options)为弹性(Elasticity),并设置弹性定义为非线性(Nonlinear),如图5。

连接器非线性刚度定义

此时,连接器的非线性刚度由连接器单元的载荷(F or M)-变形(U or UR)关系来指定。注意,连接器单元的变形以受拉为正,以受压为负,这与弹簧单元的定义正好相反。通过定义如图3所示的载荷-变形关系,即可建立具有非线性刚度的连接器单元。需要说明的是,由于这里定义了非线性刚度,因此在开展静力分析时,必须打开几何非线性(Nlgeom)选项,否则可能会得到错误的变形行为。

在完成连接器单元的截面定义后,只需通过Interaction模块的Connector Builder选项定义连接器两个端点的节点,并赋予该截面,即可完成非线性刚度的连接器单元创建。在本文中,上述过程将基于Abaqus的Python脚本自动实现,并批量创建所有滚子对应的连接器单元。

此外,脚本程序将针对每一个连接器单元自动创建时间历程输出,以输出连接器作用的轴向载荷(Connector Total Force,CTF1)。这里的轴向载荷即为轴承滚子承受的载荷。在计算完成后,基于本文提供的后处理脚本,可以批量获取每一个滚子所在区域的连接器载荷,从而得到轴承滚子的载荷分布情况。

关于圆柱滚子简化有限元模型快速建模方法的具体操作流程,可参见本文在附录提供的建模和后处理脚本,以及操作视频。

计算示例


 

考虑如图6所示的一个圆柱滚子轴承,假设滚子数量为50。

圆柱滚子轴承几何尺寸示意图

基于上述简化方法,将滚子采用连接器单元代替,因此仅划分内圈和外圈实体网格,滚子局部网格如图7所示。

圆柱滚子轴承局部网格示意图

为了便于加载,将轴承外圈的外表面节点全部施加固定约束,在轴承中心创建参考点,将参考点与轴承内圈的表面节点耦合。约束参考点除Y向平动自由度以外的全部自由度,并在参考点上施加沿Y向的集中载荷F,取值为1000 kN。采用上述方法批量建立连接器单元,得到圆柱滚子轴承简化有限元模型如图8所示。

圆柱滚子轴承简化有限元模型示意图

计算完成后,采用上述后处理脚本提取每个连接器上的载荷,并将同一个滚子上所有连接器的载荷累加,即可得到作用于单个滚子上的载荷。通过统计所有滚子上作用的载荷,可以得到圆柱滚子轴承的载荷分布如图9所示。

圆柱滚子轴承的载荷分布

在图9中,蓝色曲线代表将轴承外圈节点全部固定时的轴承载荷分布。作为对比,图中的橙色曲线代表将轴承外圈节点部分固定时的轴承载荷分布。可以看到,在径向载荷的作用下,轴承上部的滚子并不会受到载荷的作用,载荷将主要集中在下半部分。在这里,部分固定和完全固定轴承外圈节点可视为轴承周围结构的局部刚度对轴承载荷分布的影响。不难看出,当轴承连接的局部结构的刚度较小时,轴承载荷的分布范围更广,并且载荷峰值将会略微降低。通过本文提出的方法,建立考虑完整结构和简化轴承的有限元模型,可以考虑大载荷作用时结构刚度对于轴承载荷分布的影响。

模型局限性


 

现有模型在模拟真实轴承的载荷-变形行为时仍存在一定的局限性。如上述模型尚无法考虑轴承承受轴向力时的情况。在此类情况下,需要在外圈和内圈滚道之间建立梁单元,以模拟滚子的轴向刚度。此外,现有模型将外圈和内圈滚道节点直接通过具有非线性刚度的连接器单元连接。因此,不能实现轴承外圈和内圈的相对转动。一种可能的解决方法为将内圈节点与孤立节点连接,然后建立孤立节点与外圈节点之间的接触关系,由该方法可以在考虑滚子刚度的情况下,模拟轴承外圈和内圈之间的转动。

附录


 

   

   

   

圆柱滚子轴承简化有限元模型建模脚本(Python)

#-* - coding:UTF-8 -*-
#------------------------------------------------------------------
#文件名: Bearing_Connector_Generator
#程序用于批量生成轴承简化有限元模型所需要连接器单元
#当前程序假设轴承轴向方向为Z向
#作者: Tian Xu, Southwest Jiaotong University
#------------------------------------------------------------------

from abaqus import *
from abaqusConstants import *
from caeModules import *
import math

#--------------------------程序输入参数定义--------------------------
#模型名称
Model_Name='Main_Bearing'

#存放外圈滚道所有节点的集 合名
Outer_Ring_Node_Set_Name='Outer_Ring_Node'

#存放内圈滚道所有节点的集 合名
Inner_Ring_Node_Set_Name='Inner_Ring_Node'

#定义连接器载荷历程输出的分析步名称
Step_Name='Step-1'

#轴承滚子数量
Roller_Num=50

#第一个滚子的圆心坐标
Roller1_Pos_Coord_X=0.0
Roller1_Pos_Coord_Y=-653.0

#滚子刚度定义数据
Roller_Stiffness_Data_U=[-1.00.01.0]       #滚子刚度定义数据-变形值
Roller_Stiffness_Data_F=[-7.0e5,0.0,7.0e5]     #滚子刚度定义数据-载荷值

#-------------------------------------------------------------------


#-------------------生成连接器截面信息(滚子非线性刚度)-----------------
My_Model=mdb.models[Model_Name]

#创建连接器截面(连接器类型:Axial 活动自由度:U1)
My_Connector_SEC=My_Model.ConnectorSection(name='Bearing_Srping_SEC',
 translationalType=AXIAL)

#设置连接器非线性刚度
Stiffness_Table=tuple([(Roller_Stiffness_Data_F[i], 
 Roller_Stiffness_Data_U[i]) for i in range(len(Roller_Stiffness_Data_U))])
My_Stiffness_Data=connectorBehavior.ConnectorElasticity(components=(1, ), 
    behavior=NONLINEAR, table=Stiffness_Table)
My_Connector_SEC.setValues(behaviorOptions=(My_Stiffness_Data,))
#-------------------------------------------------------------------


#-------------------输出轴承内圈和外圈滚道所有节点的信息---------------
#获取存放外圈滚道所有节点的节点集对象
My_Outer_Ring_Node_Set=My_Model.rootAssembly.sets[Outer_Ring_Node_Set_Name]

#获取存放内圈滚道所有节点的节点集对象
My_Inner_Ring_Node_Set=My_Model.rootAssembly.sets[Inner_Ring_Node_Set_Name]

#创建列表存放节点坐标信息
Outer_Ring_Node_Set_Coord_X=[]
Outer_Ring_Node_Set_Coord_Y=[]
Outer_Ring_Node_Set_Coord_Z=[]

Inner_Ring_Node_Set_Coord_X=[]
Inner_Ring_Node_Set_Coord_Y=[]
Inner_Ring_Node_Set_Coord_Z=[]


#读取外圈滚道所有节点的节点号
Outer_Ring_Node_ID_List=[]
for node in My_Outer_Ring_Node_Set.nodes:
 Outer_Ring_Node_ID_List.append(node.label)
 coords=node.coordinates
 Outer_Ring_Node_Set_Coord_X.append(coords[0])
 Outer_Ring_Node_Set_Coord_Y.append(coords[1])
 Outer_Ring_Node_Set_Coord_Z.append(coords[2])

#读取内圈滚道所有节点的节点号
Inner_Ring_Node_ID_List=[]
for node in My_Inner_Ring_Node_Set.nodes:
 Inner_Ring_Node_ID_List.append(node.label)
 coords=node.coordinates
 Inner_Ring_Node_Set_Coord_X.append(coords[0])
 Inner_Ring_Node_Set_Coord_Y.append(coords[1])
 Inner_Ring_Node_Set_Coord_Z.append(coords[2])


#输出外圈和内圈滚道所有节点的节点号至屏幕
#print('Node Set '+Outer_Ring_Node_Set_Name+ ':')
#print(Outer_Ring_Node_ID_List)
#print('Node Set '+Inner_Ring_Node_Set_Name+ ':')
#print(Inner_Ring_Node_ID_List)
#-------------------------------------------------------------------


#------------------------建立滚子所在节点的节点集---------------------
#创建列表存放节点坐标信息(极坐标形式)
Outer_Ring_Node_Set_PolarCoord_R=[]
Outer_Ring_Node_Set_PolarCoord_Theta=[]
Outer_Ring_Node_Set_PolarCoord_Z=[]

Inner_Ring_Node_Set_PolarCoord_R=[]
Inner_Ring_Node_Set_PolarCoord_Theta=[]
Inner_Ring_Node_Set_PolarCoord_Z=[]

#计算外圈和内圈滚道所有节点的极坐标值
for i in range(len(Outer_Ring_Node_ID_List)):
 X=Outer_Ring_Node_Set_Coord_X[i]
 Y=Outer_Ring_Node_Set_Coord_Y[i]
 Z=Outer_Ring_Node_Set_Coord_Z[i]
#计算极径
 R=math.sqrt(X**2.0+Y**2.0)
#计算角度(从-pi到pi)
 Theta=math.atan2(Y,X)
#变换角度(从0到2pi)
if0.0<=Theta<=math.pi:
  Theta=Theta
else:
  Theta=Theta+2.0*math.pi
#存放计算结果
 Outer_Ring_Node_Set_PolarCoord_R.append(R)
 Outer_Ring_Node_Set_PolarCoord_Theta.append(Theta)
 Outer_Ring_Node_Set_PolarCoord_Z.append(Z)

for i in range(len(Inner_Ring_Node_ID_List)):
 X=Inner_Ring_Node_Set_Coord_X[i]
 Y=Inner_Ring_Node_Set_Coord_Y[i]
 Z=Inner_Ring_Node_Set_Coord_Z[i]
#计算极径
 R=math.sqrt(X**2.0+Y**2.0)
#计算角度(从-pi到pi)
 Theta=math.atan2(Y,X)
#变换角度(从0到2pi)
if0.0<=Theta<=math.pi:
  Theta=Theta
else:
  Theta=Theta+2.0*math.pi
#存放计算结果
 Inner_Ring_Node_Set_PolarCoord_R.append(R)
 Inner_Ring_Node_Set_PolarCoord_Theta.append(Theta)
 Inner_Ring_Node_Set_PolarCoord_Z.append(Z)

#格式化输出外圈和内圈全部节点的笛卡尔和极坐标信息至外部文件(程序调试用)
Outer_Ring_Node_Set_Info_File=open('Outer_Ring_Node_Set_Info.txt','w')
for index, cx, cy, cz, pr, ptheta, pz in zip(
 Outer_Ring_Node_ID_List,
 Outer_Ring_Node_Set_Coord_X,
 Outer_Ring_Node_Set_Coord_Y,
 Outer_Ring_Node_Set_Coord_Z,
 Outer_Ring_Node_Set_PolarCoord_R,
 Outer_Ring_Node_Set_PolarCoord_Theta,
 Outer_Ring_Node_Set_PolarCoord_Z):
 Outer_Ring_Node_Set_Info_File.write(
'%6d %.6f %.6f %.6f %.6f %.6f %.6f\n' %(index, cx, cy, cz, pr, ptheta, pz))
Outer_Ring_Node_Set_Info_File.close()

Inner_Ring_Node_Set_Info_File=open('Inner_Ring_Node_Set_Info.txt','w')
for index, cx, cy, cz, pr, ptheta, pz in zip(
 Inner_Ring_Node_ID_List,
 Inner_Ring_Node_Set_Coord_X,
 Inner_Ring_Node_Set_Coord_Y,
 Inner_Ring_Node_Set_Coord_Z,
 Inner_Ring_Node_Set_PolarCoord_R,
 Inner_Ring_Node_Set_PolarCoord_Theta,
 Inner_Ring_Node_Set_PolarCoord_Z):
 Inner_Ring_Node_Set_Info_File.write(
'%6d %.6f %.6f %.6f %.6f %.6f %.6f\n' %(index, cx, cy, cz, pr, ptheta, pz))
Inner_Ring_Node_Set_Info_File.close()


#筛选外圈滚子所在区域的节点
#计算第一个滚子所在位置的极角(从-pi到pi)
Roller1_Pos_Coord_Theta=math.atan2(Roller1_Pos_Coord_Y,Roller1_Pos_Coord_X)
#变换第一个滚子所在位置的极角(从0到2pi)
if0.0<=Roller1_Pos_Coord_Theta<=math.pi:
 Roller1_Pos_Coord_Theta=Roller1_Pos_Coord_Theta
else:
 Roller1_Pos_Coord_Theta=Roller1_Pos_Coord_Theta+2.0*math.pi

#计算筛选滚子节点所用的角度容差(滚子数量的100倍)
Pi_Val=math.pi
Angle_Tol=2.0*Pi_Val/(Roller_Num*1000.0)
for Roller_Index in range(1,Roller_Num+1):
#计算当前滚子所在位置的准确角度值
 Roller_Angle=0.0+2.0*Pi_Val/Roller_Num*(Roller_Index-1)
#初始化存放滚子所在区域节点的列表
 Outer_Ring_Roller_Node=[]
#计算考虑角度容差时角度筛选的上限和下限值
 Roller_Angle_Max_Lim=Roller_Angle+Angle_Tol
 Roller_Angle_Min_Lim=Roller_Angle-Angle_Tol
#基于角度筛选符合要求的节点
for i in range(len(Outer_Ring_Node_ID_List)):
#计算将节点变换到以第一个滚子为起始位置时的角度(局部坐标)
  Local_CSYS_PolarCoord_Theta=\
   Outer_Ring_Node_Set_PolarCoord_Theta[i]+2.0*math.pi-Roller1_Pos_Coord_Theta
if Local_CSYS_PolarCoord_Theta>=2.0*math.pi:
   Local_CSYS_PolarCoord_Theta=Local_CSYS_PolarCoord_Theta-2.0*math.pi
#筛选获得滚子所在区域的节点
if Roller_Angle_Min_Lim<=Local_CSYS_PolarCoord_Theta<=Roller_Angle_Max_Lim:
   Outer_Ring_Roller_Node.append(My_Outer_Ring_Node_Set.nodes[i])
#将节点列表转换为MeshNodeArray对象
 Outer_Ring_Roller_Node=mesh.MeshNodeArray(Outer_Ring_Roller_Node)
#创建新的节点集存放外圈滚子的节点
 My_Model.rootAssembly.Set(nodes=Outer_Ring_Roller_Node,
  name='Outer_Ring_Roller'+str(Roller_Index)+'_Node_Set')


#筛选内圈滚子所在区域的节点
for Roller_Index in range(1,Roller_Num+1):
#计算当前滚子所在位置的准确角度值
 Roller_Angle=0.0+2.0*Pi_Val/Roller_Num*(Roller_Index-1)
#初始化存放滚子所在区域节点的列表
 Inner_Ring_Roller_Node=[]
#计算考虑角度容差时角度筛选的上限和下限值
 Roller_Angle_Max_Lim=Roller_Angle+Angle_Tol
 Roller_Angle_Min_Lim=Roller_Angle-Angle_Tol
#基于角度筛选符合要求的节点
for i in range(len(Inner_Ring_Node_ID_List)):
#计算将节点变换到以第一个滚子为起始位置时的角度(局部坐标)
  Local_CSYS_PolarCoord_Theta=\
   Inner_Ring_Node_Set_PolarCoord_Theta[i]+2.0*math.pi-Roller1_Pos_Coord_Theta
if Local_CSYS_PolarCoord_Theta>=2.0*math.pi:
   Local_CSYS_PolarCoord_Theta=Local_CSYS_PolarCoord_Theta-2.0*math.pi
#筛选获得滚子所在区域的节点
if Roller_Angle_Min_Lim<=Local_CSYS_PolarCoord_Theta<=Roller_Angle_Max_Lim:
   Inner_Ring_Roller_Node.append(My_Inner_Ring_Node_Set.nodes[i])
#将节点列表转换为MeshNodeArray对象
 Inner_Ring_Roller_Node=mesh.MeshNodeArray(Inner_Ring_Roller_Node)
#创建新的节点集存放外圈滚子的节点
 My_Model.rootAssembly.Set(nodes=Inner_Ring_Roller_Node,
  name='Inner_Ring_Roller'+str(Roller_Index)+'_Node_Set')
#-------------------------------------------------------------------


#--------------------批量创建各个滚子的所有连接器单元-----------------
for Roller_Index in range(1,Roller_Num+1):
#处理滚子的外圈节点的索引
#读取待处理的节点集
 Processed_Set_Name='Outer_Ring_Roller'+str(Roller_Index)+'_Node_Set'
 My_Processed_Set=My_Model.rootAssembly.sets[Processed_Set_Name]
#初始化用于存放滚子外圈节点索引排序索引的列表
#获取节点列表
 My_Processed_Set_Nodes=My_Processed_Set.nodes
#构建索引和坐标z对应的列表
 temp_list=[]
for i in range(len(My_Processed_Set_Nodes)):
  z_coord=My_Processed_Set_Nodes[i].coordinates[2]
  temp_list.append((z_coord,i))
#基于x坐标进行排序
 temp_list.sort()
#提取按x坐标排序后的索引
 Outer_Ring_Arrange_Index_List=[item[1for item in temp_list]

#处理滚子的内圈节点的索引
#读取待处理的节点集
 Processed_Set_Name='Inner_Ring_Roller'+str(Roller_Index)+'_Node_Set'
 My_Processed_Set=My_Model.rootAssembly.sets[Processed_Set_Name]
#初始化用于存放滚子外圈节点索引排序索引的列表
#获取节点列表
 My_Processed_Set_Nodes=My_Processed_Set.nodes
#构建索引和坐标z对应的列表
 temp_list=[]
for i in range(len(My_Processed_Set_Nodes)):
  z_coord=My_Processed_Set_Nodes[i].coordinates[2]
  temp_list.append((z_coord,i))
#基于x坐标进行排序
 temp_list.sort()
#提取按x坐标排序后的索引
 Inner_Ring_Arrange_Index_List=[item[1for item in temp_list]

#批量生成当前滚子对应的所有连接器单元
for j in range(len(Inner_Ring_Arrange_Index_List)):
#读取当前处理的滚子对应的外圈和内圈滚动节点
  Processed_Set_Name='Outer_Ring_Roller'+str(Roller_Index)+'_Node_Set'
  Process_Outer_Node_Set=My_Model.rootAssembly.sets[Processed_Set_Name]
  Processed_Set_Name='Inner_Ring_Roller'+str(Roller_Index)+'_Node_Set'
  Process_Inner_Node_Set=My_Model.rootAssembly.sets[Processed_Set_Name]
#创建基准坐标系(坐标原点位于外圈节点 x轴指向内圈节点)
#origin和point1的输入必须是一个网格节点对象
  My_Datum_CSYS=My_Model.rootAssembly.DatumCsysByThreePoints(
   origin=Process_Outer_Node_Set.nodes[Outer_Ring_Arrange_Index_List[j]], 
   point1=Process_Inner_Node_Set.nodes[Inner_Ring_Arrange_Index_List[j]], 
   coordSysType=CARTESIAN)
  My_Datum_CSYS_ID=My_Model.rootAssembly.datums[My_Datum_CSYS.id]
#创建连接线
  My_Wire=My_Model.rootAssembly.WirePolyLine(
   points=((Process_Outer_Node_Set.nodes[Outer_Ring_Arrange_Index_List[j]], 
    Process_Inner_Node_Set.nodes[Inner_Ring_Arrange_Index_List[j]]), ), 
   mergeType=IMPRINT, 
   meshable=False)
#更改连接线名称
  My_Model.rootAssembly.features.changeKey(fromName=My_Wire.name,
   toName='Spring-'+str(Roller_Index)+'-'+str(j+1))
#存放连接线至几何集 合
  My_Edges=My_Model.rootAssembly.edges[0:1]
  My_Model.rootAssembly.Set(edges=My_Edges,
   name='Spring-'+str(Roller_Index)+'-'+str(j+1))
#赋予连接器截面至连接线
  My_Region=My_Model.rootAssembly.sets['Spring-'+str(Roller_Index)+'-'+str(j+1)]
  My_CSA=My_Model.rootAssembly.SectionAssignment(
   sectionName='Bearing_Srping_SEC', region=My_Region)
#赋予连接器方向
  My_Model.rootAssembly.ConnectorOrientation(
   region=My_CSA.getSet(), localCsys1=My_Datum_CSYS_ID)
#--------------------------------------------------------------------


#-----------------------创建连接器单元作用力的时间历程输出--------------
for Roller_Index in range(1,Roller_Num+1):
for j in range(len(Inner_Ring_Arrange_Index_List)):
#定义时间历程输出的节点集
  Hist_Output_Region_Name='Spring-'+str(Roller_Index)+'-'+str(j+1)
  Hist_Output_Region=My_Model.rootAssembly.sets[Hist_Output_Region_Name]
#创建各个连接器单元作用力(轴力)时间历程数据输出
  My_Model.HistoryOutputRequest(
   name=Hist_Output_Region_Name,
   createStepName=Step_Name,variables=('CTF1', ),
   region=Hist_Output_Region,sectionPoints=DEFAULT, rebar=EXCLUDE)
#--------------------------------------------------------------------



   

   

   

圆柱滚子轴承简化有限元模型连接器载荷提取脚本(Python)

#-* - coding:UTF-8 -*-
#------------------------------------------------------------------
#文件名: Bearing_Load_Extract
#程序用于批量提取轴承简化有限元模型中的轴承载荷(连接器载荷)
#程序与Bearing_Connector_Generator程序配合使用
#作者: Tian Xu, Southwest Jiaotong University
#------------------------------------------------------------------

from abaqus import *
from abaqusConstants import *
#from caeModules import *
from odbAccess import *
from abaqusConstants import *

#--------------------------程序输入参数定义--------------------------
#数据库文件名(.odb)
ODB_File_Name='Main_Bearing.odb'

#读取数据所在分析步名称
Step_Name='Step-1'

#轴承滚子数量
Roller_Num=50

#单个滚子使用的连接器数量
Roller_Spring_Num=14
#------------------------------------------------------------------


#---------------------------批量提取滚子载荷-------------------------
#打开数据库文件(以session对象的形式)
My_Odb=session.openOdb(name=ODB_File_Name)

#打开外部文件用于存放轴承载荷数据
Bearing_Load_File=open('Bearing_Load.txt','w')

#初始化存放轴承载荷数据的列表
Bearing_Load_List=[]

#批量读取连接器载荷
#初始化连接器编号
Connector_Index=0
for Roller_Index in range(1,Roller_Num+1):
for j in range(1,Roller_Spring_Num+1):
#累加连接器编号
  Connector_Index=Connector_Index+1
#构造当前连接器的时间历程输出名称
  Output_Hist_Name='Connector element total force: CTF1 PI: rootAssembly Element '+\
  str(Connector_Index)+' in ELSET SPRING-'+str(Roller_Index)+'-'+str(j)
#构造XYData的显示名称(不影响数据读取)
  XYData_Name='Bearing Load-'+str(Roller_Index)+'-'+str(j)
#通过XYData的形式读取时间历程输出数据
  My_Hist_Data=session.XYDataFromHistory(
   name=XYData_Name,odb=My_Odb,
   outputVariableName=Output_Hist_Name,steps=(Step_Name,))
#储存连接器载荷数据(CTF1)(分析步最后时刻的载荷)
  Bearing_Load_List.append(My_Hist_Data[-1][1])
#写入连接器载荷数据至文件
  Bearing_Load_File.write('%6d %6d %.6f\n' %(Roller_Index,j,My_Hist_Data[-1][1]))

#关闭文件
Bearing_Load_File.close()
#-------------------------------------------------------------------

   

   

   

圆柱滚子轴承非线性载荷-变形关系计算程序(MATLAB)

clear,clc
%--------------------------------------------------------------------------
%程序用于计算圆柱滚子轴承中滚子-滚道接触的载荷-变形关系
%--------------------------------------------------------------------------

%------------------------------参数输入-------------------------------------
L=113;                                        %滚子有效长度(mm)
D=63;                                         %滚子直径(mm)
Play_Val=0;                                   %轴承游隙(mm)                                   

%载荷-变形系数计算使用的常数(Brändlein et al. (1999))
C=2.65e4;
n1=0.9189;
n2=0;
n3=1.0811;
%--------------------------------------------------------------------------

%----------------------------计算载荷-变形关系------------------------------
%设置压缩变形量(mm)(零游隙)
Delta_Negative=linspace(10,0,21)';

%计算压缩变形量对应的滚子载荷(N)
Q_Negative=C*(L.^n1).*(D.^n2).*(Delta_Negative.^n3);

Delta_Negative=-1*Delta_Negative;
Q_Negative=-1*Q_Negative;

%设置拉伸变形量(mm)(零游隙)
Delta_Positive=10;

%计算拉伸变形量对应的滚子载荷(N)
Q_Positive=0;

%组装滚子的完整载荷-变形关系(零游隙)
Delta=[Delta_Negative;Delta_Positive];
Q=[Q_Negative;Q_Positive];

%计算滚子的完整载荷-变形关系(考虑游隙)
Delta=Delta-Play_Val;

%输出滚子的完整载荷-变形关系(考虑游隙)
Roller_Load_Disp_Data=[Q Delta];

%绘制滚子的载荷-变形关系
plot(Delta,Q,'-o');
hold on;scatter(0,0);
%--------------------------------------------------------------------------

     

     

     

轴承载荷分布绘制(MATLAB)

clear,clc
%--------------------------------------------------------------------------
%程序用于读取轴承载荷数据并绘制轴承载荷分布
%轴承载荷数据文件格式:滚子编号-单个滚子的连接器编号-连接器载荷
%--------------------------------------------------------------------------

%------------------------------参数输入-------------------------------------
%轴承滚子数量
Roller_Num=50;
%--------------------------------------------------------------------------

%------------------------读取并处理轴承载荷数据------------------------------
%读取载荷数据文件
Bearing_Load_Data=importdata('Bearing_Load.txt');

%获取单个轴承滚子使用的连接器数量
Roller_Spring_Num=size(Bearing_Load_Data,1)/Roller_Num;

%初始化数组存放轴承滚子全局载荷(单个滚子所有连接器载荷之和)
Roller_Global_Load=zeros(Roller_Num,1);

%循环读取轴承载荷数据
Data_Pair_Num=0;
for Roller_Index=1:Roller_Num
    k=0;
    temp_Load_Data=zeros(Roller_Spring_Num,1);
    for Spring_Index=1:Roller_Spring_Num
        k=k+1;
        Data_Pair_Num=Data_Pair_Num+1;
        temp_Load_Data(k,1)=Bearing_Load_Data(Data_Pair_Num,3);
    end
    Roller_Global_Load(Roller_Index)=sum(temp_Load_Data);
    field_name = ['Roller', num2str(Roller_Index)];
    Bearing_Data_Struct.(field_name)=temp_Load_Data;
end


%绘制滚子全局载荷分布
Theta=linspace(0,2*pi,Roller_Num)';
plot(Theta,Roller_Global_Load,'-o');
%--------------------------------------------------------------------------


来源:FEM and FEA
ACTAbaqusSTEPS非线性二次开发MATLABpython理论传动试验
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2025-12-13
最近编辑:8月前
追逐繁星的Mono
硕士 签名征集中
获赞 59粉丝 143文章 69课程 0
点赞
收藏
作者推荐

基于Abaqus求解考虑裂纹面接触的裂尖应力强度因子的可行性分析

对于承受滚动接触载荷的含裂纹结构,如车轮、轴承等,由于压缩载荷的作用,裂纹面有可能会出现闭合的情况,为了准确考虑裂纹面闭合对于疲劳裂纹扩展的影响,往往需要在考虑裂纹面接触的情况下求解裂纹尖端的应力强度因子。通用有限元软件Abaqus具备求解含裂纹结构在任意载荷作用下的应力强度因子K、J积分和T应力等断裂参量的功能。然而,一些研究表明,Abaqus无法准确求解考虑裂纹面接触时裂纹尖端的应力强度因子。为此,本文以承受滚动接触载荷作用的含斜裂纹平板为例,分别基于有限元软件Abaqus、断裂分析软件Franc3D在考虑和不考虑裂纹面接触的情况下求解裂纹尖端的应力强度因子,并分析了在此类情况下采用Abaqus准确求解裂尖应力强度因子的可行性。有限元建模 模型简介考虑长度为30 mm,高度和厚度均为10 mm的平板,在平板中部存在一条长度为4 mm的穿透型斜裂纹,如图1所示。假设平板为线弹性材料,材料的弹性模量E为200 GPa,泊松比ν为0.3。 图1 含斜裂纹平板示意图该平板受到滚动接触载荷的作用,当滚动接触载荷移动到斜裂纹上方所在的区域时,裂纹面将会产生接触。在本例中,将该滚动接触载荷简化为Hertz接触。因此,作用在平板上的接触压力p(x)可表示为: 式中,p0为接触中心的最大接触压力,本例中取为100 MPa;a为接触斑半径,取为0.5mm。载荷的移动速度v取为30 mm/s。下面,需要计算在该滚动接触载荷作用下,裂纹尖端应力强度因子的变化。 基于有限元软件Abaqus的建模方法当采用有限元软件Abaqus进行建模时,需建立含有裂纹的平板有限元模型,并通过内置的围线积分法求解裂纹体的应力强度因子。为保证计算精度,在平板表面和裂纹尖端区域采用细密网格进行划分,网格尺寸分别取为0.2 mm和0.1 mm,对于远离平板表面和裂纹尖端的区域,则采用较为稀疏的网格划分。为模拟裂纹面间的接触行为,本文在上、下裂纹面之间建立自接触(Self contact),并取裂纹面间的摩擦系数为0.1。约束平板底面的全部位移自由度,并通过用户子程序DLOAD施加滚动接触载荷。最终建立的有限元模型如图2所示。图2 含斜裂纹平板示意图(有限元软件Abaqus) 基于断裂分析软件Franc3D的建模方法当采用断裂分析软件Franc3D求解应力强度因子时,需首先在有限元软件Abaqus中建立不含裂纹的平板模型,并设置好载荷和边界条件。然后,将不含裂纹的有限元模型导入到Franc3D中,并在Franc3D中植入裂纹和设置裂纹面接触,并递交有限元软件Abaqus求解。最后,Franc3D将读取Abaqus的结果文件,以计算裂纹尖端的应力强度因子。在Abaqus中建立的不含裂纹的平板有限元模型如图3所示,图中不同颜色 区域具有相同的材料属性,但材料名称不同,以便在导入Franc3D时区分裂纹重划分区域。图3 不含裂纹的平板有限元模型(断裂分析软件Franc3D)待定义完成后,将上述模型导入到断裂分析软件Franc3D中。需要注意的是,一般情况下,Franc3D会将含有边界条件的单元面或节点设定为保留区域。此时,在植入裂纹或者重划分裂纹的过程中,保留区域的节点布置不会被改变,能够更加方便且精确地将不含裂纹的有限元模型的边界条件映射到含有裂纹的有限元模型的边界条件。如果没有将含有边界条件的单元面或节点设定为保留区域,则这些区域在网格重划分之后可能发生改变,此时Franc3D需要根据原有模型的边界条件,通过外插来重新计算重划分之后模型的边界条件。需要注意的是,无论是否设定保留区域,Franc3D都会执行边界条件的映射操作,但通过设定保留区域,可以尽可能保证映射之后的边界条件仍然是准确的。但是,在本例中,裂纹重划分区域恰好位于边界条件的施加区域内,在植入裂纹的过程中,必然会破坏原有的节点分布。因此,不能将图3中黄色 区域的上表面设定为保留区域,图4给出了在Franc3D中取消选择保留的边界条件表面的设置,图中Load_Surf即为滚动接触载荷的施加表面。图4 取消选择保留的边界条件表面然后,在Franc3D中通过预制的裂纹模版植入穿透型斜裂纹,Franc3D将自动完成裂纹网格的重划分工作。待裂纹网格重划分完成后,在分析菜单中选择执行静态裂纹分析,并勾选定义裂纹面接触,如图5所示。为了与采用Abaqus分析时的模型一致,取接触类型同样为自接触,并且摩擦系数为0.1。图5 裂纹面接触定义待定义完成后,即可递交Abaqus执行计算。需要注意的是,与常规计算不同是,本文在施加移动载荷时调用了用户子程序DLOAD,因此在执行计算之前必须指定定义有DLOAD子程序的Fortran文件。一种指定方法为在图6所示的界面中选择查看/编辑命令,并在调用Abaqus的命令行中增加对子程序文件的引用。另一种方法为在图6所示的界面中勾选写入文件但不运行分析,此时Franc3D将会写入含斜裂纹平板的求解文件(工作文件名+_full.inp),但不会递交Abaqus计算。此时用户需要手动递交Abaqus进行计算。需要注意的是,当使用该方法进行计算时,Franc3D无法直接计算应力强度因子,而是需要用户在计算完成后,在Abaqus后处理界面中运行与求解文件同时生成的writeDtpFile.py脚本文件。该脚本文件将读取Abaqus的数据文件(.odb格式),以提取裂尖区域的位移等参量,并输出为dtp文件。随后,通过在Franc3D中读取该文件,即可计算应力强度因子。图6 生成求解文件第二种方法的优点为由于用户可以手动提交Franc3D生成的inp文件,因此对于Franc3D不支持的关键字类型,可以在提交计算之前修改该inp文件,加入Franc3D不支持的关键字类型,然后再提交计算。基于这种方法,理论上可以实现任意复杂载荷条件下的应力强度因子计算。因此,本文采用第二种方法来计算裂纹尖端的应力强度因子,具体的计算流程将在下一节中介绍。应力强度因子提取方法 基于有限元软件Abaqus的提取方法当采用有限元软件Abaqus进行求解时,可以使用Abaqus内置的围线积分法求解并提取裂纹前缘的应力强度因子。此时,需要在相互作用模块中通过指定裂纹前缘节点和裂纹扩展方向以定义裂纹,并在分析步模块中以时间历程变量的形式定义应力强度因子输出,如图7所示。图7 应力强度因子输出定义待计算完成后,裂纹前缘的应力强度因子和节点坐标值将以时间历程变量的形式给出。关于在有限元软件Abaqus中提取应力强度因子的流程,这里不再赘述。 基于断裂分析软件Franc3D的提取方法当采用Franc3D进行计算时,需要首先提交Franc3D生成的含斜裂纹平板模型的求解文件。需要注意的是,Franc3D会生成三个inp文件,其中以_GLOBAL和_LOCAL结尾的inp文件分别代表重划分区域以外和重划分区域的网格文件,只有以_full结尾的inp文件才是完整的求解文件。将该求解文件提交Abaqus计算,以生成结果文件(.odb格式)。然后,在Abaqus后处理界面中运行随inp文件同时生成的writeDtpFile.py脚本文件。在本例中,其对应的writeDtpFile.py脚本文件内容如下所示。from odbAccess import *import os# analysis specific datadirectory = &#39;.&#39;file_name = &#39;Inclined_Crack_CT_full&#39;node_set = &#39;LOCAL_CRACKED_NODES&#39;elem_set = &#39;TEMPLATE_ELEMENTS&#39;do_all_frames = Truedo_nodal_strain = Falsedo_integration_sed = Falsedo_integration_stress = False# function to output the data for one nodal field valuedef OutputNodeValues(fw,dtp_label,frame,odb_key,node_set): print &gt;&gt; fw, dtp_label field_output = frame.fieldOutputs[odb_key] if node_set != None: field_output = field_output.getSubset(region=node_set) if len(field_output.values) == 0: return data_item = field_output.values[0].data if field_output.values[0].type == SCALAR: for field_value in field_output.values: data = float(field_value.data) if data != 0.0: nid = field_value.nodeLabel print &gt;&gt; fw, nid, float(data) elif len(data_item) == 3: for field_value in field_output.values: nid = field_value.nodeLabel data = field_value.data print &gt;&gt; fw,nid,float(data[0]),float(data[1]),float(data[2])# function to output the data for one element value at the nodesdef OutputElemAtNodeValues(fw,dtp_label,frame,odb_key,elems,elem_set): print &gt;&gt; fw, dtp_label field_output = frame.fieldOutputs[odb_key] if elem_set != None: field = field_output.getSubset(position=ELEMENT_NODAL,region=elem_set) else: field = field_output.getSubset(position=ELEMENT_NODAL) nc = 0 el_id = 0 for field_value in field.values: elem = field_value.elementLabel if el_id != elem: el_id = elem nc = 0 else: nc += 1 conn = elems[elem] data = field_value.data if len(data) &gt;= 6: print &gt;&gt; fw,elem,conn[nc],float(data[0]),float(data[1]),float(data[2]), \ float(data[3]),float(data[4]),float(data[5])# function to output the data for one element value at the gauss pointsdef OutputElemAtGpValues(fw,dtp_label,frame,odb_key,elem_set): print &gt;&gt; fw, dtp_label field_output = frame.fieldOutputs[odb_key] if elem_set != None: field = field_output.getSubset(position=INTEGRATION_POINT,region=elem_set) else: field = field_output.getSubset(position=INTEGRATION_POINT) el_id = 0 ip = 0 for field_value in field.values: elem = field_value.elementLabel if el_id != elem: el_id = elem ip = 0 else: ip += 1 data = field_value.data if field_value.type == SCALAR: print &gt;&gt; fw, elem,ip,float(data) elif len(data) &gt;= 6: print &gt;&gt; fw, elem,ip,float(data[0]),float(data[1]),float(data[2]), \ float(data[3]),float(data[4]),float(data[5])# function to find element connectivitydef GetElemConn(assembly): elems = {} for name, instance in assembly.instances.items(): num_elem = len(instance.elements) for element in instance.elements: elems[element.label] = element.connectivity return elems# function to check for a uniform temperaturedef SameTemp(frame,odb_key): temp = None for field_out in frame.fieldOutputs[odb_key].values: if temp == None: temp = field_out.data else: if field_out.data != temp: return False return True# function to process one framedef DoFrame(frame): # create a dictionary that maps the first word of a field output # to the full keys key_map = {} for key in frame.fieldOutputs.keys(): v = key.split() key_map[v[0]] = key# print &gt;&gt; fw, &#39;STEPTIME&#39;, frame.description print &gt;&gt; fw, &#39;TIME&#39;, frame.frameValue # output the data for specific types of data if key_map.has_key(&#39;U&#39;): OutputNodeValues(fw,&#39;DISPLACEMENT&#39;,frame,key_map[&#39;U&#39;],node_set) if key_map.has_key(&#39;NT11&#39;): if SameTemp(frame,key_map[&#39;NT11&#39;]): fT = frame.fieldOutputs[&#39;NT11&#39;].values[0].data print &gt;&gt; fw, &#39;TEMPERATURE&#39; print &gt;&gt; fw, &#39;ALL &#39;, fT else: OutputNodeValues(fw,&#39;TEMPERATURE&#39;,frame,key_map[&#39;NT11&#39;],node_set) if key_map.has_key(&#39;CPRESS&#39;): OutputNodeValues(fw,&#39;PRESSURE&#39;,frame,key_map[&#39;CPRESS&#39;],node_set) if key_map.has_key(&#39;CSHEAR1&#39;): OutputNodeValues(fw,&#39;SHEAR STRESS 1&#39;,frame,key_map[&#39;CSHEAR1&#39;],node_set) if key_map.has_key(&#39;CSHEAR2&#39;): OutputNodeValues(fw,&#39;SHEAR STRESS 2&#39;,frame,key_map[&#39;CSHEAR2&#39;],node_set) if do_nodal_strain: if key_map.has_key(&#39;E&#39;): OutputElemAtNodeValues(fw,&#39;STRAIN ELEMENT NODAL&#39;,frame,key_map[&#39;E&#39;],elems,elem_set) if key_map.has_key(&#39;EE&#39;): OutputElemAtNodeValues(fw,&#39;ELASTIC STRAIN ELEMENT NODAL&#39;,frame,key_map[&#39;EE&#39;],elems,elem_set) if key_map.has_key(&#39;THE&#39;): OutputElemAtNodeValues(fw,&#39;THERMAL STRAIN ELEMENT NODAL&#39;,frame,key_map[&#39;THE&#39;],elems,elem_set) if do_integration_sed: if key_map.has_key(&#39;SENER&#39;): OutputElemAtGpValues(fw,&#39;ELASTIC_STRAIN_ENERGY_DENSITY ELEMENT INTEGRATION POINTS&#39;, frame,key_map[&#39;SENER&#39;],elem_set) if key_map.has_key(&#39;PENER&#39;): OutputElemAtGpValues(fw,&#39;PLASTIC_STRAIN_ENERGY_DENSITY ELEMENT INTEGRATION POINTS&#39;, frame,key_map[&#39;PENER&#39;],elem_set) if do_integration_stress: if key_map.has_key(&#39;S&#39;): OutputElemAtGpValues(fw,&#39;STRESS ELEMENT INTEGRATION POINTS&#39;, frame,key_map[&#39;S&#39;],elem_set)def GetFrameLabel(frame): # extract the frame &#39;description&#39; and get the increment desc = odb.steps[step_name].frames[i].description di = desc.split() if di[0] == &#39;Increment&#39;: ilabel = di[1].split(&#39;:&#39;) return ilabel[0] else: return None# process the fileos.chdir(directory)odb = openOdb(&#39;%s.odb&#39; % (file_name,))fw = open(&#39;%s.dtp&#39; % (file_name,),&#39;w&#39;)if do_nodal_strain or do_integration_sed or do_integration_stress: elems = GetElemConn(odb.rootAssembly)if odb.rootAssembly.instances[&#39;PART-1-1&#39;].nodeSets.has_key(node_set): node_set = odb.rootAssembly.instances[&#39;PART-1-1&#39;].nodeSets[node_set]else: node_set = Noneif odb.rootAssembly.instances[&#39;PART-1-1&#39;].elementSets.has_key(elem_set): elem_set = odb.rootAssembly.instances[&#39;PART-1-1&#39;].elementSets[elem_set]else: elem_set = None# loop through the load stepsprint &gt;&gt; fw, &#39;NUM STEP&#39;, len(odb.steps.keys())for step_name in odb.steps.keys(): step = odb.steps[step_name] step_num = step.number print &gt;&gt; fw, &#39;LOADSTEP&#39;, step_num# print &gt;&gt; fw, &#39;TIMEPERIOD&#39;, step.timePeriod num_frames = len(odb.steps[step_name].frames) if num_frames == 1: start_frame = 0 end_frame = 0 else: start_frame = 0 end_frame = num_frames - 1 if not do_nodal_strain: start_frame += 1 if not do_all_frames: start_frame = num_frames - 1 end_frame = start_frame if end_frame &gt; start_frame:# substep_cnt = 1 for i in xrange(start_frame,end_frame+1): ilab = GetFrameLabel(odb.steps[step_name].frames[i]) if ilab != None: print &gt;&gt; fw,&#39;SUBSTEP&#39;,ilab else: print &gt;&gt; fw,&#39;SUBSTEP&#39;,i# print &gt;&gt; fw,&#39;SUBSTEP&#39;,substep_cnt DoFrame(odb.steps[step_name].frames[i])# substep_cnt += 1 else: DoFrame(odb.steps[step_name].frames[num_frames-1])fw.close() 可以看到,该脚本文件主要是在Abaqus后处理界面中基于Python语言读取Abaqus生成的脚本文件,并将裂纹尖端节点的位移等信息写入到dtp文件。Franc3D可以读取dtp文件中的信息,并基于这些信息,采用M积分法或其他数值方法计算裂纹尖端的应力强度因子等断裂参量。在该脚本文件中,directory代表数据文件所在的文件路径,file_name代表数据文件名称,node_set为Franc3D自动创建的节点集,存放了整个裂纹重划分区域的节点,elem_set为Franc3D自动创建的单元集,存放了裂纹前缘模版内的单元,如图8中的红色 区域所示。图8 裂纹前缘模版内的单元需要注意的是,如果直接运行该脚本文件,则生成的dpt文件中只会包含结果文件中最后一个增量步的信息。如果需要计算每个增量步下应力强度因子,以输出应力强度因子的时程曲线,则需要将逻辑变量do_all_frames的取值更改为True,即输出每一个增量步下的信息。待提取完成后,在Franc3D中重新打开Franc3D的项目文件(.fdb格式),并点击文件菜单中的读取结果选项,即可读取脚本文件生成的dpt文件,以计算裂纹前缘的应力强度因子,如图9所示。图9 dpt文件读取计算结果分析 不考虑裂纹面接触的情况通过取消裂纹面间定义的自接触,图10给出了不考虑裂纹面接触时,由Abaqus和Franc3D计算得到的裂纹前缘中部的I型应力强度因子和II型应力强度因子的变化曲线。图10 应力强度因子变化曲线(不考虑裂纹面接触)从图中可以看到,由Abaqus计算得到的I型应力强度因子KI和II型应力强度因子KII与Franc3D给出的计算结果完全吻合,这证明在不考虑裂纹面接触的情况下,基于Abaqus能够准确计算裂纹体的应力强度因子,这符合本文的预期。 考虑裂纹面接触的情况图11给出了当考虑裂纹面接触时,由Abaqus和Franc3D给出的I型和II型应力强度因子的变化曲线。图11 应力强度因子变化曲线(考虑裂纹面接触)从图中可以看到,在考虑裂纹面接触的情况下,I型和II型应力强度因子的峰值要明显偏低,这意味着在不考虑裂纹面接触的情况下,将给出偏于危险的预测结果。同时,由Abaqus给出的II型应力强度因子变化曲线与Franc3D给出的结果较为吻合,而I型应力强度因子的预测结果则存在较大偏差。为了分析产生偏差的原因,图12给出了在考虑裂纹面接触的情况下,由Abaqus计算得到的不同围线上I型应力强度因子的变化曲线。从图中可以看到,在计算初期,不同围线上的I型应力强度因子非常吻合,这是因为采用围线积分法计算应力强度因子时,应力强度因子的计算值并不依赖于积分路径。然而,当滚动载荷靠近裂纹时,不同围线上的I型应力强度因子出现了明显的发散,对比图11可以看到,这正好对应了Abaqus与Franc3D计算结果存在明显差异的区域。需要注意的是,图11是通过将不同围线上的计算结果取平均值获得的。图12 不同围线上的I型应力强度因子变化曲线(考虑裂纹面接触)理论上来说,当裂纹面受到压应力作用而产生闭合时,裂纹尖端的I型应力强度因子应该为零。从图12中可以看到,应力强度因子出现不收敛的起始位置恰好出现在裂纹面产生闭合时。因此,本文认为,Abaqus和Franc3D的计算结果存在差异的原因为:Abaqus在采用围线积分法计算应力强度因子时,并未考虑裂纹面间的接触力对应力强度因子的影响。当滚动载荷远离裂纹尖端时,裂纹面不存在接触力,因此Abaqus与Franc3D的计算结果吻合;而随着滚动载荷靠近裂纹尖端,裂纹面将逐渐接触,并产生接触应力,对于不同围线形成的封闭区域,作用在裂纹面上的接触力显然并不相同,Abaqus并未考虑裂纹面间接触力的影响,导致不同围线上的应力强度因子出现了不收敛的情况。事实上,在采用围线积分法求解应力强度因子时,通过在围线积分中引入考虑裂纹面接触应力的修正项,可以在考虑裂纹面接触的情况下准确计算裂纹尖端的应力强度因子,但似乎在笔者使用的Abaqus 2020版本以及更高的版本,目前仍未解决该问题。相比之下,由于Franc3D能够考虑裂纹面接触对应力强度因子的影响,因此能够给出更为精确的结果。需要注意的是,从图11中可以看到,当裂纹闭合时,由Franc3D给出的结果要略小于零,这可能是由于Franc3D默认的裂纹模版中,裂尖环形单元的层数较少,导致裂纹尖端区域的接触应力存在较大误差,导致应力强度因子的计算结果不准确,如果增加裂尖环形单元的层数,预计计算结果将更接近零。此外,在图11中,由Abaqus和Franc3D给出的II型应力强度因子曲线非常吻合,这主要是由于在此种载荷条件下,裂纹面间的摩擦剪切应力较小,因此裂纹面接触对II型应力强度因子的影响不明显。当裂纹面间摩擦剪切应力较大时,不同围线上的II型应力强度因子仍然会出现发散的现象。总结 本文以受滚动接触载荷作用的含斜裂纹平板为例,分别基于有限元软件Abaqus和断裂分析软件Franc3D求解了裂纹尖端的应力强度因子变化曲线。研究发现,当不考虑裂纹面接触时,Abaqus和Franc3D的计算结果吻合;当考虑裂纹面接触时,Abaqus和Franc3D的计算结果不吻合,Abaqus给出的不同围线上的应力强度因子出现了发散现象,这表明在存在裂纹面接触的情况下,现有版本的Abaqus(Abaqus 2020)不能准确计算裂纹尖端的应力强度因子。来源:FEM and FEA

未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈