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 并记录缺失原因,而不是用默认值填充,否则会掩盖真实差异。
五、一个可复用的解析记录结构
为了让汇总阶段能直接消费解析结果,建议每条记录至少包含以下字段。字段名可自行调整,但语义应保持一致:
| 字段 | 含义 | 示例值 |
|---|---|---|
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 设置,汇总前必须统一换算并记录原始单位。第四,不要丢弃异常文件。未收敛、截断、重启合并的文件应保留在数据集中并打上标签,否则筛选阶段会误以为样本完整。
完成本节解析后,每条计算记录都应具备稳定的字段、明确的质量标签和可追溯的元数据。这样在后续汇总与筛选中,才能按方法、基组、收敛状态、能量区间等条件可靠地过滤和排序,而不是在一堆无法解释的文本中反复人工核对。