def test_mapping_symmetry(self): l = Lattice.cubic(1) l2 = Lattice.orthorhombic(1.1001, 1, 1) self.assertEqual(l.find_mapping(l2, ltol=0.1), None) self.assertEqual(l2.find_mapping(l, ltol=0.1), None) l2 = Lattice.orthorhombic(1.0999, 1, 1) self.assertNotEqual(l2.find_mapping(l, ltol=0.1), None) self.assertNotEqual(l.find_mapping(l2, ltol=0.1), None)
def test_mapping_symmetry(self): l = Lattice.cubic(1) l2 = Lattice.orthorhombic(1.1001, 1, 1) self.assertEqual(l.find_mapping(l2, ltol=0.1), None) self.assertEqual(l2.find_mapping(l, ltol=0.1), None) l2 = Lattice.orthorhombic(1.0999, 1, 1) self.assertNotEqual(l2.find_mapping(l, ltol=0.1), None) self.assertNotEqual(l.find_mapping(l2, ltol=0.1), None)
def test_kpath_generation(self): triclinic = [1, 2] monoclinic = range(3, 16) orthorhombic = range(16, 75) tetragonal = range(75, 143) rhombohedral = range(143, 168) hexagonal = range(168, 195) cubic = range(195, 231) species = ['K', 'La', 'Ti'] coords = [[.345, 5, .77298], [.1345, 5.1, .77298], [.7, .8, .9]] for i in range(230): sg_num = i + 1 if sg_num in triclinic: lattice = Lattice([[3.0233057319441246,0,0], [0,7.9850357844548681,0], [0,0,8.1136762279561818]]) elif sg_num in monoclinic: lattice = Lattice.monoclinic(2, 9, 1, 99) elif sg_num in orthorhombic: lattice = Lattice.orthorhombic(2, 9, 1) elif sg_num in tetragonal: lattice = Lattice.tetragonal(2, 9) elif sg_num in rhombohedral: lattice = Lattice.hexagonal(2, 95) elif sg_num in hexagonal: lattice = Lattice.hexagonal(2, 9) elif sg_num in cubic: lattice = Lattice.cubic(2) struct = Structure.from_spacegroup(sg_num, lattice, species, coords) kpath = HighSymmKpath(struct) #Throws error if something doesn't work, causing test to fail.
def test_is_compatible(self): cubic = Lattice.cubic(1) hexagonal = Lattice.hexagonal(1, 2) rhom = Lattice.rhombohedral(3, 80) tet = Lattice.tetragonal(1, 2) ortho = Lattice.orthorhombic(1, 2, 3) sg = SpaceGroup("Fm-3m") self.assertTrue(sg.is_compatible(cubic)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("R-3mH") self.assertFalse(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(hexagonal)) sg = SpaceGroup("R-3m") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("Pnma") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("P12/c1") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("P-1") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertTrue(sg.is_compatible(rhom)) self.assertTrue(sg.is_compatible(hexagonal))
def test_kpath_generation(self): triclinic = [1, 2] monoclinic = range(3, 16) orthorhombic = range(16, 75) tetragonal = range(75, 143) rhombohedral = range(143, 168) hexagonal = range(168, 195) cubic = range(195, 231) species = ["K", "La", "Ti"] coords = [[0.345, 5, 0.77298], [0.1345, 5.1, 0.77298], [0.7, 0.8, 0.9]] for i in range(230): sg_num = i + 1 if sg_num in triclinic: lattice = Lattice( [[3.0233057319441246, 1, 0], [0, 7.9850357844548681, 1], [0, 1.2, 8.1136762279561818]] ) elif sg_num in monoclinic: lattice = Lattice.monoclinic(2, 9, 1, 99) elif sg_num in orthorhombic: lattice = Lattice.orthorhombic(2, 9, 1) elif sg_num in tetragonal: lattice = Lattice.tetragonal(2, 9) elif sg_num in rhombohedral: lattice = Lattice.hexagonal(2, 95) elif sg_num in hexagonal: lattice = Lattice.hexagonal(2, 9) elif sg_num in cubic: lattice = Lattice.cubic(2) struct = Structure.from_spacegroup(sg_num, lattice, species, coords) kpath = KPathSeek(struct) # Throws error if something doesn't work, causing test to fail.
def test_lattice_2_lmpbox(self): matrix = np.diag(np.random.randint(5, 14, size=(3,))) + np.random.rand(3, 3) * 0.2 - 0.1 init_latt = Lattice(matrix) frac_coords = np.random.rand(10, 3) init_structure = Structure(init_latt, ["H"] * 10, frac_coords) origin = np.random.rand(3) * 10 - 5 box, symmop = lattice_2_lmpbox(lattice=init_latt, origin=origin) boxed_latt = box.to_lattice() np.testing.assert_array_almost_equal(init_latt.abc, boxed_latt.abc) np.testing.assert_array_almost_equal(init_latt.angles, boxed_latt.angles) cart_coords = symmop.operate_multi(init_structure.cart_coords) - origin boxed_structure = Structure(boxed_latt, ["H"] * 10, cart_coords, coords_are_cartesian=True) np.testing.assert_array_almost_equal(boxed_structure.frac_coords, frac_coords) tetra_latt = Lattice.tetragonal(5, 5) tetra_box, _ = lattice_2_lmpbox(tetra_latt) self.assertIsNone(tetra_box.tilt) ortho_latt = Lattice.orthorhombic(5, 5, 5) ortho_box, _ = lattice_2_lmpbox(ortho_latt) self.assertIsNone(ortho_box.tilt) rot_tetra_latt = Lattice([[5, 0, 0], [0, 2, 2], [0, -2, 2]]) _, rotop = lattice_2_lmpbox(rot_tetra_latt) np.testing.assert_array_almost_equal( rotop.rotation_matrix, [ [1, 0, 0], [0, 2 ** 0.5 / 2, 2 ** 0.5 / 2], [0, -(2 ** 0.5) / 2, 2 ** 0.5 / 2], ], )
def test_find_all_mappings(self): m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]]) latt = Lattice(m) op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, -1, 3], 40) rot = op.rotation_matrix scale = np.array([[0, 2, 0], [1, 1, 0], [0, 0, 1]]) latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T) for (aligned_out, rot_out, scale_out) in latt.find_all_mappings(latt2): self.assertArrayAlmostEqual(np.inner(latt2.matrix, rot_out), aligned_out.matrix, 5) self.assertArrayAlmostEqual(np.dot(scale_out, latt.matrix), aligned_out.matrix) self.assertArrayAlmostEqual(aligned_out.lengths_and_angles, latt2.lengths_and_angles) self.assertFalse( np.allclose(aligned_out.lengths_and_angles, latt.lengths_and_angles)) latt = Lattice.orthorhombic(9, 9, 5) self.assertEqual(len(list(latt.find_all_mappings(latt))), 16) #catch the singular matrix error latt = Lattice.from_lengths_and_angles([1, 1, 1], [10, 10, 10]) for l, _, _ in latt.find_all_mappings(latt, ltol=0.05, atol=11): self.assertTrue(isinstance(l, Lattice))
def test_kpath_generation(self): triclinic = [1, 2] monoclinic = range(3, 16) orthorhombic = range(16, 75) tetragonal = range(75, 143) rhombohedral = range(143, 168) hexagonal = range(168, 195) cubic = range(195, 231) species = ['K', 'La', 'Ti'] coords = [[.345, 5, .77298], [.1345, 5.1, .77298], [.7, .8, .9]] for i in range(230): sg_num = i + 1 if sg_num in triclinic: lattice = Lattice([[3.0233057319441246, 0, 0], [0, 7.9850357844548681, 0], [0, 0, 8.1136762279561818]]) elif sg_num in monoclinic: lattice = Lattice.monoclinic(2, 9, 1, 99) elif sg_num in orthorhombic: lattice = Lattice.orthorhombic(2, 9, 1) elif sg_num in tetragonal: lattice = Lattice.tetragonal(2, 9) elif sg_num in rhombohedral: lattice = Lattice.hexagonal(2, 95) elif sg_num in hexagonal: lattice = Lattice.hexagonal(2, 9) elif sg_num in cubic: lattice = Lattice.cubic(2) struct = Structure.from_spacegroup(sg_num, lattice, species, coords) kpath = HighSymmKpath(struct) # Throws error if something doesn't work, causing test to fail. struct_file_path = os.path.join(test_dir_structs, 'ICSD_170.cif') struct = Structure.from_file(struct_file_path) hkp = HighSymmKpath(struct) self.assertEqual(hkp.name, 'MCLC5')
def test_is_compatible(self): cubic = Lattice.cubic(1) hexagonal = Lattice.hexagonal(1, 2) rhom = Lattice.rhombohedral(3, 80) tet = Lattice.tetragonal(1, 2) ortho = Lattice.orthorhombic(1, 2, 3) msg = MagneticSpaceGroup("Fm-3m") self.assertTrue(msg.is_compatible(cubic)) self.assertFalse(msg.is_compatible(hexagonal)) msg = MagneticSpaceGroup("Pnma") self.assertTrue(msg.is_compatible(cubic)) self.assertTrue(msg.is_compatible(tet)) self.assertTrue(msg.is_compatible(ortho)) self.assertFalse(msg.is_compatible(rhom)) self.assertFalse(msg.is_compatible(hexagonal)) msg = MagneticSpaceGroup("P2/c") self.assertTrue(msg.is_compatible(cubic)) self.assertTrue(msg.is_compatible(tet)) self.assertTrue(msg.is_compatible(ortho)) self.assertFalse(msg.is_compatible(rhom)) self.assertFalse(msg.is_compatible(hexagonal)) msg = MagneticSpaceGroup("P-1") self.assertTrue(msg.is_compatible(cubic)) self.assertTrue(msg.is_compatible(tet)) self.assertTrue(msg.is_compatible(ortho)) self.assertTrue(msg.is_compatible(rhom)) self.assertTrue(msg.is_compatible(hexagonal))
def test_from_magnetic_spacegroup(self): # AFM MnF s1 = Structure.from_magnetic_spacegroup("P4_2'/mnm'", Lattice.tetragonal(4.87, 3.30), ["Mn", "F"], [[0, 0, 0], [0.30, 0.30, 0.00]], {'magmom': [4, 0]}) self.assertEqual(s1.formula, "Mn2 F4") self.assertEqual(sum(map(float, s1.site_properties['magmom'])), 0) self.assertEqual(max(map(float, s1.site_properties['magmom'])), 4) self.assertEqual(min(map(float, s1.site_properties['magmom'])), -4) # AFM LaMnO3, ordered on (001) planes s2 = Structure.from_magnetic_spacegroup("Pn'ma'", Lattice.orthorhombic(5.75, 7.66, 5.53), ["La", "Mn", "O", "O"], [[0.05, 0.25, 0.99], [0.00, 0.00, 0.50], [0.48, 0.25, 0.08], [0.31, 0.04, 0.72]], {'magmom': [0, Magmom([4, 0, 0]), 0, 0]}) self.assertEqual(s2.formula, "La4 Mn4 O12") self.assertEqual(sum(map(float, s2.site_properties['magmom'])), 0) self.assertEqual(max(map(float, s2.site_properties['magmom'])), 4) self.assertEqual(min(map(float, s2.site_properties['magmom'])), -4)
def test_find_all_mappings(self): m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]]) latt = Lattice(m) op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, -1, 3], 40) rot = op.rotation_matrix scale = np.array([[0, 2, 0], [1, 1, 0], [0,0,1]]) latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T) for (aligned_out, rot_out, scale_out) in latt.find_all_mappings(latt2): self.assertArrayAlmostEqual(np.inner(latt2.matrix, rot_out), aligned_out.matrix, 5) self.assertArrayAlmostEqual(np.dot(scale_out, latt.matrix), aligned_out.matrix) self.assertArrayAlmostEqual(aligned_out.lengths_and_angles, latt2.lengths_and_angles) self.assertFalse(np.allclose(aligned_out.lengths_and_angles, latt.lengths_and_angles)) latt = Lattice.orthorhombic(9, 9, 5) self.assertEqual(len(list(latt.find_all_mappings(latt))), 16) #catch the singular matrix error latt = Lattice.from_lengths_and_angles([1,1,1], [10,10,10]) for l, _, _ in latt.find_all_mappings(latt, ltol=0.05, atol=11): self.assertTrue(isinstance(l, Lattice))
def test_kpath_acentered(self): species = ["K", "La", "Ti"] coords = [[0.345, 5, 0.77298], [0.1345, 5.1, 0.77298], [0.7, 0.8, 0.9]] lattice = Lattice.orthorhombic(2, 9, 1) struct = Structure.from_spacegroup(38, lattice, species, coords) sga = SpacegroupAnalyzer(struct) struct_prim = sga.get_primitive_standard_structure(international_monoclinic=False) kpath = KPathLatimerMunro(struct_prim) kpoints = kpath._kpath["kpoints"] labels = list(kpoints.keys()) self.assertEqual( sorted(labels), sorted(["a", "b", "c", "d", "d_{1}", "e", "f", "q", "q_{1}", "Γ"]), ) self.assertAlmostEqual(kpoints["a"][0], 0.0) self.assertAlmostEqual(kpoints["a"][1], 0.4999999999999997) self.assertAlmostEqual(kpoints["a"][2], 0.0) self.assertAlmostEqual(kpoints["f"][0], -0.49999999999999933) self.assertAlmostEqual(kpoints["f"][1], 0.4999999999999992) self.assertAlmostEqual(kpoints["f"][2], 0.4999999999999999) self.assertAlmostEqual(kpoints["c"][0], 0.0) self.assertAlmostEqual(kpoints["c"][1], 0.0) self.assertAlmostEqual(kpoints["c"][2], 0.5) self.assertAlmostEqual(kpoints["b"][0], -0.5000000000000002) self.assertAlmostEqual(kpoints["b"][1], 0.500000000000000) self.assertAlmostEqual(kpoints["b"][2], 0.0) self.assertAlmostEqual(kpoints["Γ"][0], 0) self.assertAlmostEqual(kpoints["Γ"][1], 0) self.assertAlmostEqual(kpoints["Γ"][2], 0) self.assertAlmostEqual(kpoints["e"][0], 0.0) self.assertAlmostEqual(kpoints["e"][1], 0.49999999999999956) self.assertAlmostEqual(kpoints["e"][2], 0.5000000000000002) d = False if np.allclose(kpoints["d_{1}"], [0.2530864197530836, 0.25308641975308915, 0.0], atol=1e-5) or np.allclose( kpoints["d"], [0.2530864197530836, 0.25308641975308915, 0.0], atol=1e-5 ): d = True self.assertTrue(d) q = False if np.allclose(kpoints["q_{1}"], [0.2530864197530836, 0.25308641975308915, 0.5], atol=1e-5) or np.allclose( kpoints["q"], [0.2530864197530836, 0.25308641975308915, 0.5], atol=1e-5 ): q = True self.assertTrue(q)
def test_kpath_acentered(self): species = ["K", "La", "Ti"] coords = [[0.345, 5, 0.77298], [0.1345, 5.1, 0.77298], [0.7, 0.8, 0.9]] lattice = Lattice.orthorhombic(2, 9, 1) struct = Structure.from_spacegroup(38, lattice, species, coords) kpath = KPathSetyawanCurtarolo(struct) kpoints = kpath._kpath["kpoints"] labels = list(kpoints.keys()) self.assertEqual( sorted(labels), sorted( ["\\Gamma", "A", "A_1", "R", "S", "T", "X", "X_1", "Y", "Z"]), ) self.assertEqual(kpoints["\\Gamma"][0], 0.00000000) self.assertAlmostEqual(kpoints["\\Gamma"][1], 0.00000000) self.assertAlmostEqual(kpoints["\\Gamma"][2], 0.00000000) self.assertAlmostEqual(kpoints["A"][0], 0.25308642) self.assertAlmostEqual(kpoints["A"][1], 0.25308642) self.assertAlmostEqual(kpoints["A"][2], 0.50000000) self.assertAlmostEqual(kpoints["A_1"][0], -0.25308642) self.assertAlmostEqual(kpoints["A_1"][1], 0.74691358) self.assertAlmostEqual(kpoints["A_1"][2], 0.50000000) self.assertAlmostEqual(kpoints["R"][0], 0.00000000) self.assertAlmostEqual(kpoints["R"][1], 0.50000000) self.assertAlmostEqual(kpoints["R"][2], 0.50000000) self.assertAlmostEqual(kpoints["S"][0], 0.00000000) self.assertAlmostEqual(kpoints["S"][1], 0.50000000) self.assertAlmostEqual(kpoints["S"][2], 0.00000000) self.assertAlmostEqual(kpoints["T"][0], -0.50000000) self.assertAlmostEqual(kpoints["T"][1], 0.50000000) self.assertAlmostEqual(kpoints["T"][2], 0.50000000) self.assertAlmostEqual(kpoints["X"][0], 0.25308642) self.assertAlmostEqual(kpoints["X"][1], 0.25308642) self.assertAlmostEqual(kpoints["X"][2], 0.00000000) self.assertAlmostEqual(kpoints["X_1"][0], -0.25308642) self.assertAlmostEqual(kpoints["X_1"][1], 0.74691358) self.assertAlmostEqual(kpoints["X_1"][2], 0.00000000) self.assertAlmostEqual(kpoints["Y"][0], -0.50000000) self.assertAlmostEqual(kpoints["Y"][1], 0.50000000) self.assertAlmostEqual(kpoints["Y"][2], 0.00000000) self.assertAlmostEqual(kpoints["Z"][0], 0.00000000) self.assertAlmostEqual(kpoints["Z"][1], 0.00000000) self.assertAlmostEqual(kpoints["Z"][2], 0.50000000)
def test_kpath_acentered(self): species = ['K', 'La', 'Ti'] coords = [[.345, 5, .77298], [.1345, 5.1, .77298], [.7, .8, .9]] lattice = Lattice.orthorhombic(2, 9, 1) struct = Structure.from_spacegroup(38, lattice, species, coords) kpath = HighSymmKpath(struct) kpoints = kpath._kpath['kpoints'] labels = list(kpoints.keys()) self.assertEqual( sorted(labels), sorted( ['\\Gamma', 'A', 'A_1', 'R', 'S', 'T', 'X', 'X_1', 'Y', 'Z'])) self.assertEqual(kpoints['\\Gamma'][0], 0.00000000) self.assertAlmostEqual(kpoints['\\Gamma'][1], 0.00000000) self.assertAlmostEqual(kpoints['\\Gamma'][2], 0.00000000) self.assertAlmostEqual(kpoints['A'][0], 0.25308642) self.assertAlmostEqual(kpoints['A'][1], 0.25308642) self.assertAlmostEqual(kpoints['A'][2], 0.50000000) self.assertAlmostEqual(kpoints['A_1'][0], -0.25308642) self.assertAlmostEqual(kpoints['A_1'][1], 0.74691358) self.assertAlmostEqual(kpoints['A_1'][2], 0.50000000) self.assertAlmostEqual(kpoints['R'][0], 0.00000000) self.assertAlmostEqual(kpoints['R'][1], 0.50000000) self.assertAlmostEqual(kpoints['R'][2], 0.50000000) self.assertAlmostEqual(kpoints['S'][0], 0.00000000) self.assertAlmostEqual(kpoints['S'][1], 0.50000000) self.assertAlmostEqual(kpoints['S'][2], 0.00000000) self.assertAlmostEqual(kpoints['T'][0], -0.50000000) self.assertAlmostEqual(kpoints['T'][1], 0.50000000) self.assertAlmostEqual(kpoints['T'][2], 0.50000000) self.assertAlmostEqual(kpoints['X'][0], 0.25308642) self.assertAlmostEqual(kpoints['X'][1], 0.25308642) self.assertAlmostEqual(kpoints['X'][2], 0.00000000) self.assertAlmostEqual(kpoints['X_1'][0], -0.25308642) self.assertAlmostEqual(kpoints['X_1'][1], 0.74691358) self.assertAlmostEqual(kpoints['X_1'][2], 0.00000000) self.assertAlmostEqual(kpoints['Y'][0], -0.50000000) self.assertAlmostEqual(kpoints['Y'][1], 0.50000000) self.assertAlmostEqual(kpoints['Y'][2], 0.00000000) self.assertAlmostEqual(kpoints['Z'][0], 0.00000000) self.assertAlmostEqual(kpoints['Z'][1], 0.00000000) self.assertAlmostEqual(kpoints['Z'][2], 0.50000000)
def test_sulfide_type(self): # NaS2 -> polysulfide latt = Lattice.tetragonal(9.59650, 11.78850) species = ["Na"] * 2 + ["S"] * 2 coords = [ [0.00000, 0.00000, 0.17000], [0.27600, 0.25000, 0.12500], [0.03400, 0.25000, 0.29600], [0.14700, 0.11600, 0.40000], ] struct = Structure.from_spacegroup(122, latt, species, coords) self.assertEqual(sulfide_type(struct), "polysulfide") # NaCl type NaS -> sulfide latt = Lattice.cubic(5.75) species = ["Na", "S"] coords = [[0.00000, 0.00000, 0.00000], [0.50000, 0.50000, 0.50000]] struct = Structure.from_spacegroup(225, latt, species, coords) self.assertEqual(sulfide_type(struct), "sulfide") # Na2S2O3 -> None (sulfate) latt = Lattice.monoclinic(6.40100, 8.10000, 8.47400, 96.8800) species = ["Na"] * 2 + ["S"] * 2 + ["O"] * 3 coords = [ [0.29706, 0.62396, 0.08575], [0.37673, 0.30411, 0.45416], [0.52324, 0.10651, 0.21126], [0.29660, -0.04671, 0.26607], [0.17577, 0.03720, 0.38049], [0.38604, -0.20144, 0.33624], [0.16248, -0.08546, 0.11608], ] struct = Structure.from_spacegroup(14, latt, species, coords) self.assertEqual(sulfide_type(struct), None) # Na3PS3O -> sulfide latt = Lattice.orthorhombic(9.51050, 11.54630, 5.93230) species = ["Na"] * 2 + ["S"] * 2 + ["P", "O"] coords = [ [0.19920, 0.11580, 0.24950], [0.00000, 0.36840, 0.29380], [0.32210, 0.36730, 0.22530], [0.50000, 0.11910, 0.27210], [0.50000, 0.29400, 0.35500], [0.50000, 0.30300, 0.61140], ] struct = Structure.from_spacegroup(36, latt, species, coords) self.assertEqual(sulfide_type(struct), "sulfide") # test for unphysical cells struct.scale_lattice(struct.volume * 10) self.assertEqual(sulfide_type(struct), "sulfide")
def test_kpath_acentered(self): species = ['K', 'La', 'Ti'] coords = [[.345, 5, .77298], [.1345, 5.1, .77298], [.7, .8, .9]] lattice = Lattice.orthorhombic(2, 9, 1) struct = Structure.from_spacegroup(38, lattice, species, coords) kpath = HighSymmKpath(struct) kpoints = kpath._kpath['kpoints'] labels = list(kpoints.keys()) self.assertEqual(sorted(labels), sorted(['\\Gamma', 'A', 'A_1', 'R', 'S', 'T', 'X', 'X_1', 'Y', 'Z'])) self.assertEqual(kpoints['\\Gamma'][0], 0.00000000) self.assertAlmostEqual(kpoints['\\Gamma'][1], 0.00000000) self.assertAlmostEqual(kpoints['\\Gamma'][2], 0.00000000) self.assertAlmostEqual(kpoints['A'][0], 0.25308642) self.assertAlmostEqual(kpoints['A'][1], 0.25308642) self.assertAlmostEqual(kpoints['A'][2], 0.50000000) self.assertAlmostEqual(kpoints['A_1'][0], -0.25308642) self.assertAlmostEqual(kpoints['A_1'][1], 0.74691358) self.assertAlmostEqual(kpoints['A_1'][2], 0.50000000) self.assertAlmostEqual(kpoints['R'][0], 0.00000000) self.assertAlmostEqual(kpoints['R'][1], 0.50000000) self.assertAlmostEqual(kpoints['R'][2], 0.50000000) self.assertAlmostEqual(kpoints['S'][0], 0.00000000) self.assertAlmostEqual(kpoints['S'][1], 0.50000000) self.assertAlmostEqual(kpoints['S'][2], 0.00000000) self.assertAlmostEqual(kpoints['T'][0], -0.50000000) self.assertAlmostEqual(kpoints['T'][1], 0.50000000) self.assertAlmostEqual(kpoints['T'][2], 0.50000000) self.assertAlmostEqual(kpoints['X'][0], 0.25308642) self.assertAlmostEqual(kpoints['X'][1], 0.25308642) self.assertAlmostEqual(kpoints['X'][2], 0.00000000) self.assertAlmostEqual(kpoints['X_1'][0], -0.25308642) self.assertAlmostEqual(kpoints['X_1'][1], 0.74691358) self.assertAlmostEqual(kpoints['X_1'][2], 0.00000000) self.assertAlmostEqual(kpoints['Y'][0], -0.50000000) self.assertAlmostEqual(kpoints['Y'][1], 0.50000000) self.assertAlmostEqual(kpoints['Y'][2], 0.00000000) self.assertAlmostEqual(kpoints['Z'][0], 0.00000000) self.assertAlmostEqual(kpoints['Z'][1], 0.00000000) self.assertAlmostEqual(kpoints['Z'][2], 0.50000000)
def setUp(self): self.lattice = Lattice.cubic(10.0) self.cubic = self.lattice self.tetragonal = Lattice.tetragonal(10, 20) self.orthorhombic = Lattice.orthorhombic(10, 20, 30) self.monoclinic = Lattice.monoclinic(10, 20, 30, 66) self.hexagonal = Lattice.hexagonal(10, 20) self.rhombohedral = Lattice.rhombohedral(10, 77) family_names = ["cubic", "tetragonal", "orthorhombic", "monoclinic", "hexagonal", "rhombohedral"] self.families = {} for name in family_names: self.families[name] = getattr(self, name)
def setUp(self): self.lattice = Lattice.cubic(10.0) self.cubic = self.lattice self.tetragonal = Lattice.tetragonal(10, 20) self.orthorhombic = Lattice.orthorhombic(10, 20, 30) self.monoclinic = Lattice.monoclinic(10, 20, 30, 66) self.hexagonal = Lattice.hexagonal(10, 20) self.rhombohedral = Lattice.rhombohedral(10, 77) family_names = ["cubic", "tetragonal", "orthorhombic", "monoclinic", "hexagonal", "rhombohedral"] self.families = {} for name in family_names: self.families[name] = getattr(self, name)
def test_selling_vector(self): a1 = 10 np.testing.assert_array_almost_equal( Lattice.cubic(a1).selling_vector.round(4), np.array([0, 0, 0, -(a1**2), -(a1**2), -(a1**2)]), ) a2, c2 = 5, 8 np.testing.assert_array_almost_equal( Lattice.tetragonal(a2, c2).selling_vector.round(4), np.array([0, 0, 0, -(a2**2), -(a2**2), -(c2**2)]), ) a3, b3, c3 = 4, 6, 7 np.testing.assert_array_almost_equal( Lattice.orthorhombic(a3, b3, c3).selling_vector.round(4), np.array([0, 0, 0, -(a3**2), -(b3**2), -(c3**2)]), )
def test_is_compatible(self): cubic = Lattice.cubic(1) hexagonal = Lattice.hexagonal(1, 2) rhom = Lattice.rhombohedral(3, 80) tet = Lattice.tetragonal(1, 2) ortho = Lattice.orthorhombic(1, 2, 3) sg = SpaceGroup("Fm-3m") self.assertTrue(sg.is_compatible(cubic)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("R-3m:H") self.assertFalse(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(hexagonal)) sg = SpaceGroup("R-3m:R") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("Pnma") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("P12/c1") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("P-1") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertTrue(sg.is_compatible(rhom)) self.assertTrue(sg.is_compatible(hexagonal)) sg = SpaceGroup("Pmmn:2") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup.from_int_number(165) self.assertFalse(sg.is_compatible(cubic)) self.assertFalse(sg.is_compatible(tet)) self.assertFalse(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertTrue(sg.is_compatible(hexagonal))
def test_from_magnetic_spacegroup(self): # AFM MnF s1 = Structure.from_magnetic_spacegroup( "P4_2'/mnm'", Lattice.tetragonal(4.87, 3.30), ["Mn", "F"], [[0, 0, 0], [0.30, 0.30, 0.00]], {'magmom': [4, 0]}) self.assertEqual(s1.formula, "Mn2 F4") self.assertEqual(sum(map(float, s1.site_properties['magmom'])), 0) self.assertEqual(max(map(float, s1.site_properties['magmom'])), 4) self.assertEqual(min(map(float, s1.site_properties['magmom'])), -4) # AFM LaMnO3, ordered on (001) planes s2 = Structure.from_magnetic_spacegroup( "Pn'ma'", Lattice.orthorhombic(5.75, 7.66, 5.53), ["La", "Mn", "O", "O"], [[0.05, 0.25, 0.99], [0.00, 0.00, 0.50], [0.48, 0.25, 0.08], [0.31, 0.04, 0.72]], {'magmom': [0, Magmom([4, 0, 0]), 0, 0]}) self.assertEqual(s2.formula, "La4 Mn4 O12") self.assertEqual(sum(map(float, s2.site_properties['magmom'])), 0) self.assertEqual(max(map(float, s2.site_properties['magmom'])), 4) self.assertEqual(min(map(float, s2.site_properties['magmom'])), -4)
def get_conventional_standard_structure(self, international_monoclinic=True): """ Gives a structure with a conventional cell according to certain standards. The standards are defined in Setyawan, W., & Curtarolo, S. (2010). High-throughput electronic band structure calculations: Challenges and tools. Computational Materials Science, 49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010 They basically enforce as much as possible norm(a1)<norm(a2)<norm(a3) Returns: The structure in a conventional standardized cell """ tol = 1e-5 struct = self.get_refined_structure() latt = struct.lattice latt_type = self.get_lattice_type() sorted_lengths = sorted(latt.abc) sorted_dic = sorted([{ 'vec': latt.matrix[i], 'length': latt.abc[i], 'orig_index': i } for i in [0, 1, 2]], key=lambda k: k['length']) if latt_type in ("orthorhombic", "cubic"): #you want to keep the c axis where it is #to keep the C- settings transf = np.zeros(shape=(3, 3)) if self.get_spacegroup_symbol().startswith("C"): transf[2] = [0, 0, 1] a, b = sorted(latt.abc[:2]) sorted_dic = sorted([{ 'vec': latt.matrix[i], 'length': latt.abc[i], 'orig_index': i } for i in [0, 1]], key=lambda k: k['length']) for i in range(2): transf[i][sorted_dic[i]['orig_index']] = 1 c = latt.abc[2] else: for i in range(len(sorted_dic)): transf[i][sorted_dic[i]['orig_index']] = 1 a, b, c = sorted_lengths latt = Lattice.orthorhombic(a, b, c) elif latt_type == "tetragonal": #find the "a" vectors #it is basically the vector repeated two times transf = np.zeros(shape=(3, 3)) a, b, c = sorted_lengths for d in range(len(sorted_dic)): transf[d][sorted_dic[d]['orig_index']] = 1 if abs(b - c) < tol: a, c = c, a transf = np.dot([[0, 0, 1], [0, 1, 0], [1, 0, 0]], transf) latt = Lattice.tetragonal(a, c) elif latt_type in ("hexagonal", "rhombohedral"): #for the conventional cell representation, #we allways show the rhombohedral lattices as hexagonal #check first if we have the refined structure shows a rhombohedral #cell #if so, make a supercell a, b, c = latt.abc if np.all(np.abs([a - b, c - b, a - c]) < 0.001): struct.make_supercell(((1, -1, 0), (0, 1, -1), (1, 1, 1))) a, b, c = sorted(struct.lattice.abc) if abs(b - c) < 0.001: a, c = c, a new_matrix = [[a / 2, -a * math.sqrt(3) / 2, 0], [a / 2, a * math.sqrt(3) / 2, 0], [0, 0, c]] latt = Lattice(new_matrix) transf = np.eye(3, 3) elif latt_type == "monoclinic": #you want to keep the c axis where it is #to keep the C- settings if self.get_spacegroup().int_symbol.startswith("C"): transf = np.zeros(shape=(3, 3)) transf[2] = [0, 0, 1] sorted_dic = sorted([{ 'vec': latt.matrix[i], 'length': latt.abc[i], 'orig_index': i } for i in [0, 1]], key=lambda k: k['length']) a = sorted_dic[0]['length'] b = sorted_dic[1]['length'] c = latt.abc[2] new_matrix = None for t in itertools.permutations(list(range(2)), 2): m = latt.matrix landang = Lattice([m[t[0]], m[t[1]], m[2]]).lengths_and_angles if landang[1][0] > 90: #if the angle is > 90 we invert a and b to get #an angle < 90 landang = Lattice([-m[t[0]], -m[t[1]], m[2]]).lengths_and_angles transf = np.zeros(shape=(3, 3)) transf[0][t[0]] = -1 transf[1][t[1]] = -1 transf[2][2] = 1 a, b, c = landang[0] alpha = math.pi * landang[1][0] / 180 new_matrix = [[a, 0, 0], [0, b, 0], [0, c * cos(alpha), c * sin(alpha)]] continue elif landang[1][0] < 90: transf = np.zeros(shape=(3, 3)) transf[0][t[0]] = 1 transf[1][t[1]] = 1 transf[2][2] = 1 a, b, c = landang[0] alpha = math.pi * landang[1][0] / 180 new_matrix = [[a, 0, 0], [0, b, 0], [0, c * cos(alpha), c * sin(alpha)]] if new_matrix is None: #this if is to treat the case #where alpha==90 (but we still have a monoclinic sg new_matrix = [[a, 0, 0], [0, b, 0], [0, 0, c]] transf = np.zeros(shape=(3, 3)) for c in range(len(sorted_dic)): transf[c][sorted_dic[c]['orig_index']] = 1 #if not C-setting else: #try all permutations of the axis #keep the ones with the non-90 angle=alpha #and b<c new_matrix = None for t in itertools.permutations(list(range(3)), 3): m = latt.matrix landang = Lattice([m[t[0]], m[t[1]], m[t[2]]]).lengths_and_angles if landang[1][0] > 90 and landang[0][1] < landang[0][2]: landang = Lattice([-m[t[0]], -m[t[1]], m[t[2]]]).lengths_and_angles transf = np.zeros(shape=(3, 3)) transf[0][t[0]] = -1 transf[1][t[1]] = -1 transf[2][t[2]] = 1 a, b, c = landang[0] alpha = math.pi * landang[1][0] / 180 new_matrix = [[a, 0, 0], [0, b, 0], [0, c * cos(alpha), c * sin(alpha)]] continue elif landang[1][0] < 90 and landang[0][1] < landang[0][2]: transf = np.zeros(shape=(3, 3)) transf[0][t[0]] = 1 transf[1][t[1]] = 1 transf[2][t[2]] = 1 a, b, c = landang[0] alpha = math.pi * landang[1][0] / 180 new_matrix = [[a, 0, 0], [0, b, 0], [0, c * cos(alpha), c * sin(alpha)]] if new_matrix is None: #this if is to treat the case #where alpha==90 (but we still have a monoclinic sg new_matrix = [[sorted_lengths[0], 0, 0], [0, sorted_lengths[1], 0], [0, 0, sorted_lengths[2]]] transf = np.zeros(shape=(3, 3)) for c in range(len(sorted_dic)): transf[c][sorted_dic[c]['orig_index']] = 1 if international_monoclinic: # The above code makes alpha the non-right angle. # The following will convert to proper international convention # that beta is the non-right angle. op = [[0, 1, 0], [1, 0, 0], [0, 0, -1]] transf = np.dot(op, transf) new_matrix = np.dot(op, new_matrix) beta = Lattice(new_matrix).beta if beta < 90: op = [[-1, 0, 0], [0, -1, 0], [0, 0, 1]] transf = np.dot(op, transf) new_matrix = np.dot(op, new_matrix) latt = Lattice(new_matrix) elif latt_type == "triclinic": #we use a LLL Minkowski-like reduction for the triclinic cells struct = struct.get_reduced_structure("LLL") a, b, c = latt.lengths_and_angles[0] alpha, beta, gamma = [ math.pi * i / 180 for i in latt.lengths_and_angles[1] ] new_matrix = None test_matrix = [ [a, 0, 0], [b * cos(gamma), b * sin(gamma), 0.0], [ c * cos(beta), c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), c * math.sqrt( sin(gamma)**2 - cos(alpha)**2 - cos(beta)**2 + 2 * cos(alpha) * cos(beta) * cos(gamma)) / sin(gamma) ] ] def is_all_acute_or_obtuse(m): recp_angles = np.array(Lattice(m).reciprocal_lattice.angles) return np.all(recp_angles <= 90) or np.all(recp_angles > 90) if is_all_acute_or_obtuse(test_matrix): transf = np.eye(3) new_matrix = test_matrix test_matrix = [ [-a, 0, 0], [b * cos(gamma), b * sin(gamma), 0.0], [ -c * cos(beta), -c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), -c * math.sqrt( sin(gamma)**2 - cos(alpha)**2 - cos(beta)**2 + 2 * cos(alpha) * cos(beta) * cos(gamma)) / sin(gamma) ] ] if is_all_acute_or_obtuse(test_matrix): transf = [[-1, 0, 0], [0, 1, 0], [0, 0, -1]] new_matrix = test_matrix test_matrix = [ [-a, 0, 0], [-b * cos(gamma), -b * sin(gamma), 0.0], [ c * cos(beta), c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), c * math.sqrt( sin(gamma)**2 - cos(alpha)**2 - cos(beta)**2 + 2 * cos(alpha) * cos(beta) * cos(gamma)) / sin(gamma) ] ] if is_all_acute_or_obtuse(test_matrix): transf = [[-1, 0, 0], [0, -1, 0], [0, 0, 1]] new_matrix = test_matrix test_matrix = [ [a, 0, 0], [-b * cos(gamma), -b * sin(gamma), 0.0], [ -c * cos(beta), -c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), -c * math.sqrt( sin(gamma)**2 - cos(alpha)**2 - cos(beta)**2 + 2 * cos(alpha) * cos(beta) * cos(gamma)) / sin(gamma) ] ] if is_all_acute_or_obtuse(test_matrix): transf = [[1, 0, 0], [0, -1, 0], [0, 0, -1]] new_matrix = test_matrix latt = Lattice(new_matrix) new_coords = np.dot(transf, np.transpose(struct.frac_coords)).T new_struct = Structure(latt, struct.species_and_occu, new_coords, site_properties=struct.site_properties, to_unit_cell=True) return new_struct.get_sorted_structure()
def test_kpath_acentered(self): species = ["K", "La", "Ti"] coords = [[0.345, 5, 0.77298], [0.1345, 5.1, 0.77298], [0.7, 0.8, 0.9]] lattice = Lattice.orthorhombic(2, 9, 1) struct = Structure.from_spacegroup(38, lattice, species, coords) kpath = KPathSeek(struct) kpoints = kpath._kpath["kpoints"] labels = list(kpoints.keys()) self.assertEqual( sorted(labels), sorted( ["B_0", "B_2", "DELTA_0", "F_0", "GAMMA", "G_0", "G_2", "R", "R_2", "S", "T", "T_2", "Y", "Z", "Z_2"] ), ) self.assertAlmostEqual(kpoints["GAMMA"][0], 0.0) self.assertAlmostEqual(kpoints["GAMMA"][1], 0.0) self.assertAlmostEqual(kpoints["GAMMA"][2], 0.0) self.assertAlmostEqual(kpoints["Y"][0], 0.5) self.assertAlmostEqual(kpoints["Y"][1], 0.5) self.assertAlmostEqual(kpoints["Y"][2], 0.0) self.assertAlmostEqual(kpoints["T"][0], 0.5) self.assertAlmostEqual(kpoints["T"][1], 0.5) self.assertAlmostEqual(kpoints["T"][2], 0.5) self.assertAlmostEqual(kpoints["T_2"][0], 0.5) self.assertAlmostEqual(kpoints["T_2"][1], 0.5) self.assertAlmostEqual(kpoints["T_2"][2], -0.5) self.assertAlmostEqual(kpoints["Z"][0], 0.0) self.assertAlmostEqual(kpoints["Z"][1], 0.0) self.assertAlmostEqual(kpoints["Z"][2], 0.5) self.assertAlmostEqual(kpoints["Z_2"][0], 0.0) self.assertAlmostEqual(kpoints["Z_2"][1], 0.0) self.assertAlmostEqual(kpoints["Z_2"][2], -0.5) self.assertAlmostEqual(kpoints["S"][0], 0.0) self.assertAlmostEqual(kpoints["S"][1], 0.5) self.assertAlmostEqual(kpoints["S"][2], 0.0) self.assertAlmostEqual(kpoints["R"][0], 0.0) self.assertAlmostEqual(kpoints["R"][1], 0.5) self.assertAlmostEqual(kpoints["R"][2], 0.5) self.assertAlmostEqual(kpoints["R_2"][0], 0.0) self.assertAlmostEqual(kpoints["R_2"][1], 0.5) self.assertAlmostEqual(kpoints["R_2"][2], -0.5) self.assertAlmostEqual(kpoints["DELTA_0"][0], -0.25308641975308643) self.assertAlmostEqual(kpoints["DELTA_0"][1], 0.25308641975308643) self.assertAlmostEqual(kpoints["DELTA_0"][2], 0.0) self.assertAlmostEqual(kpoints["F_0"][0], 0.25308641975308643) self.assertAlmostEqual(kpoints["F_0"][1], 0.7469135802469136) self.assertAlmostEqual(kpoints["F_0"][2], 0.0) self.assertAlmostEqual(kpoints["B_0"][0], -0.25308641975308643) self.assertAlmostEqual(kpoints["B_0"][1], 0.25308641975308643) self.assertAlmostEqual(kpoints["B_0"][2], 0.5) self.assertAlmostEqual(kpoints["B_2"][0], -0.25308641975308643) self.assertAlmostEqual(kpoints["B_2"][1], 0.25308641975308643) self.assertAlmostEqual(kpoints["B_2"][2], -0.5) self.assertAlmostEqual(kpoints["G_0"][0], 0.25308641975308643) self.assertAlmostEqual(kpoints["G_0"][1], 0.7469135802469136) self.assertAlmostEqual(kpoints["G_0"][2], 0.5) self.assertAlmostEqual(kpoints["G_2"][0], 0.25308641975308643) self.assertAlmostEqual(kpoints["G_2"][1], 0.7469135802469136) self.assertAlmostEqual(kpoints["G_2"][2], -0.5)
def get_conventional_standard_structure( self, international_monoclinic=True): """ Gives a structure with a conventional cell according to certain standards. The standards are defined in Setyawan, W., & Curtarolo, S. (2010). High-throughput electronic band structure calculations: Challenges and tools. Computational Materials Science, 49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010 They basically enforce as much as possible norm(a1)<norm(a2)<norm(a3) Returns: The structure in a conventional standardized cell """ tol = 1e-5 struct = self.get_refined_structure() latt = struct.lattice latt_type = self.get_lattice_type() sorted_lengths = sorted(latt.abc) sorted_dic = sorted([{'vec': latt.matrix[i], 'length': latt.abc[i], 'orig_index': i} for i in [0, 1, 2]], key=lambda k: k['length']) if latt_type in ("orthorhombic", "cubic"): #you want to keep the c axis where it is #to keep the C- settings transf = np.zeros(shape=(3, 3)) if self.get_spacegroup_symbol().startswith("C"): transf[2] = [0, 0, 1] a, b = sorted(latt.abc[:2]) sorted_dic = sorted([{'vec': latt.matrix[i], 'length': latt.abc[i], 'orig_index': i} for i in [0, 1]], key=lambda k: k['length']) for i in range(2): transf[i][sorted_dic[i]['orig_index']] = 1 c = latt.abc[2] else: for i in range(len(sorted_dic)): transf[i][sorted_dic[i]['orig_index']] = 1 a, b, c = sorted_lengths latt = Lattice.orthorhombic(a, b, c) elif latt_type == "tetragonal": #find the "a" vectors #it is basically the vector repeated two times transf = np.zeros(shape=(3, 3)) a, b, c = sorted_lengths for d in range(len(sorted_dic)): transf[d][sorted_dic[d]['orig_index']] = 1 if abs(b - c) < tol: a, c = c, a transf = np.dot([[0, 0, 1], [0, 1, 0], [1, 0, 0]], transf) latt = Lattice.tetragonal(a, c) elif latt_type in ("hexagonal", "rhombohedral"): #for the conventional cell representation, #we allways show the rhombohedral lattices as hexagonal #check first if we have the refined structure shows a rhombohedral #cell #if so, make a supercell a, b, c = latt.abc if np.all(np.abs([a - b, c - b, a - c]) < 0.001): struct.make_supercell(((1, -1, 0), (0, 1, -1), (1, 1, 1))) a, b, c = sorted(struct.lattice.abc) if abs(b - c) < 0.001: a, c = c, a new_matrix = [[a / 2, -a * math.sqrt(3) / 2, 0], [a / 2, a * math.sqrt(3) / 2, 0], [0, 0, c]] latt = Lattice(new_matrix) transf = np.eye(3, 3) elif latt_type == "monoclinic": #you want to keep the c axis where it is #to keep the C- settings if self.get_spacegroup().int_symbol.startswith("C"): transf = np.zeros(shape=(3, 3)) transf[2] = [0, 0, 1] sorted_dic = sorted([{'vec': latt.matrix[i], 'length': latt.abc[i], 'orig_index': i} for i in [0, 1]], key=lambda k: k['length']) a = sorted_dic[0]['length'] b = sorted_dic[1]['length'] c = latt.abc[2] new_matrix = None for t in itertools.permutations(list(range(2)), 2): m = latt.matrix landang = Lattice( [m[t[0]], m[t[1]], m[2]]).lengths_and_angles if landang[1][0] > 90: #if the angle is > 90 we invert a and b to get #an angle < 90 landang = Lattice( [-m[t[0]], -m[t[1]], m[2]]).lengths_and_angles transf = np.zeros(shape=(3, 3)) transf[0][t[0]] = -1 transf[1][t[1]] = -1 transf[2][2] = 1 a, b, c = landang[0] alpha = math.pi * landang[1][0] / 180 new_matrix = [[a, 0, 0], [0, b, 0], [0, c * cos(alpha), c * sin(alpha)]] continue elif landang[1][0] < 90: transf = np.zeros(shape=(3, 3)) transf[0][t[0]] = 1 transf[1][t[1]] = 1 transf[2][2] = 1 a, b, c = landang[0] alpha = math.pi * landang[1][0] / 180 new_matrix = [[a, 0, 0], [0, b, 0], [0, c * cos(alpha), c * sin(alpha)]] if new_matrix is None: #this if is to treat the case #where alpha==90 (but we still have a monoclinic sg new_matrix = [[a, 0, 0], [0, b, 0], [0, 0, c]] transf = np.zeros(shape=(3, 3)) for c in range(len(sorted_dic)): transf[c][sorted_dic[c]['orig_index']] = 1 #if not C-setting else: #try all permutations of the axis #keep the ones with the non-90 angle=alpha #and b<c new_matrix = None for t in itertools.permutations(list(range(3)), 3): m = latt.matrix landang = Lattice( [m[t[0]], m[t[1]], m[t[2]]]).lengths_and_angles if landang[1][0] > 90 and landang[0][1] < landang[0][2]: landang = Lattice( [-m[t[0]], -m[t[1]], m[t[2]]]).lengths_and_angles transf = np.zeros(shape=(3, 3)) transf[0][t[0]] = -1 transf[1][t[1]] = -1 transf[2][t[2]] = 1 a, b, c = landang[0] alpha = math.pi * landang[1][0] / 180 new_matrix = [[a, 0, 0], [0, b, 0], [0, c * cos(alpha), c * sin(alpha)]] continue elif landang[1][0] < 90 and landang[0][1] < landang[0][2]: transf = np.zeros(shape=(3, 3)) transf[0][t[0]] = 1 transf[1][t[1]] = 1 transf[2][t[2]] = 1 a, b, c = landang[0] alpha = math.pi * landang[1][0] / 180 new_matrix = [[a, 0, 0], [0, b, 0], [0, c * cos(alpha), c * sin(alpha)]] if new_matrix is None: #this if is to treat the case #where alpha==90 (but we still have a monoclinic sg new_matrix = [[sorted_lengths[0], 0, 0], [0, sorted_lengths[1], 0], [0, 0, sorted_lengths[2]]] transf = np.zeros(shape=(3, 3)) for c in range(len(sorted_dic)): transf[c][sorted_dic[c]['orig_index']] = 1 if international_monoclinic: # The above code makes alpha the non-right angle. # The following will convert to proper international convention # that beta is the non-right angle. op = [[0, 1, 0], [1, 0, 0], [0, 0, -1]] transf = np.dot(op, transf) new_matrix = np.dot(op, new_matrix) beta = Lattice(new_matrix).beta if beta < 90: op = [[-1, 0, 0], [0, -1, 0], [0, 0, 1]] transf = np.dot(op, transf) new_matrix = np.dot(op, new_matrix) latt = Lattice(new_matrix) elif latt_type == "triclinic": #we use a LLL Minkowski-like reduction for the triclinic cells struct = struct.get_reduced_structure("LLL") a, b, c = latt.lengths_and_angles[0] alpha, beta, gamma = [math.pi * i / 180 for i in latt.lengths_and_angles[1]] new_matrix = None test_matrix = [[a, 0, 0], [b * cos(gamma), b * sin(gamma), 0.0], [c * cos(beta), c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), c * math.sqrt(sin(gamma) ** 2 - cos(alpha) ** 2 - cos(beta) ** 2 + 2 * cos(alpha) * cos(beta) * cos(gamma)) / sin(gamma)]] def is_all_acute_or_obtuse(m): recp_angles = np.array(Lattice(m).reciprocal_lattice.angles) return np.all(recp_angles <= 90) or np.all(recp_angles > 90) if is_all_acute_or_obtuse(test_matrix): transf = np.eye(3) new_matrix = test_matrix test_matrix = [[-a, 0, 0], [b * cos(gamma), b * sin(gamma), 0.0], [-c * cos(beta), -c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), -c * math.sqrt(sin(gamma) ** 2 - cos(alpha) ** 2 - cos(beta) ** 2 + 2 * cos(alpha) * cos(beta) * cos(gamma)) / sin(gamma)]] if is_all_acute_or_obtuse(test_matrix): transf = [[-1, 0, 0], [0, 1, 0], [0, 0, -1]] new_matrix = test_matrix test_matrix = [[-a, 0, 0], [-b * cos(gamma), -b * sin(gamma), 0.0], [c * cos(beta), c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), c * math.sqrt(sin(gamma) ** 2 - cos(alpha) ** 2 - cos(beta) ** 2 + 2 * cos(alpha) * cos(beta) * cos(gamma)) / sin(gamma)]] if is_all_acute_or_obtuse(test_matrix): transf = [[-1, 0, 0], [0, -1, 0], [0, 0, 1]] new_matrix = test_matrix test_matrix = [[a, 0, 0], [-b * cos(gamma), -b * sin(gamma), 0.0], [-c * cos(beta), -c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), -c * math.sqrt(sin(gamma) ** 2 - cos(alpha) ** 2 - cos(beta) ** 2 + 2 * cos(alpha) * cos(beta) * cos(gamma)) / sin(gamma)]] if is_all_acute_or_obtuse(test_matrix): transf = [[1, 0, 0], [0, -1, 0], [0, 0, -1]] new_matrix = test_matrix latt = Lattice(new_matrix) new_coords = np.dot(transf, np.transpose(struct.frac_coords)).T new_struct = Structure(latt, struct.species_and_occu, new_coords, site_properties=struct.site_properties, to_unit_cell=True) return new_struct.get_sorted_structure()