def external_basis(self): """The basis for small displacements in the external degrees of freedom. The basis is expressed in mass-weighted Cartesian coordinates. The three translations are along the x, y, and z-axis. The three rotations are about an axis parallel to the x, y, and z-axis through the center of mass. The returned result depends on the periodicity of the system: * When the system is periodic, only the translation external degrees are included. The result is an array with shape (3,3N) * When the system is not periodic, the rotational external degrees are also included. The result is an array with shape (6,3N). The first three rows correspond to translation, the latter three rows correspond to rotation. """ center = (self.coordinates*self.masses3.reshape((-1,3))).sum(0)/self.mass # center of mass result = transrot_basis(self.coordinates - center, not self.periodic) result *= np.sqrt(self.masses3) # transform basis to mass weighted coordinates return result
def compute_moments(coordinates, masses3, center, axis, indexes): """Computes the absolute and the relative moment of an internal rotor Arguments: | ``coordinates`` -- The coordinates of all atoms, float numpy array with shape (N,3). | ``masses3`` -- The diagonal of the mass matrix, each mass is repeated three tines, float numpy array with shape 3N. | ``center`` -- A point on the rotation axis. Float numpy array with shape 3. | ``axis`` -- A unit vector with the direction of the rotation axis. Float numpy array with shape 3. | ``indexes`` -- The indexes of the atoms that belong to the rotor. The implementation is based on the transformation of the mass-matrix to the internal rotation coordinate. The derivative of the internal coordinate towards cartesian coordinates represents a small displacement of the atoms. This displacement is constrained to show no external linear or rotational moment. """ # the derivative of the cartesian coordinates towards the rotation # angle of the top: rot_tangent = numpy.zeros((len(coordinates)*3), float) for i in indexes: rot_tangent[3*i:3*i+3] = numpy.cross(coordinates[i]-center, axis) # transform this to a derivative without global linear or angular # momentum. This is done by projecting on the basis of external degrees # of freedom in mass-weighted coordinates, and subsequently subtracting # that projection from the original tangent basis = transrot_basis(coordinates) A = numpy.dot(basis*masses3, basis.transpose()) B = numpy.dot(basis*masses3, rot_tangent) alphas = numpy.linalg.solve(A,B) rot_tangent_relative = rot_tangent - numpy.dot(alphas, basis) return ( (rot_tangent**2*masses3).sum(), (rot_tangent_relative**2*masses3).sum() )
def compute_moments(coordinates, masses3, center, axis, indexes): """Computes the absolute and the relative moment of an internal rotor Arguments: | ``coordinates`` -- The coordinates of all atoms, float numpy array with shape (N,3). | ``masses3`` -- The diagonal of the mass matrix, each mass is repeated three tines, float numpy array with shape 3N. | ``center`` -- A point on the rotation axis. Float numpy array with shape 3. | ``axis`` -- A unit vector with the direction of the rotation axis. Float numpy array with shape 3. | ``indexes`` -- The indexes of the atoms that belong to the rotor. The implementation is based on the transformation of the mass-matrix to the internal rotation coordinate. The derivative of the internal coordinate towards cartesian coordinates represents a small displacement of the atoms. This displacement is constrained to show no external linear or rotational moment. """ # the derivative of the cartesian coordinates towards the rotation # angle of the top: rot_tangent = np.zeros((len(coordinates) * 3), float) for i in indexes: rot_tangent[3 * i:3 * i + 3] = np.cross(coordinates[i] - center, axis) # transform this to a derivative without global linear or angular # momentum. This is done by projecting on the basis of external degrees # of freedom in mass-weighted coordinates, and subsequently subtracting # that projection from the original tangent basis = transrot_basis(coordinates) A = np.dot(basis * masses3, basis.transpose()) B = np.dot(basis * masses3, rot_tangent) alphas = np.linalg.solve(A, B) rot_tangent_relative = rot_tangent - np.dot(alphas, basis) return ((rot_tangent**2 * masses3).sum(), (rot_tangent_relative**2 * masses3).sum())