第4节:受体和配体文件的准备(PDBQT格式)
说实话,AutoDock Vina 跑对接的第一步,也是最容易翻车的一步,就是准备正确的输入文件。很多初学者兴冲冲地装好 Vina,直接把从 PDB 数据库下载的原始 `.pdb` 文件扔进去跑,结果不是报错就是结果离谱。
为什么会这样?因为原始 PDB 文件里有很多东西 Vina 不认识——结晶水、多余的配体、金属离子、不完整的侧链,还有最重要的:缺少氢原子和电荷。
Vina 要求输入文件必须是 PDBQT 格式。这个格式比普通 PDB 多了两列:Q(部分电荷)和 T(原子类型)。说白了,它告诉 Vina「哪个原子带多少电,属于什么类型,哪些键可以旋转」。
我个人习惯把这一步叫作「数据清洗+特征标注」——跟做机器学习一样,垃圾进,垃圾出。下面我带你一步步走完这个过程。
4.1 PDBQT 格式的结构
我先快速讲一下 PDBQT 长什么样。它和 PDB 很像,但每行末尾多了两列。
ATOM 1 N THR A 1 -2.323 0.193 -1.597 0.00 0.00 -0.500 N
ATOM 2 CA THR A 1 -1.080 0.134 -0.800 0.00 0.00 0.140 C
ATOM 3 C THR A 1 -0.529 1.550 -0.598 0.00 0.00 0.620 C
ATOM 4 O THR A 1 -1.202 2.529 -1.069 0.00 0.00 -0.500 OA
ATOM 5 CB THR A 1 -1.202 -0.663 0.516 0.00 0.00 0.140 C
注意到倒数第二列了吗?那是 部分电荷(Partial Charge),最后一列是 原子类型(AutoDock Atom Type)。Vina 打分函数里的静电项靠这个 Q 值,疏水项和 π-π 堆积靠这个 T 值。
| 列位 | 内容 | 说明 |
|---|---|---|
| 1-6 | ATOM / HETATM | 记录类型,配体用 HETATM |
| 7-11 | 原子名称 | 保持与原始 PDB 一致 |
| 12-16 | 残基名 + 链 | 蛋白质用标准三字母码 |
| 17-26 | 残基编号 | 整数序号 |
| 31-54 | X Y Z 坐标 | 单位 Å |
| 55-66 | Occupancy + Temp Factor | 通常填 0.00 0.00 |
| 67-76 | 部分电荷 | Gasteiger 电荷,浮点数 |
| 77-78 | 原子类型 | C, N, O, P, S, H, F, Cl, Br, I, A, OA, NA, SA, HD, MG, N3 等 |
关键点:配体的电荷总和必须为整数(或接近零)。如果电荷和是 0.45 这种,说明 Gasteiger 计算有问题,对接结果会凭空多出静电偏差。
4.2 获取受体和配体结构
这一步看似简单,其实坑不少。我总结了几类主流来源:
- RCSB PDB 数据库(PDB ID):最权威,但文件里通常包含结晶水、缓冲剂分子、多构象。
- AlphaFold / ESMFold 预测结构:没有配体共结晶结构时的选择。记得检查 plDDT 置信度,低置信度区域直接删掉。
- 自己构建的配体(SMILES → 3D):用 RDKit 或 Open Babel 生成初始构象。我建议生成多个低能构象,不要只用最稳定那个——对接时 Vina 会采样扭转角,但好的初始构象能加速搜索。
举个例子,用 RDKit 从 SMILES 生成配体 3D 结构:
from rdkit import Chem
from rdkit.Chem import AllChem
mol = Chem.MolFromSmiles('CCO') # 乙醇
mol = Chem.AddHs(mol)
AllChem.EmbedMolecule(mol, AllChem.ETKDG())
AllChem.MMFFOptimizeMolecule(mol)
print(f"原子数: {mol.GetNumAtoms()}")
Chem.MolToPDBFile(mol, 'ligand_ethanol.pdb')
避坑指南:我曾经从 PDB 下载了一个激酶结构,带着原配体直接准备受体文件。结果原配体里有个硫酸根离子被我当成水删掉了,电荷平衡直接崩了,对接打分全都偏正十几 kcal/mol。花了两天才排查出来。记住:受体文件必须不含任何配体、水、离子(除非是结构必需的金属离子)。
4.3 加氢与电荷计算
这是最核心的一步。原始 PDB 里的氢原子几乎全缺失(X 射线衍射看不到氢),而 Vina 打分函数却严重依赖氢键。没有氢,供体和受体都识别不出来。
我推荐用 AutoDockTools(ADT) 来做这个操作。原因有几点:
- 加氢时会自动根据 pH 调整组氨酸质子化状态
- 内置 Gasteiger-Marsili 电荷计算器
- 能正确设置芳香环的原子类型(A 和 OA)
在 ADT 里的标准流程:
# 受体操作步骤
1. File → Read Molecule → 选择 .pdb 文件
2. Edit → Add Hydrogen → 选择 Add Only
(如果蛋白质有金属离子,选 Add Including Hydrogens on Metals)
3. Edit → Gasteiger Charge → Compute
4. File → Save → Write PDBQT → 保存为 receptor.pdbqt
# 配体操作步骤
1. File → Read Molecule → 选择配体 .pdb
2. Edit → Add Hydrogen → Add
3. Edit → Gasteiger Charge → Compute
4. Ligand → Torsion Tree → Detect Root
(自动检测可旋转键)
5. Ligand → Torsion Tree → Choose Torsions
(手动调整:固定酰胺键、酯键等不要旋转)
6. Ligand → Output → Save as PDBQT → 保存为 ligand.pdbqt
4.4 原子类型分配规则
ADT 会自动分配原子类型,但有时会出问题。尤其是配体中含有杂环、卤素、硝基等基团时。我遇到过好几次 ADT 把芳香环上的氮原子误标为 N(非芳香氮),导致 π-π 堆积打分直接失效。
| 原子类型 | 说明 | 常见错误 |
|---|---|---|
| C | 碳(非芳香) | 芳香碳误标为 C 而非 A |
| A | 芳香碳 | 在苯环、吡啶环上必须用 A |
| OA | 芳香氧(如呋喃) | 酯基氧有时被误标为 OA |
| N | 氮(非芳香) | 胺基、酰胺 N |
| NA | 芳香氮(如吡啶 N) | 吡咯氮也可能被标为 N |
| HD | 氢键供体上的氢 | OH、NH 上的 H 必须为 HD |
| F / Cl / Br / I | 卤素 | ADT 有时漏标 F |
你可以手动检查并修正 PDBQT 文件里的原子类型列。用文本编辑器打开配体 PDBQT,看一下芳香环上的碳是不是 A 而不是 C。如果不是,用 sed 或 Python 脚本批量替换:
# 把吡啶环上的 C 改为 A(但只改环上的,不要改取代基上的)
sed -i 's/^ATOM.\{12\}\(C2\|C3\|C4\|C5\|C6\).*$/& A/' ligand.pdbqt
我的习惯:写完 PDBQT 后,我会用 Python 读一遍,统计每种原子类型的数量,再和期望结构对比。如果 C 和 A 的数量不对,肯定有问题。写个几行脚本做自动化校验,能省掉很多手动查错的时间。
4.5 可旋转键的设置
Vina 在对接过程中会采样配体的扭转角。但并不是所有单键都应该旋转。
- 应该旋转的:sp³-sp³ 单键、sp³-sp² 单键(除了特殊情况)
- 不应该旋转的:酰胺键(保持平面,因为存在共振)、酯键(最好固定,否则打分函数会过度惩罚)、环内单键(环不能被拆开)
在 ADT 的 Torsion Tree 界面里,绿色表示可旋转,红色表示固定。默认设置通常是对的,但总有例外。
# 用 Open Babel 在命令行直接设置可旋转键
obabel ligand.pdb -O ligand.pdbqt --rotatable --gen3d
# 但这个方法会有遗漏,建议还是用 ADT 手动确认
我曾经犯过的错:有一次做糖类配体的对接,忘了把吡喃环上的端基异构键固定。Vina 硬是把环劈开了,得分看起来不错,但构象根本不对。从那以后,我每次都会检查环上的键是不是都被固定为红色。
4.6 批量处理与脚本化
如果你需要处理几百个配体,手动操作是不可能的。我用一套 Python + ADT 的脚本做批量准备。
核心思路是:用 ADT 的 Python API 调用 prepare_ligand4.py 和 prepare_receptor4.py。
# 批量准备配体
import os
import subprocess
pdb_directory = "./ligands_pdb/"
output_directory = "./ligands_pdbqt/"
for filename in os.listdir(pdb_directory):
if filename.endswith(".pdb"):
input_path = os.path.join(pdb_directory, filename)
output_path = os.path.join(output_directory, filename.replace(".pdb", ".pdbqt"))
cmd = f"prepare_ligand4.py -l {input_path} -o {output_path}"
subprocess.run(cmd, shell=True)
print(f"Done: {filename}")
如果你用 ADFR 套件(AutoDock-FR),还有更现代的 prepare_ligand 和 prepare_receptor 工具,支持多线程和自动修复。我强烈推荐它做批量。
4.7 文件检验清单
每次准备完文件,我都会过一遍这个清单:
| 检查项 | 方法 | 正常结果 |
|---|---|---|
| PDBQT 格式无空行 | cat -A 查看 | 没有 ^@ 或连续换行 |
| 原子类型全部合法 | grep -o ' [A-Z]\+$' | sort -u | 只含 AutoDock 标准类型 |
| 电荷和(配体) | awk 求和倒数第二列 | 整数(±0.01 以内) |
| 可旋转键数量 | 查看文件头部的 ROOT 后 BRANCH 数量 | 一般在 0-20 之间 |
| 受体是否含有配体 | grep HETATM | 只能有必需的金属离子或辅因子 |
| 氢原子 HD 类型 | grep HD | 所有氢键供体 H 均为 HD |
说实话,这个清单看着很琐碎,但你在批量处理 500 个配体时,任何一个环节出问题都会导致整个 VS 失效。我个人会把它写成一个 Python 脚本,自动跑一遍,不合格的文件直接标红。
老生常谈的提醒:永远保留原始 PDB 文件的备份。我习惯把原始文件放在 ./raw/ 目录,做好质量控制再进入 ./clean/。万一发现 PDBQT 准备有误,不需要重新下载,直接从备份重做就行。
4.8 一个小案例:用 Open Babel 替代 ADT
如果你没法用 ADT(比如在纯命令行环境),Open Babel 也可以生成 PDBQT,但不如 ADT 精细。
# 配体转换
obabel my_ligand.sdf -O my_ligand.pdbqt --gen3D --partialcharge gasteiger
# 受体转换
obabel receptor_protein.pdb -O receptor.pdbqt -xr
-xr 参数默认只加极氢(对 Vina 来说够用)。但 Open Babel 有一个缺点:它不认识 AutoDock 的全部原子类型(尤其是 A 和 OA 的区分),可能导致芳香性判断错误。
我的建议是:小数据集用 ADT,大数据集再用 Open Babel 批量,但一定要抽样手动检查。
文件准备这一步,我花了大量篇幅来讲。因为它直接决定了后面几十个对接跑下来,得到的是可重复的物理意义,还是无意义的数字游戏。你花 30 分钟把 PDBQT 弄清楚了,后面节省的可能是几天的时间。