基於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]
一支致力於讓專業化軟件更加人性化的倔強團隊!!!
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------