def reorient_molecule(self, nuclei_list): first_nuclei = nuclei_list.pop(0) coordinates = first_nuclei.coordinates first_nuclei.coordinates = (0, 0, 0) for nuclei in nuclei_list: x = nuclei.coordinates[0] - coordinates[0] y = nuclei.coordinates[1] - coordinates[1] z = nuclei.coordinates[2] - coordinates[2] nuclei.coordinates = (x, y, z) if len(nuclei_list) >= 1: second_nuclei = nuclei_list[0] coordinates = normalize(second_nuclei.coordinates) quaternion = create_quaternion( (-coordinates[1], coordinates[0], 0.0), -theta(coordinates)) for nuclei in nuclei_list: nuclei.coordinates = quaternion_rotation( quaternion, nuclei.coordinates) if len(nuclei_list) >= 2: third_nuclei = nuclei_list[1] coordinates = normalize(third_nuclei.coordinates) quaternion = create_quaternion((0.0, 0.0, 1.0), -phi(coordinates) + np.pi / 2) for nuclei in nuclei_list: nuclei.coordinates = quaternion_rotation( quaternion, nuclei.coordinates) return [first_nuclei], nuclei_list
def standard_orientation(self, nuclei_array, rotation_symmetry, reflection_symmetry): vector_i = vector_j = (0.0, 0.0, 0.0) if len(rotation_symmetry) > 1: highest_n_folds = heapq.nlargest( 2, [rotation.fold for rotation in rotation_symmetry]) for rotation in rotation_symmetry: if rotation.fold == highest_n_folds[0]: vector_i = rotation.vector break for rotation in rotation_symmetry: if rotation.fold == highest_n_folds[ 1] and rotation.vector != vector_i: vector_j = rotation.vector break if len(rotation_symmetry) == 1: vector_i = rotation_symmetry[0].vector for reflection in reflection_symmetry: if phi(reflection.vector) > self.error: vector_j = reflection.vector break if len(rotation_symmetry) == 0 and len(reflection_symmetry) > 1: vector_i = reflection_symmetry[0].vector vector_j = reflection_symmetry[1].vector if rho(nuclei_array[0].coordinates) > 1e-3: i = 0 else: i = 1 if len(rotation_symmetry) == 0 and len(reflection_symmetry) == 1: vector_i = reflection_symmetry[0].vector vector_j = nuclei_array[i].coordinates if len(rotation_symmetry) == 0 and len(reflection_symmetry) == 0: vector_i = nuclei_array[i].coordinates vector_j = nuclei_array[i + 1].coordinates if rho(vector_i) <= self.error: vector_i = (1.0, 0.0, 0.0) quaternion_i = create_quaternion((-vector_i[1], vector_i[0], 0.0), -theta(vector_i)) quaternion_j = create_quaternion((0.0, 0.0, 1.0), -phi(vector_j)) quaternion = quaternion_multi(quaternion_j, quaternion_i) for rotation in rotation_symmetry: rotation.vector = quaternion_rotation(quaternion, rotation.vector) for reflection in reflection_symmetry: reflection.vector = quaternion_rotation(quaternion, reflection.vector) for nuclei in nuclei_array: nuclei.coordinates = quaternion_rotation(quaternion, nuclei.coordinates) return nuclei_array, rotation_symmetry, reflection_symmetry
def test_create_quaternion_returns_quaternion_for_45_degree_rotation_around_x_axis( self): axis_of_rotation = (1.0, 0.0, 0.0) theta = pi / 4 quaternion = create_quaternion(axis_of_rotation, theta) testing.assert_array_almost_equal(quaternion, (0.923880, 0.382683, 0.0, 0.0), 6)
def test_create_quaternion_returns_quaternion_for_90_degree_rotation_around_y_axis( self): axis_of_rotation = (0.0, 1.0, 0.0) theta = pi / 2 quaternion = create_quaternion(axis_of_rotation, theta) testing.assert_array_almost_equal(quaternion, (0.707107, 0.0, 0.707107, 0.0), 6)
def test_rotation_of_unit_y_vector_with_axis_of_rotation_y_by_90_degrees( self): theta = pi / 2 axis_of_rotation = (0, 1, 0) x_vector = (1, 0, 0) quaternion = create_quaternion(axis_of_rotation, theta) rotated_vector = quaternion_rotation(quaternion, x_vector) testing.assert_array_almost_equal(rotated_vector, (0, 0, -1), 6)
def test_rotation_of_unit_z_vector_with_axis_of_rotation_x_by_45_degrees( self): theta = pi / 4 axis_of_rotation = (1, 0, 0) z_vector = (0, 0, -1) quaternion = create_quaternion(axis_of_rotation, theta) rotated_vector = quaternion_rotation(quaternion, z_vector) testing.assert_array_almost_equal(rotated_vector, (0, 0.707107, -0.707107), 6)
def brute_force_reflection_symmetry(self, nuclei_array, rotation_symmetry, vertices, cross_vertices_vertices, cross_edge_vertices): # rotate all orthogonal vectors by principal axis by half it's n-fold angle vector_cross = self.remove_duplicate(vertices + cross_vertices_vertices + cross_edge_vertices) vectors_cross_rotated = [] if len(rotation_symmetry) > 0: highest_symmetries = [] highest_n_fold = max( [rotation.fold for rotation in rotation_symmetry]) for rotation in rotation_symmetry: if rotation.fold == highest_n_fold: highest_symmetries.append(rotation) for highest_symmetry in highest_symmetries: quaternion_list = [] vector = highest_symmetry.vector for i in range(1, highest_symmetry.fold): theta_i = pi * i / highest_symmetry.fold quaternion = create_quaternion(vector, theta_i) quaternion_list.append(quaternion) for quaternion in quaternion_list: for orthogonal_vector_i in vector_cross: orthogonal_vector_j = quaternion_rotation( quaternion, orthogonal_vector_i) vectors_cross_rotated.append(orthogonal_vector_j) reflection_planes = [] if len(vector_cross) > 0: total_vectors_cross = cross_vertices_vertices + vectors_cross_rotated vectors_reflection_plane = self.remove_duplicate( total_vectors_cross) planes_of_reflection = [] for planes in vectors_reflection_plane: householder_matrix = ReflectionSymmetry(planes) planes_of_reflection.append(householder_matrix) # check each reflection for plane_of_reflection in planes_of_reflection: if self.check_symmetry_operation(nuclei_array, plane_of_reflection): reflection_planes.append(plane_of_reflection) return reflection_planes
def operate(self, coordinate): """Rotates a point around the axis of rotation for a angle of 2 * pi / self.fold Parameters ---------- coordinate : Tuple[float, float, float] Returns ------- : Tuple[float, float, float] """ angle = 2 * pi / self.fold quaternion = create_quaternion(self.vector, angle) return quaternion_rotation(quaternion, coordinate)
def operate(self, coordinate): """Rotates a point around the axis of rotation for a angle of 2 * pi / self.fold and then inverts. Parameters ---------- coordinate : Tuple[float, float, float] Returns ------- : Tuple[float, float, float] """ angle = 2 * pi / self.fold quaternion = create_quaternion(self.vector, angle) householder_matrix = create_householder_matrix(self.vector) x, y, z = householder_matrix_reflection( quaternion_rotation(quaternion, coordinate), householder_matrix) return x, y, z
def int_operate(self, coordinate): """Returns the rotation symmetry operation on a coordinate but returns a tuple of ints. This method is useful for seeing how the symmetry operation affects the sign of a gaussian functions integral exponents. Parameters ---------- coordinate : Tuple[float, float, float] Returns ------- : Tuple[int, int, int] """ angle = 2 * pi / self.fold quaternion = create_quaternion(self.vector, angle) x, y, z = quaternion_rotation(quaternion, coordinate) return int(round(x, 1)), int(round(y, 1)), int(round(z, 1))