关于 post-processing
面向数值模拟分析的后处理 Skill,指导从模拟输出中提取字段、统计数据、计算派生量并生成报告。它强调先核实文件中的实际字段和网格信息,再开展分析与结果验证。
主要功能
- 01提取空间字段与线剖面
- 02分析时间序列和统计分布
- 03计算梯度、积分等派生量
- 04与参考数据比较
- 05生成汇总报告
- 06验证收敛、守恒与数据有效性
适用场景
- 01检查模拟结果中的指定字段
- 02判断残差收敛或物理量是否达稳态
- 03比较模拟曲线与解析或实验数据
- 04整理模拟分析报告
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ heshamfs/ materials-simulation-skills --skill post-processing安装后在 Claude Code 中输入/post-processing确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdevals/evals.jsonevals/files/analytical.jsonfield_output.jsonhistory.jsonprofile.jsonreferences/comparison_metrics.mddata_formats.mdderived_quantities_guide.mdstatistical_methods.mdscripts/comparison_tool.pyderived_quantities.pyfield_extractor.pyprofile_extractor.pyreport_generator.pystatistical_analyzer.pytime_series_analyzer.py详细介绍
后处理技能
分析并提取仿真输出数据中的有效信息。
目标
通过提取字段、统计分析、计算派生量、生成可视化结果以及与参考数据对比,将原始仿真输出转化为可执行的见解。
需收集的输入
运行后处理脚本前,请收集以下信息:
-
输出数据位置
- 仿真输出文件的路径(JSON、CSV、HDF5、VTK)
- 感兴趣的时间步/快照索引
- 要提取的字段名称
请从文件中读取字段名称,切勿自行假设。 提取前,打开输出文件(或运行
field_extractor.py --input <file> --list --json),并且只使用fields中实际出现的字段名称。 如果文件中没有temperature等字段,请勿自行编造;也不要假设网格大小,应从数据中读取实际的shape/count。 -
分析类型
- 字段提取(特定时刻的空间数据)
- 时间序列(量的时间演化)
- 线剖面(穿过计算域的一维截面)
- 统计汇总(均值、标准差、分布)
- 派生量(梯度、积分、通量)
- 与参考数据对比
-
输出要求
- 输出格式(JSON、CSV、表格)
- 可视化需求
- 报告格式
脚本
| 脚本 | 用途 | 关键输入 |
|---|---|---|
field_extractor.py | 从输出文件中提取字段数据 | --input、--field、--timestep |
time_series_analyzer.py | 分析时间演化 | --input、--quantity、--window |
profile_extractor.py | 提取线剖面 | --input、--field、--start、--end |
statistical_analyzer.py | 计算字段统计信息 | --input、--field、--region |
derived_quantities.py | 计算派生量 | --input、--quantity、--params |
comparison_tool.py | 与参考数据进行比较 | --simulation、--reference、--metric |
report_generator.py | 生成汇总报告 | --input、--template、--output |
工作流
1. 数据清单
首先了解有哪些可用数据:
# List available fields and timesteps
python scripts/field_extractor.py --input results/ --list --json
2. 字段提取
提取特定时间步的空间字段数据:
# Extract concentration field at timestep 100
python scripts/field_extractor.py \
--input results/field_0100.json \
--field concentration \
--json
# Extract multiple fields
python scripts/field_extractor.py \
--input results/field_0100.json \
--field "phi,concentration,temperature" \
--json
3. 时间序列分析
分析各量的时间演化:
# Extract total energy vs time
python scripts/time_series_analyzer.py \
--input results/history.json \
--quantity total_energy \
--json
# Compute moving average with window
python scripts/time_series_analyzer.py \
--input results/history.json \
--quantity mass \
--window 10 \
--json
# Detect steady state (relative-variation test; best for physical quantities)
python scripts/time_series_analyzer.py \
--input results/history.json \
--quantity residual \
--detect-steady-state \
--tolerance 1e-6 \
--json
# Convergence by absolute threshold (physically correct test for residuals)
python scripts/time_series_analyzer.py \
--input results/history.json \
--quantity residual \
--absolute-threshold 1e-6 \
--json
4. 线剖面提取
提取穿过计算域的一维剖面:
# Extract profile along x-axis at y=0.5
python scripts/profile_extractor.py \
--input results/field_0100.json \
--field concentration \
--start "0,0.5,0" \
--end "1,0.5,0" \
--points 100 \
--json
# Interface profile (through center)
python scripts/profile_extractor.py \
--input results/field_0100.json \
--field phi \
--axis x \
--slice-position 0.5 \
--json
5. 统计分析
计算字段数据的统计信息:
# Global statistics
python scripts/statistical_analyzer.py \
--input results/field_0100.json \
--field concentration \
--json
# Statistics in a specific spatial region (1D/2D fields only).
# Coordinates are derived from the field shape and grid spacing
# (explicit dx/dy, or Lx/Ly via dx = Lx/(nx-1)); only the variables
# x, y, z compared against numbers, joined by and/or, are allowed.
python scripts/statistical_analyzer.py \
--input results/field_0100.json \
--field phi \
--region "x>0.3 and x<0.7" \
--json
# Distribution analysis
python scripts/statistical_analyzer.py \
--input results/field_0100.json \
--field phi \
--histogram \
--bins 50 \
--json
6. 派生量
根据原始数据计算物理量:
# Compute interface area
python scripts/derived_quantities.py \
--input results/field_0100.json \
--quantity interface_area \
--threshold 0.5 \
--json
# Compute gradient magnitude
python scripts/derived_quantities.py \
--input results/field_0100.json \
--quantity gradient_magnitude \
--field phi \
--json
# Compute volume fractions
python scripts/derived_quantities.py \
--input results/field_0100.json \
--quantity volume_fraction \
--field phi \
--threshold 0.5 \
--json
# Compute flux through boundary
python scripts/derived_quantities.py \
--input results/field_0100.json \
--quantity boundary_flux \
--field concentration \
--boundary "x=0" \
--json
7. 与参考数据对比
将仿真结果与参考数据进行比较:
# Compare to analytical solution
python scripts/comparison_tool.py \
--simulation results/profile.json \
--reference reference/analytical.json \
--metric l2_error \
--json
# Compare to experimental data
python scripts/comparison_tool.py \
--simulation results/history.json \
--reference experimental_data.csv \
--metric rmse \
--interpolate \
--json
# Compare two simulations
python scripts/comparison_tool.py \
--simulation results_fine/field.json \
--reference results_coarse/field.json \
--metric max_difference \
--json
8. 生成报告
自动生成报告:
# Generate summary report
python scripts/report_generator.py \
--input results/ \
--output report.json \
--json
# Generate with specific sections
python scripts/report_generator.py \
--input results/ \
--sections "summary,statistics,convergence" \
--output report.json \
--json
典型后处理流程
完整的仿真分析流程:
python scripts/field_extractor.py --input results/ --list --json # 1. inventory
python scripts/statistical_analyzer.py --input results/field_final.json --field phi --json # 2. final-state stats
python scripts/time_series_analyzer.py --input results/history.json --quantity residual --detect-steady-state --json # 3. convergence
python scripts/derived_quantities.py --input results/field_final.json --quantity volume_fraction --field phi --json # 4. derived quantities
python scripts/comparison_tool.py --simulation results/profile.json --reference benchmark/expected.json --metric l2_error --json # 5. compare to reference
python scripts/report_generator.py --input results/ --output analysis_report.json --json # 6. summary report
结果解读指南
时间序列分析
根据量的类型,以不同方式解读收敛情况,因为分析器报告的两个信号(convergence.{rate,type} 和 steady_state.reached)回答的是不同问题,二者合理地出现不一致。
残差/误差量(例如 residual、error):
- 根据绝对值与容差的比较判断收敛:残差低于或等于目标容差(例如
1e-6)即为收敛。使用--absolute-threshold <tol>可获取convergence_threshold块,这是针对残差在物理上正确的检验方式。 - 相对的
--detect-steady-state检验回答的是“残差是否已停止变化?”,而不是“残差是否已收敛?”。对于仍在下降的残差,steady_state.reached = false是预期结果,并不表示失败。 - 残差出现平台期意味着求解器停滞(
convergence.type = "stalled"),而非达到稳态。 - 综合判断这些信号:如果
convergence.type为fast/linear,且最终残差较小(或convergence_threshold.reached = true),即使steady_state.reached = false,也应将本次运行报告为已收敛。
物理量(例如 energy、volume_fraction、mass、interface_area):
- 能量单调下降:系统正趋近于平衡。
- 平台期(
steady_state.reached = true):已达到稳态。 - 振荡:可能表示时间步长过大。
- 突然跳变:可能存在数值不稳定。
统计分析
- 序参量的双峰分布:两相混合
- 高方差:微观结构不均匀
- 偏斜分布:相分数不对称
比较指标
| 指标 | 解读 |
|---|---|
| L2 误差 < 1% | 极佳的一致性 |
| L2 误差 1-5% | 良好的一致性 |
| L2 误差 5-10% | 中等一致性 |
| L2 误差 > 10% | 一致性较差,需进一步调查 |
输出格式
所有脚本都支持 --json 标志,以生成机器可读的输出。大多数脚本会输出一个扁平的顶层对象,其键取决于具体脚本。例如,对单个字段运行 field_extractor.py --include-data 会输出:
{
"field": "concentration",
"found": true,
"data": [[0.1, 0.9], [0.3, 0.6]],
"shape": [2, 2],
"min": 0.1,
"max": 0.9,
"mean": 0.475,
"count": 4,
"source_file": "results/field_0100.json",
"timestep_info": {"timestep": 100, "time": 1.5}
}
关于封装结构的说明(各脚本的结构并不统一):
field_extractor.py、statistical_analyzer.py、time_series_analyzer.py、profile_extractor.py和comparison_tool.py会输出一个扁平对象,其中包含source_file键和特定于脚本的结果键。derived_quantities.py会将其负载封装在{ "inputs": {...}, "results": {...} }结构中。report_generator.py会在顶层输出report_version和generator键,以及所请求的报告部分。
没有脚本会输出顶层的 script、version 或 input_file 键;字段统计信息(min/max/mean/count)位于顶层,而非嵌套在 data 对象下。
验证清单
在信任或报告后处理结果之前,请生成并记录以下具体证据(与此技能的脚本和输出键对应):
- 先列出实际字段。 运行
field_extractor.py --list --json,并记录实际的fields名称和shape;后续每个--field参数都必须出现在该列表中(不得假设存在temperature,也不得猜测网格大小)。 - 根据量的类型使用正确的收敛测试。 对于残差/误差,记录通过
--absolute-threshold <tol>得到的convergence_threshold.reached和final_value(即|x_final| <= tol测试),而不是依赖steady_state.reached;对于物理量,记录通过--detect-steady-state得到的steady_state.{reached,relative_variation,value}。 - 核对两个收敛信号。 将
convergence.type和convergence.rate与steady_state.reached一同记录,并确认convergence.type = "stalled"应解读为求解器停滞(而非稳态);残差仍在下降但steady_state.reached = false时,不应报告为失败。 - 根据容差检查守恒性。 记录首个和最后一个时间步的守恒积分(
derived_quantities.py --quantity mass/integral,或volume_fraction),并确认漂移在该动力学的文档所述容差范围内(Cahn-Hilliard 守恒序参量时约为 0;Allen-Cahn 中则预期会变化)。 - 确认网格间距具有物理意义。 记录
derived_quantities.py回显的spacing块(dx/dy/dz),并验证它来自显式的dx/dy,或正确的Lx/(nx-1)推导;同时确认 stderr 中未输出WARNING: explicit dx ... inconsistent with Lx。 - 确认非有限值未破坏结果。 确认派生量脚本未触发
Field contains non-finite value(NaN/Inf),且报告的min/max在物理上合理(例如,序参量始终处于预期范围内)。 - 根据文档所述区间评定比较误差。 记录
comparison_tool.py的指标值(例如l2_error),并将其对应到此技能中的一致性区间(<1% 为优秀……>10% 为较差,需调查);同时先确认模拟结果和参考数据已对齐/插值到同一坐标轴上。
常见误区与自我辩解
| 看似省事的做法 | 为什么不对/应该怎么做 |
|---|---|
"steady_state.reached = false,所以求解器没有收敛。" | 相对稳态测试问的是“它是否已停止变化?”,对于仍在下降的残差,答案是否定的。对于残差,请使用 --absolute-threshold <tol> 并读取 convergence_threshold.reached;同时结合 convergence.type/rate 判断。 |
| “残差已趋于平稳,所以它达到了稳态。” | 残差持平意味着求解器停滞(convergence.type = "stalled",rate > 0.99),而不是收敛。称其已收敛前,请确认平台值确实小于或等于容差。 |
“我直接提取 temperature/假设网格是 256×256 就行。” | 字段名称和形状没有保证。请先运行 field_extractor.py --list --json,并且只使用文件实际报告的 fields 和 shape。 |
| “两个网格/两次运行结果一致,所以结果与网格无关。” | 对两个场使用 comparison_tool.py 只能界定它们之间的差异,不能确定渐近范围。声称结果与网格无关前,请使用 >=3 个分辨率估算观测阶数。 |
| “体积分数看起来稳定,所以质量守恒。” | 稳定的 volume_fraction(经过阈值处理的计数)并不是守恒积分。请检查首个与最后一个时间步之间 --quantity integral/mass 的漂移是否在容差范围内——并且只有对于守恒的(Cahn-Hilliard)动力学,才应期待漂移约为 0。 |
“默认的 dx=1.0 足以计算派生量。” | 如果文件中没有间距信息,脚本会回退到 dx=dy=dz=1.0,因此任何长度/面积/通量/积分的单位都是网格单位,而非物理单位。请提供 --dx/--dy(或在文件中提供 Lx/Ly),并核对回显的 spacing 块。 |
| “程序运行完并输出了 JSON,所以数值有效。” | 执行完成不代表结果正确。报告前请检查守恒漂移、收敛判定、数值是否有限,以及比较误差范围。 |
安全性
输入验证
- 用户提供的字段名称会根据
[a-zA-Z_][a-zA-Z0-9_.-]*进行验证,以防止通过构造的字段名称进行注入 statistical_analyzer.py会在使用前,根据严格的允许列表验证--region条件:只接受坐标变量x、y、z与数值字面量进行比较(< <= > >= == !=),并通过and/or连接;其他任何内容都会以代码 2 退出。解析后的条件会作为真实的坐标掩码应用(不使用eval/exec),因此报告的统计数据反映的是请求的区域profile_extractor.py会根据相同的模式验证字段名称,并将点坐标验证为有限数值,维度最多为 3comparison_tool.py中的--metric值会根据固定的允许列表进行验证(l1_error、l2_error、linf_error、rmse、mae、max_difference、correlation、r_squared);未知指标会返回错误report_generator.py中的--sections会根据已知的节名称进行验证(summary、statistics、convergence、validation、files、parameters、all);未知节会以代码 2 退出--bins(statistical_analyzer)、--points(profile_extractor)和--window(time_series_analyzer)会被验证为带上限的正整数;超出范围的值会以代码 2 退出
文件访问
- 所有 JSON 和 CSV 加载函数都会在解析前拒绝超过 500 MB 的文件
- 加载的 JSON 文件必须以对象(dict)作为根元素
report_generator.py将目录列表限制为最多 10,000 个条目,以防止资源耗尽- 脚本会读取用户指定的模拟输出文件(JSON、CSV),但不会遍历明确指定范围之外的目录
- 除非 Agent 使用 Write 保存报告,否则输出会写入 stdout(JSON)
工具限制
- Read:用于检查脚本源代码、参考资料和模拟输出文件
- Write:用于保存分析结果、比较报告或生成的摘要;写入范围仅限用户的工作目录
- Grep/Glob:用于定位模拟输出文件和搜索参考资料
- 此技能的
allowed-tools不包含Bash,以防 Agent 在处理不可信的模拟输出文件时执行任意命令
安全措施
- 不使用
eval()、exec()或动态代码生成——区域解析使用正则表达式匹配,绝不执行代码 - 所有子进程调用均使用显式参数列表(不使用
shell=True) - 缩减工具范围(不包含 Bash)将 Agent 限制为仅执行读写操作
- 使用前会对字段名称和区域表达式进行清理,以防注入
参考资料
详细信息请参阅:
references/data_formats.md- 支持的输入/输出格式references/statistical_methods.md- 统计分析方法references/derived_quantities_guide.md- 物理量计算references/comparison_metrics.md- 误差指标及其解读
要求
- Python 3.10+
- NumPy(用于数值运算)
- 核心功能不依赖其他外部依赖项
版本历史
权威记录请参阅 CHANGELOG.md。
- v1.1.3 (2026-06-24):新增“验证清单”(基于证据,并与脚本的实际输出键对应:字段列表、残差与物理量的收敛性对比、信号核对、守恒漂移、网格间距合理性、非有限值保护、比较误差区间),并在安全部分之前新增“常见陷阱与合理化说辞”表格。仅更新文档;不改变脚本行为。
- v1.1.2 (2026-06-23):使评估套件可独立运行且具有区分能力——将真实测试样例复制到
evals/files/(仅包含phi/concentration字段,网格为 10x10;残差序列以 5e-6 结束),重写所有评估提示词,使其引用这些确切文件,并新增确定性的script_checks,用于固定经过验证的脚本输出(包括 1e-6 绝对残差阈值未达到的正确判定)。新增指南,说明应从输出文件读取字段名称,而非自行假设。 - v1.1.1 (2026-06-23):在
statistical_analyzer.py中实现了基于实际坐标的--region筛选;修复report_generator.py,使其能够读取嵌套的fields.*.values输出;在derived_quantities.py的网格间距计算中明确规定dx/dy/dz的优先级;新增--absolute-threshold收敛模式和关于残差与物理量解读的指南;修正 Output Format 示例和版本元数据;新增--bins/--window边界验证。 - v1.1.0 (2026-03-26):优化描述、评估套件、安全审查,标准化元数据,并新增 CHANGELOG。
- v1.0.0 (2026-02-25):首次发布。