分子动力学 / 轨迹分析

分子动力学模拟结果怎么分析:RMSD、RMSF、回转半径、氢键与 SASA

本页按 GROMACS 2026 的当前命令整理每个指标的选组规则、曲线读法和常见误读,并给出判断平衡与收敛的可操作方法、多副本作图脚本,以及论文报告的最低要求。

直接答案

分析 GROMACS 轨迹的顺序是:先用 gmx trjconv 按 whole、nojump、居中的顺序处理周期性边界,再计算指标。RMSD(gmx rms)衡量结构相对参考结构的整体偏离,配体 RMSD 要先按蛋白骨架叠合再算配体;RMSF(gmx rmsf -res)衡量每个残基围绕平均位置的波动;回转半径(gmx gyrate)衡量蛋白的紧密程度;氢键(gmx hbond,GROMACS 2024 起需要 -r 和 -t 两个选择)默认判据是供体–受体距离 0.35 nm、角度 30°;SASA(gmx sasa)的计算组必须包含全部非溶剂原子。RMSD 曲线变平不能证明体系已经平衡,应使用每个条件至少 3 个独立副本、块平均误差和主成分余弦含量来判断。

第一步

周期性边界处理是轨迹分析的第一步。蛋白跨过盒子边界时会被切成两段,或整体跳到另一侧,RMSD 因此出现几个 nm 的尖峰。

GROMACS 手册给出的推荐顺序是:先修补分子(-pbc whole);需要时做聚类(-pbc cluster);以第一帧为参考去掉跨盒跳跃(-pbc nojump);按某个组居中(居中会平移体系,此后不能再用 nojump);需要时用 -pbc 或 -ur 把分子放回盒子;最后做叠合(-fit),叠合之后不再使用任何 PBC 相关选项。trjconv 手册也写明,-pbc、-fit、-ur、-center 不一定能在一次调用里组合出想要的结果,应分多次调用。

叠合后的轨迹只用于可视化和 MDAnalysis。gmx rms、gmx rmsf、gmx covar 自身会叠合;gmx hbond、gmx sasa、gmx rdf、gmx dssp 计算距离时使用周期性边界,而叠合会旋转坐标、盒子向量不变,所以这些工具应读取居中后、未叠合的轨迹。下文命令统一使用 md_center.xtc。

只做一步处理的后果有论坛实例:一个 GROMACS 2024 的 DNA 体系只用 -pbc mol -ur compact -center 处理后,RMSD 在 0 到 6 nm 之间跳动;改为 whole、nojump、居中三步后,RMSD 降到 0.2 到 0.6 nm。

单链蛋白(溶菌酶)bash
# 单链可溶蛋白(如溶菌酶):两次调用即可
# 第 1 次:以 Protein 居中,整个体系按分子放回盒子;输出 System
printf "Protein\nSystem\n" | gmx trjconv -s md.tpr -f md.xtc -o md_center.xtc -pbc mol -center -ur compact
# 第 2 次(只用于可视化和 MDAnalysis):以 Backbone 叠合,输出 System;此后不再做任何 PBC 处理
printf "Backbone\nSystem\n" | gmx trjconv -s md.tpr -f md_center.xtc -o md_fit.xtc -fit rot+trans
多链蛋白或蛋白-配体复合物bash
# 多链蛋白或蛋白-配体复合物:按官方顺序 whole -> nojump -> center -> fit
# 0) 建一个“蛋白+配体”组(配体残基名以 LIG 为例)
printf '"Protein" | "LIG"\nq\n' | gmx make_ndx -f md.tpr -o index.ndx
# 1) 修补被盒子切断的分子
printf "System\n" | gmx trjconv -s md.tpr -f md.xtc -o md_whole.xtc -pbc whole
# 2) 做一个蛋白与配体在同一侧的参考帧(导出后在 VMD/PyMOL 中确认),再以它为参考做 nojump
printf "Protein_LIG\nSystem\n" | gmx trjconv -s md.tpr -f md_whole.xtc -n index.ndx -o frame0.gro -dump 0 -pbc mol -center -ur compact
printf "System\n" | gmx trjconv -s frame0.gro -f md_whole.xtc -o md_nojump.xtc -pbc nojump
# 3) 以蛋白+配体居中;居中之后不能再用 -pbc nojump
printf "Protein_LIG\nSystem\n" | gmx trjconv -s md.tpr -f md_nojump.xtc -n index.ndx -o md_center.xtc -center
# 4) 只用于可视化和 MDAnalysis:以蛋白骨架叠合;之后不再使用任何 PBC 选项
printf "Backbone\nSystem\n" | gmx trjconv -s md.tpr -f md_center.xtc -n index.ndx -o md_fit.xtc -fit rot+trans
区分真实解离和显示问题bash
# 配体是真的解离还是显示问题:最小距离按周期性边界计算,不受 trjconv 处理影响
printf "Protein\nLIG\n" | gmx mindist -s md.tpr -f md.xtc -n index.ndx -od mindist_pl.xvg -tu ns
# 蛋白与自身周期性镜像的最小距离,应始终大于非键截断(rcoulomb、rvdw)
printf "Protein\n" | gmx mindist -s md.tpr -f md.xtc -pi -od mindist_pi.xvg -tu ns

经验:nojump 的参考帧本身必须是完整的

nojump 以 -s 文件中的坐标为起点保持连续。如果参考结构里蛋白和配体本来就分在盒子两侧,整条轨迹会一直保持这种分离。gmx-users 上有用户因此得到 1.5 nm 的 RMSD,而其他副本只有约 0.3 nm。Justin Lemkul 的解释是:分子是否完整由拓扑决定,任何 tpr 都能用于 -pbc whole,但并非每个 tpr 的坐标都适合作为居中和 nojump 的参考。所以上面第 2 步先导出居中后的参考帧,确认后再用。

经验:看到配体“飘走”先用 gmx mindist 判断

论坛中多次出现“处理后配体离开蛋白”的求助,回复者建议先在 VMD 中看原始轨迹,区分 trjconv 显示问题和真实解离。更直接的办法是对原始 md.xtc 计算蛋白与配体的最小距离:gmx mindist 按最小镜像计算距离,结果与 trjconv 怎样处理无关。最小距离一直保持在接触距离内,说明只是显示问题;最小距离持续增大,说明配体确实离开了结合位点。

经验:检查蛋白与自身镜像的距离

gmx mindist -pi 给出蛋白与其周期性镜像的最小距离。这个距离小于非键截断时,蛋白会与自身镜像直接相互作用,RMSD、Rg 等结果都会受影响,需要加大盒子重新模拟。

体系推荐处理只用一步时的典型问题
单链可溶蛋白(溶菌酶等)-pbc mol -center -ur compact 一次,再单独叠合一般够用
多链蛋白、蛋白-配体、蛋白-核酸whole → 以第 0 帧为参考 nojump → 以复合物居中 → 叠合链之间或配体与蛋白被分到盒子两侧,RMSD 和配体距离出现突跳
膜蛋白whole → nojump → 以膜或蛋白居中,必要时 -pbc cluster 处理脂质脂质被切断,膜厚、面积和蛋白倾角错误
选组:居中组选蛋白或蛋白+配体,输出组选 System;叠合组选 Backbone。

版本差异

多数中文教程基于 GROMACS 2018–2022。下表列出在 2026 版中行为已经改变的命令。

命令变化与版本旧写法的问题当前写法
gmx do_dsspGROMACS 2023 起由原生 gmx dssp 取代,实现 DSSP v4命令不存在;不再需要安装 mkdssp 和设置 DSSP 环境变量gmx dssp -sel Protein -o dssp.dat -num dssp_num.xvg;-nopolypro 复现 DSSP v2 行为
gmx hbondGROMACS 2024 重写,旧实现改名 gmx hbond-legacy旧教程用交互方式选两个组,并用 -life、-ac、-hbm用 -r、-t 两个选择(都必须给);新实现没有 -ac、-life、-hbm,需要时调用 gmx hbond-legacy
gmx hbond -num新实现中 -num 是可选输出不写 -num 就不生成氢键数随时间变化的文件;旧版 hbnum.xvg 有两列,新版只有一列显式写 -num hbnum.xvg
gmx gyrateGROMACS 2024 重写,旧实现改名 gmx gyrate-legacy-p、-moi、-nz 等旧选项不在新实现中-sel 选组,-mode mass|charge|geometry;输出 4 列:Rg 和绕 x、y、z 轴的分量
-tu 与 -b/-e-b、-e、-dt 按 -tu 的单位解释(源码中为时间型选项)-tu ns -b 10000 表示从 10000 ns 开始;本页实测 gmx rms 直接报 Specified frame (time 10000000.000000) doesn't exist or file corrupt/inconsistent.用 -tu ns 时写 -b 10;不加 -tu 时写 -b 10000(ps)
gmx hbond 选区内无供体或受体2024.3 修复了程序提前退出的问题(issue 5080)早期 2024 版本中某些选区直接报错退出使用 2024.3 及以上;配体含羧酸根或磺酸根时,用 hbond-legacy 或 MDAnalysis 交叉核对。ACPYPE 生成的配体拓扑缺原子序数时也会报这条错,见“氢键”一节

RMSD

RMSD(均方根偏差)是每一帧在叠合到参考结构后,所选原子与参考结构对应原子距离的均方根。它衡量整体偏离,不反映哪一段在动。

gmx rms 的第一个提示是叠合组,第二个是计算组。蛋白一般两次都选 Backbone 或 C-alpha。配体 RMSD 的叠合组选蛋白 Backbone、计算组选配体:此时数值同时包含配体在口袋中的平移、旋转和自身构象变化。如果两次都选配体,配体离开口袋也只会得到很小的 RMSD,这是审稿人常问的问题。

参考结构用 md.tpr 时是生产模拟的起点;用 em.tpr 时是能量最小化后的晶体结构。两条曲线的起始差值反映平衡阶段已经发生的偏离。

读曲线时看三件事:上升段持续多久;之后围绕什么值波动、波动幅度多大;是否出现台阶式跳变。台阶式跳变先排除周期性边界问题,再判断是否是真实构象转变;配体 RMSD 的台阶常对应结合模式改变或解离。

RMSD 命令(GROMACS 2026)bash
# 蛋白骨架 RMSD:第一个提示是叠合组,第二个是计算组
printf "Backbone\nBackbone\n" | gmx rms -s md.tpr -f md_center.xtc -o rmsd_bb.xvg -tu ns
# 相对晶体结构(能量最小化前后的 em.tpr)的 RMSD
printf "Backbone\nBackbone\n" | gmx rms -s em.tpr -f md_center.xtc -o rmsd_xtal.xvg -tu ns
# 配体 RMSD:先按蛋白骨架叠合,再算配体,不对配体自身叠合
printf "Backbone\nLIG\n" | gmx rms -s md.tpr -f md_center.xtc -n index.ndx -o rmsd_lig.xvg -tu ns
# 只看配体自身构象变化(与上一条含义不同,论文中要分开写)
printf "LIG\nLIG\n" | gmx rms -s md.tpr -f md_center.xtc -n index.ndx -o rmsd_lig_self.xvg -tu ns
# all-to-all RMSD 矩阵,用于判断是否回到已采样构象
printf "Backbone\nBackbone\n" | gmx rms -s md.tpr -f md_center.xtc -m rmsd_matrix.xpm -dt 100

误读:配体 RMSD 小于 2 Å 才算模拟成功

2 Å 是对接和共折叠方法评估位姿复现的成功阈值,例如 PoseBusters 统计 RMSD ≤ 2 Å 的比例。它不是 MD 稳定性的标准。MD 中应结合骨架叠合后的配体 RMSD、配体与口袋关键残基的距离和氢键占有率,判断结合模式是否保持。

误读:RMSD 变平说明体系已经平衡

Knapp 等让 MD 研究者对同一组 RMSD 图判断平衡点,结果没有共识,且判断受坐标轴等作图参数影响。体系在多个与参考结构距离相近的状态之间切换时,RMSD 也会保持平稳。判断方法见下文“平衡与收敛”。

误读:RMSD 越小蛋白越稳定

RMSD 小只说明结构接近参考结构。柔性区域多的蛋白、无序肽和多结构域蛋白,正常 RMSD 就会更大。比较突变体或不同配体时,应比较同一选组、同一参考、多副本的均值与区间。

RMSF

RMSF(均方根涨落)是每个原子在轨迹中相对其平均位置的位移的标准差。gmx rmsf 默认先做最小二乘叠合,-res 给出按残基的平均值。

去掉平衡段后计算 Cα RMSFbash
# 去掉前 10 ns(-b 单位为 ps,此命令不加 -tu),按残基输出 Cα RMSF
printf "C-alpha\n" | gmx rmsf -s md.tpr -f md_center.xtc -b 10000 -res -o rmsf.xvg -oq bfac.pdb
  • 计算 RMSF 前去掉平衡段(-b)。包含升温和平衡阶段时,所有残基的 RMSF 都会被抬高。
  • RMSF 峰通常出现在 N、C 末端和表面环区。把峰直接解释为活性位点没有依据;需要与已知功能位点、晶体 B 因子或无配体体系的 RMSF 对照。
  • 多链蛋白应按链分别计算,或者先按单链叠合,否则链间相对运动会叠加到每个残基上。
  • 比较两个体系时,把各副本的 RMSF 求均值并画出副本间的区间。单条轨迹上 0.05 nm 量级的差异常在副本间波动范围内。
  • -oq 把 RMSF 换算成 B 因子写入 PDB,可以在 PyMOL 中按 B 因子着色,与晶体结构的 B 因子并排比较。

回转半径与 SASA

回转半径(Rg)是所选原子到其质心距离的质量加权均方根,衡量蛋白的紧密程度。SASA(溶剂可及表面积)是半径 0.14 nm 的探针球在分子表面滚动时,球心轨迹所围成的面积。

回转半径与 SASAbash
# 回转半径(GROMACS 2024 起的新实现,用 -sel 选择)
gmx gyrate -s md.tpr -f md_center.xtc -sel Protein -o gyrate.xvg -tu ns
# 溶剂可及表面积:-surface 包含全部非溶剂原子,-output 取其子集
gmx sasa -s md.tpr -f md_center.xtc -surface Protein -o sasa.xvg -or resarea.xvg -tu ns
# 蛋白-配体体系
gmx sasa -s md.tpr -f md_center.xtc -surface 'group "Protein" or resname LIG' \
         -output 'group "Protein"' 'resname LIG' -o sasa_pl.xvg -tu ns

Rg 只衡量所选原子的紧密程度

只对蛋白计算的 Rg 与配体结合强度无关。头部教程中“回旋半径越小,蛋白与配体结合越紧密”的说法没有依据。Rg 持续上升提示部分展开或结构域分离;Rg 平稳只说明整体尺寸稳定。

SASA 的计算组不能只选溶剂或只选一部分

gmx sasa 手册要求 -surface 包含体系中全部非溶剂原子,需要分组结果时用 -output 选择其子集。选 SOL 作为计算组得到的是水的表面积。只选配体作为计算组,会把被蛋白遮住的配体表面也算成可及表面。

默认精度与单位

默认每个原子 24 个表面点(-ndots 24),逐残基比较时可以增大 -ndots。gmx sasa 输出单位为 nm²;MDTraj 的 shrake_rupley 输出也是 nm²,MDAnalysis 的长度单位为 Å,混用时注意换算。

氢键

GROMACS 2024 起的 gmx hbond 采用几何判据:供体–受体距离不超过 0.35 nm(-hbr),氢–供体–受体夹角不超过 30°(-hba),供体与受体元素默认为 N 和 O。

新 gmx hbond 要求 -r 与 -t 两个选区完全相同或互不重叠。论坛报告过 2024 版新工具对 POPC 选区报“has no donors AND has no acceptors”,而 hbond-legacy 正常;GitLab issue 4985 报告小分子羧酸根和磺酸根未被识别为受体。配体含这类基团时,用 hbond-legacy 或 MDAnalysis 再算一次。

本页实测(GROMACS 2026.3):配体拓扑来自 ACPYPE 时,gmx hbond -t 'resname LIG' 直接报 Selection 'resname LIG' has no donors AND has no acceptors! Nothing to be done.,而同一配体有羟基,hbond-legacy 也能找到它与 Gln102 的氢键。原因是 ACPYPE 写出的 [ atomtypes ] 没有原子序数列,tpr 中配体原子的 atomnumber 为 -1,新 gmx hbond 按元素(-de、-ae 默认 N O)识别供体和受体。在 atomtypes 中补上原子序数后重新 grompp 即可,做法见《GROMACS 蛋白质-配体复合物模拟》第 3 步。tpr 中的原子序数可以用 gmx dump -s md.tpr | grep atomnumber 检查。

gmx hbond(新)与 gmx hbond-legacy(寿命)bash
# GROMACS 2024+ 新实现:-r 与 -t 都必须给;-num 必须显式写出才会输出
gmx hbond -s md.tpr -f md_center.xtc -r Protein -t Protein -num hbnum.xvg -tu ns
# 蛋白-配体氢键,-o 写出每对氢键的原子索引
gmx hbond -s md.tpr -f md_center.xtc -r Protein -t 'resname LIG' -num hbnum_pl.xvg -o hbond_pl.ndx -tu ns
# 需要氢键寿命或存在矩阵时用旧实现:-ac 给出 Luzar-Chandler 速率常数,-hbm 给出每对氢键逐帧存在矩阵
printf "Protein\nLIG\n" | gmx hbond-legacy -s md.tpr -f md_center.xtc -n index.ndx \
         -num hbnum_legacy.xvg -ac hbac.xvg -hbn hbond.ndx -hbm hbmap.xpm
需要的结果工具说明
氢键数随时间变化gmx hbond -num新实现,单列输出
每对氢键的占有率gmx hbond-legacy -hbn -hbm,或 MDAnalysis count_by_ids()占有率 = 存在的帧数 / 总帧数;论文中通常列出占有率最高的几对
氢键寿命gmx hbond-legacy -ac,或 MDAnalysis lifetime()legacy 的 -ac 按 Luzar–Chandler 模型给出速率常数;开发者建议看 -ac 结果中的 Forward 行,-life 的输出不作为寿命使用
与其他软件结果对比写明判据MDAnalysis 默认 D–A 3.0 Å、D–H–A ≥ 150°,与 GROMACS 默认 0.35 nm、30° 不同,计数会有差别

二级结构

gmx dssp 根据残基间的氢键模式指定二级结构,输出 H(α 螺旋)、E(β 链)、G(3₁₀ 螺旋)、I(π 螺旋)、P(κ 螺旋,即多聚脯氨酸 II)、T、S、B 和 ~(无规则卷曲)等单字母代码。

gmx dsspbash
# GROMACS 2023+ 内置 DSSP v4,不再需要外部 dssp 程序和 DSSP 环境变量
gmx dssp -s md.tpr -f md_center.xtc -sel Protein -o dssp.dat -num dssp_num.xvg -tu ns
# 结构不含氢(如粗处理后的 PDB):由 C、O 生成氢的伪原子
gmx dssp -s protein_noH.pdb -f protein_noH.pdb -sel Protein -hmode dssp -clear -o dssp_noH.dat
  • -num 输出每帧各类二级结构的残基数,适合做随时间变化的堆积图;dssp.dat 每行对应一帧,可用 Python 画残基 × 时间的二级结构图。
  • 默认 -hmode gromacs 使用结构中已有的氢;结构不含氢时必须用 -hmode dssp,并加 -clear 去掉缺失关键原子的残基。
  • 本页实测:同一个去氢的溶菌酶结构,用默认 -hmode gromacs 时 gmx dssp 不报错,但螺旋几乎全部输出为 S(弯曲);改用 -hmode dssp 后得到正常的 H 和 E。不含氢的结构忘记加 -hmode dssp,不会有任何提示。
  • 与旧版 do_dssp 或 VMD 结果不一致时,先确认对比的是同一个 DSSP 版本:gmx dssp 默认等价于 DSSP v4,-nopolypro 对应 DSSP v2。
  • 单个残基在少数帧中由卷曲变为 β 桥属于常见波动。只有在多个副本中重复出现、并持续相当比例时间的二级结构变化,才适合写成结论。

平衡与收敛

平衡指体系已经离开初始结构的影响;收敛指所关心的量在现有采样下已经有可靠的估计。两者都不能靠 RMSD 曲线是否变平来判断。

副本数量的依据:Communications Biology 2023 的可靠性清单要求每个条件至少 3 次模拟并做统计分析,并给出结果与初始构型无关的证据。Knapp 等(JCTC 2018)对两个体系各跑 100 个副本,经验规则是至少 5 到 10 个副本,且多个较短副本得出的结论比单条长轨迹更可靠。

余弦含量的局限:Berk Hess 在 gmx-users 邮件列表中指出,前 10 个本征向量张成的子空间收敛,不代表前几个本征向量本身收敛。余弦含量低只能排除“接近随机扩散”,不能证明已经充分采样。

块平均、余弦含量与子空间重叠bash
# 块平均误差估计(Hess 2002 方法),只用生产段
gmx analyze -f gyrate.xvg -b 10 -ee gyrate_errest.xvg
# 余弦含量:每次只投影一个主成分,再交给 gmx analyze -cc
printf "C-alpha\nC-alpha\n" | gmx covar -s md.tpr -f md_center.xtc -b 10000 -o eigenval.xvg -v eigenvec.trr -av average.pdb
printf "C-alpha\nC-alpha\n" | gmx anaeig -s md.tpr -f md_center.xtc -b 10000 -v eigenvec.trr -eig eigenval.xvg -first 1 -last 1 -proj pc1.xvg
gmx analyze -f pc1.xvg -cc pc1_cosine.xvg
# 前后两半各做一次 covar(此例生产段 10-60 ns),再比较前 10 个本征向量张成的子空间
printf "C-alpha\nC-alpha\n" | gmx covar -s md.tpr -f md_center.xtc -b 10000 -e 35000 -o eigval_h1.xvg -v eigvec_h1.trr
printf "C-alpha\nC-alpha\n" | gmx covar -s md.tpr -f md_center.xtc -b 35000 -e 60000 -o eigval_h2.xvg -v eigvec_h2.trr
gmx anaeig -v eigvec_h1.trr -v2 eigvec_h2.trr -first 1 -last 10 -over overlap.xvg
延长模拟与续跑后拼接bash
# 延长已结束的模拟(单位 ps,此处加 100 ns)
gmx convert-tpr -s md.tpr -extend 100000 -o md_ext.tpr
gmx mdrun -deffnm md -s md_ext.tpr -cpi md.cpt   # 默认追加写入原文件
# 若用了 -noappend,会得到 md.part0002.xtc 等文件(编号是模拟段号,之后每段递增),分析前先拼接
gmx trjcat -f md.xtc md.part0002.xtc -o md_all.xtc
方法怎么做判断依据出处
独立副本从 NVT 开始用不同随机种子(gen_seed = -1)重新生成速度,每个条件至少 3 个副本各副本均值及其置信区间相互重叠;不重叠说明采样不足Communications Biology 2023 可靠性清单 1c;Grossfield 等 2018 第 4.4 节
块平均把生产段等分成不同数量的块,计算块均值的标准误标准误随块长增大出现平台;一直上升说明相关时间与轨迹长度相当Grossfield 等 2018 第 7.3.2 节;gmx analyze -ee(Hess 2002)
主成分余弦含量对生产段做 PCA,计算 PC1、PC2 投影的余弦含量接近 1 时模拟肯定未收敛,运动接近随机扩散;单条 1 ns 片段的数值分布很宽,不能单独作为收敛证明Hess, Phys. Rev. E 2002
前后半段比较前后两半各做一次 PCA,比较子空间重叠;或比较两半的指标分布两半给出的分布与主要运动方向一致gmx anaeig -over 手册
all-to-all RMSD 矩阵gmx rms -m 计算每两帧之间的 RMSD非对角区出现低 RMSD 区块,说明体系回到已采样的状态Grossfield 等 2018 第 4.2 节

PCA 与 FEL

PCA 对叠合后原子坐标的协方差矩阵做对角化,本征值最大的几个本征向量(主成分)描述幅度最大的集体运动。自由能形貌图(FEL)把轨迹在两个主成分上的二维分布 P 换算成 G = −kT ln P。

PCA 与 FEL 流程bash
# 1) 协方差矩阵:只用 Cα,去掉平衡段(-b 单位 ps)
printf "C-alpha\nC-alpha\n" | gmx covar -s md.tpr -f md_center.xtc -b 10000 -o eigenval.xvg -v eigenvec.trr -av average.pdb
# 2) 投影到 PC1、PC2;-2d 输出两列(PC1 PC2),不含时间列
printf "C-alpha\nC-alpha\n" | gmx anaeig -s md.tpr -f md_center.xtc -b 10000 -v eigenvec.trr -eig eigenval.xvg \
       -first 1 -last 2 -2d 2dproj.xvg
# 3) 沿 PC1 的两端极值结构,用于看运动方向
printf "C-alpha\nC-alpha\n" | gmx anaeig -s md.tpr -f md_center.xtc -v eigenvec.trr -first 1 -last 1 -extr pc1_extreme.pdb -nframes 10
# 4) 自由能形貌:必须 -notime;-tsham 改成模拟温度
gmx sham -f 2dproj.xvg -notime -tsham 300 -ngrid 40 40 40 -nlevels 50 -ls fel.xpm -lp prob.xpm
  • gmx covar 的内存和时间至少随原子数平方增长,内存不足时会直接 Segmentation fault。用 Cα 或骨架,不用全原子。
  • gmx anaeig -2d 输出的两列是 PC1 和 PC2,不含时间列。gmx sham 默认把第一列当作时间(-time 默认开启),不加 -notime 会得到一维分布。
  • 判断 gmx sham 是否按二维处理:屏幕输出应为 Read 2 sets of N points;漏写 -notime 时显示 Read 1 sets of N points,并提示 There are 40 bins in the 1-dimensional histogram(本页实测)。
  • -tsham 默认 298.15 K,应改为模拟温度;不设 -xmin/-xmax 时坐标范围由数据自动确定。gmx sham 输出单位为 kJ/mol,最低点为 0。
  • 比较两个体系(例如有无配体)的 FEL 时,先把两组轨迹拼接后做一次 covar,再分别投影,两张图才在同一坐标系中。分别做 PCA 得到的 PC1 方向不同,不能直接比较。
  • eigenval.xvg 给出各本征值,可计算 PC1、PC2 占总方差的比例并写进图注。
  • FEL 中的极小值深度取决于采样量。单条短轨迹的 FEL 反映的是这条轨迹停留过的位置,不代表平衡分布;多个副本拼接后的 FEL 更可靠,并应报告所用帧数。
  • 从极小值取代表构象(gmx-users 上的经验做法):在 2dproj.xvg 中找到 PC1、PC2 落在该极小值格子内的帧,再用 gmx trjconv -dump 导出。下文 fel_from_2dproj.py 直接打印最低格子中的帧序号;帧序号从 anaeig 的 -b 起点开始计数,乘以输出间隔得到时间。
  • 需要用其他两个量(例如 RMSD 与 Rg)作 FEL 时,可以用 paste 把两个 xvg 的数值列拼成两列文件再交给 gmx sham -notime;gmx sham 本质上只是把直方图换算成能量,输入什么量由你决定。

其他指标

MSD(均方位移)用于计算扩散系数,RDF(径向分布函数)描述某类粒子在参考粒子周围的密度分布。

gmx msd 默认在 MSD 曲线 10% 到 90% 的区间做线性拟合;曲线两端不呈线性时用 -beginfit、-endfit 指定区间。MSD 使用已做 nojump 的轨迹(见上文复合物流程第 2 步)。gmx rdf 默认 bin 宽 0.002 nm,-rmax 为 0 时取半个盒长。

bash
# 水的自扩散系数(默认在 MSD 曲线 10%-90% 区间拟合)
gmx msd -s md.tpr -f md_nojump.xtc -sel 'resname SOL and name OW' -o msd.xvg
# 配体周围水氧的径向分布函数
gmx rdf -s md.tpr -f md_center.xtc -ref 'resname LIG' -sel 'resname SOL and name OW' -selrpos res_com -o rdf.xvg

Python

第一个脚本读取多个副本的 .xvg,画出各副本曲线、均值和 ±1 SD 区间,并输出生产段的副本间标准误和块平均标准误。第二个脚本由 2dproj.xvg 直接画 FEL。第三个脚本用 MDAnalysis 和 MDTraj 计算同样的指标。

MDAnalysis 2.10.0 读取 GROMACS 2026.3 生成的 tpr 时报 Your tpx version is 138, which this parser does not support, yet(本页实测)。先用 gmx trjconv -s md.tpr -f md_fit.xtc -o frame0.pdb -dump 0(输出组选 System)导出 frame0.pdb 作为拓扑,脚本中 MDTraj 部分也读取这个文件。PDB 中没有电荷,guess_hydrogens 不可用,脚本检测到没有电荷时改用按原子名的显式选择。

脚本中的 count_by_ids() 返回的是原子 id(PDB 和 tpr 中从 1 开始编号),不是 AtomGroup 的索引;直接写 u.atoms[d] 会错位一个原子,打印出的供体会变成相邻的氢。本页实测(MDAnalysis 2.10.0,3HTB 复合物 50 ps 轨迹):修正后输出 LIG164:O -> GLN102:OE1,与晶体结构中 2-丙基苯酚羟基和 Gln102 的氢键一致。

MDAnalysis 的 RMSF 类不做叠合,必须先把轨迹对齐到平均结构;脚本中的 AlignTraj 使用 in_memory=True,会改写内存中的坐标,所以 RMSF 放在 RMSD 和氢键之后计算。

plot_replicas.py(用法:python plot_replicas.py "rep*/rmsd.xvg" 10 "RMSD (nm)")python
# 用法:python plot_replicas.py "rep*/rmsd.xvg" 10 RMSD_nm
# 参数:xvg 通配符、丢弃的平衡段(与 xvg 时间列同单位)、y 轴标签
import glob
import sys

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np


def read_xvg(path):
    """读取 GROMACS .xvg:跳过 # 和 @ 注释行,遇到 & 停止(只读第一个数据集)"""
    rows = []
    with open(path) as fh:
        for line in fh:
            s = line.strip()
            if not s or s[0] in "#@":
                continue
            if s.startswith("&"):
                break
            rows.append([float(v) for v in s.split()])
    return np.array(rows)


def block_se(x, n_blocks):
    """块平均标准误:把序列等分成 n_blocks 块,返回块均值的标准误"""
    m = len(x) // n_blocks
    blocks = x[: m * n_blocks].reshape(n_blocks, m).mean(axis=1)
    return blocks.std(ddof=1) / np.sqrt(n_blocks)


pattern, t_equil, ylabel = sys.argv[1], float(sys.argv[2]), sys.argv[3]
files = sorted(glob.glob(pattern))
if len(files) < 2:
    sys.exit("need at least 2 replicas, found %d" % len(files))
data = [read_xvg(f) for f in files]
n = min(len(d) for d in data)
t = data[0][:n, 0]
for f, d in zip(files, data):
    if not np.allclose(d[:n, 0], t):
        sys.exit("time axis differs: %s" % f)
Y = np.stack([d[:n, 1] for d in data])  # 第 2 列;Rg 的总值也在第 2 列
mean, sd = Y.mean(axis=0), Y.std(axis=0, ddof=1)

fig, ax = plt.subplots(figsize=(6, 3.5), dpi=200)
for f, y in zip(files, Y):
    ax.plot(t, y, lw=0.6, alpha=0.5, label=f.split("/")[0])
ax.plot(t, mean, lw=1.5, color="black", label="mean")
ax.fill_between(t, mean - sd, mean + sd, color="gray", alpha=0.3, label="±1 SD")
ax.axvline(t_equil, ls="--", lw=0.8, color="gray")
ax.set_xlabel("Time (same unit as xvg)")
ax.set_ylabel(ylabel)
ax.legend(fontsize=6, frameon=False)
fig.tight_layout()
fig.savefig("replicas.png")

# 生产段统计:每个副本先求均值,再用副本间标准差 / sqrt(n) 得标准误
prod = Y[:, t >= t_equil]
rep_means = prod.mean(axis=1)
se = rep_means.std(ddof=1) / np.sqrt(len(rep_means))
print("replica means:", np.round(rep_means, 4))
print("mean = %.4f, SE across replicas = %.4f (n=%d)" % (rep_means.mean(), se, len(rep_means)))
# 块平均:标准误随块变大应趋于平台;不出现平台说明采样不足
for nb in (40, 20, 10, 5):
    if prod.shape[1] < 2 * nb:  # 每块至少 2 帧,帧数太少时跳过
        continue
    print("rep1 blocks=%2d  SE=%.4f" % (nb, block_se(prod[0], nb)))
fel_from_2dproj.py(用法:python fel_from_2dproj.py 2dproj.xvg 300)python
# 用法:python fel_from_2dproj.py 2dproj.xvg 300
# 与 gmx sham 相同的定义:G = -kT ln P,再平移使最低点为 0
import sys

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

path, T = sys.argv[1], float(sys.argv[2])
xy = np.array([[float(v) for v in l.split()[:2]] for l in open(path)
               if l.strip() and l.strip()[0] not in "#@&"])
H, xe, ye = np.histogram2d(xy[:, 0], xy[:, 1], bins=40)
P = H / H.sum()
kT = 0.0083144626 * T  # kJ/mol
with np.errstate(divide="ignore"):
    G = -kT * np.log(P)
G -= G[np.isfinite(G)].min()
fig, ax = plt.subplots(figsize=(4.5, 3.8), dpi=200)
im = ax.pcolormesh(xe, ye, np.ma.masked_invalid(G).T, cmap="viridis", shading="flat")
fig.colorbar(im, label="G (kJ/mol)")
ax.set_xlabel("PC1 (nm)")
ax.set_ylabel("PC2 (nm)")
fig.tight_layout()
fig.savefig("fel.png")
print("frames: %d, empty bins: %d / %d" % (len(xy), int((H == 0).sum()), H.size))
# 最低自由能格子中的帧序号(从 anaeig -b 指定的起点开始计数),用 gmx trjconv -dump 导出代表构象
i, j = np.unravel_index(np.nanargmin(np.where(np.isfinite(G), G, np.nan)), G.shape)
ix = np.clip(np.digitize(xy[:, 0], xe) - 1, 0, len(xe) - 2)
iy = np.clip(np.digitize(xy[:, 1], ye) - 1, 0, len(ye) - 2)
print("frames in the minimum bin:", np.where((ix == i) & (iy == j))[0][:20])
mda_analysis.py(用法:python mda_analysis.py frame0.pdb md_fit.xtc)python
# 用法:python mda_analysis.py frame0.pdb md_fit.xtc
# MDAnalysis 2.10 读不了 GROMACS 2026 的 tpr(报 Your tpx version is 138, which this parser does not support),
# 先用 gmx trjconv -dump 0 导出 frame0.pdb 作拓扑;能读 tpr 的组合也可以直接传 md.tpr
import sys

import MDAnalysis as mda
import mdtraj as md
import numpy as np
from MDAnalysis.analysis import align, rms
from MDAnalysis.analysis.hydrogenbonds import HydrogenBondAnalysis

top, traj = sys.argv[1], sys.argv[2]
u = mda.Universe(top, traj)
protein = u.select_atoms("protein")
has_lig = len(u.select_atoms("resname LIG")) > 0

# 1) RMSD:按骨架叠合;配体 RMSD 用 groupselections,在骨架叠合后计算且不再单独叠合
R = rms.RMSD(u, u, select="backbone",
             groupselections=["resname LIG"] if has_lig else None, ref_frame=0).run()
np.savetxt("rmsd_mda.dat", R.results.rmsd, fmt="%.4f",
           header="frame time_ps backbone_A" + (" ligand_A" if has_lig else ""))

# 2) 回转半径(Å,质量加权)
rg = np.array([(ts.time, protein.radius_of_gyration()) for ts in u.trajectory])
np.savetxt("rg_mda.dat", rg, fmt="%.4f", header="time_ps rg_A")

# 3) 氢键:判据写成与 GROMACS 默认接近的 3.5 Å;论文中写明所用判据
sel = "protein or resname LIG" if has_lig else "protein"
if hasattr(u.atoms, "charges"):  # tpr 拓扑:按电荷猜测氢和受体
    hb = HydrogenBondAnalysis(u, between=["protein", "resname LIG"] if has_lig else None,
                              d_a_cutoff=3.5, d_h_a_angle_cutoff=150)
    hb.hydrogens_sel = hb.guess_hydrogens(sel)
    hb.acceptors_sel = hb.guess_acceptors(sel)
else:  # PDB 拓扑没有电荷:按原子名显式指定 N/O 供体、受体和氢
    hb = HydrogenBondAnalysis(u, between=["protein", "resname LIG"] if has_lig else None,
                              donors_sel="(%s) and (name N* or name O*)" % sel,
                              hydrogens_sel="(%s) and name H*" % sel,
                              acceptors_sel="(%s) and (name O* or (resname HI* and name ND1 NE2))" % sel,
                              d_a_cutoff=3.5, d_h_a_angle_cutoff=150)
hb.run()
np.savetxt("hbnum_mda.dat", np.column_stack([hb.times, hb.count_by_time()]),
           fmt="%.3f", header="time_ps n_hbonds")
id2ix = {i: k for k, i in enumerate(u.atoms.ids)}  # count_by_ids 返回原子 id(从 1 开始),不是索引
for d, h, a, n in hb.count_by_ids()[:15]:  # 占有率最高的 15 对
    D, A = u.atoms[id2ix[d]], u.atoms[id2ix[a]]
    print("%s%d:%s -> %s%d:%s  occupancy=%.2f" % (
        D.resname, D.resid, D.name, A.resname, A.resid, A.name, n / u.trajectory.n_frames))
tau, acf = hb.lifetime(tau_max=50)  # 连续型自相关;tau 以帧为单位
np.savetxt("hb_lifetime_acf.dat", np.column_stack([tau, acf]), fmt="%.4f")

# 4) RMSF:MDAnalysis 的 RMSF 不做叠合,先对 Cα 平均结构对齐(in_memory 会改写 u 中的坐标)
avg = align.AverageStructure(u, u, select="protein and name CA", ref_frame=0).run()
align.AlignTraj(u, avg.results.universe, select="protein and name CA", in_memory=True).run()
ca = u.select_atoms("protein and name CA")
F = rms.RMSF(ca).run()
np.savetxt("rmsf_mda.dat", np.column_stack([ca.resids, F.results.rmsf]), fmt="%.4f",
           header="resid rmsf_A")

# 5) SASA:用 MDTraj 的 Shrake-Rupley(探针 0.14 nm,结果单位 nm^2)
t = md.load(traj, top="frame0.pdb")
t = t.atom_slice(t.topology.select("protein"))
sasa = md.shrake_rupley(t, probe_radius=0.14, mode="residue")
np.savetxt("sasa_total_nm2.dat", np.column_stack([t.time, sasa.sum(axis=1)]), fmt="%.3f")

论文

以下要求来自 Communications Biology 2023 的 MD 可靠性与可重复性清单和 Grossfield 等关于不确定度的最佳实践。模拟时长没有公认的最低值,需要与所研究过程的时间尺度对应。

审稿人常见质疑回应所需的证据
只有一条轨迹补充至少 3 个独立副本,报告副本间均值与区间
仅凭 RMSD 平稳就宣称平衡块平均误差、前后半段比较、余弦含量或 all-to-all RMSD 矩阵
均值中包含了平衡段说明丢弃的时间段,并展示结论对丢弃长度不敏感
配体 RMSD 只对配体自身叠合改为按蛋白骨架叠合后计算配体 RMSD,并补充配体与口袋残基的距离
氢键判据未说明或与文献不同写明距离和角度阈值及所用工具
RMSF 峰被解释为功能位点与已知功能位点、B 因子或无配体体系对照
FEL 来自单条短轨迹多副本拼接后统一做 PCA,并报告帧数和温度
结果与实验不符检查力场与水模型、质子化状态、模拟温度和离子浓度是否与实验条件一致,并说明模拟时长能否覆盖实验观测的时间尺度
  • 每个模拟条件至少 3 个独立副本,并写明副本如何生成(不同初始速度或不同初始构型)。
  • 写明平衡段与生产段如何划分,以及分析使用了哪一段和多少帧。
  • 写明模拟与分析软件及版本,例如 GROMACS 2026.3、MDAnalysis 版本号;氢键、SASA 等写明判据和参数。
  • 提供体系组成表:盒子尺寸、原子总数、离子浓度、质子化状态。
  • 提供初始坐标、输入文件(mdp、top、itp)和最终坐标,作为补充材料或放在公开仓库中。
  • 均值给出不确定度,写明是标准差、标准误还是 95% 置信区间;副本少时把每个副本的值都画出来,不只画均值和误差棒。
  • 数值只保留有效数字,例如 1.23456 ± 0.1 写成 1.2 ± 0.1。
  • 尽可能把模拟结果与实验数据联系起来,例如晶体 B 因子、NMR 化学位移或 SAXS 曲线。

国内经验

以下来自 Sobereva 博客、Jerkwin 博客、计算化学公社答疑和 CSDN 教程,已对照 GROMACS 2026 手册和工具当前版本核对。

DuIvyTools 常用命令bash
# DuIvyTools 0.6.0(pip 安装,命令名 dit)
pip install DuIvyTools
dit xvg_show -f rmsd.xvg                      # 查看单条曲线
dit xvg_compare -f rep1/rmsd.xvg rep2/rmsd.xvg rep3/rmsd.xvg -c 1 1 1   # 多副本同图比较
dit xpm_show -f fel.xpm                       # 查看 gmx sham 输出的自由能形貌图
dit xpm2csv -f fel.xpm -o fel.csv             # 转成 x, y, z 三列,交给 Origin 等软件作图
dit dssp -f dssp.dat -o dssp.xpm -x "Frame"     # 把 gmx dssp 的 dssp.dat 转成旧式 xpm 和两个 xvg

Jerkwin 中文教程的分析命令已过时

Jerkwin 的《GROMACS中文教程》和《GROMACS中文手册》页首都标注“本手册已过时, 不再更新”。教程的分析部分基于 GROMACS 4.6/5.1,使用 g_rms、g_sas、do_dssp、g_hbond 和 g_MMPBSA。GROMACS 2026 中只有 gmx 加工具名的形式,g_sas 对应 gmx sasa;do_dssp 和 gmx hbond 的变化见上文版本差异表。教程里的分析思路仍可参考,命令要按当前手册改写。

FEL 的格子数按帧数选

gmx sham 的 -ngrid 默认是 32。Sobereva 用 10,000 帧的 PC1/PC2 投影比较了 50×50、75×75、100×100 和 200×200 格:格子多时图像破碎、低能区出现空洞,格子少时边缘呈棱角,这个例子中 75×75 最合适,一般在 60×60 到 120×120 之间试。帧数少时(例如每 10 帧取 1 帧只剩 1,000 个点)要减少格子数,或者对数据点做高斯展宽。公社有人发帖说 FEL 上看不到低谷,Sobereva 的答复之一是作图的格点间距偏大。

导入 Origin 等软件作图时保留空格子

概率为 0 的格子没有自由能值。如果只导出有数据的格子再交给 SigmaPlot、Origin 等软件插值,空白区域会被插出原本不存在的低能区。Sobereva 的做法是保留这些格子,把它们的值设为比最大有效值高 1 到 1.5 kT 的常数,再调整色标的上下限。用脚本把 fel.xpm 转成 x、y、G 三列时,同样保留空格子。

PCA 的原子选择与方差占比

Sobereva 的示例体系有 232 个 Cα,前 10 个主成分只解释 58.7% 的运动,PC1 与 PC2 合计 32.2%,他据此判断对全部 Cα 做 PCA 意义不大。柔性末端等无关区域运动幅度大时,会掩盖关心区域的运动;可以只选结合口袋或某个结构域的原子做 gmx covar。PC1 与 PC2 的方差占比写进图注;占比低时,FEL 只反映了一小部分运动。

gmx dssp 不再输出 xpm 图

GROMACS 2023 起的 gmx dssp 只输出数据文件,不生成旧版 do_dssp 的 xpm 图,按 xpm 写的作图脚本不能直接用。Jerkwin 为此写了 dssp2gp,把 dssp.dat 转成 gnuplot 绘图脚本;DuIvyTools 的 dit dssp 可以把它转成 xpm 和 xvg。dssp.dat 中的残基从 1 开始重新编号,与 PDB 原始编号不一致时,在 dssp2gp 中用“起始残基:终止残基:起始编号”指定起始编号。

DuIvyTools:国内常用的 xvg、xpm 作图工具

DuIvyTools 是国内开发者写的 GROMACS 结果作图工具,中文文档在 duivytools.readthedocs.io。CSDN 上的分析教程常用它快速查看曲线和 xpm,命令见下方代码块。它适合检查数据和出草图;论文图中的多副本统计仍用上文的 Python 脚本,以便给出均值和区间。

交给 Agent

以 Scientify 中的“溶菌酶分子动力学模拟”案例为例,可以用一句话描述分析任务。

指令示例:“对溶菌酶 1AKI 在 300 K 下跑 3 个独立副本,每个 50 ns;按 whole、nojump、居中处理周期性边界,计算骨架 RMSD、Cα RMSF、回转半径、SASA、蛋白内氢键和 DSSP;用块平均和余弦含量评估收敛;画出多副本均值 ±SD 图和 PC1/PC2 自由能形貌图。”

智能体在云电脑中用预装的 GROMACS 2026.3 GPU 版完成建模、模拟和分析:生成 mdp 和 tpr,按需租用 GPU 运行 3 个副本,执行本页的 trjconv 与分析命令,再用 Python 汇总作图。工作区中保留 mdp、tpr、日志、xvg、PNG 图和分析脚本,可以复现。智能体会对结果做对抗审阅,检查每个副本是否跑完、PBC 处理后是否仍有跳变。

你仍需要自己核对:力场和水模型是否适合你的问题,模拟时长是否覆盖你关心的过程,选组是否与论文叙述一致,以及结论是否被副本间的差异所支持。

参考资料

常见问题

RMSD 和 RMSF 有什么区别?

RMSD 对每一帧计算一个值,是所选原子相对参考结构的整体偏离,横轴是时间。RMSF 对每个原子或残基计算一个值,是它在整段轨迹中围绕平均位置的波动,横轴是残基编号。RMSD 用来看整体结构随时间的变化,RMSF 用来定位柔性区域。

RMSD 多大算稳定?有没有统一阈值?

没有统一阈值。常见的“小于 0.2 nm”来自对接位姿复现评测,不适用于 MD。应比较同一选组、同一参考结构下多个副本的均值与区间,并用块平均或副本间比较判断是否收敛。

GROMACS 2024 以后怎么算氢键寿命?

新版 gmx hbond 不提供寿命计算。可以用 gmx hbond-legacy -ac,按 Luzar–Chandler 模型得到速率常数和寿命;或用 MDAnalysis 的 HydrogenBondAnalysis.lifetime() 计算自相关函数。论文中写明所用判据和工具。

gmx do_dssp 报命令不存在怎么办?

GROMACS 2023 起 do_dssp 已由内置的 gmx dssp 取代,不需要外部 dssp 程序。命令为 gmx dssp -s md.tpr -f md_center.xtc -sel Protein -o dssp.dat -num dssp_num.xvg。

模拟结果与实验不符,先查什么?

先确认分析本身没有问题:周期性边界是否处理、是否去掉平衡段、选组是否正确。再检查模拟条件与实验是否一致:力场和水模型、质子化状态、温度、离子浓度。最后判断模拟时长能否覆盖实验观测的过程,以及多个副本是否给出一致结果。

续跑后的轨迹怎么分析?

用 gmx convert-tpr -extend 延长并以 -cpi 续跑时,mdrun 默认追加到原文件,直接分析即可。用了 -noappend 时会生成 .part0002 等文件,先用 gmx trjcat 拼接,再按同样的周期性边界流程处理。

把这套流程交给 Scientify

科学智能体在隔离云电脑中运行预装的 GROMACS 2026.3 GPU 版、MDAnalysis 和 MDTraj,需要时自动租用 GPU,跑完多副本模拟后按本页流程完成周期性边界处理、指标计算、收敛检验和作图,并保留全部参数文件、日志和脚本。新注册用户免费获得 5 美元等值额度。