分子对接与虚拟筛选
本页目录 · 共 43 节
- 配套代码
- 0. 这份笔记怎么用
- 1. 原理最小集(先把这几个词搞懂)
- 1.1 分子对接在做什么
- 1.2 打分函数
- 1.3 结合口袋与搜索盒子(grid box)
- 1.4 文件格式:PDB / SDF / MOL2 / PDBQT
- 1.5 一次完整对接的流程
- 2. 资源总表
- T1 原理与总览
- T2 受体与配体准备
- T3 AutoDock Vina 官方教程与自带示例
- T4 批量虚拟筛选与化合物库
- T5 后处理(MM-GBSA 与分子动力学)
- T6 结果可视化
- 3. 零基础上手路径(按周推进)
- 第 1 周:跑通第一个对接(目标:拿到一个打分)
- 第 2 周:学会准备自己的输入(目标:用自己的体系跑通)
- 第 3 周:做一次小规模虚拟筛选(目标:一张排序表)
- 第 4 周:往后处理走(目标:给候选一个更可信的排名)
- 4. 最小可跑案例:把伊马替尼对接回 c-Abl(1IEP)
- 4.0 准备数据
- 4.1 装环境
- 4.2 准备受体
- 4.3 准备配体
- 4.4 可选:算 AutoDock4 的 affinity maps
- 4.5 跑对接
- 4.6 预期输出
- 4.7 导出结果、可视化
- 4.8 用 Python API 跑同一件事
- 5. 批量虚拟筛选:从化合物库到排序表
- 5.1 官方最小批量用法
- 5.2 用本包脚本跑批量筛选
- 5.3 配体从哪来
- 5.4 怎么判断筛选结果可信
- 5.5 规模上来之后的工具
- 6. 后处理:MM-GBSA 与分子动力学(简要路径)
- 6.1 思路
- 6.2 走一遍的步骤
- 6.3 注意事项
- 7. 结果可视化
- 8. 常见坑与自查清单
- 附录:资源与核验说明
配套代码
下面这些脚本随本模块一起提供,右边标的是它在真实环境里的验证状态;点「展开代码」可以直接在网页上看全文,点「下载」拿到原文件。
批量虚拟筛选模板:多进程并行调用 AutoDock Vina,把每个配体的最优打分汇总成一张排序 CSV。
展开代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
vs_batch.py —— 批量虚拟筛选模板(AutoDock Vina 命令行 + 多进程 + 结果汇总)
用途
给一个已经准备好的受体(PDBQT)和一个装满配体(PDBQT)的文件夹,
用多进程并行跑 Vina,把每个配体的最优打分汇总成一张 CSV。
依赖
- AutoDock Vina 可执行文件(vina 或 vina.exe),并已加入 PATH
安装:conda install -c conda-forge vina 或 pip install -U vina
- 仅需 Python 标准库(subprocess / multiprocessing / csv / argparse / re)
典型用法
# 1) 先准备受体(含极性氢)与配体(PDBQT)
python vs_batch.py \
--receptor 1iep_receptor.pdbqt \
--ligands ligands/ \
--config 1iep_receptor.box.txt \
--out-dir poses \
--csv results.csv \
--nproc 8 \
--exhaustiveness 16 \
--top-n 5
# 2) 只想重新汇总已有结果,不重跑对接
python vs_batch.py --ligands ligands/ --out-dir poses --csv results.csv --summarize-only
config 文件(--config 指向的文本文件)内容示例:
center_x = 15.190
center_y = 53.903
center_z = 16.917
size_x = 20.0
size_y = 20.0
size_z = 20.0
若没有 config 文件,也可以直接用命令行给盒子:
--center 15.190 53.903 16.917 --size 20 20 20
"""
import argparse
import csv
import os
import re
import shutil
import subprocess
import sys
from collections import Counter
from concurrent.futures import ProcessPoolExecutor, as_completed
from glob import glob
# 匹配输出 PDBQT 里的结果行,例如:
# REMARK VINA RESULT: -13.2 0.000 0.000
_RESULT_RE = re.compile(
r"^REMARK\s+VINA RESULT:\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)"
)
def parse_scores(pdbqt_path):
"""读取一个 Vina 输出 PDBQT,返回 [(affinity, rmsd_lb, rmsd_ub), ...](按出现顺序=按打分排序)。"""
scores = []
try:
with open(pdbqt_path, "r", errors="ignore") as fh:
for line in fh:
m = _RESULT_RE.match(line.strip())
if m:
scores.append((float(m.group(1)), float(m.group(2)), float(m.group(3))))
except OSError:
return []
return scores
def find_ligands(paths):
"""把 --ligands 传进来的目录 / glob / 文件统一展开成 PDBQT 文件绝对路径列表。"""
files = []
for p in paths:
if os.path.isdir(p):
files.extend(glob(os.path.join(p, "*.pdbqt")))
elif any(ch in p for ch in "*?["):
files.extend(glob(p))
elif os.path.isfile(p):
files.append(p)
# 去重并排序,保证可复现
files = sorted(set(os.path.abspath(f) for f in files))
# 排除已经带 _out 的结果文件,避免重复对接
return [f for f in files if not os.path.basename(f).endswith("_out.pdbqt")]
def assign_stems(ligands):
"""给每个配体分配唯一的输出名(stem),避免不同目录下的同名配体互相覆盖。
基线是文件名去掉扩展名;同一个 basename 出现多次时,统一追加 __1、__2 … 后缀。
返回 (stems, dups):
stems —— {配体绝对路径: 输出名}
dups —— 出现冲突的 basename 列表(排序后),供提示用
"""
bases = [os.path.splitext(os.path.basename(f))[0] for f in ligands]
total = Counter(bases)
seen = Counter()
stems = {}
for f, b in zip(ligands, bases):
if total[b] == 1:
stems[f] = b
else:
seen[b] += 1
stems[f] = "%s__%d" % (b, seen[b])
dups = sorted(b for b, c in total.items() if c > 1)
return stems, dups
def build_box_config(box_path, center, size):
"""没有现成 config 时,按 center/size 生成一个临时 config 文件。"""
with open(box_path, "w") as fh:
fh.write("center_x = %.3f\n" % center[0])
fh.write("center_y = %.3f\n" % center[1])
fh.write("center_z = %.3f\n" % center[2])
fh.write("size_x = %.1f\n" % size[0])
fh.write("size_y = %.1f\n" % size[1])
fh.write("size_z = %.1f\n" % size[2])
return box_path
def run_one(job):
"""单个配体对接。job 是一个 dict,方便进程池序列化。"""
ligand = job["ligand"]
name = job.get("stem") or os.path.splitext(os.path.basename(ligand))[0]
out_file = os.path.join(job["out_dir"], name + "_out.pdbqt")
log_file = os.path.join(job["out_dir"], name + ".log")
cmd = [
job["vina"],
"--receptor", job["receptor"],
"--ligand", ligand,
"--config", job["config"],
"--out", out_file,
"--exhaustiveness", str(job["exhaustiveness"]),
"--cpu", str(job["cpu_per_job"]),
]
if job["scoring"]:
cmd += ["--scoring", job["scoring"]]
if job["seed"] is not None:
cmd += ["--seed", str(job["seed"])]
try:
with open(log_file, "w") as log:
proc = subprocess.run(
cmd, stdout=log, stderr=subprocess.STDOUT,
timeout=job["timeout"], check=False,
)
except subprocess.TimeoutExpired:
return {"ligand": name, "status": "timeout", "out_file": out_file}
except FileNotFoundError:
return {"ligand": name, "status": "vina-not-found", "out_file": out_file}
if proc.returncode != 0 or not os.path.isfile(out_file):
return {"ligand": name, "status": "failed(rc=%d)" % proc.returncode, "out_file": out_file}
scores = parse_scores(out_file)
if not scores:
return {"ligand": name, "status": "no-result", "out_file": out_file}
return {
"ligand": name,
"status": "ok",
"out_file": out_file,
"best_affinity": scores[0][0],
"best_rmsd_lb": scores[0][1],
"best_rmsd_ub": scores[0][2],
"n_poses": len(scores),
}
def summarize(out_dir, csv_path, top_n):
"""扫描 out_dir 下所有 *_out.pdbqt,汇总最优打分到 CSV。"""
rows = []
for out_file in sorted(glob(os.path.join(out_dir, "*_out.pdbqt"))):
name = os.path.basename(out_file)[:-len("_out.pdbqt")]
scores = parse_scores(out_file)
if scores:
best = scores[0]
rows.append({
"ligand": name,
"best_affinity": best[0],
"best_rmsd_lb": best[1],
"best_rmsd_ub": best[2],
"n_poses": len(scores),
"out_file": out_file,
})
rows.sort(key=lambda r: r["best_affinity"]) # 越负越靠前
with open(csv_path, "w", newline="") as fh:
writer = csv.writer(fh)
writer.writerow(["rank", "ligand", "best_affinity_kcal_mol",
"rmsd_lb", "rmsd_ub", "n_poses", "out_file"])
for i, r in enumerate(rows, 1):
writer.writerow([i, r["ligand"], r["best_affinity"],
r["best_rmsd_lb"], r["best_rmsd_ub"],
r["n_poses"], r["out_file"]])
return rows
def main():
ap = argparse.ArgumentParser(description="AutoDock Vina 批量虚拟筛选模板")
ap.add_argument("--receptor", help="受体 PDBQT 文件")
ap.add_argument("--ligands", nargs="+", required=True,
help="配体 PDBQT:目录 / glob / 文件,可给多个")
ap.add_argument("--config", help="Vina config 文本(含 center/size)")
ap.add_argument("--center", nargs=3, type=float, metavar=("X", "Y", "Z"),
help="盒子中心;与 --size 搭配,替代 --config")
ap.add_argument("--size", nargs=3, type=float, metavar=("X", "Y", "Z"),
help="盒子边长(埃);与 --center 搭配")
ap.add_argument("--out-dir", default="poses", help="输出目录(默认 poses)")
ap.add_argument("--csv", default="vs_results.csv", help="汇总 CSV 路径")
ap.add_argument("--nproc", type=int, default=os.cpu_count() or 1,
help="并行进程数(同时跑多少个配体)")
ap.add_argument("--cpu-per-job", type=int, default=1,
help="每个 vina 进程内部使用几个 CPU 核(默认 1)")
ap.add_argument("--exhaustiveness", type=int, default=16,
help="搜索强度;越大越慢越稳(默认 16,正式筛选可用 32)")
ap.add_argument("--scoring", default=None, choices=["vina", "ad4", "vinardo"],
help="打分函数;默认用 vina。用 ad4 时需先算 affinity maps 并改用 --maps")
ap.add_argument("--seed", type=int, default=None, help="随机种子,固定可复现")
ap.add_argument("--timeout", type=int, default=3600, help="单个配体超时秒数")
ap.add_argument("--top-n", type=int, default=0, help="打印前 N 名(0=不打印)")
ap.add_argument("--summarize-only", action="store_true",
help="跳过对接,只重新汇总 out-dir 里已有结果")
ap.add_argument("--vina", default=None, help="vina 可执行文件路径(默认从 PATH 找)")
args = ap.parse_args()
os.makedirs(args.out_dir, exist_ok=True)
vina_bin = args.vina or shutil.which("vina") or "vina"
if args.summarize_only:
rows = summarize(args.out_dir, args.csv, args.top_n)
print("汇总完成:%d 条结果 -> %s" % (len(rows), args.csv))
_print_top(rows, args.top_n)
return
if not args.receptor:
ap.error("需要 --receptor(受体 PDBQT)")
if not args.config:
if not (args.center and args.size):
ap.error("需要 --config,或同时给出 --center 与 --size")
args.config = build_box_config(os.path.join(args.out_dir, "_box.txt"),
args.center, args.size)
ligands = find_ligands(args.ligands)
if not ligands:
print("没有找到任何配体 PDBQT,检查 --ligands 路径。", file=sys.stderr)
sys.exit(1)
# 提前校验输入:这些问题逐个配体报一遍既费时间又难定位,直接拦在前面
if not os.path.isfile(args.receptor):
ap.error("找不到受体文件:%s" % args.receptor)
if not os.path.isfile(args.config):
ap.error("找不到 config 文件:%s" % args.config)
if not (os.path.isfile(vina_bin) or shutil.which(vina_bin)):
ap.error("找不到 vina 可执行文件(%s)。请先 conda install -c conda-forge vina,"
"或用 --vina 指定完整路径。" % vina_bin)
# 不同目录下的同名配体输出会互相覆盖,这里统一改名规避
stems, dups = assign_stems(ligands)
if dups:
print("提示:以下配体重名,输出名已自动加 __N 后缀避免覆盖:%s"
% ", ".join(dups))
print("vina : %s" % vina_bin)
print("受体 : %s" % os.path.abspath(args.receptor))
print("config : %s" % os.path.abspath(args.config))
print("配体数量 : %d" % len(ligands))
print("并行进程 : %d(每进程 %d 核)" % (args.nproc, args.cpu_per_job))
print("搜索强度 : %d" % args.exhaustiveness)
jobs = [{
"ligand": lig,
"stem": stems[lig],
"receptor": os.path.abspath(args.receptor),
"config": os.path.abspath(args.config),
"out_dir": os.path.abspath(args.out_dir),
"vina": vina_bin,
"exhaustiveness": args.exhaustiveness,
"cpu_per_job": args.cpu_per_job,
"scoring": args.scoring,
"seed": args.seed,
"timeout": args.timeout,
} for lig in ligands]
done = 0
results = []
with ProcessPoolExecutor(max_workers=args.nproc) as pool:
futures = {pool.submit(run_one, j): j for j in jobs}
for fut in as_completed(futures):
r = fut.result()
results.append(r)
done += 1
tag = "%s(%s)" % (r["ligand"], r["status"])
print("[%d/%d] %s" % (done, len(jobs), tag))
rows = summarize(args.out_dir, args.csv, args.top_n)
ok = sum(1 for r in results if r["status"] == "ok")
print("\n对接结束:成功 %d / 共 %d,汇总 -> %s" % (ok, len(jobs), args.csv))
_print_top(rows, args.top_n)
def _print_top(rows, top_n):
if top_n and rows:
print("\n打分最优的前 %d 个配体(kcal/mol,越负越可能结合):" % top_n)
for i, r in enumerate(rows[:top_n], 1):
print(" %2d. %-30s %8.2f" % (i, r["ligand"], r["best_affinity"]))
if __name__ == "__main__":
main()Python 依赖清单(vina / meeko / rdkit / openbabel 等)。
展开代码
# ---------------------------------------------------------------
# 环境依赖(批量虚拟筛选)
# 建议用 conda / mamba 建独立环境,避免与系统 Python 冲突
# ---------------------------------------------------------------
# 对接引擎(同时提供命令行 vina 和 Python API)
# conda 更稳;也可 pip install -U vina
vina>=1.2.5
# 分子读写与构象
numpy
scipy
rdkit
# 受体 / 配体 PDBQT 准备(提供 mk_prepare_ligand.py、mk_prepare_receptor.py、mk_export.py)
meeko>=0.6
# 给配体加氢 / 生成 3D 构象 / 枚举质子化与互变异构(提供 scrub.py)
# 注意:scrub.py 内部 import joblib,但 molscrub 没把它写进依赖,必须单独装,
# 否则跑 scrub.py 会报 ModuleNotFoundError: No module named 'joblib'
molscrub
joblib
# 蛋白结构处理(官方 Colab 工作流里用到)
gemmi
prody
# 可视化(可选,用于看结果)
py3Dmol
# 说明:
# - AutoDock-GPU(GPU 加速大规模对接):https://github.com/ccsb-scripps/AutoDock-GPU
# - Ringtail(虚拟筛选结果入库与富集分析):https://github.com/forlilab/ringtail
# - ad4 打分需要 autogrid4 预计算 affinity maps:conda install -c conda-forge autogrid脚本使用说明:装环境、准备输入、跑流程、怎么读结果。
这份笔记是“生信带教包”的第二模块。目标很明确:让零基础的人从装环境开始, 一周能跑出第一个对接结果,一个月能独立完成一次小规模虚拟筛选。 里面每一条资源都是真实存在、能打开的(除了个别被站点反爬拦住、已单独标注的), 不是凑数用的链接,跟着点就行。
0. 这份笔记怎么用
- 第 1 章把必须懂的概念压到最小,看不懂先跳过,跑完第 4 章再回来读。
- 第 2 章是资源总表,按主题分好,实验时按需查。
- 第 3 章是按周推进的路径,照着走不会迷路。
- 第 4 章是最小可跑案例,照着敲命令,能拿到一个真实结果。
- 第 5、6、7 章是往上游和下游延伸:批量筛选、后处理、可视化。
scripts/目录里有一个批量筛选脚本模板,第 5 章讲怎么用。
1. 原理最小集(先把这几个词搞懂)
1.1 分子对接在做什么
一句话:把一个小分子(配体,ligand)塞进蛋白质(受体,receptor)的某个口袋里, 反复调整它的位置和姿态,找让两者结合最稳的那个构象。
对接软件做的其实是两件事:搜索(构象采样)和打分(评价好坏)。
搜索常用蒙特卡洛 / 遗传算法,打分靠打分函数。我们后面要调的所有参数,
本质都在这两件事上做取舍:exhaustiveness 控制搜索多狠,力场选择控制怎么打分。
对接跟另外两个概念别搞混:
- 分子动力学(MD):让配体和蛋白在模拟的溶剂里都动起来,看一段时间的演化。
- 基于配体的筛选:不看受体结构,只比化合物的相似性。
前两个是基于结构的(structure-based),也是这个模块的重点。
1.2 打分函数
打分函数给一个蛋白-配体构象打一个分,单位通常是 kcal/mol,数值越负表示预测结合越强。 AutoDock 家族常用的有三套:
| 力场 | 特点 | 是否需要预计算 |
|---|---|---|
vina |
Vina 默认,速度快,是现在虚拟筛选的主力 | 不需要,Vina 内部自己算格点 |
ad4 |
老牌 AutoDock4 力场,更依赖格点 | 需要先用 autogrid4 算 affinity maps |
vinardo |
基于 Vina 改的,某些体系更准 | 不需要 |
一个必须记住的坑:不同力场打出来的分不能互相比较。用 vina 跑的分和
ad4 跑的分放一起排名是没有意义的。一次筛选从头到尾只用一套力场。
Vina 打分函数大致由几项加和:空间排斥、疏水接触、氢键、高斯项(惩罚偏离理想距离)。 关于它在虚拟筛选里的实际表现和局限,可以读 arXiv:2006.16955(见资源表 T1-4)。
1.3 结合口袋与搜索盒子(grid box)
对接不会让配体在整个蛋白上乱跑,而是限定在一个长方体区域里,叫搜索盒子。 盒子用中心坐标(center_x/y/z)和边长(size_x/y/z)定义,单位是埃(Å)。
盒子怎么定:
- 有共晶配体(蛋白里本来带着的小分子)时,盒子中心对准它,边长比它大一圈(20 Å 起步)。
- 没有共晶配体时,用工具找口袋(例如 AutoSite、fpocket),或者把整个蛋白设为搜索空间。
- 盒子太小会漏掉真实结合位点,太大又不准又慢,这是新手最容易犯的错。
1.4 文件格式:PDB / SDF / MOL2 / PDBQT
对接流程里会反复遇到这几种格式,分清它们能少走很多弯路:
- PDB:蛋白结构的通用格式,从 Protein Data Bank 下载的就是它。
- SDF / MOL2:小分子格式,带键的信息,是配体准备的首选输入。
- SMILES:一串文本表示分子结构,适合批量。
- PDBQT:AutoDock 家族的专用格式,在 PDB 基础上加了两样东西—— 极性氢和部分电荷,还有一个标记原子类型和可旋转键的字段。
关键提醒:不要用 PDB 格式准备小分子。PDB 里没有键的信息,软件只能猜键级, 对复杂分子经常猜错。配体一律从 SDF 或 MOL2 走。
1.5 一次完整对接的流程
PDB 结构 SDF / SMILES
│ │
去水/去杂/加氢 加氢/生成3D/定质子化态
│ │
mk_prepare_receptor.py mk_prepare_ligand.py
│ │
receptor.pdbqt ligand.pdbqt
└──────────┬───────────────────┘
vina(+ 盒子 config)
│
poses(打分排序)
│
导出 SDF → PyMOL 看结合模式
│
(可选)MM-GBSA / MD 复算2. 资源总表
字段说明:名称 / 链接 / 类型 / 语言 / 难度 / 是否可直接跑通 / 一句话说明。 “可否直接跑通”指跟着做能不能在本机复现结果;纯文档类标“阅读”。
T1 原理与总览
| 名称 | 链接 | 类型 | 语言 | 难度 | 可否直接跑通 | 说明 |
|---|---|---|---|---|---|---|
| AutoDock Vina 官方文档站 | https://autodock-vina.readthedocs.io/en/latest/ | 文档·教程 | 英 | 入门 | 阅读 | 主入口,安装、基础对接、批量对接、Python 脚本全在这 |
| Forli 等 2016, Nature Protocols | https://pmc.ncbi.nlm.nih.gov/articles/PMC4868550/ | 论文·教程 | 英 | 进阶 | 阅读 | AutoDock 官方授权流程论文,讲透打分、口袋、exhaustiveness 的含义 |
| Vina 软件需求与安装页 | https://autodock-vina.readthedocs.io/en/latest/docking_requirements.html | 文档 | 英 | 入门 | 是 | 一行命令装齐 Meeko、AutoGrid、ADFR 等依赖 |
| arXiv:2006.16955(SMINA docking benchmark) | https://arxiv.org/abs/2006.16955 | 论文 | 英 | 进阶 | 阅读 | 从另一个角度讨论对接打分在分子设计里的可信度,适合进阶读 |
T2 受体与配体准备
| 名称 | 链接 | 类型 | 语言 | 难度 | 可否直接跑通 | 说明 |
|---|---|---|---|---|---|---|
| Meeko(AutoDock 接口) | https://meeko.readthedocs.io/en/develop/ | 工具·文档 | 英 | 入门 | 是 | Vina 官方指定的 PDBQT 准备工具,提供 mk_prepare_ligand / receptor 脚本 |
| Meeko Basic Docking 教程 | https://meeko.readthedocs.io/en/develop/tutorial1.html | 教程·案例 | 英 | 入门 | 是 | 单个配体准备 + 批量准备 + 结果处理,一页讲完主流程 |
| Molscrub | https://github.com/forlilab/molscrub | 工具 | 英 | 入门 | 是 | 提供 scrub.py,给分子加氢、生成 3D 构象、枚举质子化与互变异构 |
| RDKit | https://rdkit.org/ | 工具·文档 | 英 | 入门 | 是 | 开源化学信息学工具包,配体处理、相似性、指纹都靠它 |
| RDKit Cookbook | https://rdkit.org/docs/Cookbook.html | 教程·代码 | 英 | 进阶 | 是 | 一堆可复制的 RDKit 代码片段,遇到具体问题翻这里 |
| Open Babel | https://openbabel.org/ | 工具 | 英 | 入门 | 是 | 支持 110 多种化学文件格式互转的老牌工具箱 |
| PDB2PQR | https://pdb2pqr.readthedocs.io/en/latest/ | 工具·文档 | 英 | 入门 | 是 | 补缺失重原子、估质子化态、分配电荷与半径 |
T3 AutoDock Vina 官方教程与自带示例
| 名称 | 链接 | 类型 | 语言 | 难度 | 可否直接跑通 | 说明 |
|---|---|---|---|---|---|---|
| Basic docking(1IEP 重对接) | https://autodock-vina.readthedocs.io/en/latest/docking_basic.html | 教程·案例 | 英 | 入门 | 是 | 本模块第 4 章的蓝本,伊马替尼对接回 c-Abl,含预期打分 |
| Docking in batch mode | https://autodock-vina.readthedocs.io/en/latest/docking_in_batch.html | 教程 | 英 | 入门 | 是 | 一条命令批量对接一批配体,虚拟筛选的官方最小用法 |
| Multiple ligands docking | https://autodock-vina.readthedocs.io/en/latest/docking_multiple_ligands.html | 教程·案例 | 英 | 进阶 | 是 | 同时对接两个配体(碎片设计场景),5x72 示例 |
| Python scripting | https://autodock-vina.readthedocs.io/en/latest/docking_python.html | 教程·代码 | 英 | 进阶 | 是 | 用 vina 的 Python API 写脚本,批量筛选的核心接口 |
| Colab Examples | https://autodock-vina.readthedocs.io/en/latest/colab_examples.html | 课程·案例 | 英 | 入门 | 是 | 免安装,浏览器里跑完整对接,含免费 GPU,最省事的上手方式 |
| 官方示例数据(GitHub) | https://github.com/ccsb-scripps/AutoDock-Vina/tree/develop/example/basic_docking | 代码·数据 | — | 入门 | 是 | 1IEP 例子的输入与预期输出文件都在这里。该链接引自官方文档原文,GitHub 对自动抓取有限制,未能单独打开核验,使用时直接在浏览器打开即可。 |
T4 批量虚拟筛选与化合物库
| 名称 | 链接 | 类型 | 语言 | 难度 | 可否直接跑通 | 说明 |
|---|---|---|---|---|---|---|
| AutoDock-GPU | https://github.com/ccsb-scripps/AutoDock-GPU | 工具 | 英 | 进阶 | 是 | GPU 加速对接,配体上万时的首选,实现 ad4 力场 |
| GNINA | https://github.com/gnina/gnina | 工具 | 英 | 进阶 | 是 | 基于 Vina 加了 CNN 打分,能自动定盒子,适合大规模筛选 |
| GNINA 文档站 | https://gnina.github.io/gnina/ | 文档·课程 | 英 | 进阶 | 阅读 | GNINA 用法与 workshop 材料 |
| smina | https://sourceforge.net/projects/smina/ | 工具 | 英 | 进阶 | 是 | Vina 的分支,专注打分函数开发和能量最小化,脚本化友好 |
| Dockey | https://github.com/lmdu/dockey | 工具·论文 | 英 | 进阶 | 是 | 图形界面全流程大规模对接,自动检测相互作用,对新手友好 |
| Ringtail | https://github.com/forlilab/ringtail | 工具 | 英 | 进阶 | 是 | 把虚拟筛选结果存进 SQLite 并做富集分析,配体上万后的刚需 |
| DUD-E | https://dude.docking.org/ | 数据集 | 英 | 入门 | 是 | 102 个靶点的活性物 + 诱饵,对接程序基准测试的标准集 |
| DUDE-Z | https://dudez.docking.org/ | 数据集 | 英 | 进阶 | 是 | DUD-E 的升级版诱饵集,更贴近真实筛选难度 |
| ZINC20 | https://zinc20.docking.org/ | 数据集 | 英 | 入门 | 是 | 可直接下载的 ready-to-dock 化合物库,虚拟筛选配体来源 |
| PubChem | https://pubchem.ncbi.nlm.nih.gov/ | 数据集 | 英 | 入门 | 是 | 全球最大的免费化学信息库,查结构、下 SDF、批量拿 CID 都在这 |
| docking.org | https://docking.org | 数据集·工具索引 | 英 | 入门 | 是 | Shoichet / Irwin 实验室资源总入口,ZINC、DUD-E、DOCK 都从这进 |
| 阿里云 E-HPC:用 AutoDock Vina 做虚拟筛选 | https://help.aliyun.com/zh/e-hpc/e-hpc-1-0/use-cases/use-autodock-vina-to-screen-potential-drugs | 教程·案例 | 中 | 进阶 | 是 | 中文实战,讲怎么把 Vina 放到集群上跑作业数组 |
T5 后处理(MM-GBSA 与分子动力学)
| 名称 | 链接 | 类型 | 语言 | 难度 | 可否直接跑通 | 说明 |
|---|---|---|---|---|---|---|
| gmx_MMPBSA 文档 | https://valdes-tresanco-ms.github.io/gmx_MMPBSA/dev/ | 工具·文档 | 英 | 进阶 | 是 | 用 GROMACS 轨迹做 MM/PB(GB)SA,开源且更新活跃 |
| gmx_MMPBSA:AMBER 输入示例 | https://valdes-tresanco-ms.github.io/gmx_MMPBSA/dev/examples/AMBER/ | 案例 | 英 | 进阶 | 是 | RAS-RAF 结合自由能完整命令,可照抄 |
| gmx_MMPBSA 输入文件说明 | https://valdes-tresanco-ms.github.io/gmx_MMPBSA/v1.5.6/input_file/ | 文档 | 英 | 进阶 | 阅读 | gb / pb / rism / decomp 各 namelist 怎么写 |
| GROMACS 官网 | https://www.gromacs.org/ | 工具·文档 | 英 | 入门 | 是 | 开源 MD 主力软件,下载、手册、教程入口 |
| GROMACS 入门教程 | https://tutorials.gromacs.org/md-intro-tutorial.html | 教程 | 英 | 入门 | 是 | 官方入门课,从零跑一个蛋白在水里的模拟 |
| Justin Lemkul 的 GROMACS 系列教程 | https://www.mdtutorials.com/gmx/ | 教程 | 英 | 入门 | 是 | 公认最好的 GROMACS 教学系列,Tutorial 3 是蛋白-配体复合物 |
| MM(PB/GB)SA 快速上手指南 | https://www.blopig.com/blog/2022/05/mmpb-gbsa-a-quick-start-guide/ | 教程 | 英 | 进阶 | 是 | 用纯开源工具从 PDB 走到结合自由能的完整流程 |
| MMPBSA.py 官方手册 | http://archive.ambermd.org/201005/att-0941/MMPBSA_Python_Manual.pdf | 文档 | 英 | 进阶 | 阅读 | 讲清 MM/PB(GB)SA 的原理、拓扑构建和常见报错 |
| g_mmpbsa | https://g-mmpbsa.readthedocs.io/en/stable/ | 工具·文档 | 英 | 进阶 | 是 | 另一款 GROMACS 上的 MM-PBSA 工具,纯 Python 实现 |
T6 结果可视化
| 名称 | 链接 | 类型 | 语言 | 难度 | 可否直接跑通 | 说明 |
|---|---|---|---|---|---|---|
| PyMOL 官方文档 | https://pymol.org/dokuwiki/ | 文档·教程 | 英 | 入门 | 阅读 | 命令参考、教程、示例图都在这 |
| PyMOL Wiki | https://pymolwiki.org/ | 教程·文档 | 英 | 入门 | 阅读 | 社区维护的支持站,问题基本都能搜到 |
| Practical PyMOL for Beginners | https://pymolwiki.org/index.php/Practical_Pymol_for_Beginners | 教程 | 英 | 入门 | 是 | 从界面讲到出图,最友好的 PyMOL 上手文 |
| py3Dmol | https://3dmol.org/ | 工具·文档 | 英 | 入门 | 是 | 在网页或 Jupyter 里直接展示 3D 结构,官方 Colab 示例用的就是它 |
3. 零基础上手路径(按周推进)
给一个四周的节奏,每周有明确产出物。动手时间按每天 2 小时估。
第 1 周:跑通第一个对接(目标:拿到一个打分)
| 天 | 做什么 | 用什么 | 产出 |
|---|---|---|---|
| D1 | 读第 1 章 + Vina 官方文档安装页,把环境装好 | T1-1、T1-3 | 命令行敲 vina 有输出 |
| D2 | 读 Basic docking 教程,理解每步在干嘛 | T3-1 | 笔记:受体准备/配体准备/盒子各做什么 |
| D3 | 跟第 4 章走完 1IEP 案例 | T3-1 | 1iep_ligand_vina_out.pdbqt |
| D4 | 装 PyMOL,把受体和结果姿态叠一起看 | T6-1、T6-3 | 一张结合模式截图 |
| D5 | 换个盒子大小重跑,看打分怎么变 | T3-1 | 一段结论:盒子大小对结果的影响 |
| D6–7 | 读 Forli 2016 论文的前半部分 | T1-2 | 笔记:打分函数在筛选中能信到什么程度 |
第 2 周:学会准备自己的输入(目标:用自己的体系跑通)
| 天 | 做什么 | 用什么 | 产出 |
|---|---|---|---|
| D1 | 读 Meeko Basic Docking,练配体准备 | T2-2 | 一批 SDF → PDBQT |
| D2 | 练受体准备,处理去水、去配体、补氢 | T2-1、T2-7 | 自己的 receptor.pdbqt |
| D3 | 学 RDKit 处理分子、看 SMILES | T2-4、T2-5 | 一段能跑的 RDKit 小脚本 |
| D4 | 用 scrub.py 给 SMILES 生成构象并枚举质子化态 | T2-3 | 理解为什么质子化态不能凑合 |
| D5 | 找一个自己感兴趣或本课题的靶点,定盒子 | T1-1 | 一份 config 文件 |
| D6–7 | 完成一次单配体对接并复盘 | 前面全部 | 一次完整流程记录 |
第 3 周:做一次小规模虚拟筛选(目标:一张排序表)
| 天 | 做什么 | 用什么 | 产出 |
|---|---|---|---|
| D1 | 读 batch mode 教程 + Python scripting | T3-2、T3-4 | 明白批量模式的输入输出 |
| D2 | 从 ZINC 或 PubChem 下一小批配体(先 50–100 个练手) | T4-9、T4-10 | ligands/ 一堆 PDBQT |
| D3 | 跑 scripts/vs_batch.py,拿到 results.csv |
本包脚本 | results.csv |
| D4 | 读 DUD-E 的构造,理解诱饵和富集因子 | T4-7 | 笔记:怎么判断筛选靠不靠谱 |
| D5 | 挑前 10 个候选,用 PyMOL 逐个看结合模式 | T6-1 | 一张候选清单 |
| D6–7 | 用 Ringtail 或自己写脚本统计打分分布 | T4-6 | 打分分布图 |
第 4 周:往后处理走(目标:给候选一个更可信的排名)
| 天 | 做什么 | 用什么 | 产出 |
|---|---|---|---|
| D1 | 读 MM(PB/GB)SA 快速上手 | T5-7 | 明白后处理在算什么 |
| D2 | 读 GROMACS 入门教程,跑一个小体系 | T5-5、T5-6 | 一次 MD 跑通 |
| D3–4 | 对手上最好的几个候选建拓扑、跑短 MD | T5-1、T5-4 | 拓扑与轨迹文件 |
| D5 | 用 gmx_MMPBSA 算结合自由能 | T5-1、T5-2 | FINAL_RESULTS_MMPBSA.dat |
| D6 | 对比对接打分和 MM-GBSA 的排序是否一致 | — | 一段分析 |
| D7 | 整体复盘,把流程写成自己的 SOP | — | 一份可供师姐复用的流程文档 |
4. 最小可跑案例:把伊马替尼对接回 c-Abl(1IEP)
这个案例来自 AutoDock Vina 官方教程(T3-1)。用抗癌药伊马替尼(imatinib)重对接回 它的靶点 c-Abl 激酶域,看能不能把配体放回晶体结构里原来的位置(这叫重对接/redocking, 是检验对接流程有没有搭对的黄金标准)。
4.0 准备数据
- 受体坐标:
1iep_receptorH.pdb(已加氢,去掉了原配体) - 配体坐标:
1iep_ligand.sdf - 两个文件都在 AutoDock-Vina 官方仓库的
example/basic_docking目录里(见 T3-6)。
自检习惯:每次做对接都应该设一个阳性对照——对接一个已知能结合的分子, 跑通、打分合理,再做未知分子。否则算出来的东西没法判断真假。
4.1 装环境
# 方式一:pip(最快)
pip install -U numpy scipy rdkit vina meeko gemmi prody
# 方式二:conda(更稳,推荐)
conda create -n vina python=3.10 -y
conda activate vina
conda install -c conda-forge numpy scipy rdkit vina meeko gemmi autogrid -y
pip install prody装好后这几个命令应该都能用:vina、mk_prepare_receptor.py、mk_prepare_ligand.py、mk_export.py。
4.2 准备受体
mk_prepare_receptor.py -i 1iep_receptorH.pdb -o 1iep_receptor -p -v \
--box_size 20 20 20 --box_center 15.190 53.903 16.917参数含义:-p 生成受体 PDBQT;-v 连同盒子信息生成 config 与盒子 PDB;
--box_size / --box_center 就是搜索盒子。跑完会得到:
1iep_receptor.pdbqt 受体(含极性氢和部分电荷)
1iep_receptor.box.txt 盒子配置,可直接当 config 用
1iep_receptor.box.pdb 盒子可视化文件,拖进 PyMOL 能看4.3 准备配体
mk_prepare_ligand.py -i 1iep_ligand.sdf -o 1iep_ligand.pdbqt4.4 可选:算 AutoDock4 的 affinity maps
只有想用 ad4 力场时才需要。在 4.2 的命令里加 -g 生成 GPF,再跑 autogrid4:
mk_prepare_receptor.py -i 1iep_receptorH.pdb -o 1iep_receptor -p -v -g \
--box_size 20 20 20 --box_center 15.190 53.903 16.917
autogrid4 -p 1iep_receptor.gpf -l 1iep_receptor.glg会生成 1iep_receptor.*.map(各原子类型)、.d.map(去溶剂化)、.e.map(静电)。
4.5 跑对接
用 Vina 力场(推荐先跑这个),1iep_receptor.box.txt 内容如下:
center_x = 15.190
center_y = 53.903
center_z = 16.917
size_x = 20.0
size_y = 20.0
size_z = 20.0vina --receptor 1iep_receptor.pdbqt --ligand 1iep_ligand.pdbqt \
--config 1iep_receptor.box.txt --exhaustiveness=32 \
--out 1iep_ligand_vina_out.pdbqt用 AutoDock4 力场(需要 4.4 的 maps):
vina --ligand 1iep_ligand.pdbqt --maps 1iep_receptor --scoring ad4 \
--exhaustiveness 32 --out 1iep_ligand_ad4_out.pdbqt关于 exhaustiveness:默认值只有 8,官方明确说这个体系用默认参数有时找不到正确姿态,
建议提到 32。这个值越大搜索越充分,也越慢。
4.6 预期输出
Vina 力场下,最佳打分大约 −13 kcal/mol:
Scoring function : vina
Rigid receptor: 1iep_receptor.pdbqt
Ligand: 1iep_ligand.pdbqt
Grid center: X 15.19 Y 53.903 Z 16.917
Grid size : X 20 Y 20 Z 20
Grid space : 0.375
Exhaustiveness: 32
CPU: 0AutoDock4 力场下,最佳打分大约 −14 kcal/mol(两套力场的分不能互相比)。
看到接近这个数量级、且最优姿态能叠回晶体结构原配体的位置,就说明流程搭对了。
4.7 导出结果、可视化
mk_export.py 1iep_ligand_vina_out.pdbqt -s 1iep_ligand_vina_out.sdf为什么用 Meeko 的 mk_export.py 而不是别家工具:PDBQT 里没存完整的键级信息,
从 PDBQT 反推键级对复杂分子经常出错。Meeko 在写 PDBQT 时把 SMILES 塞进了文件头,
导出时能还原成正确的键级和电荷。
可视化:PyMOL 里先载入 1iep_receptor.pdbqt,再载入导出的 SDF,就能看到配体
落在口袋里的姿态,以及周围残基。
4.8 用 Python API 跑同一件事
from vina import Vina
v = Vina(sf_name='vina')
v.set_receptor('1iep_receptor.pdbqt')
v.set_ligand_from_file('1iep_ligand.pdbqt')
v.compute_vina_maps(center=[15.190, 53.903, 16.917], box_size=[20, 20, 20])
energy = v.score()
print('打分(优化前):%.3f kcal/mol' % energy[0])
energy_min = v.optimize()
print('打分(局部优化后):%.3f kcal/mol' % energy_min[0])
v.dock(exhaustiveness=32, n_poses=20)
v.write_poses('1iep_ligand_vina_out.pdbqt', n_poses=5, overwrite=True)这段脚本在官方教材里也有,对应仓库的 example/python_scripting。
5. 批量虚拟筛选:从化合物库到排序表
单配体对接是学流程,真正做事要面对成百上千个分子。这一步的核心是并行—— 不同配体之间互不依赖,天然适合多核或 GPU 并行。
5.1 官方最小批量用法
Vina 自带批量模式:
vina --receptor 1iep_receptor.pdbqt --batch ligands/*.pdbqt \
--config config.txt --dir poses输出会写到 poses/ 下,命名为 <配体名>_out.pdbqt,重名时自动加索引。
分子上千时,更推荐用 Python 脚本管理并行(下一节),或者干脆换 AutoDock-GPU。
5.2 用本包脚本跑批量筛选
scripts/vs_batch.py 是一个可直接复用的模板,用多进程并行调用 Vina 命令行,
把最优打分会总成 CSV。完整用法见 scripts/README.md,最短示例:
python scripts/vs_batch.py \
--receptor 1iep_receptor.pdbqt \
--ligands ligands/ \
--config 1iep_receptor.box.txt \
--out-dir poses \
--csv results.csv \
--nproc 8 \
--exhaustiveness 16 \
--seed 42 \
--top-n 20跑完得到 results.csv,按最优打分升序排列,字段为
rank, ligand, best_affinity_kcal_mol, rmsd_lb, rmsd_ub, n_poses, out_file。
它做了几件实用的事:自动展开配体目录、跳过已完成的 *_out.pdbqt、
单个配体可设超时、固定随机种子保证可复现、--summarize-only 支持断点续跑汇总。
5.3 配体从哪来
- ZINC20(T4-9):直接下 ready-to-dock 的库,选 lead-like / fragment-like 子集。
- PubChem(T4-10):按靶点或性质查到一批化合物,拿 CID 批量下 SDF。
- DUD-E(T4-7):想验证方法靠不靠谱,用它自带的活性物 + 诱饵做基准。
拿到 SDF 后统一走 scrub.py 加氢生成构象,再 mk_prepare_ligand.py
批量转 PDBQT(命令见 scripts/README.md)。
5.4 怎么判断筛选结果可信
打分排名只是第一步,别直接拿 best_affinity 当结论。三个动作能让结果靠谱很多:
- 看关键相互作用:目标口袋里的关键残基有没有形成氢键或疏水接触。 打分好但一个关键接触都没打上,多半是假阳性。
- 看富集:有活性/诱饵标签的数据集(如 DUD-E)可以算富集因子, 检验打分能不能把活性物排到前面。
- 后处理复算:挑前几十个候选做 MM-GBSA 或短 MD(第 6 章), 让排名稳一稳。
5.5 规模上来之后的工具
- 配体上万、有 GPU:换 AutoDock-GPU(T4-1)或 GNINA(T4-2)。
- 结果太多要管理:用 Ringtail(T4-6)入库并算富集。
- 想少写代码:用 Dockey(T4-5)的图形界面。
- 上集群:参考阿里云那篇中文实战(T4-12),把每个配体拆成作业数组。
6. 后处理:MM-GBSA 与分子动力学(简要路径)
对接打分是快但粗的估计。想给候选一个更可信的结合自由能,常见做法是: 对接 → 分子动力学(MD)→ MM-GBSA 复算。
6.1 思路
- MD:把对接出来的复合物放进水盒子里,跑几百纳秒,看结合是否稳定 (配体有没有跑掉、有没有变形)。
- MM-GBSA / MM-PBSA:从 MD 轨迹里抽一批快照,算复合物、受体、配体三者的 能量差,用隐式溶剂近似溶剂效应,得到 ΔG_bind 的估计。
6.2 走一遍的步骤
- 建拓扑:用 tleap(Amber)或 GROMACS 的 pdb2gmx 给复合物建力场拓扑, 注意受体、配体、复合物的拓扑必须同源同力场、同 PBRadii 设置。
- 跑 MD:最小化 → 加热 → 平衡 → 生产。GROMACS 的入门教程(T5-5、T5-6)可以照着做。
- 抽帧去水:把轨迹里的水去掉,只留复合物。
- 算能量:用 gmx_MMPBSA(T5-1),它能在 GROMACS 轨迹上跑 MM/PB(GB)SA, 输入文件怎么写在 T5-3,示例命令在 T5-2。
一条典型的 gmx_MMPBSA 命令结构(来自官方 AMBER 示例):
gmx_MMPBSA -O \
-i mmpbsa.in \
-cs complex.tpr -ct traj.xtc \
-ci index.ndx \
-cg 1 13 \
-o FINAL_RESULTS_MMPBSA.dat \
-eo FINAL_RESULTS_MMPBSA.csv6.3 注意事项
- MM-GBSA 对同一批配体做相对排序比较可靠,绝对值误差大,别当 Kd 用。
- 拓扑别搞错:受体、配体、复合物三个拓扑必须一致,否则能量差全是噪声。
- 熵项(−TS)计算代价高,很多流程直接省略,报告结果时要说清楚。
- 嫌 gmx_MMPBSA 重,可以用纯 Python 的 g_mmpbsa(T5-9)。
7. 结果可视化
对接做完,最终是要看图讲故事的。常用工具:
- PyMOL(T6-1):主流选择。标准动作是——载入受体显示 cartoon, 载入配体显示 sticks,指着口袋里的关键残基标出来,调好视角出图。 PyMOL Wiki 的 Practical PyMOL(T6-3)够新手用。
- py3Dmol(T6-4):想在网页或 Jupyter 里交互看结构就用它, 官方 Colab 示例用的就是它。
- VMD:MD 轨迹分析更强,做后处理动画时用得上。
出图建议:受体用浅灰 cartoon(低调),配体用 sticks + 明显的元素配色,
关键残基单独高亮并标名字,最后叠上对接盒子的 PDB(1iep_receptor.box.pdb)
能直观说明搜索范围。
8. 常见坑与自查清单
跑之前对一遍,能省很多调错时间。
- 配体用了 PDB 格式 → 键级会被猜错。配体一定要从 SDF / MOL2 走。
- 受体没加氢 → PDBQT 需要全氢坐标,先补氢(REDUCE、PDB2PQR 都行)。
- 盒子定小了或偏了 → 配体被塞在不该在的位置。有共晶配体就对准它。
exhaustiveness太低 → 结果不稳定,同一配体跑两次分差很大。正式筛选用 32。- 混用两套力场比较打分 → vina 和 ad4 的分不能放一起排名。
- 质子化态没管 → 一个氢的位置能把对接结果带偏,用 scrub.py 枚举再定。
- 只看打分不看相互作用 → 假阳性高。关键残基接触是第二条过滤线。
- 忘记阳性对照 → 没有已知结合分子做参照,结果好坏无从判断。
- 并行时把内存跑爆 →
--nproc别超过核数,--cpu-per-job适当降。 - 结果不可复现 → 固定
--seed,记录版本号(vina、meeko、力场)。
附录:资源与核验说明
- 资源条目:共 42 条,分布在 6 个主题(原理 4、受体配体准备 7、 Vina 教程 6、批量筛选与库 12、后处理 9、可视化 4,其中 1 条中文实战归入批量筛选)。
- 核验方式(如实标注):42 条均经联网检索核验,其中约 30 条用 web_fetch 直接打开网页正文、确认存在且内容相关(AutoDock Vina、Meeko、GROMACS、 gmx_MMPBSA、PyMOL、DUD-E、smina 等为逐页精读);其余条目为官方文档站原文 直接给出的仓库页或数据页,或经检索返回完整内容的页面交叉确认,链接均指向 真实项目。
- 需在浏览器手动打开的一条:T3-6(GitHub 官方示例目录),因 GitHub 对自动 抓取有限制,未能单独打开正文;该链接引自 AutoDock Vina 官方文档原文,已在表中标注。
- 因无法可靠核验而舍弃的条目:4 条,分别是——
- RCSB PDB 首页(
rcsb.org):被站点安全策略拦截,未能打开,故不单列。 - Amber 官方 MM-PBSA 教程页(
ambermd.org/.../tutorial3):robots.txt 禁止自动访问,舍弃。 - smina 的 GitHub 仓库页:robots.txt 禁止,改用 SourceForge 官方页(T4-7 已核验)。
- molscrub 的 PyPI 页:被反爬拦截,改用 GitHub 仓库页(T2-3 已核验)。
- GitHub 说明:本模块涉及的多个仓库(AutoDock-Vina、Meeko、RDKit 等)首页都会被 GitHub 的 robots.txt 拒绝自动抓取,因此这些资源是通过其官方文档站 (readthedocs / 官网)完成的存在性与内容核验,链接指向的仓库均为真实项目。