随着 CAE 的广泛应用,CAE 用户的水平日渐提高,新需求日渐增多,CAE 软件的二次开发逐渐成为工程师的必备技能。Python 语言简单易懂、开源包众多,是非常流行的 编程语言 。Abaqus 作为一款以 Python 语言为前后处理内核的 CAE 软件,兼具 CAD 软件基于特征建模的方法,还提供了内核与 GUI 二次开发接口,所以基于 Abaqus 进行二次开发的自由度非常大。
Abaqus 的内核脚本二次开发可以从学习日志文件 abaqus.rpy 起步,GUI 脚本二次开发可以从 GUI 用户手册起步。熟悉之后,简单问题可以直接用脚本编写。但是 Abaqus 毕竟不是专业的集成开发环境(IDE),代码补全、参数提示功能较弱,借助专业 IDE 可提高开发效率。由于 Abaqus 的 Python 解释器 无法被专业 IDE 直接调用,需要创建代理模块模拟 Abaqus 各种方法的接口。
本文从学习研究的角度探讨了创建 Abaqus 代理接口的方法,提供了有关脚本及生成的代理文件下载链接(欢迎打赏下载币)。
在pyCharm中,内核脚本的快捷文档(光标在方法后、括号前,按Ctrl+Q)如下:
在 pyCharm 中,GUI 脚本的方法提示如下:
在 pyCharm 中,内核脚本的参数提示(Ctrl+P)如下:
Abaqus 自身的 CLI (command line interface) 窗口具有代码补全功能,补全快捷键为 Tab,其核心模块为 completerABQ.pyc(实现自动补全功能) 和 docstringLookup.pyc(多个字典,保存了方法的路径、参数及说明)。自动补全只支持 CLI 窗口的内核脚本,不支持 GUI 脚本。
Abaqus 的 GUI 二次开发较为繁琐,无法直接调试,查找方法非常不方便。pyCham 的代码补全、参数提示功能很棒,Ctrl+P 参数提示, Ctrl+Q 查看函数、方法文档,很方便。Abaqus 的 python 2.x 解释器经过订制,无法(未找到方法)用于 pyCharm 调试 Abaqus 脚本。
通过生成 Abaqus 代理模块,模拟 Abaqus 各种方法的接口定义,可在通用 Python 解释器中“简单调试”(参数提示、查看文档、语法检查) Abaqus 内核脚本及 GUI 脚本。
1. gen_Abaqus_Agent_from_2020_docs.py
运行环境: Python3
脚本说明:通过解析 htm 文件,将 Abauqs 2020 的脚本参考手册转化为代理模块 abaqus.py,输入参数、返回值都有类型及说明。因为部分 htm 文件的编码为 utf-8,为便于处理,选用 python3。
2. gen_AbaqusConstants_Agent.py
运行环境:Abaqus CAE
脚本说明:将 abaqusConstants 模块转为代理模型 abaqusConstants.py。调用内置模块,必须在 Abaqus 环境执行。
3. getAbaquStructure.py
运行环境:Abaqus CAE
脚本说明:(不推荐)借助 docstringLookup 模块生成代理 abaqus.py, xyPlot.py 等,输入参数无类型,无返回值。 调用内置模块,必须在 Abaqus 环境执行。
4. transferAbaquGUIFunctionFromDocumentation.py
运行环境:Python
脚本说明:GUI 参考手册的结构比较复杂(或者说比较混乱),很多类型没有介绍,无法程序自动识别。此脚本只起辅助作用,从 GUI 参考手册的网页中手动复制内容到文本文件,然后用脚本解析文本文件,生成单个类型,然后手动添加到 abaqusGui.py 中,需要注意类型的创建顺序。
1.gen_Abaqus_Agent_from_2020_docs.py
#-*- coding:gbk -*-
from bs4 import BeautifulSoup
import re,os,pickle
'''This script transfers "Abaqus 2020 Scripting Reference Documentatation" to an Agent Model File : abaqus.py
The generated agent "abaqus.py" can be used in pycham for code completion
1.replace pathDir in __main__ eg:
pathDir = r'C:\Program Files\Dassault Systemes\SIMULIA2020doc\English\SIMACAEKERRefMap'
2. run this scipt in python3 get "abaqus.py"
3. run gen_AbaqusConstants_Agent.py in abaqus to get 'abaqusConstants.py'
by alienwxy 2020-05-05
'''
def cutInfo(info):
info = info.strip()
return info
cutLen = 50
rst = re.findall('[A-Z][A-Z_0-9]+',info)
if rst and info.startswith('A SymbolicConstant'):
return ', '.join(rst)
else:
if len(info)>cutLen*2:
return info[:cutLen]+' ... '+info[-cutLen:]
else:
return info
#解析目录所有htm文件
def partseDir(dirPath):
modules = {
} #'moduleName': methods, constructs, members
objects = {
}
failed = []
# 先更新所有方法
for fname in os.listdir(dirPath):
if fname.endswith('.pkl'):
try:
with open(os.path.join(dirPath, fname), 'rb') as fp:
titleList, methodDict, constructDict, memberList = pickle.load(fp)
titletype,titlename,titleintro = titleList
if titletype == 'object':
if titlename in objects: #对象已经存在,忽略标题,合并方法,合并成员变量
dic =objects[titlename] #对象字典
if methodDict:
mtddic = dic['methodDict']
for name,body in methodDict.items():
if name in mtddic: #方法名已存在
if mtddic[name] == body:
continue
else:
pname = name[:-1] if name[-1].isdigit() else name #不含结尾数字的名称
name = pname+str(len([n for n in mtddic.keys() if n.startswith(pname)])) #新名称
mtddic[name] = body
if memberList:
mmblst = dic['memberList']
mmblst.extend(memberList)
else: #对象不存在,创建标题,方法字典、成员变量列表
objects[titlename] = {
'intro':titleintro, #''
'methodDict':methodDict,#intro reqargs, optArgs, returns
'memberList':memberList, #[[n,i,v],[n,i,v]] []
}
elif titletype =='module':
if titlename in modules: # 对象已经存在,忽略标题,合并方法,合并成员变量
dic = modules[titlename] # 对象字典
if methodDict:
mtddic = dic['methodDict']
for name, body in methodDict.items():
if name in mtddic: # 方法名已存在
if mtddic[name] == body:
continue
else:
pname = name[:-1] if name[-1].isdigit() else name # 不含结尾数字的名称
name = pname + str(len([n for n in mtddic.keys() if n.startswith(pname)])) # 新名称
mtddic[name] = body
if memberList:
mmblst = dic['memberList']
mmblst.extend(memberList)
else: # 对象不存在,创建标题,方法字典、成员变量列表
modules[titlename] = {
'intro': titleintro, # ''
'methodDict': methodDict, # intro reqargs, optArgs, returns
'memberList': memberList, # [[n,i,v],[n,i,v]] []
}
else:
continue
except:
print(fname)
failed.append(os.path.join(dirPath,fname))
# 更新所有构造器--只针对 objects
for fname in os.listdir(dirPath):
if fname.endswith('.pkl'):
# try:
with open(os.path.join(dirPath, fname), 'rb') as fp:
titleList, methodDict, constructDict, memberList = pickle.load(fp)
titletype, titlename, titleintro = titleList
if constructDict:
for name,body in constructDict.items():
if body['paths']:
for path in body['paths']:
objectName = recoverObjectFromPathString(path)
if not objectName: continue
if objectName in objects: # 对象已经存在,添加方法
dic = objects[objectName] # 对象字典
mtddic = dic['methodDict']
if name in mtddic: # 方法名已存在
if mtddic[name] == body:
pass
else:
pname = name[:-1] if name[-1].isdigit() else name # 不含结尾数字的名称
name = pname + str(len([n for n in mtddic.keys() if n.startswith(pname)])) # 新名称
mtddic[name] = body
else: # 对象不存在,创建标题,方法字典、成员变量列表
objects[objectName] = {
'intro': '', # ''
'methodDict': {
name:body}, # intro reqargs, optArgs, returns
'memberList': [], # [[n,i,v],[n,i,v]] []
}
# except:
# pass
modules = list(modules.items())
objects = list(objects.items())
modules.sort()
objects.sort()
writeObjects(objects)
# writeModules(modules)
if failed:
with open('failed.txt','w') as fp:
for i in failed:
fp.write('%s\n' % i)
#写入函数
def writeFunction2file(fp, funcName,funcBody):
intro = funcBody['intro']
reqArgs = funcBody['reqArgs']
optArgs = funcBody['optArgs']
returns = funcBody['returns']
if reqArgs:
reqstr = ', '.join([i[0] for i in reqArgs])
if optArgs:
optstr = ', '.join(['%s=%s' % (i[0], i[2]) for i in optArgs])
argstr = ', '.join([reqstr, optstr])
else:
argstr = reqstr
else:
if optArgs:
optstr = ', '.join(['%s=%s' % (i[0], i[2]) for i in optArgs])
argstr = optstr
else:
argstr = ''
if funcName in ('print','import','class','def'):
funcName = funcName + '_'
fp.write('def %s(%s):\n' % (funcName, argstr))
fp.write(' """\n')
fp.write(' %s\n\n' % cutInfo(intro))
if reqArgs:
for arg, info in reqArgs:
fp.write(' :param %s: %s\n' % (arg, cutInfo(info)))
if optArgs:
for arg, info, value in optArgs:
fp.write(' :param %s: %s\n' % (arg, cutInfo(info)))
if returns:
value, info = returns
fp.write(' :return %s: %s\n' % (value, cutInfo(info)))
fp.write(' """\n')
if returns:
value, info = returns
fp.write(' return %s\n' % (value,))
#写入方法
def writeMethod2file(fp,funcName,funcBody):
intro = funcBody['intro']
reqArgs = funcBody['reqArgs']
optArgs = funcBody['optArgs']
returns = funcBody['returns']
if reqArgs:
reqstr = ', '.join([i[0] for i in reqArgs])
if optArgs:
optstr = ', '.join(['%s=%s' % (i[0], i[2]) for i in optArgs])
argstr = ', '.join(['self',reqstr, optstr])
else:
argstr = ', '.join(['self',reqstr])
else:
if optArgs:
optstr = ', '.join(['%s=%s' % (i[0], i[2]) for i in optArgs])
argstr = ', '.join(['self', optstr])
else:
argstr = 'self'
if funcName in ('print','import','class','def'):
funcName = funcName + '_'
fp.write(' def %s(%s):\n' % (funcName, argstr))
fp.write(' """\n')
fp.write(' %s\n\n' % cutInfo(intro))
if reqArgs:
for arg, info in reqArgs:
fp.write(' :param %s: %s\n' % (arg, cutInfo(info)))
if optArgs:
for arg, info, value in optArgs:
fp.write(' :param %s: %s\n' % (arg, cutInfo(info)))
if returns:
value, info = returns
fp.write(' :return %s: %s\n' % (value, cutInfo(info)))
fp.write(' """\n')
if returns:
value, info = returns
fp.write(' return %s\n' % (value,))
def _writeRepositoryClass2file(fp,className,classBody,objects):
intro = classBody['intro']
methodDict = classBody['methodDict']
memberList = classBody['memberList']
fp.write('class %s(tuple):\n' % className)
fp.write(' def __init__(self, rtype="", *args, **kwargs):\n'
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删