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)
 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 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 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 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 = heapq.nlargest(1, [rotation.fold for rotation in rotation_symmetry])[0]
            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 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))
 def test_create_quaternion_returns_quaternion_for_0_degree_rotation_around_x_axis(self):
     axis_of_rotation = (1.0, 0.0, 0.0)
     theta = 0
     quaternion = create_quaternion(axis_of_rotation, theta)
     testing.assert_array_almost_equal(quaternion, (1.0, 0.0, 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)