基于Abaqus的自动化仿真工具研究
1 前言
Abaqus是一套功能强大的工程模拟的有限元软件,其解决问题的范围从相对简单的线性分析到许多复杂的非线性问题。为了提高仿真效率小编对Abaqus的二次开发进行了研究,基于Abaqus的批处理技术开发了面向某设备的自动化仿真工具,进行了仿真模型的参数化建立、自动装配、网格自动划分、载荷自动添加、边界条件的自动添加、仿真结果自动提取及仿真报告自动生成,最终开发了基于Abaqus的无人值守、全自动、快速专家仿真工具。
2 Abaqus二次开发
2.1 Abaqus简介
ABAQUS 是一套功能强大的工程模拟的有限元软件,其解决问题的范围从相对简单的线性分析到许多复杂的非线性问题。 ABAQUS 包括一个丰富的、可模拟任意几何形状的单元库。并拥有各种类型的材料模型库,可以模拟典型工程材料的性能,其中包括金属、橡胶、高分子材料、复合材料、钢筋混凝土、可压缩超弹性泡沫材料以及土壤和岩石等地质材料。作为通用的模拟工具, ABAQUS 除了能解决大量结构(应力 / 位移)问题,还可以模拟其他工程领域的许多问题,例如热传导、质量扩散、热电耦合分析、声学分析、岩土力学分析(流体渗透 / 应力耦合分析)及压电介质分析。
2.2 开发语言
从CAE软件二次开发的角度而言,区别于ANSYS等其他CAE软件,Abaqus是个很容易开发的软件。Abaqus在运行的时候,会自动生成大部分操作的python语言的.rpy操作日志文件,这个文件一般在如下的路径中。
\SIMULIA\Temp
这个文件是对Abaqus进而二次开发的强大武器,要熟悉指定操作对应的脚本需要每操作一步就查看文件中对应的脚本。
刚才说到abaqus二次开发用到的编程语言是python,可能好多同学望而却步了,毕竟能想到搞这个软件开发的大多数还是非计算机专业的同学。这里小编要给大家一颗定心丸,不懂编程也不意味着开发不了abaqus。abaqus用到的那些python语句基本都是软件内部定义的,大家完全可以把它当成一种标记型的语言理解就好,只要能将具体的脚本和对应的操作对应起来就可以实现abaqus的二次开发。
总结一下,abaqus的编程语言是python,只要看懂abaqus记录操作的.rpy文件就可以进行abaqus的二次开发。
3 关键技术
3.1 前处理脚本实现
前处理包括参数化建模、自动划分网格、添加约束载荷等。下面给出了我自己封装的参数化建模、装配模型、划分网格、添加约束载荷及添加分析步的脚本,有一说一都是一步步操作然后查看.rpy文件生成的对应的脚本整理的。过程虽然很辛苦,但是疗效还是不错的。
def parametric_modeling():
p = mdb.models['Model-1'].parts['Part-1']
session.viewports['Viewport: 1'].setValues(displayedObject=p)
p = mdb.models['Model-1'].parts['Part-1']
s = p.features['Shell planar-1'].sketch
mdb.models['Model-1'].ConstrainedSketch(name='__edit__', objectToCopy=s)
s1 = mdb.models['Model-1'].sketches['__edit__']
g, v, d, c = s1.geometry, s1.vertices, s1.dimensions, s1.constraints
s1.setPrimaryObject(option=SUPERIMPOSE)
p.projectReferencesOntoSketch(sketch=s1,upToFeature=p.features['Shell planar-1'], filter=COPLANAR_EDGES)
#--------------------删除旧约束------------------------------------
s1.delete(objectList=(d[1],))
s1.delete(objectList=(d[0],))
s1.delete(objectList=(d[3],))
s1.delete(objectList=(d[4],))
s1.delete(objectList=(d[2],))
s1.delete(objectList=(d[5],))
s1.delete(objectList=(d[13],))
s1.delete(objectList=(d[6],))
s1.delete(objectList=(d[7],))
s1.delete(objectList=(d[8],))
s1.delete(objectList=(d[9],))
s1.delete(objectList=(d[10],))
s1.delete(objectList=(d[11],))
s1.delete(objectList=(d[12],))
#--------------------添加新的约束------------------------------------
s1.RadialDimension(curve=g[4], textPoint=(123.286316143786, 0.258663984079395), radius=simuinfo[""]["R4"]["value"] )
s1.DistanceDimension(entity1=v[2], entity2=g[2], textPoint=(69.2119979858398, -14.4988307952881), value=simuinfo[""]["Distan1"]["value"])
s1.RadialDimension(curve=g[5], textPoint=(119.733726501465, 1.4805303812027), radius=simuinfo[""]["R3"]["value"])
s1.HorizontalDimension(vertex1=v[5], vertex2=v[2], textPoint=(122.07674407959, -0.124851405620575), value=simuinfo[""]["h1"]["value"])
s1.VerticalDimension(vertex1=v[5], vertex2=v[2], textPoint=(120.597770690918, 0.413793683052063), value=simuinfo[""]["h2"]["value"])
s1.DistanceDimension(entity1=g[7], entity2=g[3], textPoint=(126.956832885742, 0.931050896644592), value=simuinfo[""]["H"]["value"])
s1.RadialDimension(curve=g[8], textPoint=(123.122192382813, 2.98901391029358), radius=simuinfo[""]["R1"]["value"])
s1.RadialDimension(curve=g[9], textPoint=(121.781723022461, 2.07928419113159), radius=simuinfo[""]["R2"]["value"])
s1.AngularDimension(line1=g[10], line2=g[11], textPoint=(122.132789611816, 2.32126188278198), value=simuinfo[""]["jiao1"]["value"])
s1.DistanceDimension(entity1=g[13], entity2=g[6], textPoint=(120.765113830566, 0.700745701789856), value=simuinfo[""]["t"]["value"])
s1.AngularDimension(line1=g[17], line2=g[7], textPoint=(124.364456176758, 2.09015274047852), value=simuinfo[""]["jiao2"]["value"])
s1.RadialDimension(curve=g[18], textPoint=(123.774154663086, 2.06717729568481), radius=simuinfo[""]["c1"]["value"])
s1.RadialDimension(curve=g[19], textPoint=(123.522178649902, 1.81678450107574), radius=simuinfo[""]["c2"]["value"])
s1.DistanceDimension(entity1=v[5], entity2=g[20], textPoint=(123.31396484375, 1.17441308498383), value=simuinfo[""]["h"]["value"])
#--------------------------特征重新生成-----------------------------------------------------------------------
s1.unsetPrimaryObject()
p = mdb.models['Model-1'].parts['Part-1']
p.features['Shell planar-1'].setValues(sketch=s1)
del mdb.models['Model-1'].sketches['__edit__']
p = mdb.models['Model-1'].parts['Part-1']
p.regenerate()
#-------------------------------------------------------------------------------------------
p1 = mdb.models['Model-1'].parts['Part-2']
session.viewports['Viewport: 1'].setValues(displayedObject=p1)
p = mdb.models['Model-1'].parts['Part-2']
s = p.features['Shell planar-1'].sketch
mdb.models['Model-1'].ConstrainedSketch(name='__edit__', objectToCopy=s)
s2 = mdb.models['Model-1'].sketches['__edit__']
g, v, d, c = s2.geometry, s2.vertices, s2.dimensions, s2.constraints
s2.setPrimaryObject(option=SUPERIMPOSE)
p.projectReferencesOntoSketch(sketch=s2, upToFeature=p.features['Shell planar-1'], filter=COPLANAR_EDGES)
#--------------------------------删除旧约束----------------------------------------
s2.delete(objectList=(d[2],))#删除轴心距离
s2.delete(objectList=(d[3],))#删除环高
s2.delete(objectList=(d[1],))#删除块厚
s2.delete(objectList=(d[0],))#删除块宽
#-------------------------------添加新的约束------------------------------------------
s2.ObliqueDimension(vertex1=v[3], vertex2=v[0], textPoint=(122.24291229248, 5.57848644256592), value=simuinfo[""]["h1_yk"]["value"])
s2.ObliqueDimension(vertex1=v[0], vertex2=v[1], textPoint=(118.957969665527, 2.78910183906555), value=simuinfo[""]["t_yk"]["value"])
s2.DistanceDimension(entity1=g[6], entity2=g[2], textPoint=(32.0289764404297, 28.8339805603027), value=simuinfo[""]["distan"]["value"])#添加轴心距离
s2.DistanceDimension(entity1=g[5], entity2=g[3], textPoint=(128.655029296875, 1.35438060760498), value=simuinfo[""]["H_yk"]["value"])#添加环高度
#--------------------------------特征重新生成-------------------------------------------
s2.unsetPrimaryObject()
p = mdb.models['Model-1'].parts['Part-2']
p.features['Shell planar-1'].setValues(sketch=s2)
del mdb.models['Model-1'].sketches['__edit__']
p = mdb.models['Model-1'].parts['Part-2']
p.regenerate()
#----------创建材料---------------
def creat_material_and_section():
session.viewports['Viewport: 1'].partDisplay.setValues(sectionAssignments=ON, engineeringFeatures=ON)
session.viewports['Viewport: 1'].partDisplay.geometryOptions.setValues(referenceRepresentation=OFF)
#--------------------------创建两种材料---------------------------------
mdb.models['Model-1'].Material(name='Material-1')
mdb.models['Model-1'].materials['Material-1'].Elastic(table=((simuinfo["material_paras_dic"]["material1"]["yong_modulus"], simuinfo["material_paras_dic"]["material1"]["poisson_ratio"]),))
mdb.models['Model-1'].Material(name='Material-2')
mdb.models['Model-1'].materials['Material-2'].Elastic(table=((simuinfo["material_paras_dic"]["material2"]["yong_modulus"], simuinfo["material_paras_dic"]["material2"]["poisson_ratio"]),))
#---------------------------创建截面属性--------------------------------
mdb.models['Model-1'].HomogeneousSolidSection(name='Section-1', material='Material-1', thickness=None)
mdb.models['Model-1'].HomogeneousSolidSection(name='Section-2', material='Material-2', thickness=None)
#---------------------------指派截面属性--------------------------------
p = mdb.models['Model-1'].parts['Part-1']
session.viewports['Viewport: 1'].setValues(displayedObject=p)
p = mdb.models['Model-1'].parts['Part-1']
f = p.faces
faces = f.getSequenceFromMask(mask=('[#1 ]',), )
region = p.Set(faces=faces, name='Set-1')
p = mdb.models['Model-1'].parts['Part-1']
p.SectionAssignment(region=region, sectionName='Section-1', offset=0.0, offsetType=MIDDLE_SURFACE, offsetField='',
thicknessAssignment=FROM_SECTION)
p = mdb.models['Model-1'].parts['Part-2']
session.viewports['Viewport: 1'].setValues(displayedObject=p)
p = mdb.models['Model-1'].parts['Part-2']
f = p.faces
faces = f.getSequenceFromMask(mask=('[#1 ]',), )
region = p.Set(faces=faces, name='Set-1')
p = mdb.models['Model-1'].parts['Part-2']
p.SectionAssignment(region=region, sectionName='Section-2', offset=0.0, offsetType=MIDDLE_SURFACE, offsetField='',
thicknessAssignment=FROM_SECTION)
#------------装配函数----------------
def assemble_two_parts():
seemble_dis = simuinfo["fyh_paras_dic"]["H"]["value"]*2 + simuinfo["yk_paras_dic"]["t_yk"]["value"]
a = mdb.models['Model-1'].rootAssembly
session.viewports['Viewport: 1'].setValues(displayedObject=a)
session.viewports['Viewport: 1'].assemblyDisplay.setValues(optimizationTasks=OFF, geometricRestrictions=OFF,
stopConditions=OFF)
a = mdb.models['Model-1'].rootAssembly
a.DatumCsysByThreePoints(coordSysType=CYLINDRICAL, origin=(0.0, 0.0, 0.0),
point1=(1.0, 0.0, 0.0), point2=(0.0, 0.0, -1.0))
p = mdb.models['Model-1'].parts['Part-1']
a.Instance(name='Part-1-1', part=p, dependent=ON)
a = mdb.models['Model-1'].rootAssembly
p = mdb.models['Model-1'].parts['Part-2']
a.Instance(name='Part-2-1', part=p, dependent=ON)
a = mdb.models['Model-1'].rootAssembly
a.LinearInstancePattern(instanceList=('Part-2-1',), direction1=(1.0, 0.0, 0.0), direction2=(0.0, -1.0, 0.0),
number1=1, number2=2, spacing1=2.92, spacing2=seemble_dis)
#--------创建分析步-------------------
def creat_step():
session.viewports['Viewport: 1'].assemblyDisplay.setValues(adaptiveMeshConstraints=ON)
mdb.models['Model-1'].StaticStep(name='Step-1', previous='Initial', maxNumInc=simuinfo["analysis_paras_dic"]["0"]["vale"])
session.viewports['Viewport: 1'].assemblyDisplay.setValues(step='Step-1')
mdb.models['Model-1'].FieldOutputRequest(name='F-Output-2', createStepName='Step-1', variables=('RT',))
#--------创建相互接触---------------
def creat_intertact():
session.viewports['Viewport: 1'].assemblyDisplay.setValues(interactions=ON, constraints=ON, connectors=ON,
engineeringFeatures=ON, adaptiveMeshConstraints=OFF)
mdb.models['Model-1'].ContactProperty('IntProp-1')
mdb.models['Model-1'].interactionProperties['IntProp-1'].TangentialBehavior(
formulation=PENALTY, directionality=ISOTROPIC, slipRateDependency=OFF,
pressureDependency=OFF, temperatureDependency=OFF, dependencies=0, table=((
simuinfo["analysis_paras_dic"]["1"]["vale"],),), shearStressLimit=None, maximumElasticSlip=FRACTION, fraction=0.005, elasticSlipStiffness=None)
a = mdb.models['Model-1'].rootAssembly
s1 = a.instances['Part-2-1'].edges
side1Edges1 = s1.getSequenceFromMask(mask=('[#4 ]',), )
region1 = a.Surface(side1Edges=side1Edges1, name='m_Surf-1')
a = mdb.models['Model-1'].rootAssembly
s1 = a.instances['Part-1-1'].edges
side1Edges1 = s1.getSequenceFromMask(mask=('[#200000 ]',), )
region2 = a.Surface(side1Edges=side1Edges1, name='s_Surf-1')
mdb.models['Model-1'].SurfaceToSurfaceContactStd(name='Int-1',
createStepName='Step-1', master=region1, slave=region2,
sliding=FINITE,
thickness=ON, interactionProperty='IntProp-1', adjustMethod=NONE,
initialClearance=OMIT, datumAxis=None, clearanceRegion=None)
a = mdb.models['Model-1'].rootAssembly
s1 = a.instances['Part-2-1-lin-1-2'].edges
side1Edges1 = s1.getSequenceFromMask(mask=('[#1 ]',), )
region1 = a.Surface(side1Edges=side1Edges1, name='m_Surf-3')
a = mdb.models['Model-1'].rootAssembly
s1 = a.instances['Part-1-1'].edges
side1Edges1 = s1.getSequenceFromMask(mask=('[#10 ]',), )
region2 = a.Surface(side1Edges=side1Edges1, name='s_Surf-3')
mdb.models['Model-1'].SurfaceToSurfaceContactStd(name='Int-2',
createStepName='Step-1', master=region1, slave=region2,
sliding=FINITE,
thickness=ON, interactionProperty='IntProp-1', adjustMethod=NONE,
initialClearance=OMIT, datumAxis=None, clearanceRegion=None)
#---------创建载荷------------------
def creat_load():
session.viewports['Viewport: 1'].assemblyDisplay.setValues(loads=ON, bcs=ON,
predefinedFields=ON, interactions=OFF, constraints=OFF,
engineeringFeatures=OFF)
a = mdb.models['Model-1'].rootAssembly
e1 = a.instances['Part-2-1-lin-1-2'].edges
edges1 = e1.getSequenceFromMask(mask=('[#4 ]',), )
region = a.Set(edges=edges1, name='Set-1')
mdb.models['Model-1'].EncastreBC(name='BC-1', createStepName='Step-1',
region=region, localCsys=None)
a = mdb.models['Model-1'].rootAssembly
e1 = a.instances['Part-2-1'].edges
edges1 = e1.getSequenceFromMask(mask=('[#1 ]',), )
region = a.Set(edges=edges1, name='Set-2')
mdb.models['Model-1'].DisplacementBC(name='BC-2', createStepName='Step-1',
region=region, u1=0.0, u2=simuinfo["analysis_paras_dic"]["2"]["vale"], ur3=0.0, amplitude=UNSET, fixed=OFF,
distributionType=UNIFORM, fieldName='', localCsys=None)
#---------网格划分------------------
def generate_mesh():
session.viewports['Viewport: 1'].assemblyDisplay.setValues(mesh=ON, loads=OFF,
bcs=OFF, predefinedFields=OFF, connectors=OFF)
session.viewports['Viewport: 1'].assemblyDisplay.meshOptions.setValues(
meshTechnique=ON)
p = mdb.models['Model-1'].parts['Part-1']
session.viewports['Viewport: 1'].setValues(displayedObject=p)
p = mdb.models['Model-1'].parts['Part-1']
p.seedPart(size=simuinfo["analysis_paras_dic"]["3"]["vale"], deviationFactor=0.1, minSizeFactor=0.1)
p = mdb.models['Model-1'].parts['Part-1']
p.generateMesh()
p = mdb.models['Model-1'].parts['Part-2']
session.viewports['Viewport: 1'].setValues(displayedObject=p)
p = mdb.models['Model-1'].parts['Part-2']
p.seedPart(size=simuinfo["analysis_paras_dic"]["4"]["vale"], deviationFactor=0.1, minSizeFactor=0.1)
p = mdb.models['Model-1'].parts['Part-2']
p.generateMesh()
3.2 仿真作业提交
仿真作业提交没有什么难度,如法炮制。马上想到强大的工具.rpy日志脚本,下面是在.rpy文件中拿到的关于作业提交的脚本。
a1 = mdb.models['Model-1'].rootAssembly
a1.regenerate()
a = mdb.models['Model-1'].rootAssembly
session.viewports['Viewport: 1'].setValues(displayedObject=a)
session.viewports['Viewport: 1'].assemblyDisplay.setValues(mesh=OFF)
session.viewports['Viewport: 1'].assemblyDisplay.meshOptions.setValues(
meshTechnique=OFF)
mdb.Job(name='Job-1', model='Model-1', description='', type=ANALYSIS,
atTime=None, waitMinutes=0, waitHours=0, queue=None, memory=90,
memoryUnits=PERCENTAGE, getMemoryFromAnalysis=True,
explicitPrecision=SINGLE, nodalOutputPrecision=SINGLE, echoPrint=OFF,
modelPrint=OFF, contactPrint=OFF, historyPrint=OFF, userSubroutine='',
scratch='', resultsFormat=ODB, multiprocessingMode=DEFAULT, numCpus=5,
numDomains=simuinfo["job_para_dic"]["8"]["value"], numGPUs=simuinfo["job_para_dic"]["9"]["value"])
3.3 后处理实现
在abaqus中通过脚本可以完成很多操作,诸如获取某云图的极值数据,导出云图到指定路径、及提取某指定结点的应力、位移、支反力等,还可以获取结点的座标。下图为abaqus后处理部分的命名空间,最外层的对象为odb仿真结果对象,通过rootAssembly可以获取指定part的各个节点座标;通过steps可以获取场输出信息,如支反力等。以上各个功能本人均开发实现,且亲测有效。下面附上本人研究的从abaqus导出云图的脚本,首先调整云图视角然后导出云图至指定路径。
session.viewports['Viewport: 1'].view.fitView()
session.printOptions.setValues(vpDecorations=OFF, vpBackground=ON)
session.printToFile(fileName=simu_instance_path + '/pic_rt', format=PNG,
canvasObjects=(session.viewports['Viewport: 1'],))
4 调度工具开发
前面说明了如何在abaqus中探索脚本,开发我们关心的功能。下面介绍下如何通过批处理的方式实现自动化仿真。有了这些脚本是实现开发自动仿真工具的第一步,还需要开发仿真作业调度管理工具。该工具要实现外部调用abaqus执行脚本、自动调度abaqus进行仿真作业及仿真结束后分析仿真结果生成仿真报告。
4.1 Abaqus外部调用
abaqus的外部调用是通过命令行参数的方式实现的,调用的同时传入控制进行批处理的参数及要执行的脚本文件,就可以实现abaqus的批处理模式仿真。
4.2 仿真作业调度
所谓仿真作业调度是指用户可以添加多个仿真,然后软件负责调度一个个仿真依次进行直到所有仿真结束,实现”无人值守“仿真。
4.3 仿真报告生成
仿真报告生成是通过基于word进行二次开发实现的,系统解析由abaqus仿真得到的额仿真数据和云图,结合word仿真报告模板快速生成面向某次仿真的仿真报告模板。
//---------------------------------------------承接CAD/CAE软件二次开发---------------------------------------------------------------------------
我们有着强大的二次开发团队,常年从事CAD/CAE软件二次开发工作。已经开发过UG/CATIA等CAD软件,近年来又攻坚克难攻克了CAE软件ansy /workbench/abaqus的二次开发工作。
希望广大有兴趣的朋友交流咨询二次开发技术,欢迎有需求的客户咨询二次开发业务。
邮箱:[email protected]
一支致力于让专业化软件更加人性化的倔强团队!!!
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------