计算化学公社

 找回密码 Forget password
 注册 Register
Views: 185|回复 Reply: 4
打印 Print 上一主题 Last thread 下一主题 Next thread

[综合交流] 求助:分子重组能较小但 RMSD 值偏大,这种情况是否合理?

[复制链接 Copy URL]

13

帖子

0

威望

61

eV
积分
74

Level 2 能力者

跳转到指定楼层 Go to specific reply
楼主
本帖最后由 gonglijing 于 2026-2-1 08:24 编辑

想向各位请教一个问题:我计算了分子的重组能,同时通过 VMD 软件计算 RMSD 以表征两个结构间的几何偏差,得到具体数据如下:空穴重组能 = 0.185,对应 RMSD=1.1764;电子重组能 = 0.085,对应 RMSD=4.3345。对应空穴重组能和电子重组能的两个结构的 RMSD 几何偏差图分别见下面左图和右图。
目前发现重组能数值偏小,但对应的 RMSD 值却显著偏大,即两结构间的几何偏差较大,想请教各位该结果是否合理?若存在问题,该从哪些方面排查解决(跑了两边计算,数据提取已核对过,没问题)?恳请指点,谢谢!


712

帖子

13

威望

2932

eV
积分
3904

Level 5 (御坂)

鸩羽

2#
发表于 Post on 2026-1-31 21:36:41 | 只看该作者 Only view this author
感觉没对齐
某不知名实验组从苞米地里长出来的计算选手

13

帖子

0

威望

61

eV
积分
74

Level 2 能力者

3#
 楼主 Author| 发表于 Post on 2026-1-31 22:15:49 | 只看该作者 Only view this author

您好,点击align了,难道还有其他对其的方式吗?

455

帖子

1

威望

2917

eV
积分
3392

Level 5 (御坂)

4#
发表于 Post on 2026-1-31 23:58:43 | 只看该作者 Only view this author
本帖最后由 snljty2 于 2026-2-1 09:47 编辑
gonglijing 发表于 2026-1-31 22:15
您好,点击align了,难道还有其他对其的方式吗?

VMD的align对齐是考虑原子顺序打乱的,有可能会收敛到一些局部极小值。如果你两个分子的原子顺序完全一致,可以手写一个对齐,比如这个Python小脚本(需要先用VMD把两个结构存成.xyz格式,然后执行下面命令):
  1. python xxx.py structure1.xyz structure2.xyz
复制代码

这里面没考虑只选择一部分原子对齐的功能,需要的话可以自己改一下。
  1. #!/usr/bin/env python3

  2. import os
  3. import sys
  4. import numpy as np
  5. from numpy.typing import NDArray

  6. def K_cross_mat(vec: NDArray[np.double]) -> NDArray[np.double]: # cross matrix of a 3d vector
  7.     return np.array([[0., - vec[2], vec[1]], [vec[2], 0., - vec[0]], [- vec[1], vec[0], 0.]], dtype=np.double)

  8. def L_quat_mat(q: NDArray[np.double]) -> NDArray[np.double]: # left-multiply matrix of a quaternion
  9.     return np.block([[q[0], - q[1:4][np.newaxis, :]], [q[1:4][:, np.newaxis], q[0] * np.identity(3, dtype=np.double) + \
  10.         K_cross_mat(q[1:4])]])

  11. def R_quat_mat(q: NDArray[np.double]) -> NDArray[np.double]: # right-multiply matrix of a quaternion
  12.     return np.block([[q[0], - q[1:4][np.newaxis, :]], [q[1:4][:, np.newaxis], q[0] * np.identity(3, dtype=np.double) - \
  13.         K_cross_mat(q[1:4])]])

  14. def quat_rot_mat(q: NDArray[np.double]) -> NDArray[np.double]: # 4x4 rotate matrix of a quaternion
  15.     return L_quat_mat(q) @ R_quat_mat(q).T

  16. def get_rotation_matrix(coord1: NDArray[np.double], coord2: NDArray[np.double], allow_reflection: bool=False):
  17.     assert coord1.shape == coord2.shape and coord1.shape[1] == 3
  18.     H = coord1.T @ coord2
  19.     U, Sigma, Vt = np.linalg.svd(H)
  20.     R = Vt.T @ U.T
  21.     if not allow_reflection:
  22.         # only half of O(3) is SO(3)
  23.         if np.linalg.det(R) < 0.:
  24.             Vt[-1, :] = - Vt[-1, :]
  25.             R = Vt.T @ U.T
  26.     return R

  27. def get_rot_quaternion(coord1: NDArray[np.double], coord2: NDArray[np.double]) -> NDArray[np.double]:
  28.     assert coord1.shape == coord2.shape and coord1.shape[1] == 3
  29.     H = coord1.T @ coord2

  30.     Delta = np.array([H[1, 2] - H[2, 1], H[2, 0] - H[0, 2], H[0, 1] - H[1, 0]], dtype=np.double)
  31.     tr_H = np.trace(H)

  32.     N = np.block([[tr_H, Delta[np.newaxis, :]], [Delta[:, np.newaxis], H + H.T - tr_H * np.identity(3, dtype=np.double)]])

  33.     eig_val, eig_vec = np.linalg.eigh(N)

  34.     q = eig_vec[:, -1].copy()
  35.     if q[0] < 0.: q = - q # SU(2) has a 2->1 mapping to SO(3)

  36.     return q

  37. def rotate_by_rotation_matrix(coord1: NDArray[np.double], coord2: NDArray[np.double], allow_reflection: bool=False):
  38.     assert coord1.shape == coord2.shape and coord1.shape[1] == 3
  39.     coord1 -= coord1.mean(axis=0)
  40.     coord2 -= coord2.mean(axis=0)
  41.     R = get_rotation_matrix(coord1, coord2, allow_reflection=allow_reflection)
  42.     coord1 @= R.T

  43. def rotate_by_quaternion(coord1: NDArray[np.double], coord2: NDArray[np.double]):
  44.     assert coord1.shape == coord2.shape and coord1.shape[1] == 3
  45.     coord1 -= coord1.mean(axis=0)
  46.     coord2 -= coord2.mean(axis=0)
  47.     q = get_rot_quaternion(coord1, coord2)
  48.     coord1 = ((quat_rot_mat(q) @ (np.hstack([np.zeros((len(coord1), 1), dtype=np.double), coord1])).T).T)[:, 1:]

  49. def align_molecules(ifilename1: str, ifilename2: str, imethod: int=2, allow_reflection: bool=False):
  50.     # 1 for Kabsch, 2 for quaternion
  51.     if imethod == 1:
  52.         align_molecules_Kabsch(ifilename1, ifilename2, allow_reflection=allow_reflection)
  53.     elif imethod == 2:
  54.         if allow_reflection:
  55.             raise ValueError("Quaternion does not allow reflection.")
  56.         align_moleculs_quaternion(ifilename1, ifilename2)
  57.     else:
  58.         raise ValueError(f"Unsupported imethod: {imethod:d}")

  59. def align_molecules_Kabsch(ifilename1: str, ifilename2: str, allow_reflection: bool=False):
  60.     ifilename1_split = os.path.splitext(ifilename1)
  61.     ifilename2_split = os.path.splitext(ifilename2)
  62.     assert ifilename1_split[1] == ".xyz" and ifilename2_split[1] == ".xyz"
  63.     elements = np.loadtxt(ifilename1, unpack=True, usecols=0, skiprows=2, dtype=np.dtype("<U2"))
  64.     coord1 = np.loadtxt(ifilename1, usecols=(1, 2, 3), skiprows=2, dtype=np.double)
  65.     coord2 = np.loadtxt(ifilename2, usecols=(1, 2, 3), skiprows=2, dtype=np.double)
  66.     rotate_by_rotation_matrix(coord1, coord2, allow_reflection=allow_reflection)
  67.     ofilename1 = ifilename1_split[0] + "_aligned.xyz"
  68.     ofilename2 = ifilename2_split[0] + "_aligned.xyz"
  69.     with open(ofilename1, "w") as ofile1, open(ofilename2, "w") as ofile2:
  70.         print(len(elements), file=ofile1)
  71.         print(len(elements), file=ofile2)
  72.         print(f"aligned from {ifilename1:s}", file=ofile1)
  73.         print(f"aligned from {ifilename2:s}", file=ofile2)
  74.         for iatom in range(len(elements)):
  75.             print(f" {elements[iatom]:<2s}" + ("    {:13.8f}" * 3).format(* coord1[iatom]), file=ofile1)
  76.             print(f" {elements[iatom]:<2s}" + ("    {:13.8f}" * 3).format(* coord2[iatom]), file=ofile2)

  77. def align_molecules_quaternion(ifilename1: str, ifilename2: str):
  78.     ifilename1_split = os.path.splitext(ifilename1)
  79.     ifilename2_split = os.path.splitext(ifilename2)
  80.     assert ifilename1_split[1] == ".xyz" and ifilename2_split[1] == ".xyz"
  81.     elements = np.loadtxt(ifilename1, unpack=True, usecols=0, skiprows=2, dtype=np.dtype("<U2"))
  82.     coord1 = np.loadtxt(ifilename1, usecols=(1, 2, 3), skiprows=2, dtype=np.double)
  83.     coord2 = np.loadtxt(ifilename2, usecols=(1, 2, 3), skiprows=2, dtype=np.double)
  84.     rotate_by_quaternion(coord1, coord2)
  85.     ofilename1 = ifilename1_split[0] + "_aligned.xyz"
  86.     ofilename2 = ifilename2_split[0] + "_aligned.xyz"
  87.     with open(ofilename1, "w") as ofile1, open(ofilename2, "w") as ofile2:
  88.         print(len(elements), file=ofile1)
  89.         print(len(elements), file=ofile2)
  90.         print(f"aligned from {ifilename1:s}", file=ofile1)
  91.         print(f"aligned from {ifilename2:s}", file=ofile2)
  92.         for iatom in range(len(elements)):
  93.             print(f" {elements[iatom]:<2s}" + ("    {:13.8f}" * 3).format(* coord1[iatom]), file=ofile1)
  94.             print(f" {elements[iatom]:<2s}" + ("    {:13.8f}" * 3).format(* coord2[iatom]), file=ofile2)

  95. if __name__ == "__main__":
  96.     ifilename1 = sys.argv[1]
  97.     ifilename2 = sys.argv[2]
  98.     # ifilename1 = "1.xyz"
  99.     # ifilename2 = "2.xyz"
  100.     # align_molecules(ifilename1, ifilename2, imethod=1, allow_reflection=True)
  101.     align_molecules(ifilename1, ifilename2)
  102.    
复制代码

评分 Rate

参与人数
Participants 2
eV +7 收起 理由
Reason
ABetaCarw + 4 好物!
Uus/pMeC6H4-/キ + 3 好物!

查看全部评分 View all ratings

13

帖子

0

威望

61

eV
积分
74

Level 2 能力者

5#
 楼主 Author| 发表于 Post on 2026-2-1 08:19:36 | 只看该作者 Only view this author
谢谢,是没对齐,已按您们建议调整好了,再次感谢!

本版积分规则 Credits rule

手机版 Mobile version|北京科音自然科学研究中心 Beijing Kein Research Center for Natural Sciences|京公网安备 11010502035419号|计算化学公社 — 北京科音旗下高水平计算化学交流论坛 ( 京ICP备14038949号-1 )|网站地图

GMT+8, 2026-2-16 17:00 , Processed in 0.173358 second(s), 24 queries , Gzip On.

快速回复 返回顶部 返回列表 Return to list