3. 模型对象与API结构解析
在COMSOL中,模型树是用户最熟悉的界面元素:几何、网格、物理场、研究、结果依次排列,点击即可操作。但在脚本化批量仿真中,模型树不再只是界面,而是一套可编程的对象模型。理解模型树节点与API对象之间的映射关系,是编写可靠批处理脚本的前提。本节围绕Model、Component、Geometry、Mesh、Physics、Study等核心节点,说明它们在脚本中的对象类型、访问路径与常用属性。
从模型树到对象树:层级映射
COMSOL的API采用严格的树形结构。顶层对象是Model,对应一个.mph模型文件。Model之下挂载若干Component,每个Component内部再依次包含Geometry、Mesh、Physics、Study、Results等节点。脚本访问任何节点,都必须从Model出发,沿层级逐级定位。例如,要获取第一个组件的几何对象,路径是model.component("comp1").geom("geom1");要获取其中的网格,则是model.component("comp1").mesh("mesh1")。这种“父对象.子对象(标签)”的链式调用,与模型树中的展开层级完全一致。
需要特别注意的是,模型树中显示的节点名称(如“几何1”“网格1”)是标签(tag),而脚本中使用的字符串正是这些标签。标签在创建时指定,通常为geom1、mesh1、solid、std1等。如果模型由GUI手动创建,标签可能带有默认后缀;如果由脚本创建,则完全可控。批量仿真中建议统一命名规范,例如所有几何用geom1,所有网格用mesh1,避免因标签不一致导致脚本失效。
核心节点的对象类型与常用操作
Model是整个脚本的根对象。它负责模型的创建、保存、加载和求解调度。常用方法包括model.save("path.mph")、model.solve("std1")、model.result()等。在批量仿真中,通常先加载一个模板模型,再修改参数并求解,因此ModelUtil.load()和model.save()是高频调用。
Component是物理建模的容器。一个模型可以包含多个组件,但批量仿真通常只操作一个组件。Component对象提供了geom()、mesh()、physics()、study()、result()等工厂方法,用于获取或创建子节点。例如model.component("comp1").geom().create("geom2", 3)会创建一个新的三维几何节点。
Geometry节点管理几何建模序列。其下包含feature子节点,如blk1(长方体)、cyl1(圆柱)、sph1(球体)等。脚本中修改几何参数,本质是调用对应feature的set()方法。例如修改长方体尺寸:geom.feature("blk1").set("size", new double[]{0.2, 0.1, 0.05})。几何构建完成后,需要调用geom.run()使修改生效。
Mesh节点控制网格划分。常用feature包括size(全局尺寸)、ftri(自由三角形)、ftet(自由四面体)等。批量仿真中,网格参数往往随几何尺寸变化,因此需要动态设置。例如mesh.feature("size").set("hauto", 5)设置细化级别,或mesh.feature("size").set("custom", "on")后手动指定hmax。网格生成后需调用mesh.run()。
Physics节点是物理场接口的集合。每个物理场接口(如solid、ht、ec)下又有多个feature,如边界条件、域条件、初始值等。脚本中设置物理场参数,需要定位到具体feature。例如结构力学中固定约束:physics.feature("fix1").set("constrained", new int[]{1, 2});热传导中热源:physics.feature("hs1").set("Q0", 1e6)。物理场设置完成后,通常不需要单独运行,而是在求解时统一处理。
Study节点定义求解类型和求解器配置。常见类型包括std1(稳态)、time1(瞬态)、eig1(特征值)等。Study下包含feature子节点,如stat(稳态求解器)、time(瞬态求解器)。脚本中可设置求解容差、输出时间步等。例如study.feature("time").set("tlist", new double[]{0, 0.1, 0.2, 0.5})。调用model.solve("std1")即可触发求解。
批量仿真中的对象访问策略
批量仿真通常需要遍历一组参数,每次修改模型、求解、提取结果。如果每次都重新创建模型,效率极低。更合理的做法是:加载一个已配置好的模板模型,在循环中修改参数、运行几何和网格、求解、导出结果,然后重置模型状态。这里的关键是理解哪些节点需要run(),哪些只需set()。几何和网格修改后必须run(),物理场和求解器设置通常只需set(),求解时自动生效。
另一个常见问题是标签冲突。如果脚本中多次创建同名节点,COMSOL会自动添加后缀,导致后续访问路径变化。因此,建议在脚本中显式指定标签,并在修改前先检查节点是否存在。例如:
if (model.component("comp1").geom().hasFeature("blk1")) {
model.component("comp1").geom("geom1").feature("blk1").set("size", new double[]{L, W, H});
} else {
model.component("comp1").geom("geom1").create("blk1", "Block");
model.component("comp1").geom("geom1").feature("blk1").set("size", new double[]{L, W, H});
}
model.component("comp1").geom("geom1").run();
这段代码展示了“检查—修改或创建—运行”的标准模式。在批量循环中,将L、W、H替换为参数数组中的值,即可实现几何尺寸的批量变化。
model.component("comp1")可以简写为model.component("comp1"),但为了可读性,建议保留完整路径。如果模型只有一个组件,也可以使用model.geom("geom1")等快捷方式,但多组件模型下必须显式指定组件标签。
结果节点的访问
求解完成后,结果数据通过Results节点访问。常用对象包括PlotGroup(绘图组)、Numerical(数值数据)、Export(导出)等。批量仿真中,通常需要将每次求解的关键结果(如最大应力、最高温度、探针值)导出到文件。例如:
double maxStress = model.result().numerical("int1").getReal()[0];
model.result().export("data1").set("filename", "result_" + i + ".txt");
model.result().export("data1").run();
这里int1是预先定义的积分或最大值算子,getReal()返回计算结果数组。通过循环索引i生成不同文件名,即可实现批量结果导出。
对象映射的常见误区
初学者容易混淆“模型树节点”与“API对象”的对应关系。例如,模型树中“几何1”下可能显示多个几何特征,但脚本中geom("geom1")只代表几何节点本身,具体特征需要通过feature("blk1")访问。再如,物理场接口在模型树中显示为“固体力学”,但脚本中标签是solid,而非中文名称。因此,编写脚本时必须以标签为准,不能依赖界面显示名称。
此外,不同COMSOL版本的API方法名可能略有差异。例如set()方法在多数版本中通用,但某些属性名可能变化。建议在脚本开头使用ModelUtil.showProgress(true)开启进度显示,便于调试。批量仿真前,先用单个模型验证脚本路径是否正确,再扩展到参数循环。