class TestSymmetryC2H6(TestCase):

    def setUp(self):
        carbon_1 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(0.7516, -0.0225, -0.0209))
        carbon_2 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.7516, 0.0225, 0.0209))
        hydrogen_1 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(1.1851, -0.0039, 0.9875))
        hydrogen_2 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(1.1669, 0.8330, -0.5693))
        hydrogen_3 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(1.1155, -0.9329, -0.5145))
        hydrogen_4 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.1669, -0.8334, 0.5687))
        hydrogen_5 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.1157, 0.9326, 0.5151))
        hydrogen_6 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.1850, 0.0044, -0.9875))
        self.nuclei_array_c2h6 = [carbon_1, carbon_2, hydrogen_1, hydrogen_2, hydrogen_3, hydrogen_4, hydrogen_5,
        hydrogen_6]
        self.molecule_factory = MoleculeFactory()
        self.symmetry_factory = SymmetryFactory()

    def test_check_linear_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h6)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_linear(nuclei_array)
        self.assertEqual(boolean, False)

    def test_check_high_symmetry_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h6)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_high_symmetry(rotation)
        self.assertEqual(boolean, False)

    def test_check_n_two_fold_rotation_perpendicular_to_n_fold_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h6)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_n_two_fold_perpendicular_to_n_fold(rotation)
        self.assertEqual(boolean, True)

    def test_check_sigma_h_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h6)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_sigma_h(reflection)
        self.assertEqual(boolean, False)

    def test_check_n_sigma_v_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h6)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_n_sigma_v(3, reflection)
        self.assertEqual(boolean, True)

    def test_point_group_returns_d_3d_symmetry_for_cubane(self):
        symmetry = self.molecule_factory.point_group(self.nuclei_array_c2h6).point_group.label
        testing.assert_equal(symmetry, 'D_{3d}')
 def setUp(self):
     oxygen_1 = MagicMock(element='OXYGEN', charge=8, mass=16, coordinates=(-1.4186923158, 0.1090030362, 0.0000000000))
     hydrogen_1 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.7313653816, -1.6895740638, 0.0000000000))
     fluorine_1 = MagicMock(element='FLUORINE', charge=9, mass=19, coordinates=(1.2899273141, 0.0031592817, 0.0000000000))
     self.nuclei_array_hof = [oxygen_1, hydrogen_1, fluorine_1]
     self.molecule_factory = MoleculeFactory()
     self.symmetry_factory = SymmetryFactory()
 def setUp(self):
     nitrogen_1 = MagicMock(element='NITROGEN', charge=7, mass=14, coordinates=(0.0000000000, 0.0000000000, -2.2684205883))
     nitrogen_2 = MagicMock(element='NITROGEN', charge=7, mass=14, coordinates=(0.0000000000, 0.0000000000, -0.1349300877))
     oxygen_1 = MagicMock(element='OXYGEN', charge=8, mass=16, coordinates=(0.0000000000, 0.0000000000, 2.1042369647))
     self.nuclei_array_n2o = [nitrogen_1, nitrogen_2, oxygen_1]
     self.molecule_factory = MoleculeFactory()
     self.symmetry_factory = SymmetryFactory()
 def setUp(self):
     carbon_1 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.98781, 0.41551, 0.00000))
     hydrogen_1 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(0.08219, 0.41551, 0.00000))
     hydrogen_2 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.34447, 0.70319, -0.96692))
     hydrogen_3 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.34448, 1.10904, 0.73260))
     hydrogen_4 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.34448, -0.56571, 0.23432))
     self.nuclei_array_ch4 = [carbon_1, hydrogen_1, hydrogen_2, hydrogen_3, hydrogen_4]
     self.molecule_factory = MoleculeFactory()
     self.symmetry_factory = SymmetryFactory()
class TestSymmetryHOF(TestCase):

    def setUp(self):
        oxygen_1 = MagicMock(element='OXYGEN', charge=8, mass=16, coordinates=(-1.4186923158, 0.1090030362, 0.0000000000))
        hydrogen_1 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.7313653816, -1.6895740638, 0.0000000000))
        fluorine_1 = MagicMock(element='FLUORINE', charge=9, mass=19, coordinates=(1.2899273141, 0.0031592817, 0.0000000000))
        self.nuclei_array_hof = [oxygen_1, hydrogen_1, fluorine_1]
        self.molecule_factory = MoleculeFactory()
        self.symmetry_factory = SymmetryFactory()

    def test_brute_force_rotation_symmetry_returns_list_of_zero_axis_of_rotations(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_hof)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(len(rotation), 0)

    def test_brute_force_reflection_symmetry_returns_list_of_one_reflection_planes(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_hof)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(len(reflection), 1)

    def test_check_linear_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_hof)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_linear(nuclei_array)
        self.assertEqual(boolean, False)

    def test_check_high_symmetry_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_hof)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_high_symmetry(rotation)
        self.assertEqual(boolean, False)

    def test_check_sigma_h_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_hof)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_sigma_h(reflection)
        self.assertEqual(boolean, True)

    def test_point_group_returns_c_s_symmetry_for_hypofluorous_acid(self):
        symmetry = self.molecule_factory.point_group(self.nuclei_array_hof).point_group.label
        testing.assert_equal(symmetry, 'C_{s}')
class TestSymmetryC8H8(TestCase):

    def setUp(self):
        carbon_1 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(1.2455, 0.5367, -0.0729))
        carbon_2 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(0.9239, -0.9952, 0.0237))
        carbon_3 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.1226, -0.7041, 1.1548))
        carbon_4 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(0.1989, 0.8277, 1.0582))
        carbon_5 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(0.1226, 0.7042, -1.1548))
        carbon_6 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.9239, 0.9952, -0.0237))
        carbon_7 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-1.2454, -0.5367, 0.0729))
        carbon_8 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.1989, -0.8277, -1.0582))
        hydrogen_1 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(2.2431, 0.9666, -0.1313))
        hydrogen_2 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(1.6638, -1.7924, 0.0426))
        hydrogen_3 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-0.2209, -1.2683, 2.0797))
        hydrogen_4 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(0.3583, 1.4907, 1.9059))
        hydrogen_5 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(0.2208, 1.2681, -2.0799))
        hydrogen_6 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.6640, 1.7922, -0.0427))
        hydrogen_7 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-2.2430, -0.9665, 0.1313))
        hydrogen_8 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-0.3583, -1.4906, -1.9058))
        self.nuclei_array_c8h8 = [carbon_1, carbon_2, carbon_3, carbon_4, carbon_5, carbon_6, carbon_7, carbon_8,
        hydrogen_1, hydrogen_2, hydrogen_3, hydrogen_4, hydrogen_5, hydrogen_6, hydrogen_7, hydrogen_8]
        self.molecule_factory = MoleculeFactory()
        self.symmetry_factory = SymmetryFactory()
        self.inversion_symmetry = InversionSymmetry()

    def test_check_linear_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c8h8)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_linear(nuclei_array)
        self.assertEqual(boolean, False)

    def test_check_high_symmetry_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c8h8)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_high_symmetry(rotation)
        self.assertEqual(boolean, True)

    def test_point_group_returns_o_h_symmetry_for_cubane(self):
        symmetry = self.molecule_factory.point_group(self.nuclei_array_c8h8).point_group.label
        testing.assert_equal(symmetry, 'O_{h}')
 def setUp(self):
     oxygen_1 = MagicMock(
         element="OXYGEN", charge=8, mass=16, coordinates=(0.0000000000, 0.0000000000, -0.1363928482)
     )
     hydrogen_1 = MagicMock(
         element="HYDROGEN", charge=1, mass=1, coordinates=(0.0000000000, 1.4236595095, 0.9813433754)
     )
     hydrogen_2 = MagicMock(
         element="HYDROGEN", charge=1, mass=1, coordinates=(0.0000000000, -1.4236595095, 0.9813433754)
     )
     self.nuclei_array_h2o = [oxygen_1, hydrogen_1, hydrogen_2]
     self.molecule_factory = MoleculeFactory()
     self.symmetry_factory = SymmetryFactory()
 def setUp(self):
     carbon_1 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(0.7516, -0.0225, -0.0209))
     carbon_2 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.7516, 0.0225, 0.0209))
     hydrogen_1 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(1.1851, -0.0039, 0.9875))
     hydrogen_2 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(1.1669, 0.8330, -0.5693))
     hydrogen_3 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(1.1155, -0.9329, -0.5145))
     hydrogen_4 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.1669, -0.8334, 0.5687))
     hydrogen_5 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.1157, 0.9326, 0.5151))
     hydrogen_6 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.1850, 0.0044, -0.9875))
     self.nuclei_array_c2h6 = [carbon_1, carbon_2, hydrogen_1, hydrogen_2, hydrogen_3, hydrogen_4, hydrogen_5,
     hydrogen_6]
     self.molecule_factory = MoleculeFactory()
     self.symmetry_factory = SymmetryFactory()
class TestSymmetryN2O(TestCase):

    def setUp(self):
        nitrogen_1 = MagicMock(element='NITROGEN', charge=7, mass=14, coordinates=(0.0000000000, 0.0000000000, -2.2684205883))
        nitrogen_2 = MagicMock(element='NITROGEN', charge=7, mass=14, coordinates=(0.0000000000, 0.0000000000, -0.1349300877))
        oxygen_1 = MagicMock(element='OXYGEN', charge=8, mass=16, coordinates=(0.0000000000, 0.0000000000, 2.1042369647))
        self.nuclei_array_n2o = [nitrogen_1, nitrogen_2, oxygen_1]
        self.molecule_factory = MoleculeFactory()
        self.symmetry_factory = SymmetryFactory()

    def test_check_linear_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_n2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_linear(nuclei_array)
        self.assertEqual(boolean, True)

    def test_point_group_returns_c_inf_v_symmetry_for_nitrous_oxide(self):
        symmetry = self.molecule_factory.point_group(self.nuclei_array_n2o).point_group.label
        testing.assert_equal(symmetry, 'C_{4v}')
class TestSymmetryN2(TestCase):

    def setUp(self):
        nitrogen_1 = MagicMock(element='NITROGEN', charge=7, mass=14, coordinates=(0.0000000000, 0.0000000000, 1.0399092291))
        nitrogen_2 = MagicMock(element='NITROGEN', charge=7, mass=14, coordinates=(0.0000000000, 0.0000000000, -1.0399092291))
        self.nuclei_array_n2 = [nitrogen_1, nitrogen_2]
        self.molecule_factory = MoleculeFactory()
        self.symmetry_factory = SymmetryFactory()

    def test_check_linear_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_n2)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_linear(nuclei_array)
        self.assertEqual(boolean, True)

    # D_{4h} because D_{inf h} is not useful for reducing integrals
    def test_point_group_returns_d_4_h_symmetry_for_nitrogen(self):
        symmetry = self.molecule_factory.point_group(self.nuclei_array_n2).point_group.label
        testing.assert_equal(symmetry, 'D_{4h}')
 def setUp(self):
     carbon_1 = MagicMock(
         element="CARBON", charge=6, mass=12, coordinates=(0.0000000000, 1.2594652672, 0.0000000000)
     )
     carbon_2 = MagicMock(
         element="CARBON", charge=6, mass=12, coordinates=(0.0000000000, -1.2594652672, 0.0000000000)
     )
     hydrogen_1 = MagicMock(
         element="HYDROGEN", charge=1, mass=1, coordinates=(1.7400646600, 2.3216269636, 0.0000000000)
     )
     hydrogen_2 = MagicMock(
         element="HYDROGEN", charge=1, mass=1, coordinates=(-1.7400646600, 2.3216269636, 0.0000000000)
     )
     hydrogen_3 = MagicMock(
         element="HYDROGEN", charge=1, mass=1, coordinates=(1.7400646600, -2.3216269636, 0.0000000000)
     )
     hydrogen_4 = MagicMock(
         element="HYDROGEN", charge=1, mass=1, coordinates=(-1.7400646600, -2.3216269636, 0.0000000000)
     )
     self.nuclei_array_c2h4 = [carbon_1, carbon_2, hydrogen_1, hydrogen_2, hydrogen_3, hydrogen_4]
     self.molecule_factory = MoleculeFactory()
     self.symmetry_factory = SymmetryFactory()
 def setUp(self):
     carbon_1 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(1.2455, 0.5367, -0.0729))
     carbon_2 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(0.9239, -0.9952, 0.0237))
     carbon_3 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.1226, -0.7041, 1.1548))
     carbon_4 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(0.1989, 0.8277, 1.0582))
     carbon_5 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(0.1226, 0.7042, -1.1548))
     carbon_6 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.9239, 0.9952, -0.0237))
     carbon_7 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-1.2454, -0.5367, 0.0729))
     carbon_8 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.1989, -0.8277, -1.0582))
     hydrogen_1 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(2.2431, 0.9666, -0.1313))
     hydrogen_2 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(1.6638, -1.7924, 0.0426))
     hydrogen_3 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-0.2209, -1.2683, 2.0797))
     hydrogen_4 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(0.3583, 1.4907, 1.9059))
     hydrogen_5 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(0.2208, 1.2681, -2.0799))
     hydrogen_6 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.6640, 1.7922, -0.0427))
     hydrogen_7 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-2.2430, -0.9665, 0.1313))
     hydrogen_8 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-0.3583, -1.4906, -1.9058))
     self.nuclei_array_c8h8 = [carbon_1, carbon_2, carbon_3, carbon_4, carbon_5, carbon_6, carbon_7, carbon_8,
     hydrogen_1, hydrogen_2, hydrogen_3, hydrogen_4, hydrogen_5, hydrogen_6, hydrogen_7, hydrogen_8]
     self.molecule_factory = MoleculeFactory()
     self.symmetry_factory = SymmetryFactory()
     self.inversion_symmetry = InversionSymmetry()
 def __init__(self, error=1e-2):
     self.error = error
     self.symmetry_factory = SymmetryFactory(error)
class MoleculeFactory:

    def __init__(self, error=1e-2):
        self.error = error
        self.symmetry_factory = SymmetryFactory(error)

    def point_group(self, nuclei_array):
        nuclei_array = self.center_molecule(nuclei_array)

        if len(nuclei_array) == 1:                                      # Point
            return Molecule(nuclei_array, Oh())

        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.standard_orientation(nuclei_array, rotation, reflection)

        if self.check_linear(nuclei_array):                             # Linear
            if len(inversion) == 1:
                return Molecule(nuclei_array, D4h())
            else:
                return Molecule(nuclei_array, C4v())

        if self.check_high_symmetry(rotation):                          # Polyhedral
            if not len(inversion) == 1:
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'T_{d}'))
            elif any([vector.fold == 5 for vector in rotation]):
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'I_{h}'))
            else:
                return Molecule(nuclei_array, PointGroup(rotation, reflection, inversion, improper, 'O_{h}'))

        if len(rotation) == 0:                                          # Nonaxial
            if self.check_sigma_h(reflection):
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'C_{s}'))
            elif len(inversion) == 1:
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'C_{i}'))
            else:
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'C_{1}'))

        n = self.return_principal_axis(rotation).fold

        if self.check_n_two_fold_perpendicular_to_n_fold(rotation):     # Dihedral
            if self.check_sigma_h(reflection):
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'D_{' + str(n) + 'h}'))
            elif self.check_n_sigma_v(n, reflection):
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'D_{' + str(n) + 'd}'))
            else:
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'D_{' + str(n) + '}'))

        else:                                                           # Cyclic
            if self.check_sigma_h(reflection):
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'C_{' + str(n) + 'h}'))
            elif self.check_n_sigma_v(n, reflection):
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'C_{' + str(n) + 'v}'))
            elif self.check_improper_rotation(n, improper):
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'S_{2' + str(n) + '}'))
            else:
                return Molecule(nuclei_array, PointGroup(rotation, reflection, improper, inversion, 'C_{' + str(n) + '}'))

    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 check_improper_rotation(self, n, improper_rotations):
        for improper_rotation in improper_rotations:
            if improper_rotation.fold == 2 * n:
                return True
        return False

    def check_n_sigma_v(self, n, reflection_symmetry):
        i = 0
        for reflection in reflection_symmetry:
            coordinates = cartesian_to_spherical(reflection.vector)
            if coordinates[1] - pi / 2 <= self.error:
                i += 1
        if n == i:
            return True
        else:
            return False

    def check_n_two_fold_perpendicular_to_n_fold(self, rotation_symmetry):
        principal_axis = self.return_principal_axis(rotation_symmetry)
        axis_of_rotation = []
        for rotation in rotation_symmetry:
            if principal_axis != rotation and rotation.fold == 2 and (theta(rotation.vector) - pi/2 <= self.error):
                axis_of_rotation.append(rotation.vector)
        if len(axis_of_rotation) == principal_axis.fold:
            return True
        else:
            return False

    def check_sigma_h(self, reflection_symmetry):
        for reflection in reflection_symmetry:
            if theta(reflection.vector) % pi <= self.error:
                return True
        return False

    def check_high_symmetry(self, rotation_symmetry):
        i = 0
        for rotation in rotation_symmetry:
            if rotation.fold > 2:
                i += 1
        if i > 2:
            return True
        else:
            return False

    def check_linear(self, nuclei_array):
        for nuclei in nuclei_array:
            if theta(nuclei.coordinates) % pi > self.error:
                return False
        return True

    def return_principal_axis(self, rotation_symmetry):
        for rotation in rotation_symmetry:
            if theta(rotation.vector) % pi <= self.error:
                return rotation
class TestSymmetryH2O(TestCase):
    def setUp(self):
        oxygen_1 = MagicMock(
            element="OXYGEN", charge=8, mass=16, coordinates=(0.0000000000, 0.0000000000, -0.1363928482)
        )
        hydrogen_1 = MagicMock(
            element="HYDROGEN", charge=1, mass=1, coordinates=(0.0000000000, 1.4236595095, 0.9813433754)
        )
        hydrogen_2 = MagicMock(
            element="HYDROGEN", charge=1, mass=1, coordinates=(0.0000000000, -1.4236595095, 0.9813433754)
        )
        self.nuclei_array_h2o = [oxygen_1, hydrogen_1, hydrogen_2]
        self.molecule_factory = MoleculeFactory()
        self.symmetry_factory = SymmetryFactory()

    def test_brute_force_rotation_symmetry_returns_list_of_one_axis_of_rotations(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(len(rotation), 1)

    def test_brute_force_rotation_symmetry_returns_axis_of_rotation_of_two_fold_symmetry(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(rotation[0].fold, 2)

    def test_brute_force_reflection_symmetry_returns_list_of_two_reflection_planes(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(len(reflection), 2)

    def test_check_linear_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_linear(nuclei_array)
        self.assertEqual(boolean, False)

    def test_check_high_symmetry_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_high_symmetry(rotation)
        self.assertEqual(boolean, False)

    def test_get_n_fold_returns_two(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        n = self.molecule_factory.return_principal_axis(rotation).fold
        self.assertEqual(n, 2)

    def test_check_n_two_fold_rotation_perpendicular_to_n_fold_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_n_two_fold_perpendicular_to_n_fold(rotation)
        self.assertEqual(boolean, False)

    def test_check_sigma_h_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_sigma_h(reflection)
        self.assertEqual(boolean, False)

    def test_check_n_sigma_v_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_h2o)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_n_sigma_v(2, reflection)
        self.assertEqual(boolean, True)

    def test_point_group_returns_c_2v_symmetry_for_water(self):
        symmetry = self.molecule_factory.point_group(self.nuclei_array_h2o).point_group.label
        testing.assert_equal(symmetry, "C_{2v}")
class TestSymmetryC2H4(TestCase):
    def setUp(self):
        carbon_1 = MagicMock(
            element="CARBON", charge=6, mass=12, coordinates=(0.0000000000, 1.2594652672, 0.0000000000)
        )
        carbon_2 = MagicMock(
            element="CARBON", charge=6, mass=12, coordinates=(0.0000000000, -1.2594652672, 0.0000000000)
        )
        hydrogen_1 = MagicMock(
            element="HYDROGEN", charge=1, mass=1, coordinates=(1.7400646600, 2.3216269636, 0.0000000000)
        )
        hydrogen_2 = MagicMock(
            element="HYDROGEN", charge=1, mass=1, coordinates=(-1.7400646600, 2.3216269636, 0.0000000000)
        )
        hydrogen_3 = MagicMock(
            element="HYDROGEN", charge=1, mass=1, coordinates=(1.7400646600, -2.3216269636, 0.0000000000)
        )
        hydrogen_4 = MagicMock(
            element="HYDROGEN", charge=1, mass=1, coordinates=(-1.7400646600, -2.3216269636, 0.0000000000)
        )
        self.nuclei_array_c2h4 = [carbon_1, carbon_2, hydrogen_1, hydrogen_2, hydrogen_3, hydrogen_4]
        self.molecule_factory = MoleculeFactory()
        self.symmetry_factory = SymmetryFactory()

    def test_brute_force_rotation_symmetry_returns_list_of_three_axis_of_rotations(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(len(rotation), 3)

    def test_brute_force_reflection_symmetry_returns_list_of_three_reflection_planes(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(len(reflection), 3)

    def test_check_linear_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_linear(nuclei_array)
        self.assertEqual(boolean, False)

    def test_check_high_symmetry_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_high_symmetry(rotation)
        self.assertEqual(boolean, False)

    def test_check_n_two_fold_rotation_perpendicular_to_n_fold_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_n_two_fold_perpendicular_to_n_fold(rotation)
        self.assertEqual(boolean, True)

    def test_check_sigma_h_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_c2h4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_sigma_h(reflection)
        self.assertEqual(boolean, True)

    def test_point_group_returns_d_2h_symmetry_for_ethene(self):
        symmetry = self.molecule_factory.point_group(self.nuclei_array_c2h4).point_group.label
        testing.assert_equal(symmetry, "D_{2h}")
 def setUp(self):
     nitrogen_1 = MagicMock(element='NITROGEN', charge=7, mass=14, coordinates=(0.0000000000, 0.0000000000, 1.0399092291))
     nitrogen_2 = MagicMock(element='NITROGEN', charge=7, mass=14, coordinates=(0.0000000000, 0.0000000000, -1.0399092291))
     self.nuclei_array_n2 = [nitrogen_1, nitrogen_2]
     self.molecule_factory = MoleculeFactory()
     self.symmetry_factory = SymmetryFactory()
class TestSymmetryCH4(TestCase):

    def setUp(self):
        carbon_1 = MagicMock(element='CARBON', charge=6, mass=12, coordinates=(-0.98781, 0.41551, 0.00000))
        hydrogen_1 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(0.08219, 0.41551, 0.00000))
        hydrogen_2 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.34447, 0.70319, -0.96692))
        hydrogen_3 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.34448, 1.10904, 0.73260))
        hydrogen_4 = MagicMock(element='HYDROGEN', charge=1, mass=1, coordinates=(-1.34448, -0.56571, 0.23432))
        self.nuclei_array_ch4 = [carbon_1, hydrogen_1, hydrogen_2, hydrogen_3, hydrogen_4]
        self.molecule_factory = MoleculeFactory()
        self.symmetry_factory = SymmetryFactory()

    def test_center_molecule_changes_to_carbon_1_at_origin(self):
        carbon_1 = self.molecule_factory.center_molecule(self.nuclei_array_ch4)[0]
        testing.assert_array_almost_equal(carbon_1.coordinates, (0.0, 0.0, 0.0), 6)

    def test_center_molecule_changes_to_hydrogen_1(self):
        hydrogen_1 = self.molecule_factory.center_molecule(self.nuclei_array_ch4)[1]
        testing.assert_array_almost_equal(hydrogen_1.coordinates, (1.07, 0.0, 0.0), 6)

    def test_center_molecule_changes_to_hydrogen_2(self):
        hydrogen_2 = self.molecule_factory.center_molecule(self.nuclei_array_ch4)[2]
        testing.assert_array_almost_equal(hydrogen_2.coordinates, (-0.35666, 0.28768, -0.96692), 6)

    def test_center_molecule_changes_to_hydrogen_3(self):
        hydrogen_3 = self.molecule_factory.center_molecule(self.nuclei_array_ch4)[3]
        testing.assert_array_almost_equal(hydrogen_3.coordinates, (-0.35667, 0.69353, 0.73260), 6)

    def test_center_molecule_changes_to_hydrogen_4(self):
        hydrogen_4 = self.molecule_factory.center_molecule(self.nuclei_array_ch4)[4]
        testing.assert_array_almost_equal(hydrogen_4.coordinates, (-0.35667, -0.98122, 0.23432), 6)

    def test_brute_force_rotation_symmetry_returns_list_of_seven_axis_of_rotations(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_ch4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(len(rotation), 7)

    def test_brute_force_rotation_symmetry_returns_list_of_four_axis_of_rotations_with_n_three(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_ch4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual([symmetry.fold for symmetry in rotation].count(3), 4)

    def test_brute_force_rotation_symmetry_returns_list_of_four_axis_of_rotations_with_n_two(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_ch4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual([symmetry.fold for symmetry in rotation].count(2), 3)

    def test_brute_force_reflection_symmetry_returns_a_list_of_six_reflection_planes(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_ch4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.assertEqual(len(reflection), 6)

    def test_check_linear_returns_false(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_ch4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_linear(nuclei_array)
        self.assertEqual(boolean, False)

    def test_check_high_symmetry_returns_true(self):
        nuclei_array = self.molecule_factory.center_molecule(self.nuclei_array_ch4)
        rotation, reflection, improper, inversion = self.symmetry_factory.brute_force_symmetry(nuclei_array)
        self.molecule_factory.standard_orientation(nuclei_array, rotation, reflection)
        boolean = self.molecule_factory.check_high_symmetry(rotation)
        self.assertEqual(boolean, True)

    def test_point_group_returns_t_d_symmetry_for_methane(self):
        symmetry = self.molecule_factory.point_group(self.nuclei_array_ch4).point_group.label
        testing.assert_equal(symmetry, 'T_{d}')