很多刚学 Python 脚本的工程师,最喜欢把别人的代码复制粘贴。结果运行的时候,Abaqus 毫不留情地甩出一个 NameError: name 'mdb' is not defined。
这就像是你跑到饭厅里去找菜刀,或者跑到厨房里去要账单一样荒谬。在 Abaqus 的世界里,前处理(建模)和后处理(看结果)是两套完全独立的数据库。如果不弄懂这两大“城邦”的法则,你的代码永远会在跨界时迷路。
1. Mdb (Model Database) —— 造物主的“绝密图纸”Mdb(模型数据库) 对应着你保存在电脑上的 .cae 文件。当你导入 mdb 时,你调用的是前处理 API。这里包含了 parts(零件)、materials(材料)、steps(分析步) 等所有构建物理世界的元素。
Mdb 就像是一间极度机密的兵工厂。你在这里画图纸、选钢材、组装大炮。在这里,你是绝对的“造物主”,你可以随意修改任何一个零件的尺寸或属性(比如调用 mdb.models['Model-1'].materials['Steel'])。但记住,兵工厂里没有战况,你在这里是看不到任何应力云图的。
Mdb 的层级结构
Mdb 的结构就像一棵大树,从根到叶依次是:
mdb
└── models (模型集合)
└── Model-1 (具体模型)
├── parts (零件)
├── materials (材料)
├── sections (截面)
├── steps (分析步)
├── interactions (相互作用)
├── loads (载荷)
├── boundaryConditions (边界条件)
└── meshes (网格)
常用 Mdb 操作示例
# 创建新模型
mdb.Model(name='MyModel')
# 创建材料
mdb.models['MyModel'].Material(name='Steel')
mdb.models['MyModel'].materials['Steel'].Elastic(table=((210000.0, 0.3),))
# 创建零件
mdb.models['MyModel'].Part(name='Part-1', dimensionality=THREE_D, type=DEFORMABLE_BODY)
# 创建分析步
mdb.models['MyModel'].StaticStep(name='Step-1', previous='Initial')
2. Odb (Output Database) —— 战地记者的“黑匣子”Odb(输出数据库) 对应着计算完成后生成的 .odb 文件。想调用它,你必须使用 import odbAccess。它的内部结构完全不同,包含的是 steps(对应的结果步)、frames(时间帧) 和 fieldOutputs(场输出如应力应变)。
Odb 就像是装在模型身上的黑匣子或者战地记者的相册。大炮开火后(提交计算),所有的爆炸瞬间、受力情况都被逐帧拍成了照片存放在这里。
核心禁忌:Odb 是一座“只读”的博物馆(除非你动用极特殊的高级 API 强行写入)。你绝对不能在 Odb 里尝试把一个零件拉长 10 毫米,因为事情已经发生了,历史不容篡改!
Odb 的层级结构
Odb 的结构与 Mdb 完全不同,它是围绕结果数据组织的:
odb
├── steps (结果步集合)
│ └── Step-1 (具体结果步)
│ └── frames (时间帧集合)
│ └── Frame-1 (具体时间帧)
│ ├── fieldOutputs (场输出)
│ │ ├── S (应力)
│ │ ├── U (位移)
│ │ └── E (应变)
│ └── historyOutputs (历史输出)
└── rootAssembly (根装配体)
└── nodeSets (节点集)
└── elementSets (单元集)
常用 Odb 操作示例
# 打开 Odb 文件
odb = odbAccess.openOdb('model.odb')
# 获取应力场
step = odb.steps['Step-1']
frame = step.frames[-1] # 最后一个时间帧
stress = frame.fieldOutputs['S']
# 提取特定节点的应力
node_set = odb.rootAssembly.nodeSets['ALL_NODES']
nodal_stress = stress.getSubset(region=node_set)
# 关闭 Odb 文件
odb.close()
既然 Mdb 和 Odb 水火不容,那它们是怎么联系起来的?
答案是 Job(作业)。在 Mdb 中,我们用 `mdb.Job(...)` 创建一个计算任务。当调用 `job.submit()` 时,Abaqus 的求解器(Kernel)就会把 Mdb 里的图纸翻译成 `.inp` 文件,然后一顿狂算,最终生成那个装满数据的 `.odb` 文件。
Job 就像是穿梭在这两座城市之间的高铁快递员。他把 Mdb 兵工厂里的“图纸”打包带走,送到远方的超算中心去执行,最后把装满实验结果的 Odb “相册”带回给你。
Job 的生命周期
创建:`job = mdb.Job(name='Job-1', model='Model-1', description='')`
提交:`job.submit()`
监控:`job.status`
等待完成:`job.waitForCompletion()`
访问结果:通过 Odb 文件
Job 配置示例
# 创建 Job
job = mdb.Job(name='MyJob', model='MyModel', description='Static analysis')
# 配置 Job
job.setValues(numCpus=4, memory=50, memoryUnits=PERCENTAGE)
# 提交并等待完成
job.submit()
job.waitForCompletion()
# 检查状态
print(f"Job status: {job.status}")
场景 1:参数化建模
# 批量创建不同尺寸的模型
for i, radius in enumerate([10, 20, 30]):
model_name = f'Model-{i+1}'
mdb.Model(name=model_name, modelType=STANDARD_EXPLICIT)
# 创建零件、设置材料等
# ...
# 创建并提交 Job
job_name = f'Job-{i+1}'
mdb.Job(name=job_name, model=model_name)
mdb.jobs[job_name].submit()
场景 2:结果自动处理
# 批量处理多个 Odb 文件
import os
for odb_file in os.listdir('results'):
if odb_file.endswith('.odb'):
odb_path = os.path.join('results', odb_file)
odb = odbAccess.openOdb(odb_path)
# 提取应力、位移等数据
# 生成报告或图表
# ...
odb.close()
最佳实践
1. 代码组织
2. 性能优化
3. 调试技巧
打印状态:在关键步骤添加状态打印
逐步测试:分步骤测试脚本,确保每一步都正确
日志记录:保存详细的运行日志,便于排查问题
随着 Abaqus 的不断更新,Mdb 和 Odb 的 API 也在持续演进。未来可能会看到:
写 Abaqus 脚本,最重要的就是\*\*“找准对象所在的族谱”\*\*。
当你要建模型时,就在脑海中默念:mdb -> models -> parts -> ...
当你要提数据时,就在脑海中默念:odb -> steps -> frames -> fieldOutputs -> ...
记住这座双城记的法则,你以后遇到任何 API 报错,都不会再像无头苍蝇一样乱撞了!
👉互动话题:你在提取 Odb 结果时,遇到过什么麻烦?是不知道怎么提取特定节点的应力,还是提出来的数据格式一团糟?分享你的经历,也许下一期我们能帮你找到解决方案。或者,你对 Mdb 和 Odb 的使用有什么心得?欢迎在评论区交流!