3. 结果文件格式解析

在分子计算工作流中,结果文件是连接“计算”与“汇总筛选”的唯一数据载体。不同软件的输出格式差异极大:Gaussian 的 .log 是带标记行的文本流,ORCA 的 .out 使用块状段落,VASP 的 OUTCAR 是键值对与表格混合,GROMACS 的 .xvg 则是注释头加多列数值。若解析阶段只做“按行读取、正则抓数”,一旦遇到收敛失败、任务重启、多步优化或异常中断,字段就会错位。因此本节的核心不是“读文件”,而是建立一套可定位、可容错、可追溯的解析策略。

一、先识别格式族,再决定解析方式

常见输出可归为四类。第一类是标记行文本,如 Gaussian:关键结果由固定关键词引导,例如 SCF Done:、Optimized Parameters、Standard orientation。第二类是块状段落,如 ORCA 的 FINAL SINGLE POINT ENERGY 与 SCF ITERATIONS 各自成块。第三类是键值对与表格混合,如 VASP 的 E0=、free energy TOTEN 以及 POSITION 后的坐标表。第四类是列式数据,如 GROMACS 的 .xvg,以 @ 开头为元数据,# 开头为注释,其余为数值列。

判断格式族后,解析器应选择不同策略:标记行文本用“关键词锚点 + 局部窗口”,块状段落用“段首段尾配对”,键值对用“键名精确匹配”,列式数据用“列索引 + 单位声明”。切忌对所有格式统一用“第 N 行第 M 列”定位,因为行号会随任务规模、并行核数、是否重启而变化。

二、字段定位:锚点、窗口与唯一性校验

字段定位的关键是找到稳定锚点。以 Gaussian 能量为例,一次优化可能包含几十次 SCF,若直接取第一个 SCF Done,得到的是初始结构能量而非最终能量。正确做法是:先定位最后一个 SCF Done,再在其后查找 Optimization completed 或 Stationary point found,确认该能量属于收敛结构。若任务未收敛,则最后一个 SCF Done 只能标记为“中间能量”,不能写入最终结果表。

对于坐标,Gaussian 的 Standard orientation 与 Input orientation 含义不同:前者是内坐标转直角坐标后的标准取向,后者是输入取向。汇总键长、键角时应统一使用 Standard orientation,并在元数据中记录取向类型。VASP 的 POSITION 块则需注意分数坐标与笛卡尔坐标的切换,通常由 Direct 或 Cartesian 标记决定。

定位字段时,建议同时记录“锚点行号、匹配次数、取值来源块”。这样当同一文件出现多次匹配时,可以回溯到底取了哪一次,而不是只得到一个孤立的数值。

三、异常行处理:跳过、标记与隔离

异常行是解析中最容易被忽视的部分。常见异常包括:计算中断导致文件末尾截断、SCF 不收敛产生 Convergence failure、几何优化震荡出现 Optimization stopped、并行输出交错插入空行或警告、以及编码错误产生不可见字符。处理原则是不静默丢弃,而是分类标记。

可把每行分为三类:正常数据行、可忽略噪声行、异常信号行。空行、分隔线、版权头属于可忽略噪声;Error、Warning、not converged、killed 属于异常信号,必须写入解析日志并影响该记录的“质量标签”。例如某条记录能量字段存在但伴随 Convergence failure,则质量标签应为 unconverged,在后续筛选中默认排除或单独分组。

# 伪代码:异常行分类
for line in lines:
    if is_noise(line):          # 空行、分隔线、版权
        continue
    if is_error_signal(line):   # Error / not converged / killed
        record.flags.append(classify(line))
        continue
    if match_anchor(line):      # SCF Done / TOTEN / FINAL SINGLE POINT
        record.fields.update(extract(line))

四、元数据提取:让结果可追溯

只提取能量和坐标是不够的。元数据决定了结果能否被正确比较和复现。应至少提取:软件与版本、方法/泛函、基组、溶剂模型、电荷与自旋多重度、任务类型(单点、优化、频率)、收敛状态、CPU 时间与墙钟时间、以及文件哈希。对于分子模拟,还需提取力场、系综、温度、压力、时间步长和总步数。

元数据通常分散在文件头部和尾部。Gaussian 的 # 路由行给出方法、基组和任务类型;ORCA 的 | 1> 输入块给出电荷与多重度;VASP 的 INCAR 参数常被回显在 OUTCAR 中。建议在解析时维护一个 metadata 字典,字段缺失时写入 null 并记录缺失原因,而不是用默认值填充,否则会掩盖真实差异。

结果文件解析流水线:格式识别 → 字段定位 → 异常处理 → 元数据提取 原始输出文件 Gaussian .log ORCA .out VASP OUTCAR GROMACS .xvg 格式族识别 标记行 / 块状段落 键值对 / 列式数据 决定锚点策略 字段定位 关键词锚点 + 局部窗口 唯一性校验 记录锚点行号与匹配次数 异常行处理 噪声行 → 跳过 异常信号 → 标记质量标签 不静默丢弃 元数据提取(metadata 字典) 软件版本 · 方法/泛函 · 基组 · 溶剂模型 · 电荷与多重度 任务类型 · 收敛状态 · 时间 · 文件哈希 缺失字段写 null 并记录原因,不用默认值填充 结构化记录(供汇总与筛选使用) energy_final · coordinates · convergence_flag · quality_label · metadata · source_hash 质量标签示例:converged / unconverged / truncated / restart_merged

五、一个可复用的解析记录结构

为了让汇总阶段能直接消费解析结果,建议每条记录至少包含以下字段。字段名可自行调整,但语义应保持一致:

字段含义示例值
source_file源文件路径calc/mol01_opt.log
source_hash文件内容哈希,用于去重与追溯sha256:9f3a...
software软件与版本Gaussian 16 C.01
method_basis方法与基组B3LYP/6-31G(d)
charge_multiplicity电荷与自旋多重度0 / 1
task_type任务类型opt+freq
energy_final最终能量(Hartree 或 eV)-234.567891
convergence_flag是否收敛true / false
quality_label质量标签converged
parse_warnings解析过程中的异常提示["truncated_tail"]

六、实操建议与常见陷阱

第一,不要用行号定位。同一软件在不同核数、不同内存、是否重启下,输出行数会变化。第二,不要只取第一个匹配。优化任务中能量、梯度、坐标都会多次出现,必须结合收敛标记取最后一次有效值。第三,不要忽略单位。Gaussian 能量默认 Hartree,VASP 默认 eV,GROMACS 能量单位取决于 .mdp 设置,汇总前必须统一换算并记录原始单位。第四,不要丢弃异常文件。未收敛、截断、重启合并的文件应保留在数据集中并打上标签,否则筛选阶段会误以为样本完整。

若解析器遇到无法识别的行,不要直接抛出异常终止整个批次。更稳妥的做法是记录该行内容与行号,继续解析后续字段,最后统一输出“未识别行报告”。这样既能保证批量处理不中断,也能在复盘时定位格式变化。

完成本节解析后,每条计算记录都应具备稳定的字段、明确的质量标签和可追溯的元数据。这样在后续汇总与筛选中,才能按方法、基组、收敛状态、能量区间等条件可靠地过滤和排序,而不是在一堆无法解释的文本中反复人工核对。