Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from numpy import einsum, sqrt, eye, copy, amax, sign, prod, linalg, zeros, arange, zeros_like
2from mango.constants import c
5class CoM_motion_rm():
7 def __init__(self, mass, no_mol):
8 self.mass = mass
9 self.no_mol = no_mol
10 self.stats = []
12 def suscep_align(self, sus_data):
13 pos = sus_data['pos']
14 mom = sus_data['mom']
15 mag = sus_data['mag']
17 rot, inertia, angular = self._rm(pos, mom, mag)
19 sus_data['rotation'] = rot
20 sus_data['inertia'] = inertia
21 sus_data['angular'] = angular
23 return sus_data
25 def align(self, xyz_data, sus_data):
26 if xyz_data is None and sus_data is not None:
27 self.suscep_align(sus_data)
28 elif xyz_data is not None:
29 rot, inertia, angular = self.xyz_align(xyz_data)
31 if sus_data is not None:
32 sus_data['pos'][:] = xyz_data[..., 0:3]
33 sus_data['mom'][:] = xyz_data[..., 3:6]
34 sus_data['mag'][:] = xyz_data[..., 6:9]
35 sus_data['rotation'] = rot
36 sus_data['inertia'] = inertia
37 sus_data['angular'] = angular
39 return xyz_data, sus_data
41 def xyz_align(self, xyz_data):
42 pos = xyz_data[..., 0:3]
43 mom = xyz_data[..., 3:6]
44 mag = xyz_data[..., 6:9]
46 rot, inertia, angular = self._rm(pos, mom, mag)
48 return rot, inertia, angular
50 def inertia_angular(self, xyz_data, sus_data):
51 pos = sus_data['pos']
52 mom = sus_data['mom']
53 pos[:], mom[:], pos_com, mom_com = remove_CoMm(pos, mom, self.mass, self.no_mol)
54 return get_angular(pos, pos_com, mom, mom_com), get_inertia(pos, pos_com, self.mass)
56 def _rm(self, pos, mom, mag):
58 pos[:], mom[:], pos_com, mom_com = remove_CoMm(pos, mom, self.mass, self.no_mol)
60 inertia = get_inertia(pos, pos_com, self.mass)
62 rot = zeros_like(inertia)
64 # Kabsch's algorithm
65 if self.no_mol > 1:
66 # Alignment of the initial frame (diagonalise the tensor of inertia)
67 wmat, vmat = linalg.eigh(inertia[:, 0])
69 fmat = einsum('aij -> aji', vmat)
71 print("# Frame alignment (Kabsch)")
73 target = copy(pos[:, 0]) # Initial configuration
75 rmsd_max = amax(einsum('aijk,aijk->ai', pos - target[:, None], pos - target[:, None]) / self.no_mol)
77 print("# Maximum RMSD before alignment: %12.5g" % (rmsd_max))
79 rmat = einsum('abxi,axj->abij', pos, target)
80 vmat, sigma, wmat = linalg.svd(rmat)
81 umat = zeros((pos.shape[0], pos.shape[1], 3, 3))
83 loc = arange(3)
84 umat[:, :, loc, loc] = 1
85 umat[:, :, 2, 2] = sign(prod(sigma, axis=-1))
87 rmat = einsum('aij, abkj, abck, ablk -> abil', fmat, wmat, umat, vmat)
89 # Rotation
90 pos[:] = einsum('abij,abxj->abxi', rmat, pos)
91 mom[:] = einsum('abij,abxj->abxi', rmat, mom)
92 mag[:] = einsum('abij,abxj->abxi', rmat, mag)
93 rot[:] = einsum('abji', rmat)
95 target[:] = einsum('axk,ajk->ajx', fmat, target)
97 rmsd_max = amax(einsum('aijk,aijk->ai', pos - target[:, None, :, :], pos - target[:, None, :, :]) / self.no_mol)
99 print("# Maximum RMSD after alignment: %12.5g" % (rmsd_max))
101 pos[:], mom[:], pos_com, mom_com = remove_CoMm(pos, mom, self.mass, self.no_mol)
103 inertia = get_inertia(pos, pos_com, self.mass)
105 angular = get_angular(pos, pos_com, mom, mom_com)
107 return rot, inertia, angular
110def get_inertia(pos, pos_com, mass):
111 # Tensor of inertia
112 mass_scaled = einsum('aijk,j->aijk', pos - pos_com[:, :, None, :], sqrt(mass)) # mass-scaled coordinates
113 tdot = einsum('aixj,aixk->aijk', mass_scaled, mass_scaled)
115 return einsum('aixx,jk->aijk', tdot, eye(3)) - tdot
118def get_angular(pos, pos_com, mom, mom_com):
119 return einsum('xyz,aijx, aijy ->aijz', c.eijk, pos - pos_com[:, :, None, :], mom - mom_com[:, :, None, :], optimize=True)
122def remove_CoMm(pos, mom, mass, no_mol):
123 # Remove Centre of Mass Motion
124 pos_com = einsum("aijk,j->aik", pos, mass) / einsum("j->", mass)
125 pos -= pos_com[:, :, None, :]
127 mom_com = einsum("aijk->aik", mom) / no_mol
128 mom -= mom_com[:, :, None, :]
130 return pos, mom, pos_com, mom_com