简介:《ANSYS AIM and Workbench Scripting Guide》是ANSYS公司2018年1月发布的官方脚本指南,对应Release 19.0版本,面向使用ANSYS AIM与Workbench进行仿真自动化的工程师、科研人员及高校师生。资源为单一PDF文档,压缩包约17.93MB,内容围绕脚本基础、几何建模与操作、网格划分、边界条件与材料属性、求解器设置、后处理与结果可视化、工作流程集成、错误处理与调试、最佳实践及API参考等模块展开,系统讲解如何通过脚本串联多物理域分析流程。读者可借此掌握Journaling与命令窗口的录制机制,学会用脚本实现几何导入、布尔运算、参数化设计、网格质量控制及求解参数配置,并借助API文档查阅函数、类与方法,构建跨模块的自动化工作流。目前已有343人学习,适合希望减少重复操作、提升仿真效率与可维护性的中高级用户参考。
1. 从一份脚本指南说起:为什么仿真工程师迟早要碰 Workbench Scripting
如果你已经能熟练在 Workbench 里拖模块、连数据线、点 Solve,那这份《ANSYS AIM and Workbench Scripting Guide》真正想解决的问题,其实不是"怎么再点一遍鼠标",而是"怎么让这一套流程不再靠手点"。我见过太多团队,一个工况改三个参数,就要重新拖一次 Geometry、重新划一次 Mesh、重新等一次 Solve,一天下来真正思考物理的时间不到两小时。脚本化的价值就在这里:把重复的建模—网格—求解—后处理链路固化成可复现的代码,参数一改,整条链自动跑完。
这份指南覆盖的是 AIM 与 Workbench 两套环境的脚本能力,前者偏一体化快速仿真,后者偏项目级流程编排。对做结构、热、流体耦合的从业者来说,它解决的是"批量工况""参数扫描""自动化报告"这三类最耗人的活。适合谁?适合已经会用 GUI、但被重复劳动拖住的人;也适合想把仿真流程接进更大自动化体系的工程师。下面我按"先立住概念、再动手复现、最后讲坑"的顺序,把这条路走一遍。
2. Workbench 脚本的三种入口:Journal、ACT 与 Python 到底怎么选
很多人第一次接触 Workbench 脚本,是被那个自动生成的 Journal 文件吓到的——几百行记录式代码,改一个参数就全乱。要真正用好脚本,先得搞清楚 Workbench 提供的几种入口各自适合什么场景,选错了入口,后面全是返工。
2.1 Journal 录制:最快的起点,也是最容易翻车的起点
Journal 是 Workbench 自带的录制功能,你在 GUI 里做的每一步都会被记成脚本。它的优点是零门槛,缺点是"记录的是操作,不是意图"。比如你拖动一个尺寸,它记的是具体数值,而不是"这个尺寸应该等于某参数"。
常见做法是:先用 Journal 录一遍完整流程,再手动把里面的硬编码数值替换成变量。下面是一段典型的 Journal 片段改造示例:
# 原始 Journal 记录(硬编码,不可复用) # geometry1.SetParameter("FD1", "100") # 长度写死 100 # 改造后:从外部字典读取参数 param_dict = {"length": 100.0, "width": 50.0, "height": 20.0} geometry1.SetParameter("FD1", str(param_dict["length"])) geometry1.SetParameter("FD2", str(param_dict["width"])) geometry1.SetParameter("FD3", str(param_dict["height"])) # 关键:每次改完参数必须刷新,否则下游模块拿到的还是旧值 geometry1.Refresh()逻辑说明:SetParameter的第一个参数是 Workbench 内部给尺寸分配的标识(FD1、FD2 这类),不是你在 CAD 里看到的名字,所以必须先录一遍确认标识。Refresh()这一步是血泪经验,漏掉它,网格模块会基于旧几何生成,结果对不上你还找不到原因。
参数说明:param_dict的键名建议和你的设计变量表保持一致,方便后续做参数扫描时直接映射。数值统一用浮点,避免字符串拼接时精度丢失。
2.2 ACT 扩展:把脚本包装成可复用组件
如果你要把脚本给团队其他人用,Journal 就不合适了——它太脆,换个模型就崩。ACT(Ansys Customization Toolkit)允许你把脚本封装成带界面的扩展,别人填参数、点按钮就行。
ACT 的核心是 XML 定义界面 + Python/IronPython 写逻辑。一个最小可用的 ACT 向导包含三部分:main.xml定义输入控件,callback.py处理逻辑,images放图标。下面是一个参数输入回调的骨架:
# callback.py 中的参数读取逻辑 def on_apply(param1, param2): # param1/param2 来自 XML 中定义的控件 length = float(param1.Value) width = float(param2.Value) # 调用 Workbench 项目对象 geometry = ExtAPI.DataModel.Project.Model.Geometry geometry.SetParameter("FD1", str(length)) geometry.SetParameter("FD2", str(width)) geometry.Refresh() # 返回状态给界面 return "参数已应用"逻辑说明:ExtAPI.DataModel是 ACT 访问当前项目模型的入口,和 Journal 里的全局对象不同,ACT 里必须通过这个入口拿对象。on_apply是 XML 里绑定的回调名,名字要对上。
参数说明:ACT 里所有从界面来的值都是字符串或控件对象,必须显式转换类型。Refresh()同样不能省。
2.3 外部 Python 驱动:批量工况的正确姿势
当你需要跑几十上百个工况时,在 Workbench 界面里点是不现实的。正确做法是用外部 Python 通过RunWB2命令行接口驱动 Workbench,每个工况独立跑一遍,互不干扰。
# 命令行调用 Workbench 执行脚本 RunWB2 -B -R "C:\scripts\run_case.py" -F "C:\project\model.wbpj"逻辑说明:-B表示批处理模式,不弹界面;-R指定要执行的脚本;-F指定项目文件。批处理模式下 Workbench 跑完会自动退出,适合放进循环。
参数说明:脚本里要用Save()显式保存结果,批处理模式不会自动存。如果工况多,建议每个工况单独存一个项目文件,避免互相覆盖。
三种入口的选择逻辑很清晰:临时用一次选 Journal,团队复用选 ACT,批量扫描选外部 Python。选错入口的代价,往往是推倒重来。
3. 参数化建模到求解:一条能跑通的脚本链路
选好入口之后,真正要落地的是"参数进去、结果出来"这条链路。这一章把 Geometry、Mesh、Solve、Post 四个环节的脚本要点拆开讲,每一步都给可抄的写法。
3.1 Geometry 参数化:命名规范比脚本技巧更重要
参数化建模最大的坑不在脚本,在命名。Workbench 给每个尺寸分配的 FD 标识是自动生成的,你删一个特征再加一个,标识就可能变。所以我的习惯是:在 CAD 里就把关键尺寸命名成有意义的名字,再在 Workbench 里做一次映射。
# 建立 名称 -> FD标识 的映射表,避免脚本里到处写 FD1/FD2 dim_map = { "plate_length": "FD1", "plate_width": "FD2", "hole_dia": "FD3", } def set_dims(geometry, values): for name, fd in dim_map.items(): if name in values: geometry.SetParameter(fd, str(values[name])) geometry.Refresh()逻辑说明:把映射关系集中管理,后面换模型时只改dim_map,不用翻遍脚本。values字典只传需要改的参数,没传的保持默认。
参数说明:SetParameter的值必须是字符串,浮点数要先str()。如果尺寸是整数型,注意别传成"100.0",某些版本会报类型不匹配。
3.2 Mesh 脚本:全局尺寸与局部细化的参数怎么设
网格脚本最容易犯的错是"只改全局尺寸,忘了局部细化"。全局尺寸调粗,关键区域的网格也跟着粗,结果精度崩了。正确做法是全局和局部分开控制。
# 全局网格设置 mesh = Model.Mesh mesh.ElementSize = 5.0 # 全局单元尺寸 mm mesh.Resolution = 3 # 网格分辨率 1-7,越大越细 # 局部细化:对某个面单独加密 face_sel = mesh.AddNamedSelection("refine_face") face_sel.Location = "Face 12" # 目标面 mesh.AddSizing(face_sel, 1.0) # 该面单元尺寸 1.0 mm mesh.GenerateMesh()逻辑说明:ElementSize控制整体,AddSizing控制局部。Resolution是 Workbench 的网格质量档位,不是线性参数,3 是默认平衡点,调到 5 以上生成时间会明显变长。
参数说明:局部尺寸一般取全局的 1/3 到 1/5。AddNamedSelection的名字要唯一,重复添加会报错。生成后用mesh.MeshMetrics检查单元质量,别等求解报错才回头。
3.3 Solve 与 Post:批处理下怎么保证结果不丢
批处理模式最怕的是"跑完了但没存"。求解和后处理的脚本必须显式保存,而且要区分"每个工况存一份"还是"汇总存一份"。
# 求解设置 solution = Model.Solution solution.Solve() # 同步求解,批处理下必须等它返回 # 后处理:提取最大等效应力 stress = solution.GetResult("EquivalentStress") max_stress = stress.Maximum # 结果写入外部文件,避免依赖项目文件 with open("result_summary.txt", "a") as f: f.write(f"case_id={case_id}, max_stress={max_stress}\n") # 保存项目 Model.Save()逻辑说明:Solve()在批处理下是阻塞的,返回后才拿得到结果。GetResult的结果名要和求解器输出一致,写错会返回 None。结果写外部文件是为了汇总方便,不用一个个开项目看。
参数说明:Maximum是结果对象的一个属性,不同物理场属性名不同,热分析用Maximum,模态分析要用Frequency这类。追加模式"a"保证多个工况写进同一个文件。
这条链路跑通一次,后面就是改参数、循环、收结果。真正花时间的是第一次调试,把每个环节的标识和名字对上。
4. 避坑与排查:脚本跑不通时先看这五条
脚本报错最烦的是信息不明确,Workbench 经常只给一句"脚本执行失败"。下面这五条是我踩过的坑里出现频率最高的,按"现象→原因→解决"整理。
现象一:脚本在 GUI 里能跑,批处理模式报对象为空。原因:批处理模式下没有界面上下文,某些依赖当前选中对象的 API 拿不到东西。解决:所有对象引用都从ExtAPI.DataModel.Project或Model显式获取,不要依赖"当前选中"。
现象二:改了参数但结果没变。原因:漏了Refresh(),或者下游模块没有重新生成。解决:参数改完立刻Refresh(),网格和求解前确认上游状态是 Up-to-date。可以在脚本里加Model.Geometry.Refresh()和Model.Mesh.GenerateMesh()强制刷新。
现象三:批处理跑完项目文件没保存。原因:批处理模式不会自动保存,Solve()只求解不存盘。解决:脚本末尾显式Model.Save(),或者用SaveAs存到指定路径。多工况时建议每个工况单独存,避免覆盖。
现象四:FD 标识对不上,参数设到了错误的尺寸上。原因:模型修改后 Workbench 重新分配了 FD 编号。解决:不要硬编码 FD 标识,用命名映射表;每次换模型先录一遍 Journal 确认标识。
现象五:结果提取返回 None。原因:结果名拼写和求解器输出不一致,或者求解还没完成就提取。解决:先确认Solve()已返回,再用solution.GetResult拿结果;结果名从 GUI 里手动提取一次,看 Journal 里记的是什么名字,照抄。
这五条覆盖了八成以上的脚本翻车场景。剩下的两成,多半是版本差异导致的 API 行为变化,遇到时先查对应版本的脚本指南,别硬猜。
5. 进阶技巧:用参数扫描把脚本价值放大十倍
单次脚本化只是省了一次手工,真正的价值在参数扫描——把脚本套进循环,一次跑几十个工况,自动汇总结果。这一章讲怎么把前面的链路改造成扫描框架,以及怎么验证结果可信。
5.1 扫描框架:外部循环 + 独立项目文件
参数扫描的核心是"每个工况独立",避免工况之间互相污染。我的做法是:外部 Python 生成参数组合,逐个调用 Workbench 批处理,每个工况存独立项目文件。
import subprocess import itertools # 生成参数组合 lengths = [80, 100, 120] widths = [40, 50, 60] cases = list(itertools.product(lengths, widths)) for i, (L, W) in enumerate(cases): case_id = f"case_{i:03d}" # 把参数写进临时脚本 with open("run_case.py", "w") as f: f.write(f""" length = {L} width = {W} case_id = "{case_id}" # ... 这里接前面的建模求解链路 ... """) # 调用 Workbench 批处理 subprocess.run([ "RunWB2", "-B", "-R", "run_case.py", "-F", "template.wbpj" ], check=True)逻辑说明:itertools.product生成笛卡尔积组合,case_id用零填充保证排序。每个工况从模板项目复制一份,跑完存成独立文件。check=True保证某个工况失败时整个循环停下,不会静默跳过。
参数说明:模板项目template.wbpj要预先配好参数化链路,脚本只负责改值和跑。工况多时建议加日志,记录每个工况的开始和结束时间,方便排查卡在哪。
5.2 结果汇总与验证:别让扫描跑出一堆废数据
扫描跑完,最怕的是一堆结果里混着失败工况,直接拿去做趋势分析就错了。汇总时必须做有效性检查。
| 检查项 | 判断方法 | 处理方式 |
|---|---|---|
| 求解是否收敛 | 读求解日志的收敛标志 | 未收敛工况标记剔除 |
| 结果是否合理 | 对比历史值范围 | 超范围工况人工复核 |
| 网格是否达标 | 检查单元质量指标 | 质量差的重新划网格 |
| 参数是否生效 | 抽查几何尺寸 | 未生效的检查映射表 |
汇总脚本建议把每个工况的参数、关键结果、状态码写进一张表,用状态码区分成功和失败。趋势分析只取成功工况,失败工况单独列出来排查。
5.3 一个具体技巧:用结果反查参数敏感性
扫描数据最有价值的用法不是看单个结果,而是看哪个参数对结果影响最大。做法很简单:对每个参数,固定其他参数,看结果的变化幅度。
import pandas as pd df = pd.read_csv("result_summary.txt") # 只取成功工况 df = df[df["status"] == "ok"] # 按长度分组,看应力的变化幅度 sensitivity = df.groupby("length")["max_stress"].agg(["mean", "std"]) print(sensitivity)逻辑说明:groupby按参数分组,std反映该参数变化时结果的波动程度。波动大的参数就是敏感参数,后续优化优先调它。
参数说明:样本量太少时std不可靠,建议每个参数至少三个水平。如果参数之间有交互作用,单参数分析会漏掉,需要做正交试验或全因子。
我自己的习惯是:扫描跑完先看状态码分布,失败超过两成就先修脚本,别急着分析数据。数据可信比数据多重要得多。希望帮到你。
本文还有配套的精品资源,点击获取