关于 simulation-orchestrator
simulation-orchestrator 是一项用于管理模拟运行批次的 Python 技能,可生成参数扫描配置、跟踪作业状态,并使用标准库汇总已完成运行的结果。
主要功能
- 01生成网格、linspace 和 LHS 扫描
- 02初始化并管理模拟批次
- 03跟踪作业状态和进度
- 04汇总指标与运行结果
- 05按指标方向确定最佳运行
适用场景
- 01为参数研究创建配置
- 02监控模拟批次中的作业
- 03按结果指标比较已完成运行
- 04选出指标最小或最大的运行
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ heshamfs/ materials-simulation-skills --skill simulation-orchestrator安装后在 Claude Code 中输入/simulation-orchestrator确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdevals/evals.jsonevals/files/config.jsonsimulation.jsonevals/files/case3_init/config_0000.jsonconfig_0001.jsonconfig_0002.jsonconfig_0003.jsonmanifest.jsonevals/files/case3_status/campaign.jsonevals/files/case4_campaign/campaign.jsonconfig_0000.jsonconfig_0001.jsonconfig_0002.jsonresult_job_0000.jsonresult_job_0001.jsonresult_job_0002.jsonreferences/aggregation_methods.mdcampaign_patterns.mdsweep_strategies.mdscripts/campaign_manager.pyjob_tracker.pyresult_aggregator.pysweep_generator.py详细介绍
仿真编排器
目标
提供用于管理多仿真批次的工具:生成参数扫描、跟踪作业执行状态,并汇总已完成运行的结果。
要求
- Python 3.10+
- 无外部依赖(仅使用 Python 标准库)
- 可在 Linux、macOS 和 Windows 上运行
需要收集的输入
运行编排脚本前,请向用户收集以下信息:
| 输入 | 描述 | 示例 |
|---|---|---|
| 基础配置 | 仿真配置模板 | base_config.json |
| 参数范围 | 要扫描的参数及其边界 | dt:[1e-4,1e-2],kappa:[0.1,1.0] |
| 扫描方法 | 如何采样参数空间 | grid、lhs、linspace |
| 输出目录 | 批次文件的存储位置 | ./campaign_001 |
| 仿真命令 | 运行每次仿真的命令 | python sim.py --config {config} |
决策指南
如何选择扫描方法
Need every combination (full factorial)?
├── YES → Use grid (warning: exponential growth with parameters)
└── NO → Is space-filling coverage needed?
├── YES → Use lhs (Latin Hypercube Sampling)
└── NO → Use linspace for uniform sampling per parameter
| 方法 | 最适合 | 样本数量 |
|---|---|---|
grid | 低维(1-3),需要精确覆盖角点 | n^d(指数级) |
linspace | 一维扫描、均匀间隔 | 每个参数 n 个 |
lhs | 高维、空间填充 | 用户指定的预算 |
批次规模指南
| 参数数量 | 每个参数的网格点数 | 总运行次数 | 建议 |
|---|---|---|---|
| 1 | 10 | 10 | 使用网格即可 |
| 2 | 10 | 100 | 网格可接受 |
| 3 | 10 | 1,000 | 考虑使用 LHS |
| 4+ | 10 | 10,000+ | 使用 LHS 或 DOE |
脚本输出(JSON 字段)
| 脚本 | 输出字段 |
|---|---|
scripts/sweep_generator.py | configs、parameter_space、sweep_method、total_runs |
scripts/campaign_manager.py --action init | campaign_id、total_jobs、config_dir、command_template |
scripts/campaign_manager.py --action status | campaign_id、status、jobs、progress、total_jobs、created_at |
scripts/campaign_manager.py --action list | jobs(作业记录数组) |
scripts/job_tracker.py | job_id、status、start_time、end_time、exit_code |
scripts/result_aggregator.py | summary(含 minimize)、statistics、best_run、failed_runs |
关于扫描参数名称的说明:
sweep_generator.py会根据键路径将每个扫描值写入基础配置。裸名称(例如kappa)会覆盖顶层键;点号表示法名称(例如parameters.kappa)则指向嵌套键。扫描键路径必须与求解器读取该值的位置一致——如果配置中使用parameters.kappa,却扫描kappa,就会添加一个未使用的顶层键,并静默保留基础配置中的原值。请参阅references/sweep_strategies.md。
工作流
步骤 1:生成参数扫描
为所有参数组合创建配置:
python3 scripts/sweep_generator.py \
--base-config base_config.json \
--params "dt:1e-4:1e-2:5,kappa:0.1:1.0:3" \
--method linspace \
--output-dir ./campaign_001 \
--json
步骤 2:初始化批次
创建批次跟踪结构:
python3 scripts/campaign_manager.py \
--action init \
--config-dir ./campaign_001 \
--command "python sim.py --config {config}" \
--json
步骤 3:跟踪作业状态
监控正在运行的作业:
python3 scripts/job_tracker.py \
--campaign-dir ./campaign_001 \
--update \
--json
步骤 4:汇总结果
合并已完成运行的结果:
python3 scripts/result_aggregator.py \
--campaign-dir ./campaign_001 \
--metric final_energy \
--json
result_aggregator.py 默认执行最小化:best_run 是指标值最低的运行(且 summary.minimize 为 true)。如果数值越高越好(例如产量、准确率、吞吐量),请传入 --maximize,这样 best_run 就会是数值最高的运行:
# Higher is better -> select the maximum
python3 scripts/result_aggregator.py \
--campaign-dir ./campaign_001 \
--metric yield \
--maximize \
--json
决策指南:如果数值越高越好(产量、准确率、吞吐量),请传入
--maximize;否则,报告的best_run将是最小值。
CLI 示例
# Generate 5x3=15 runs varying dt (5 values) and kappa (3 values)
python3 scripts/sweep_generator.py \
--base-config sim.json \
--params "dt:1e-4:1e-2:5,kappa:0.1:1.0:3" \
--method linspace \
--output-dir ./sweep_001 \
--json
# Generate LHS samples for 4 parameters with budget of 20 runs
python3 scripts/sweep_generator.py \
--base-config sim.json \
--params "dt:1e-4:1e-2,kappa:0.1:1.0,M:1e-6:1e-4,W:0.5:2.0" \
--method lhs \
--samples 20 \
--output-dir ./lhs_001 \
--json
# Check campaign status
python3 scripts/campaign_manager.py \
--action status \
--config-dir ./sweep_001 \
--json
# List jobs (read-only), optionally filtered by status
python3 scripts/campaign_manager.py \
--action list \
--config-dir ./sweep_001 \
--status-filter failed \
--json
# Get summary statistics from completed runs (minimize: best = lowest)
python3 scripts/result_aggregator.py \
--campaign-dir ./sweep_001 \
--metric final_energy \
--json
# Maximization metric: best = highest value (yield, accuracy, throughput)
python3 scripts/result_aggregator.py \
--campaign-dir ./sweep_001 \
--metric yield \
--maximize \
--json
对话工作流示例
用户:我想为我的相场仿真对 dt 和 kappa 进行参数扫描。我想尝试 5 个介于 1e-4 和 1e-2 之间的 dt 值,以及 4 个介于 0.1 和 1.0 之间的 kappa 值。
Agent 工作流:
- 计算总运行次数:5 x 4 = 20 次运行
- 生成扫描配置:
python3 scripts/sweep_generator.py \ --base-config simulation.json \ --params "dt:1e-4:1e-2:5,kappa:0.1:1.0:4" \ --method linspace \ --output-dir ./dt_kappa_sweep \ --json - 初始化批次:
python3 scripts/campaign_manager.py \ --action init \ --config-dir ./dt_kappa_sweep \ --command "python phase_field.py --config {config}" \ --json - 用户运行仿真后,汇总结果:
python3 scripts/result_aggregator.py \ --campaign-dir ./dt_kappa_sweep \ --metric interface_width \ --json
错误处理
| 错误 | 原因 | 解决方案 |
|---|---|---|
Base config not found | 文件路径无效 | 确认基础配置文件存在 |
Invalid parameter format | 参数字符串格式错误 | 使用格式 name:min:max:count 或 name:min:max |
Output directory exists | 将覆盖现有内容 | 使用 --force 或选择新目录 |
No completed jobs | 没有可汇总的结果 | 等待任务完成或检查是否有失败 |
Metric not found | 结果文件缺少字段 | 确认结果 JSON 中的指标名称 |
与其他技能集成
simulation-orchestrator 可与其他 simulation-workflow 技能配合使用:
parameter-optimization simulation-orchestrator
│ │
│ DOE samples ────────────────>│ Generate configs
│ │
│ │ Run simulations
│ │
│<──────────────────────────── │ Aggregate results
│ │
│ Sensitivity analysis │
│ Optimizer selection │
典型的组合工作流
- 使用
parameter-optimization/doe_generator.py获取采样点 - 使用
simulation-orchestrator/sweep_generator.py创建配置 - 运行模拟(由用户负责)
- 使用
simulation-orchestrator/result_aggregator.py收集结果 - 使用
parameter-optimization/sensitivity_summary.py进行分析
验证清单
在采信某次运行的 best_run 或汇总统计数据之前,请为以下每一项记录具体证据:
- 确认扫描的键路径确实改变了求解器读取的值:打开至少一个生成的
config_NNNN.json,并验证扫描参数(例如parameters.kappa)在预期的嵌套层级中具有预期值,而不是位于未使用的重复顶层键中(sweep_generator.py按键路径写入)。 - 根据
result_aggregator.py --json核对任务统计:记录summary.total_jobs、summary.completed和summary.failed,并确认completed + failed == total_jobs。任何差额都意味着有运行被静默跳过(结果文件缺失或extract_metric返回了None),必须调查,不能忽略。 - 确认
completed > 0,并且记录的summary.metric与求解器实际写入的字段一致。指标名称拼写错误或字段不存在时,extract_metric会返回None,导致已完成运行数为零且不报错。 - 记录
summary.minimize,并在引用best_run之前确认它与预期的优化方向一致(默认是最小化;对于产量、准确率或吞吐量,使用--maximize)。 - 不要将
job_tracker.py标记的“completed”视为物理运行成功:它仅根据结果文件是否存在来标记任务完成,并将exit_code设为 0——应独立检查运行的实际退出状态和求解器日志,确认没有非零退出码或 NaN/Inf 输出。 - 对指标值进行异常值/合理性检查(例如,使用
references/aggregation_methods.md中的 Tukey 1.5x IQR 方法),并确认best_run.value在物理上合理,而非因运行崩溃产生的异常极值。 - 对于 LHS 扫描,记录所用的
--seed,并保存manifest.json(参数边界、total_runs、parameter_space),以确保采样集可复现。
常见陷阱与自我辩解
| 看似省事的做法 | 为什么不对/应该怎么做 |
|---|---|
| “作业跟踪器显示已完成,所以运行成功了。” | job_tracker.py 只要结果文件存在就会标记为“已完成”,并将 exit_code 硬编码为 0——它从不读取实际退出代码。崩溃的运行只要写入了部分结果文件,看起来就和正常运行没有区别。请检查求解器的实际退出状态和输出是否有效。 |
“completed 很高,所以我已经拿到了所有结果。” | 缺少结果文件,或 extract_metric 无法读取指标的作业会被静默跳过——既不会计入 completed,也不会计入 failed。请核对 completed + failed 是否等于 total_jobs;如果对不上,就说明有运行结果丢失。 |
“聚合器返回了 best_run,所以这就是最优结果。” | 默认情况下,聚合器会取最小值。如果数值越大越好,就必须传入 --maximize,否则 best_run 就是最差的结果。务必记录 summary.minimize 并确认优化方向。 |
“我对 kappa 做了扫描,所以各次运行的值会不同。” | sweep_generator.py 按键路径写入。如果基础配置将值嵌套在 parameters.kappa 下,但你扫描的是不带路径的 kappa,那么每个配置都会保留原有的嵌套值,同时新增一个未使用的顶层键——这样的扫描在科学上毫无意义。请扫描求解器实际读取的确切点分路径。 |
| “指标名称差不多就行。” | 指标名称拼写错误或不存在,会导致 extract_metric 对每次运行都返回 None,因此 completed 为 0,统计结果也为空——而且不会报错。请确认指标名称与求解器输出字段完全一致。 |
| “网格覆盖得很全面,所以所有参数都用网格法。” | 网格搜索的规模是 n^d——会呈指数级增长(4 个参数 × 10 个取值 = 10,000 次运行)。对于 4 个或更多维度,请使用 lhs 并合理设定预算;网格搜索仅用于 1 至 3 个参数。 |
| “LHS 是随机的,所以没必要记录任何东西。” | 只有固定 --seed,LHS 才能复现。如果不记录种子(以及 manifest.json),就无法重新生成或证明样本集的合理性。 |
安全
输入验证
- 指标名称(
result_aggregator.py --metric)会根据[a-zA-Z_][a-zA-Z0-9_.]*进行验证,以防止通过构造的键进行路径遍历或注入 - 扫描参数名称(
sweep_generator.py --params)会根据[a-zA-Z_][a-zA-Z0-9_]*(.[a-zA-Z_][a-zA-Z0-9_]*)*进行验证(使用点号表示嵌套键);无效名称会被拒绝 campaign_manager.py会验证命令模板,拒绝 shell 链接运算符(;、|、&、反引号、$)--params格式字符串会经过解析和验证(格式为name:min:max:count,数值边界必须有限——拒绝NaN/Inf——且min < max,计数必须为正整数且不超过 100,000);每次扫描最多允许 32 个参数--method会根据固定的允许列表(grid、linspace、lhs)进行验证--samples会验证为有上限的正整数(最大值为 1,000,000)--action会根据固定的允许列表(init、status、list)进行验证;对于只读的list操作,--status-filter会验证为pending、running、completed或failed
文件访问
sweep_generator.py只会读取由--base-config指定的单个基础配置文件(JSON),并将生成的配置写入--output-dirresult_aggregator.py对每个结果文件设定 10 MB 的文件大小限制,限制 JSON 最大嵌套深度,并严格检查数值类型(拒绝bool、NaN、Inf)- 结果文件中的所有字符串值在显示前都会经过清理(截断并移除控制字符)
- 插入 shell 命令的配置路径会根据安全字符允许列表进行验证,并使用
shlex.quote()转义
工具限制
- Read:用于检查脚本源代码、参考资料、基础配置和活动状态文件
- Write:用于保存生成的扫描配置、活动清单和汇总结果;写入范围仅限于用户的工作目录
- Grep/Glob:用于定位活动文件、结果文件和搜索参考资料
- 该技能的
allowed-tools不包含Bash,以防 Agent 在处理不可信的模拟输出时执行任意命令
安全措施
- 不使用
eval()、exec()或动态代码生成 - 所有子进程调用均使用显式参数列表(不使用
shell=True) - 缩减工具范围(不包含 Bash),将 Agent 限制为仅执行读写操作
- 命令模板会经过验证,但技能本身绝不会执行;执行由用户负责
限制
- 不是作业调度器:不会向 SLURM/PBS 提交作业;只生成配置并跟踪状态
- 不支持并行执行:用户必须在外部运行模拟(可使用 GNU parallel、SLURM 等)
- 基于文件的跟踪:通过文件跟踪状态;不使用数据库,也不进行实时监控
- 本地文件系统:假设所有文件都可从本地机器访问
参考资料
references/campaign_patterns.md- 常见活动结构references/sweep_strategies.md- 参数扫描设计指南references/aggregation_methods.md- 结果汇总技术
版本历史
权威的带日期历史记录请参见 CHANGELOG.md。概要:
- v1.1.3 (2026-06-24):新增验证清单和常见陷阱及其合理化解释部分,内容基于脚本的实际行为(仅根据结果文件判断“已完成”、静默跳过无法读取的指标、默认采用最小化方向、按键路径合并语义)
- v1.1.1 (2026-06-23):在
sweep_generator.py中支持点号表示法的嵌套覆盖;强化输入验证(--params名称/有限值/数量上限、--samples范围);记录--maximize和list操作;更正脚本输出表和示例中的数字 - v1.1.0 (2026-03-26):统一元数据、评估套件和安全审查,并新增 CHANGELOG
- v1.0.0 (2026-02-25):首次发布,包含扫描、活动、跟踪和汇总功能