python - 在笛卡尔坐标中对齐两个 3D 对象
问题描述
我有两个与 .xyz 文件相同的分子的副本。这意味着每个原子都有 X、Y 和 Z 坐标。但是,您可以旋转分子并获得每个原子的不同坐标,尽管相对位置相同并且分子保持不变。我想使用三个原子作为参考点来对齐两个分子。然而,我正在努力完全对齐这两个分子。
首先,我通过翻译单个原子来对齐两个分子。然后,我使用旋转矩阵进行两次后续旋转,如别处所述。出于某种原因,我需要取两个向量的叉积的负数,并使用正弦而不是余弦来使两个结构完美对齐(经过大量试验和错误后我发现了这一点)。
对于第二次旋转,我将两个要对齐的向量投影在由旋转向量定义的平面上。这是必要的,因为我不想沿着两个向量的叉积旋转来对齐,因为这会使分子的其余部分不对齐。相反,我沿着两个已经对齐的向量旋转。该项目允许我找到两个向量之间的平面角度,从而找到必要的旋转。
但是,此代码没有正确对齐两个分子。
"group1[0]" 包含要在列表中对齐的三个原子的 XYZ 坐标。同样对于“group2 [0]”和结构 2。
#Point 1: align the functional groups to the origin
O1 = np.array(coords1[group1[0][0]])
O2 = np.array(coords2[group2[0][0]])
mat_2 = np.zeros((len(atoms2), 3))
for ind, c in enumerate(coords1):
coords1[ind] = np.array(c) - O1
for ind, c in enumerate(coords2):
coords2[ind] = np.array(c) - O2
mat_2[ind] = coords2[ind]
#Point 2: align according to a first vector
v1 = np.array(coords1[group1[0][1]])#Since atom 1 is the origin, the coordinates is the vector already
v2 = np.array(coords2[group2[0][1]])#Since atom 1 is the origin, the coordinates is the vector already
v1 = v1/np.linalg.norm(v1)
v2 = v2/np.linalg.norm(v2)
#Let v be the axis of rotation
v = -np.cross(v1, v2)#why do I need a minus here?
if np.linalg.norm(v) != 0:
a = np.arccos(np.dot(v1, v2)/(np.linalg.norm(v1)*np.linalg.norm(v2)))
#c = np.dot(v1, v2)*np.cos(a)
c = np.dot(v1, v2)*np.sin(a)#The internet says cos, but this works perfectly
vx = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
rot_mat = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + vx + vx.dot(vx)*(1-c)/(1-c**2)
mat_2 = np.array(mat_2)
R_mat_rot = np.matmul(rot_mat, mat_2.T).T
else:
exit(0)
coords3 = R_mat_rot.copy()
#I get exactly what I want up until here
#Point 3: Rotate along atom2-atom1 (v1) to align the third atom
v = -v1.copy()
v2 = np.array(coords3[group2[0][2]]) - np.array(coords3[group2[0][0]]) #Since atom 1 is the origin, the coordinates is the vector already
v2 = v2/np.linalg.norm(v2)
v1 = np.array(coords1[group1[0][2]]) - np.array(coords1[group1[0][0]]) #Since atom 1 is the origin, the coordinates is the vector already
v1 = v1/np.linalg.norm(v1)
if np.linalg.norm(v) != 0:
#consider v to be the vector normal to a plane
#we want the projection of v1 and v2 unto that plane
vp1 = np.cross(v, np.cross(v1, v)) - np.array(coords1[group1[0][0]])
vp1 = vp1/np.linalg.norm(vp1)
vp2 = np.cross(v, np.cross(v2, v)) - np.array(coords3[group2[0][0]])
vp2 = vp2/np.linalg.norm(vp2)
#we find the angle between those vectors on the plane
a = np.arccos(np.dot(vp1, vp2))/(np.linalg.norm(vp1)*np.linalg.norm(vp2))
#rotation of that amount
c = np.dot(v1, v2)*np.cos(a)
vx = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
rot_mat = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + vx + np.dot(vx, vx)*(1-c)/(1-c**2)
R_mat_rot = np.matmul(rot_mat, coords3.T).T
coords4 = R_mat_rot.copy()#Final coordinates
解决方案
推荐阅读
- ruby-on-rails - 使用 Rails 作为后端进行反应时,Fetch api 无法按预期工作
- c - 在线编译器(在线 gdb)正常工作,而 Windows 10 cmd 上的 g++ 和 gcc 在比较字符串时不起作用
- angular - 懒惰模块中的Angular ngx翻译不起作用
- java - 如何在主类内的方法中调用对象数组?
- html - 如何从页面 html 获取 facebook 发布时间戳/永久链接?
- json - 读取检索 json 文件而不在 laravel 7 中添加换行
- reactjs - React Router 更改了 URL 但页面仍然没有改变
- c++ - 在c ++中使用struct,无法解决问题
- java - 如何获得负最大算法基于其评估的预测移动序列?
- vue.js - SCSS/SASS 文件不适用于电子 nuxt