def center_molecule(self, nuclei_array):
        number_of_nuclei = len(nuclei_array)
        center = [0, 0, 0]

        for nuclei in nuclei_array:
            center[0] += nuclei.coordinates[0] / number_of_nuclei
            center[1] += nuclei.coordinates[1] / number_of_nuclei
            center[2] += nuclei.coordinates[2] / number_of_nuclei

        for nuclei in nuclei_array:
            x = nuclei.coordinates[0] - center[0]
            y = nuclei.coordinates[1] - center[1]
            z = nuclei.coordinates[2] - center[2]
            nuclei.coordinates = (x, y, z)

        nuclei_array.sort(key=lambda nucleus: rho(nucleus.coordinates))

        if rho(nuclei_array[0].coordinates) <= self.error:

            for i, nuclei in enumerate(nuclei_array):
                if i == 0:
                    translation = nuclei.coordinates
                    nuclei.coordinates = (0.0, 0.0, 0.0)
                else:
                    x = nuclei.coordinates[0] - translation[0]
                    y = nuclei.coordinates[1] - translation[1]
                    z = nuclei.coordinates[2] - translation[2]
                    nuclei.coordinates = (x, y, z)

        return nuclei_array
    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 cross_products(self, vector_i, vector_j):
     cross_products = []
     for axis_i, axis_j in itertools.product(vector_i, vector_j):
         if axis_i is not axis_j:
             axis_cross = cross_product(axis_i, axis_j)
             if rho(axis_cross) > self.error:
                 axis_cross = normalize(axis_cross)
                 cross_products.append(axis_cross)
     return cross_products
 def center_two_vertices(self, nuclei_array):
     center_of_edge = []
     for nuclei_i, nuclei_j in itertools.combinations(nuclei_array, 2):
         axis_i = nuclei_i.coordinates
         axis_j = nuclei_j.coordinates
         axis_edge = vector_add(axis_i, axis_j)
         if rho(axis_edge) > self.error:
             axis_edge = normalize(axis_edge)
             center_of_edge.append(axis_edge)
     return center_of_edge
 def check_array(self, axis, axis_of_rotations_i):
     for axis_i in axis_of_rotations_i:
         if rho(cross_product(axis, axis_i)) <= self.error:
             return False
     return True
 def remove_center_nuclei(self, nuclei_array):
     nuclei_array_copy = copy.deepcopy(nuclei_array)
     for i, nuclei in enumerate(nuclei_array_copy):
         if rho(nuclei.coordinates) <= self.error:
             nuclei_array_copy.pop(i)
     return nuclei_array_copy