COMSOL Multiphysics 二次开发系列教程(12):作业序列与命令行自动化——为什么 comsol batch 不执行 Job Sequences,以及 dummy 参数技巧
版本与真实性声明
- 工具/软件:COMSOL Multiphysics 6.4(2025-11 发布);命令行参数按 6.4 参考手册页核对,模型方法示例按知识库 1250 原文核对,作业序列行为按官方博客原文核对
- 语言/环境:Windows 用
comsolbatch.exe,Linux/macOS 用comsol batch;Java(COMSOL API for use with Java)与 MPh(Python)作为对照宿主- 事实来源:官方博客《How to Use Job Sequences to Save Data After Solving Your Model》、知识库 1250《Running parametric sweeps, batch sweeps, and cluster sweeps from the command line》、6.4 参考手册 COMSOL Commands 页。凡文档未明之处一律标注"以官方文档为准"
- 本文目标:读完之后,你能写出一条"CSV 参数文件 → 模型方法 → 命令行批处理 → 落盘"的自动化链路,并明白每一步的执行边界在哪里
一句话结论:comsol batch只执行 Study 顶层的步骤,不执行 Job Configurations 下的作业序列(job sequence)——要让它执行,必须在 Global Definitions 里加一个 dummy 参数(如dummy = 1)并用参数扫描(Parametric Sweep,它是作业序列的一种特殊形态)把序列"抬"到顶层,此时comsolbatch -inputfile mymodel.mph -study std1会依次执行求解、保存模型、计算全局评估;而 Batch Sweep 与 Cluster Sweep 节点在批处理下默认被忽略,必须加-mode desktop才会执行。
〇 本篇要解决的认知问题
前 11 篇解决的是"对象模型内部长什么样、结果怎么取出来"。从本篇开始进入执行环境:同一份模型,在 GUI 里点"计算"和在命令行里跑批处理,行为并不等价。这六个问题是本篇的全部,文末 FAQ 与它们一一对应。
- 作业序列(job sequence)到底是什么?它和参数扫描(Parametric Sweep)是什么关系——为什么官方说"参数扫描是作业序列的一种特殊类型"?
- 为什么
comsol batch不能直接执行 Study 节点下的作业序列?这条限制的技术根因是什么?dummy 参数为什么能绕过它? - 用 dummy 参数绕过时,为什么扫描必须是"外部扫描(outer sweep)“而不是"内部扫描(inner sweep)”?两者在求解器层面有什么区别?
-study、-job、-methodcall三个命令行参数各自的语义和前提是什么?哪个能触发模型方法(model method)?- 命令行参数化扫描(
-pname/-plist/-paramfile)与模型方法读参数文件,两条路各产出什么形态的结果?为什么前者"每个参数一个输出文件、解不同步"? - 批处理命令行完整参数表里,哪些开关会改变"是否落盘、是否覆盖输入文件、是否用批处理许可"?
-stop/-recover/-continue的恢复语义是什么?
六个问题的答案分别落在:机制段 1.1(问题 1、2)、1.2(问题 3)、1.3(问题 4)、1.4(问题 5)、1.5(问题 6);代码段 2.1(问题 5 的可运行版本)、2.2(问题 1 的落地)。
本篇在全系列里的位置:第 5 篇给了对象树与 tag 主键,第 9 篇给了sol与解索引,第 10 篇给了三种扫描形态的对照,第 11 篇给了后处理与导出。本篇把这些接进"无人值守"的执行环境——第 20 篇的完整流水线就是本篇执行模型 + 第 11 篇导出层的组合。
一 机制解析
1.1 作业序列是"求解之后的动作清单",但它挂在 Study 之下
先给价值锚点:你日常在 GUI 里做的事——“求解 → 把结果表存成文件 → 把模型另存 → 重画所有图”——在 GUI 里就是 Job Sequences 节点。它的价值在于把后处理固化成可重复的动作序列,而不是每次手工点一遍。
官方对作业序列的定义很朴素:在 Job Configurations(作业配置)下创建一个 Sequence 节点,给它加动作子节点——Save Model to File(将模型保存到文件)、Evaluate(全局计算)、Export plot data、Export image data 等,运行序列时按顺序执行这些动作。
关键在于它和参数扫描的关系。官方原文的说法是:如果你已经运行了参数扫描,那么参数扫描就是一种特殊类型的作业序列——此时Job Configurations > Parametric Sweep节点扮演了Job Configurations > Sequence节点的角色。这个说法不是比喻,而是实现层面的事实:参数扫描节点本身就是一个"按参数值循环执行子动作"的序列容器,Solution 1、Save Model to File 1、Evaluate: Global Evaluation 1这些子节点在两种形态下行为完全一致。
顶层 Study 节点(命令行只认这一层) │ ├── Study step(Stationary / Time Dependent …) │ └── Job Configurations(作业配置) ├── Parametric Sweep ← 特殊类型的作业序列 ├── Batch Sweep ← 外部进程,批处理下默认忽略 ├── Cluster Sweep ← 外部进程,批处理下默认忽略 └── Sequence ← 纯动作清单 ├── Solution 1 ├── Save Model to File 1 └── Evaluate: Global Evaluation 11.2 命令行为什么不执行作业序列——根因是"顶层识别机制"
这是本篇最核心的机制,也是最常见的踩坑点。
操作系统的命令行接口不允许运行任何不受顶层控制的研究节点内容。批处理只被赋予一个能力:指定"运行哪个 Study"(例如comsol batch -inputfile mymodel.mph -study std1)。它拿不到Job Configurations下的节点句柄——因为顶层 Study 步骤的设置里,并没有暴露"下面挂了一个 Sequence"这一信息给命令行。
于是官方的解法是:给 Study 顶层制造一个可被识别的步骤。最简办法是在 Global Definitions > Parameters 下加一个虚设参数(dummy,例如dummy = 1),然后对这个参数做一次参数扫描。参数扫描节点本身就是特殊类型的作业序列,所以"扫描 dummy"这件事让顶层 Study 步骤产生了一个真实的、可被命令行执行的步骤,进而把 Job Configurations 下的动作序列(保存文件、全局计算)带出来执行。
这就是 dummy 参数技巧的全部逻辑——它不是"魔法开关",而是给顶层补一个执行句柄。
GUI 里点"计算" 命令行批处理 │ │ ▼ ▼ Study 1 ──▶ 识别到 Sequence Study 1 ──▶ 只识别 Study step │ │ ▼ ▼ 求解 + 保存 + 全局计算 求解(序列被跳过,静默无输出)经验法则:如果一条命令跑完没有任何文件产出、也没有报错,先怀疑序列没有被执行,而不是怀疑路径写错。
1.3 inner sweep 与 outer sweep:为什么 dummy 扫描必须是外部扫描
官方明确:要用作业序列跑命令行,扫描必须是"外部扫描(outer sweep)"。
两者的机制差异:
| 维度 | 内部扫描(inner sweep) | 外部扫描(outer sweep) |
|---|---|---|
| 求解器结构 | 复用底层求解结构(如复用因子化),同一求解器序列内循环 | 每个参数值走一遍完整的求解器序列 |
| 速度 | 通常更快 | 通常更慢 |
| 能否被命令行作业序列执行 | 不能 | 能 |
| 方向可逆性 | 可由 inner 改 outer | 不可由 outer 改 inner |
| 强制为 outer 的场景 | — | 几何参数扫描(官方:几何参数扫描必须是外部扫描) |
把扫描强制成外部扫描的操作:在 Parametric Sweep 设置里把Use parametric solver(使用参数化求解器)改为 Off,然后右键 Study 节点执行Show Default Solver(显示默认求解器),这会在 Job Configurations 下生成参数扫描节点——此时它是外部扫描形态。
最佳实践:批量流水线里默认用外部扫描。虽然慢一点,但它换来的是"命令行可执行 + 解可同步 + 动作可挂序列",而这三项正是自动化流水线的前提。内部扫描适合交互式探索,不适合无人值守。
1.4 -study、-job、-methodcall:三个参数不是一回事
| 参数 | 语义 | 前提 |
|---|---|---|
-study | 计算指定 Study(按 tag 识别) | 模型中只有一个 Study 时可省略该参数 |
-job | 启动指定的 job(按 tag 识别),行为类似-study | job 必须已存在于模型中 |
-methodcall | 执行指定的模型方法(model method),例如-methodcall methodcall1 | 模型方法已在 Application Builder 定义,且方法里显式调用了run() |
取 tag 的两个办法:GUI 里在 Model Builder 工具栏的 Model Tree Node Text(模型树节点文本)菜单选 Tag;代码里用model.study().tags()与model.study().name()。
-methodcall的价值在于:模型方法里可以写"读文件 → 设置参数 → 跑求解器序列",于是命令行参数文件(CSV)可以驱动整条链路。这是第 10 篇 KB1250 那条链路的执行入口,本篇 2.1 给出完整可运行版本。
注意一个细节:-methodcall执行的是方法本身,方法内部必须显式调用model.batch(...).run()或model.sol("sol1").runAll()——方法不会自动跑任何序列。
1.5 命令行参数扫描的两条路:结果形态不同
这是最容易被忽略的差异,直接决定后处理怎么写。
路 A:命令行直接给参数(-pname/-plist或-paramfile)。这条路要求模型里的 Parametric Sweep 节点先禁用。产出形态是:每个参数值生成一个独立输出文件,解不同步到单一文件。适合"每个参数一个结果文件、之后用脚本聚合"的模式。
路 B:模型方法读参数文件(-methodcall)。这条路把参数写进 Parametric Sweep 节点的属性(plistarr、pname、punit),然后跑序列。如果勾选了 Synchronize solutions(同步解)或 Synchronize accumulated probe table(同步累计探针表),同步行为与 GUI 运行一致——这是命令行路线能拿到"单一文件里含全部参数解"的唯一方式。
对照表:
| 维度 | -pname/-plist | -paramfile | -methodcall |
|---|---|---|---|
| 参数来源 | 命令行 | 空格分隔的表文件(首行参数名,后续行参数值元组) | 方法内读文件(CSV 格式自定义) |
| 是否要求禁用 Parametric Sweep 节点 | 是 | 是 | 否(方法写入其属性) |
| 输出文件 | 每参数一个 | 每参数一个 | 单一输出文件(若同步开启) |
| 解是否同步 | 否 | 否 | 是(Batch Settings 勾选时) |
| 探针表 | 无跨参数累计 | 无跨参数累计 | 可同步累计探针表 |
-pindex是常被忽略的参数:它给参数索引列表(整数),且数量必须与-plist给的参数个数一致——用于从已有参数列表里挑子集,而不是新造参数。
1.6 批处理参数表里那些"会改变落盘行为"的开关
批处理(batch)专用参数中,最容易出事的是这几组:
| 参数 | 行为 | 风险 |
|---|---|---|
-inputfile | 跑 Model MPH-file 或编译后的 class 文件(Java 模型文件必须先编译) | .class输入不能与 Model Manager 的dbmodel:///位置输出混用(铁律 7,第 16 篇展开) |
-outputfile | 保存输出 | 不给-outputfile时,输入文件会被输出覆盖 |
-nosave | 不保存结果模型 | 与上面组合时容易"跑完什么都没有" |
| `-error {on} | off` | 出错是否停止 |
-graphics | 加载图形库,可在分析中显示图 | 无 UI 环境下仍需要图形库才能导出图片 |
-usebatchlic | 使用批处理许可 | 需要持有 batch licenses(铁律 6) |
| `-mode {batch} | desktop` | 默认 batch 会忽略 Batch/Cluster 设置;加-mode desktop才允许批处理进程启动外部进程 |
-stop/-cancel | stop 跑完当前步返回已有数据;cancel 立即停止不返回数据 | 两者的-inputfile必须与启动进程一致,或与启动时的-outputfile一致 |
-continue/-recover | 继续中断的批处理 / 恢复失败的批处理 | 输出在数据库时,-continue必须用上一轮已保存的模型版本作为新的-inputfile,否则会重算全部已有解 |
-checklicense | 打印该 MPH 文件的许可需求 | 只读,安全,建议每次流水线前跑一次 |
铁律 5 在本篇的落点:comsol batch默认忽略 Batch Sweep / Cluster Sweep 节点;要执行必须加-mode desktop。
二 完整代码与逐行剖析
2.1 模型方法读 CSV 参数文件(知识库 1250 原文,可运行)
这是本篇的核心代码。它做的事:读一个 CSV 参数文件 → 把参数名、单位、值写进 Parametric Sweep 节点属性 → 跑序列。
CSV 格式(官方约定):第 1 行参数名,第 2 行单位,第 3 行起为参数值。
L cm 8 10模型方法(在 Application Builder 中定义;Application Builder 仅支持 Windows):
// 参数文件格式:// pname0, pname1, ...// punit0, punit1, ...// pval00, punit10, ... // 实际为 pval00, pval10, ...// pval01, pval11, ...StringthisStudy="std1";StringthisFeature="param";// (*) Parametric SweepStringthisParam="p1";StringfileName="C:\\models\\pfile.csv";String[][]pArr=readCSVFile(fileName);introws=pArr.length;intcols=pArr[0].length;StringpNames="";StringpUnits="";String[]pValues=newString[cols];// 第 0 行读参数名pNames=pArr[0][0];for(intcol=1;col<cols;col++)pNames=pNames+","+pArr[0][col];// 第 1 行读单位pUnits=pArr[1][0];for(intcol=1;col<cols;col++)pUnits=pUnits+","+pArr[1][col];// 第 2 行起读值;同一列多个值用逗号连接成 plistarrfor(intcol=0;col<cols;col++)pValues[col]=pArr[2][col];for(introw=3;row<rows;row++)for(intcol=0;col<cols;col++)pValues[col]=pValues[col]+","+pArr[row][col];// 写入 Parametric Sweep 属性// 先置空再写入:plistarr/pname/punit 是"累加式"属性,// 直接 set 会把旧值和新值拼在一起 —— 这是官方代码里// 先 set(new int[]{}) / set(new String[]{}) 的原因with(model.study(thisStudy).feature(thisFeature));set("plistarr",newint[]{});set("plistarr",pValues);set("pname",newString[]{});set("pname",pNames);set("punit",newString[]{});set("punit",pUnits);endwith();// 执行扫描model.batch(thisParam).run();// (**)逐行要点:
thisFeature = "param"是 Parametric Sweep 的 feature tag。改成"batsw"(Batch Sweep)或"clusw"(Cluster Sweep)时,执行段要换成model.batch(thisBatch).feature("daDef").run()形态,且要先remove("pr1")、remove("pr2")清掉旧的外部进程节点。model.batch(thisParam).run()的前提是这些节点已经在 GUI 里跑过一次生成过(官方明确假设:study 已在 GUI 运行、p1与 Job Configurations 下的b1已生成)。首次纯命令行跑一条从未在 GUI 里计算过的模型,这条run()会找不到对应特征。- 如果 Parametric Sweep 用的是 Parametric Solver(内部扫描),
(**)必须替换为model.sol("sol1").runAll();——这正好对应 1.3 节:命令行作业序列走的是外部扫描形态,所以属性写入后跑的是 batch 序列而不是 sol。
命令行入口:
comsol batch-inputfiletuning_fork.mph-outputfiletuning_fork_out.mph-methodcallmethodcall1多列参数文件会自动建立嵌套循环(参数必须已在 study 中定义)。
2.2 dummy 参数 + 外部扫描的完整可复现流程
- Global Definitions > Parameters 添加
dummy = 1 - Study 1 下添加 Parametric Sweep,扫描
dummy,扫描值取1 - Parametric Sweep 设置里 Use parametric solver →Off
- 右键 Study 1 → Show Default Solver(此时 Job Configurations 下出现参数扫描节点,即外部扫描形态)
- 给该序列节点加动作子节点:Save Model to File、Evaluate(全局计算)
- 命令行执行:
comsolbatch-inputfilemymodel.mph-studystd1跑完后会看到保存位置与总耗时打印——这是判定序列真的执行了的最直接证据。模型中只有一个 Study 时-study std1可省略。
2.3 Java 侧取 tag 的最小脚本(对照 GUI)
importcom.comsol.model.*;importcom.comsol.model.util.*;publicclassShowTags{publicstaticvoidmain(String[]args)throwsException{Modelmodel=ModelUtil.create("Model");// 这里用已有模型演示;实际用 ModelUtil.load 或 batch 传入的 modelString[]studyTags=model.study().tags();for(Stringt:studyTags){System.out.println("study tag = "+t+", name = "+model.study(t).name());}// Job Configurations 侧用 model.batch().tags() 取 job 序列的 tagString[]batchTags=model.batch().tags();for(Stringt:batchTags){System.out.println("batch tag = "+t+", name = "+model.batch(t).name());}}}说明:model.batch()是 Job Configurations 对应的 list;作业序列在录制代码里表现为model.batch(tag).feature("daDef")这类特征。各动作子节点的类型串(Save Model to File、Evaluate 等)以官方文档为准,本篇不臆造具体类型名——这是铁律"宁缺毋编"的直接应用。
三 常见报错与排查
1)命令行跑完没有任何输出文件,也没有报错
- 现象:
comsolbatch -inputfile x.mph -study std1正常结束,但 Save Model to File、Export 的动作没执行。 - 根因:Job Configurations 下的 Sequence 未被顶层识别(1.2 节),或扫描是 inner sweep。
- 解法:加 dummy 参数 + 参数扫描;把 Use parametric solver 设为 Off 后 Show Default Solver;确认扫描为外部扫描。
2)-plist与-pindex数量不匹配
- 现象:报参数个数不一致。
- 根因:
-pindex的整数个数必须与-plist给定的参数个数对应。 - 解法:两者数量对齐;
-pindex用于挑已有参数列表的子集,不能凭空指定不存在的索引。
3)输出文件把输入文件覆盖
- 现象:跑完原模型被改写,参数被固化。
- 根因:未给
-outputfile时默认覆盖输入文件。 - 解法:显式给
-outputfile;或加-nosave(但这样后处理动作拿不到落盘模型)。
4)Batch Sweep / Cluster Sweep 在批处理下被忽略
- 现象:GUI 里能跑、命令行跑完只有第一个参数结果。
- 根因:批处理默认忽略 Batch/Cluster 设置(铁律 5)。
- 解法:Windows 用
comsolbatch.exe -mode desktop ...,Linux/macOS 用comsol batch -mode desktop ...(5.3a 用-batch off)。分布式模式与 Cluster Sweep 需要 Floating Network License(FNL)。
5)-methodcall执行了但没跑求解
- 现象:方法被调用、参数被写入,但无解。
- 根因:方法内没有显式
run();或run()目标节点从未在 GUI 生成过。 - 解法:在方法末尾显式
model.batch(tag).run()或model.sol("sol1").runAll();首次先在 GUI 跑一遍生成节点。
四 动手练习
练习 1(判定标准:出现 3 个独立输出文件)
取一条含 Parametric Sweep 的模型,在 GUI 里禁用该扫描节点,用-pname L -plist 8[cm],10[cm],12[cm]跑批处理。成功标准:输出目录出现 3 个按参数区分的文件,且聚合脚本读它们时没有单一文件包含全部参数解(证明解未同步)。
练习 2(判定标准:控制台打印保存路径与总耗时)
用 dummy 参数(dummy = 1)+ 外部扫描 + Save Model to File 动作,跑comsolbatch -inputfile mymodel.mph -study std1。成功标准:命令结束时打印保存位置与总耗时,且.mph输出文件的时间戳晚于求解开始时间。若打印里没有保存路径,说明序列未执行——回到 1.2 节重查。
练习 3(思考题,验证要点清单)
解释为什么"几何参数扫描必须用外部扫描"。验证要点:① 能否说出 inner sweep 复用底层求解结构这一机制;② 能否说明几何重建发生在每个参数值的求解序列之前、因此不能在同一求解器序列内循环;③ 能否指出 inner→outer 不可逆这一方向性限制。三点齐全即通过。
五 小结与下一篇预告
作业序列是"求解之后的动作清单",它的可执行性取决于能否被 Study 顶层识别——命令行只认顶层步骤,所以 dummy 参数 + 外部扫描是把它抬到顶层的唯一官方途径。三个命令行参数不是一回事:-study选研究、-job选作业、-methodcall执行方法;参数扫描的两条路(命令行给参数 vs 方法读文件)产出形态不同,前者每参数一个文件且解不同步,后者在同步开启时能拿到单一文件含全部解。
下一篇预告:第 13 篇讲 add-in 与自定义 Ribbon Tab——把本篇的模型方法固化成界面入口,comsol trust与 add-in 库的信任机制。本篇的"命令行执行边界"会在第 13 篇变成"界面入口的执行边界"。
本篇认知问题回显(FAQ)
Q1:COMSOL 的 job sequence(作业序列)是什么?它和 Parametric Sweep 是什么关系?
A:作业序列是 Job Configurations 下的动作清单节点(Sequence),按顺序执行 Save Model to File、Evaluate、Export plot data 等动作;Parametric Sweep 是作业序列的一种特殊类型——按参数值循环执行同一批子动作,此时 Job Configurations 下的 Parametric Sweep 节点替代 Sequence 节点的角色。
Q2:为什么 comsol batch 不能直接执行 Study 节点下的作业序列?dummy 参数为什么能绕过这个限制?
A:命令行接口不允许运行不受顶层控制的研究节点内容——批处理只能指定"运行哪个 Study",拿不到 Job Configurations 下 Sequence 节点的句柄。在 Global Definitions 下加一个 dummy 参数(如dummy = 1)并对它做参数扫描,等于给顶层补一个可被识别的执行步骤,从而把序列动作带出来执行。
Q3:用 dummy 参数从命令行跑作业序列时,为什么扫描必须是 outer sweep?inner sweep 和 outer sweep 在求解器层面有什么区别?
A:命令行作业序列只能执行外部扫描;inner sweep 复用底层求解结构、通常更快,但不可由 outer 改回 inner,且不能被命令行序列执行。把 Use parametric solver 设为 Off 再执行 Show Default Solver,即得到外部扫描形态;几何参数扫描必须为外部扫描。
Q4:comsol batch 的 -study、-job、-methodcall 三个参数有什么区别?
A:-study按 tag 计算指定研究(模型只有一个 Study 时可省略);-job按 tag 启动指定作业,行为类似-study;-methodcall执行 Application Builder 中定义的模型方法(如-methodcall methodcall1),且方法内必须显式调用run()才会执行求解。tag 可通过模型树节点文本菜单显示,或用model.study().tags()读取。
Q5:命令行参数扫描用 -pname/-plist 和用模型方法读参数文件,产出的结果形态有什么不同?
A:-pname/-plist与-paramfile要求先禁用模型里的 Parametric Sweep 节点,每个参数值生成一个独立输出文件、解不同步到单一文件;模型方法把参数写入plistarr/pname/punit属性后跑序列,若勾选 Synchronize solutions 或 Synchronize accumulated probe table,则同步行为与 GUI 一致,可得到含全部参数解的单一输出文件。
Q6:COMSOL 批处理命令行里哪些参数会改变落盘与恢复行为?-stop、-cancel、-continue、-recover 的语义分别是什么?
A:不给-outputfile时输入文件会被输出覆盖,-nosave则完全不保存;-error off出错后继续跑;-usebatchlic需持有批处理许可;-mode desktop才允许执行 Batch Sweep/Cluster Sweep 节点。-stop跑完当前步并返回已有数据,-cancel立即停止且不返回数据;-continue继续中断的批处理,输出在数据库时必须用上一轮已保存的模型版本作为新的-inputfile,否则会重算全部已有解;-recover恢复失败的批处理,恢复用的模型版本由进程自动发现、不应手工传给-inputfile。