格式转换是计算化学中最容易被低估的错误来源:一次不当的转换可能悄无声息地改变分子的键级、电荷、立体化学或质子化态,而后续所有计算都基于这个错误的分子。
各格式的信息含量
| 格式 | 三维坐标 | 键级 | 电荷 | 立体化学 | 氢 |
|---|---|---|---|---|---|
| SMILES | 无 | 有 | 有 | 有 | 隐式 |
| SDF / MOL | 有 | 有 | 有 | 有 | 可显可隐 |
| MOL2 | 有 | 有 | 有(含部分电荷) | 有 | 通常显式 |
| PDB | 有 | 无 | 无 | 隐含于坐标 | 常缺失 |
| PDBQT | 有 | 无 | 有(部分电荷) | 隐含 | 仅极性氢 |
| XYZ | 有 | 无 | 无 | 隐含 | 显式 |
核心原则:只能从信息多的格式转到信息少的格式,反向转换必然涉及推断。从 PDB 或 XYZ 恢复键级,是靠几何猜测的——这是最主要的错误来源。
OpenBabel 基本用法
# 安装
conda install -c conda-forge openbabel
# 或 apt install openbabel / brew install open-babel
# 基本转换
obabel input.sdf -O output.mol2
# 加氢(按 pH)
obabel input.sdf -O output.sdf -p 7.4
# 删氢
obabel input.sdf -O output.sdf -d
# 生成三维坐标
obabel input.smi -O output.sdf --gen3d
# 能量最小化
obabel input.sdf -O output.sdf --minimize --ff MMFF94 --steps 500
# 批量分割多分子文件
obabel ligands.sdf -O out.sdf -m
# 只输出满足条件的分子(过滤)
obabel input.sdf -O output.sdf --filter "MW<500"
# 查看支持的格式
obabel -L formats
关键的坑
# 坑一:--gen3d 的质量不如 RDKit ETKDG
# OpenBabel 的三维生成较粗糙
# → 生成构象建议用 RDKit(见 279)
# 坑二:-p 的质子化预测不可靠
# OpenBabel 的 pH 模型很简单
# → 药物分子的质子化建议用 Dimorphite-DL(见 046)
# 坑三:PDB → SDF 的键级推断会出错
# 典型错误:
# 芳香环被识别成交替单双键(凯库勒式)或反之
# 羧酸/酰胺的键级错误
# 磷酸/硫酸基团的键级错误
# → 从 PDB 恢复配体,正确做法是用模板:
from rdkit import Chem
template = Chem.MolFromSmiles("CC(=O)Nc1ccc(O)cc1") # 已知的正确结构
pdb_mol = Chem.MolFromPDBFile("ligand.pdb", removeHs=False)
# 用模板赋予正确的键级
fixed = Chem.AllChem.AssignBondOrdersFromTemplate(template, pdb_mol)
# 坑四:立体化学在无键级的格式中容易丢失
# PDB/XYZ 中手性由坐标隐含,
# 转换时如果键级推断错了,手性判断也会错
# → 转换后必须检查:
# Chem.FindMolChiralCenters(mol, useLegacyImplementation=False)
# 坑五:静默失败
# OpenBabel 遇到问题常给出警告而非报错,
# 继续输出一个错误的分子
# → 必须检查输出,不能假设成功
什么时候用 OpenBabel,什么时候不用
| 任务 | 推荐 |
|---|---|
| SDF ↔ MOL2 ↔ PDB 的坐标转换 | OpenBabel 可以 |
| 处理罕见格式(CIF、CML 等) | OpenBabel(格式支持最广) |
| 批量分割/合并文件 | OpenBabel |
| SMILES → 三维构象 | RDKit ETKDG |
| 质子化态处理 | Dimorphite-DL |
| 分子标准化 | RDKit / ChEMBL Structure Pipeline(见 046《分子标准化》) |
| 转 PDBQT | Meeko(见 106《Meeko》) |
| PDBQT → SDF | Meeko mk_export |
| PDB 中提取配体并恢复键级 | RDKit + 模板 |
OpenBabel 的定位是「格式支持最广的通用转换器」,而非「每个任务的最佳工具」。
转换后的验证
from rdkit import Chem
def verify_conversion(before_path, after_path):
"""转换前后的一致性检查"""
a = Chem.MolFromMolFile(before_path)
b = Chem.MolFromMolFile(after_path)
if a is None or b is None:
return "解析失败"
checks = {}
# 1) 分子式是否一致(最基本的检查)
from rdkit.Chem.rdMolDescriptors import CalcMolFormula
checks["formula"] = (CalcMolFormula(a), CalcMolFormula(b))
# 2) 规范 SMILES 是否一致(最严格的检查)
checks["smiles"] = (Chem.MolToSmiles(a), Chem.MolToSmiles(b))
# 3) 净电荷
checks["charge"] = (Chem.GetFormalCharge(a), Chem.GetFormalCharge(b))
# 4) 手性中心
checks["chiral"] = (
Chem.FindMolChiralCenters(a, useLegacyImplementation=False),
Chem.FindMolChiralCenters(b, useLegacyImplementation=False),
)
diffs = {k: v for k, v in checks.items() if v[0] != v[1]}
return diffs if diffs else "一致"
# 在批量流程中,这个检查应该自动化并记录
# 任何不一致都应该报警而非静默通过
Python 接口
# OpenBabel 的 Python 绑定
from openbabel import pybel
# 读取
mol = next(pybel.readfile("sdf", "input.sdf"))
print(mol.molwt, mol.formula)
print(mol.write("smi").strip())
# 计算描述符
print(mol.calcdesc(["logP", "TPSA", "MW"]))
# 转换并写出
mol.write("mol2", "output.mol2", overwrite=True)
# 批量处理
out = pybel.Outputfile("sdf", "processed.sdf", overwrite=True)
for mol in pybel.readfile("smi", "input.smi"):
mol.make3D(forcefield="mmff94", steps=100)
out.write(mol)
out.close()
# 但在 Python 中,RDKit 通常是更好的选择
# OpenBabel 的价值主要在命令行的格式覆盖面
关键要点
- 只能从信息多的格式转到信息少的——反向转换必然涉及推断,是主要错误来源;
- 从 PDB 恢复配体应该用 RDKit 的模板方法,而非直接推断键级;
- OpenBabel 的
--gen3d与-p质量不如 RDKit 与 Dimorphite-DL; - 转换后必须验证(规范 SMILES、净电荷、手性),OpenBabel 常静默失败。
延伸资源
- Meeko:106《Meeko》;分子标准化:046《分子标准化》;
- RDKit:171《RDKit》;构象生成:279《OpenEye Omega》。