def rmatrixu(u, theta): """Return a rotation matrix caused by a right hand rotation of theta radians around vector u. """ if numpy.allclose(theta, 0.0) or numpy.allclose(numpy.dot(u, u), 0.0): return numpy.identity(3, float) x, y, z = normalize(u) sa = math.sin(theta) ca = math.cos(theta) R = numpy.array([[ 1.0 + (1.0 - ca) * (x * x - 1.0), -z * sa + (1.0 - ca) * x * y, y * sa + (1.0 - ca) * x * z ], [ z * sa + (1.0 - ca) * x * y, 1.0 + (1.0 - ca) * (y * y - 1.0), -x * sa + (1.0 - ca) * y * z ], [ -y * sa + (1.0 - ca) * x * z, x * sa + (1.0 - ca) * y * z, 1.0 + (1.0 - ca) * (z * z - 1.0) ]], float) try: assert numpy.allclose(linalg.determinant(R), 1.0) except AssertionError: print "rmatrixu(%s, %f) determinant(R)=%f" % (u, theta, linalg.determinant(R)) raise return R
def rmatrixz(vec): """Return a rotation matrix which transforms the coordinate system such that the vector vec is aligned along the z axis. """ u, v, w = normalize(vec) d = math.sqrt(u*u + v*v) if d != 0.0: Rxz = numpy.array([ [ u/d, v/d, 0.0 ], [ -v/d, u/d, 0.0 ], [ 0.0, 0.0, 1.0 ] ], float) else: Rxz = numpy.identity(3, float) Rxz2z = numpy.array([ [ w, 0.0, -d], [ 0.0, 1.0, 0.0], [ d, 0.0, w] ], float) R = numpy.dot(Rxz2z, Rxz) try: assert numpy.allclose(linalg.determinant(R), 1.0) except AssertionError: print "rmatrixz(%s) determinant(R)=%f" % (vec, linalg.determinant(R)) raise return R
def rmatrixz(vec): """Return a rotation matrix which transforms the coordinate system such that the vector vec is aligned along the z axis. """ u, v, w = normalize(vec) d = math.sqrt(u * u + v * v) if d != 0.0: Rxz = numpy.array( [[u / d, v / d, 0.0], [-v / d, u / d, 0.0], [0.0, 0.0, 1.0]], float) else: Rxz = numpy.identity(3, float) Rxz2z = numpy.array([[w, 0.0, -d], [0.0, 1.0, 0.0], [d, 0.0, w]], float) R = numpy.dot(Rxz2z, Rxz) try: assert numpy.allclose(linalg.determinant(R), 1.0) except AssertionError: print "rmatrixz(%s) determinant(R)=%f" % (vec, linalg.determinant(R)) raise return R
def calc_inertia_tensor(atom_iter, origin): """Calculate a moment-of-inertia tensor at the given origin assuming all atoms have the same mass. """ I = numpy.zeros((3, 3), float) for atm in atom_iter: x = atm.position - origin I[0, 0] += x[1]**2 + x[2]**2 I[1, 1] += x[0]**2 + x[2]**2 I[2, 2] += x[0]**2 + x[1]**2 I[0, 1] += -x[0] * x[1] I[1, 0] += -x[0] * x[1] I[0, 2] += -x[0] * x[2] I[2, 0] += -x[0] * x[2] I[1, 2] += -x[1] * x[2] I[2, 1] += -x[1] * x[2] evals, evecs = linalg.eigenvectors(I) ## order the tensor such that the largest ## principal component is along the z-axis, and ## the second largest is along the y-axis if evals[0] >= evals[1] and evals[0] >= evals[2]: if evals[1] >= evals[2]: R = numpy.array((evecs[2], evecs[1], evecs[0]), float) else: R = numpy.array((evecs[1], evecs[2], evecs[0]), float) elif evals[1] >= evals[0] and evals[1] >= evals[2]: if evals[0] >= evals[2]: R = numpy.array((evecs[2], evecs[0], evecs[1]), float) else: R = numpy.array((evecs[0], evecs[2], evecs[1]), float) elif evals[2] >= evals[0] and evals[2] >= evals[1]: if evals[0] >= evals[1]: R = numpy.array((evecs[1], evecs[0], evecs[2]), float) else: R = numpy.array((evecs[0], evecs[1], evecs[2]), float) ## make sure the tensor is right-handed if numpy.allclose(linalg.determinant(R), -1.0): I = numpy.identity(3, float) I[0, 0] = -1.0 R = numpy.dot(I, R) assert numpy.allclose(linalg.determinant(R), 1.0) return R
def calc_CCuij(U, V): """Calculate the cooralation coefficent for anisotropic ADP tensors U and V. """ invU = linalg.inverse(U) invV = linalg.inverse(V) det_invU = linalg.determinant(invU) det_invV = linalg.determinant(invV) return (math.sqrt(math.sqrt(det_invU * det_invV)) / math.sqrt( (1.0 / 8.0) * linalg.determinant(invU + invV)))
def calc_inertia_tensor(atom_iter, origin): """Calculate a moment-of-inertia tensor at the given origin assuming all atoms have the same mass. """ I = numpy.zeros((3,3), float) for atm in atom_iter: x = atm.position - origin I[0,0] += x[1]**2 + x[2]**2 I[1,1] += x[0]**2 + x[2]**2 I[2,2] += x[0]**2 + x[1]**2 I[0,1] += - x[0]*x[1] I[1,0] += - x[0]*x[1] I[0,2] += - x[0]*x[2] I[2,0] += - x[0]*x[2] I[1,2] += - x[1]*x[2] I[2,1] += - x[1]*x[2] evals, evecs = linalg.eigenvectors(I) ## order the tensor such that the largest ## principal component is along the z-axis, and ## the second largest is along the y-axis if evals[0] >= evals[1] and evals[0] >= evals[2]: if evals[1] >= evals[2]: R = numpy.array((evecs[2], evecs[1], evecs[0]), float) else: R = numpy.array((evecs[1], evecs[2], evecs[0]), float) elif evals[1] >= evals[0] and evals[1] >= evals[2]: if evals[0] >= evals[2]: R = numpy.array((evecs[2], evecs[0], evecs[1]), float) else: R = numpy.array((evecs[0], evecs[2], evecs[1]), float) elif evals[2] >= evals[0] and evals[2] >= evals[1]: if evals[0] >= evals[1]: R = numpy.array((evecs[1], evecs[0], evecs[2]), float) else: R = numpy.array((evecs[0], evecs[1], evecs[2]), float) ## make sure the tensor is right-handed if numpy.allclose(linalg.determinant(R), -1.0): I = numpy.identity(3, float) I[0,0] = -1.0 R = numpy.dot(I, R) assert numpy.allclose(linalg.determinant(R), 1.0) return R
def calc_CCuij(U, V): """Calculate the correlation coefficient for anisotropic ADP tensors U and V. """ ## FIXME: Check for non-positive Uij's, 2009-08-19 invU = linalg.inverse(U) invV = linalg.inverse(V) #invU = internal_inv3x3(U) #invV = internal_inv3x3(V) det_invU = linalg.determinant(invU) det_invV = linalg.determinant(invV) return ( math.sqrt(math.sqrt(det_invU * det_invV)) / math.sqrt((1.0/8.0) * linalg.determinant(invU + invV)) )
def calc_CCuij(U, V): """Calculate the correlation coefficient for anisotropic ADP tensors U and V. """ ## FIXME: Check for non-positive Uij's, 2009-08-19 invU = linalg.inverse(U) invV = linalg.inverse(V) #invU = internal_inv3x3(U) #invV = internal_inv3x3(V) det_invU = linalg.determinant(invU) det_invV = linalg.determinant(invV) return (math.sqrt(math.sqrt(det_invU * det_invV)) / math.sqrt( (1.0 / 8.0) * linalg.determinant(invU + invV)))
def matrix_is_symplectic(self, m, tolerance=1.0e-12): """ Confirm that a given matrix $M$ is symplectic to within numerical tolerance. This is done by taking the 4 submatrices: 1. $A = M[0::2, 0::2]$, i.e., configuration coordinates only, 2. $B = M[0::2, 1::2]$, i.e., configuration rows, momenta cols, 3. $C = M[1::2, 0::2]$, i.e., momenta rows, configuration cols, 4. $D = M[1::2, 1::2]$, i.e., momenta only, and verifying the following symplectic identities:- 1. $MJM^{T} = J$, the $2n\\times 2n$ sympletic matrix, 2. $AD^{T}-BC^{T} = I$, the $n\\times n$ identity, 3. $AB^{T}-BA^{T} = Z$, the $n\\times n$ zero, 4. $CD^{T}-DC^{T} = Z$. Finally, we confirm that $\\det{M} = 1$. """ det = determinant(m) j = self.skew_symmetric_matrix() approx_j = matrixmultiply(m, matrixmultiply(j, transpose(m))) a = m[0::2, 0::2] #even, even b = m[0::2, 1::2] #even, odd c = m[1::2, 0::2] #odd, even d = m[1::2, 1::2] #odd, odd i = self.identity_matrix(self.dof()) approx_i = matrixmultiply(a, transpose(d)) - matrixmultiply(b, transpose(c)) approx_z0 = matrixmultiply(a, transpose(b)) - matrixmultiply(b, transpose(a)) approx_z1 = matrixmultiply(c, transpose(d)) - matrixmultiply(d, transpose(c)) norm = self.matrix_norm logger.info('Matrix from diagonal to equilibrium coordinates:') logger.info('[output supressed]') #logger.info(m) logger.info('error in determinant: %s', abs(det-1.0)) logger.info('error in symplectic identity #1: %s', norm(approx_j - j)) logger.info('error in symplectic identity #2: %s', norm(approx_i - i)) logger.info('error in symplectic identity #3: %s', norm(approx_z0)) logger.info('error in symplectic identity #4: %s', norm(approx_z1)) okay = True if not (abs(det-1.0) < tolerance): okay = False if not (norm(approx_j - j) < tolerance): okay = False if not (norm(approx_i - i) < tolerance): okay = False if not (norm(approx_z0) < tolerance): okay = False if not (norm(approx_z1) < tolerance): okay = False return okay
def rmatrixquaternion(q): """Create a rotation matrix from q quaternion rotation. Quaternions are typed as Numeric Python numpy.arrays of length 4. """ assert numpy.allclose(math.sqrt(numpy.dot(q, q)), 1.0) x, y, z, w = q xx = x * x xy = x * y xz = x * z xw = x * w yy = y * y yz = y * z yw = y * w zz = z * z zw = z * w r00 = 1.0 - 2.0 * (yy + zz) r01 = 2.0 * (xy - zw) r02 = 2.0 * (xz + yw) r10 = 2.0 * (xy + zw) r11 = 1.0 - 2.0 * (xx + zz) r12 = 2.0 * (yz - xw) r20 = 2.0 * (xz - yw) r21 = 2.0 * (yz + xw) r22 = 1.0 - 2.0 * (xx + yy) R = numpy.array([[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]], float) assert numpy.allclose(linalg.determinant(R), 1.0) return R
def calc_DP2uij(U, V): """Calculate the square of the volumetric difference in the probability density function of anisotropic ADP tensors U and V. """ invU = linalg.inverse(U) invV = linalg.inverse(V) det_invU = linalg.determinant(invU) det_invV = linalg.determinant(invV) Pu2 = math.sqrt( det_invU / (64.0 * Constants.PI3) ) Pv2 = math.sqrt( det_invV / (64.0 * Constants.PI3) ) Puv = math.sqrt( (det_invU * det_invV) / (8.0*Constants.PI3 * linalg.determinant(invU + invV))) dP2 = Pu2 + Pv2 - (2.0 * Puv) return dP2
def calc_DP2uij(U, V): """Calculate the square of the volumetric difference in the probability density function of anisotropic ADP tensors U and V. """ invU = linalg.inverse(U) invV = linalg.inverse(V) det_invU = linalg.determinant(invU) det_invV = linalg.determinant(invV) Pu2 = math.sqrt(det_invU / (64.0 * Constants.PI3)) Pv2 = math.sqrt(det_invV / (64.0 * Constants.PI3)) Puv = math.sqrt((det_invU * det_invV) / (8.0 * Constants.PI3 * linalg.determinant(invU + invV))) dP2 = Pu2 + Pv2 - (2.0 * Puv) return dP2
def rmatrixu(u, theta): """Return a rotation matrix caused by a right hand rotation of theta radians around vector u. """ if numpy.allclose(theta, 0.0) or numpy.allclose(numpy.dot(u,u), 0.0): return numpy.identity(3, float) x, y, z = normalize(u) sa = math.sin(theta) ca = math.cos(theta) R = numpy.array( [[1.0+(1.0-ca)*(x*x-1.0), -z*sa+(1.0-ca)*x*y, y*sa+(1.0-ca)*x*z], [z*sa+(1.0-ca)*x*y, 1.0+(1.0-ca)*(y*y-1.0), -x*sa+(1.0-ca)*y*z], [-y*sa+(1.0-ca)*x*z, x*sa+(1.0-ca)*y*z, 1.0+(1.0-ca)*(z*z-1.0)]], float) try: assert numpy.allclose(linalg.determinant(R), 1.0) except AssertionError: print "rmatrixu(%s, %f) determinant(R)=%f" % ( u, theta, linalg.determinant(R)) raise return R
def _gaussian(self, mean, cvm, x): m = len(mean) assert cvm.shape == (m, m), \ 'bad sized covariance matrix, %s' % str(cvm.shape) try: det = LinearAlgebra.determinant(cvm) inv = LinearAlgebra.inverse(cvm) a = det ** -0.5 * (2 * Numeric.pi) ** (-m / 2.0) dx = x - mean b = -0.5 * Numeric.matrixmultiply( \ Numeric.matrixmultiply(dx, inv), dx) return a * Numeric.exp(b) except OverflowError: # happens when the exponent is negative infinity - i.e. b = 0 # i.e. the inverse of cvm is huge (cvm is almost zero) return 0
def rmatrix(alpha, beta, gamma): """Return a rotation matrix based on the Euler angles alpha, beta, and gamma in radians. """ cosA = math.cos(alpha) cosB = math.cos(beta) cosG = math.cos(gamma) sinA = math.sin(alpha) sinB = math.sin(beta) sinG = math.sin(gamma) R = numpy.array( [[cosB*cosG, cosG*sinA*sinB-cosA*sinG, cosA*cosG*sinB+sinA*sinG], [cosB*sinG, cosA*cosG+sinA*sinB*sinG, cosA*sinB*sinG-cosG*sinA ], [-sinB, cosB*sinA, cosA*cosB ]], float) assert numpy.allclose(linalg.determinant(R), 1.0) return R
def quaternionrmatrix(R): """Return a quaternion calculated from the argument rotation matrix R. """ assert numpy.allclose(linalg.determinant(R), 1.0) t = numpy.trace(R) + 1.0 if t > 1e-5: w = math.sqrt(1.0 + numpy.trace(R)) / 2.0 w4 = 4.0 * w x = (R[2, 1] - R[1, 2]) / w4 y = (R[0, 2] - R[2, 0]) / w4 z = (R[1, 0] - R[0, 1]) / w4 else: if R[0, 0] > R[1, 1] and R[0, 0] > R[2, 2]: S = math.sqrt(1.0 + R[0, 0] - R[1, 1] - R[2, 2]) * 2.0 x = 0.25 * S y = (R[0, 1] + R[1, 0]) / S z = (R[0, 2] + R[2, 0]) / S w = (R[1, 2] - R[2, 1]) / S elif R[1, 1] > R[2, 2]: S = math.sqrt(1.0 + R[1, 1] - R[0, 0] - R[2, 2]) * 2.0 x = (R[0, 1] + R[1, 0]) / S y = 0.25 * S z = (R[1, 2] + R[2, 1]) / S w = (R[0, 2] - R[2, 0]) / S else: S = math.sqrt(1.0 + R[2, 2] - R[0, 0] - R[1, 1]) * 2 x = (R[0, 2] + R[2, 0]) / S y = (R[1, 2] + R[2, 1]) / S z = 0.25 * S w = (R[0, 1] - R[1, 0]) / S q = numpy.array((x, y, z, w), float) assert numpy.allclose(math.sqrt(numpy.dot(q, q)), 1.0) return q
def quaternionrmatrix(R): """Return a quaternion calculated from the argument rotation matrix R. """ assert numpy.allclose(linalg.determinant(R), 1.0) t = numpy.trace(R) + 1.0 if t>1e-5: w = math.sqrt(1.0 + numpy.trace(R)) / 2.0 w4 = 4.0 * w x = (R[2,1] - R[1,2]) / w4 y = (R[0,2] - R[2,0]) / w4 z = (R[1,0] - R[0,1]) / w4 else: if R[0,0]>R[1,1] and R[0,0]>R[2,2]: S = math.sqrt(1.0 + R[0,0] - R[1,1] - R[2,2]) * 2.0 x = 0.25 * S y = (R[0,1] + R[1,0]) / S z = (R[0,2] + R[2,0]) / S w = (R[1,2] - R[2,1]) / S elif R[1,1]>R[2,2]: S = math.sqrt(1.0 + R[1,1] - R[0,0] - R[2,2]) * 2.0; x = (R[0,1] + R[1,0]) / S; y = 0.25 * S; z = (R[1,2] + R[2,1]) / S; w = (R[0,2] - R[2,0]) / S; else: S = math.sqrt(1.0 + R[2,2] - R[0,0] - R[1,1]) * 2; x = (R[0,2] + R[2,0]) / S; y = (R[1,2] + R[2,1]) / S; z = 0.25 * S; w = (R[0,1] - R[1,0] ) / S; q = numpy.array((x, y, z, w), float) assert numpy.allclose(math.sqrt(numpy.dot(q,q)), 1.0) return q
def rmatrix(alpha, beta, gamma): """Return a rotation matrix based on the Euler angles alpha, beta, and gamma in radians. """ cosA = math.cos(alpha) cosB = math.cos(beta) cosG = math.cos(gamma) sinA = math.sin(alpha) sinB = math.sin(beta) sinG = math.sin(gamma) R = numpy.array([[ cosB * cosG, cosG * sinA * sinB - cosA * sinG, cosA * cosG * sinB + sinA * sinG ], [ cosB * sinG, cosA * cosG + sinA * sinB * sinG, cosA * sinB * sinG - cosG * sinA ], [-sinB, cosB * sinA, cosA * cosB]], float) assert numpy.allclose(linalg.determinant(R), 1.0) return R
def rmatrixquaternion(q): """Create a rotation matrix from q quaternion rotation. Quaternions are typed as Numeric Python numpy.arrays of length 4. """ assert numpy.allclose(math.sqrt(numpy.dot(q,q)), 1.0) x, y, z, w = q xx = x*x xy = x*y xz = x*z xw = x*w yy = y*y yz = y*z yw = y*w zz = z*z zw = z*w r00 = 1.0 - 2.0 * (yy + zz) r01 = 2.0 * (xy - zw) r02 = 2.0 * (xz + yw) r10 = 2.0 * (xy + zw) r11 = 1.0 - 2.0 * (xx + zz) r12 = 2.0 * (yz - xw) r20 = 2.0 * (xz - yw) r21 = 2.0 * (yz + xw) r22 = 1.0 - 2.0 * (xx + yy) R = numpy.array([[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]], float) assert numpy.allclose(linalg.determinant(R), 1.0) return R
def matrix_is_symplectic(self, m, tolerance=1.0e-12): """ Confirm that a given matrix $M$ is symplectic to within numerical tolerance. This is done by taking the 4 submatrices: 1. $A = M[0::2, 0::2]$, i.e., configuration coordinates only, 2. $B = M[0::2, 1::2]$, i.e., configuration rows, momenta cols, 3. $C = M[1::2, 0::2]$, i.e., momenta rows, configuration cols, 4. $D = M[1::2, 1::2]$, i.e., momenta only, and verifying the following symplectic identities:- 1. $MJM^{T} = J$, the $2n\\times 2n$ sympletic matrix, 2. $AD^{T}-BC^{T} = I$, the $n\\times n$ identity, 3. $AB^{T}-BA^{T} = Z$, the $n\\times n$ zero, 4. $CD^{T}-DC^{T} = Z$. Finally, we confirm that $\\det{M} = 1$. """ det = determinant(m) j = self.skew_symmetric_matrix() approx_j = matrixmultiply(m, matrixmultiply(j, transpose(m))) a = m[0::2, 0::2] #even, even b = m[0::2, 1::2] #even, odd c = m[1::2, 0::2] #odd, even d = m[1::2, 1::2] #odd, odd i = self.identity_matrix(self.dof()) approx_i = matrixmultiply(a, transpose(d)) - matrixmultiply( b, transpose(c)) approx_z0 = matrixmultiply(a, transpose(b)) - matrixmultiply( b, transpose(a)) approx_z1 = matrixmultiply(c, transpose(d)) - matrixmultiply( d, transpose(c)) norm = self.matrix_norm logger.info('Matrix from diagonal to equilibrium coordinates:') logger.info('[output supressed]') #logger.info(m) logger.info('error in determinant: %s', abs(det - 1.0)) logger.info('error in symplectic identity #1: %s', norm(approx_j - j)) logger.info('error in symplectic identity #2: %s', norm(approx_i - i)) logger.info('error in symplectic identity #3: %s', norm(approx_z0)) logger.info('error in symplectic identity #4: %s', norm(approx_z1)) okay = True if not (abs(det - 1.0) < tolerance): okay = False if not (norm(approx_j - j) < tolerance): okay = False if not (norm(approx_i - i) < tolerance): okay = False if not (norm(approx_z0) < tolerance): okay = False if not (norm(approx_z1) < tolerance): okay = False return okay