1# coding: utf-8
2# Copyright (c) Pymatgen Development Team.
3# Distributed under the terms of the MIT License.
4
5
6import os
7import unittest
8
9import numpy as np
10
11from pymatgen.analysis.magnetism.analyzer import CollinearMagneticStructureAnalyzer
12from pymatgen.core.lattice import Lattice
13from pymatgen.core.structure import Structure
14from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
15from pymatgen.symmetry.kpath import KPathLatimerMunro
16from pymatgen.util.testing import PymatgenTest
17
18
19test_dir_structs = PymatgenTest.TEST_FILES_DIR
20
21
22class KPathLatimerMunroTest(PymatgenTest):
23    def test_kpath_generation(self):
24        triclinic = [1, 2]
25        monoclinic = range(3, 16)
26        orthorhombic = range(16, 75)
27        tetragonal = range(75, 143)
28        rhombohedral = range(143, 168)
29        hexagonal = range(168, 195)
30        cubic = range(195, 231)
31
32        species = ["K", "La", "Ti"]
33        coords = [[0.345, 5, 0.77298], [0.1345, 5.1, 0.77298], [0.7, 0.8, 0.9]]
34        for i in range(230):
35            sg_num = i + 1
36            if sg_num in triclinic:
37                lattice = Lattice(
38                    [
39                        [3.0233057319441246, 1, 0],
40                        [0, 7.9850357844548681, 1],
41                        [0, 1.2, 8.1136762279561818],
42                    ]
43                )
44            elif sg_num in monoclinic:
45                lattice = Lattice.monoclinic(2, 9, 1, 99)
46            elif sg_num in orthorhombic:
47                lattice = Lattice.orthorhombic(2, 9, 1)
48            elif sg_num in tetragonal:
49                lattice = Lattice.tetragonal(2, 9)
50            elif sg_num in rhombohedral:
51                lattice = Lattice.hexagonal(2, 95)
52            elif sg_num in hexagonal:
53                lattice = Lattice.hexagonal(2, 9)
54            elif sg_num in cubic:
55                lattice = Lattice.cubic(2)
56
57            struct = Structure.from_spacegroup(sg_num, lattice, species, coords)
58            kpath = KPathLatimerMunro(struct)  # Throws error if something doesn't work, causing test to fail.
59
60        struct_file_path = os.path.join(test_dir_structs, "AgO_kpath_test.cif")
61        struct = Structure.from_file(struct_file_path)
62        kpath = KPathLatimerMunro(struct)  # Throws error if something doesn't work, causing test to fail.
63
64    def test_kpath_acentered(self):
65        species = ["K", "La", "Ti"]
66        coords = [[0.345, 5, 0.77298], [0.1345, 5.1, 0.77298], [0.7, 0.8, 0.9]]
67        lattice = Lattice.orthorhombic(2, 9, 1)
68        struct = Structure.from_spacegroup(38, lattice, species, coords)
69        sga = SpacegroupAnalyzer(struct)
70        struct_prim = sga.get_primitive_standard_structure(international_monoclinic=False)
71        kpath = KPathLatimerMunro(struct_prim)
72
73        kpoints = kpath._kpath["kpoints"]
74        labels = list(kpoints.keys())
75
76        self.assertEqual(
77            sorted(labels),
78            sorted(["a", "b", "c", "d", "d_{1}", "e", "f", "q", "q_{1}", "Γ"]),
79        )
80
81        self.assertAlmostEqual(kpoints["a"][0], 0.0)
82        self.assertAlmostEqual(kpoints["a"][1], 0.4999999999999997)
83        self.assertAlmostEqual(kpoints["a"][2], 0.0)
84
85        self.assertAlmostEqual(kpoints["f"][0], -0.49999999999999933)
86        self.assertAlmostEqual(kpoints["f"][1], 0.4999999999999992)
87        self.assertAlmostEqual(kpoints["f"][2], 0.4999999999999999)
88
89        self.assertAlmostEqual(kpoints["c"][0], 0.0)
90        self.assertAlmostEqual(kpoints["c"][1], 0.0)
91        self.assertAlmostEqual(kpoints["c"][2], 0.5)
92
93        self.assertAlmostEqual(kpoints["b"][0], -0.5000000000000002)
94        self.assertAlmostEqual(kpoints["b"][1], 0.500000000000000)
95        self.assertAlmostEqual(kpoints["b"][2], 0.0)
96
97        self.assertAlmostEqual(kpoints["Γ"][0], 0)
98        self.assertAlmostEqual(kpoints["Γ"][1], 0)
99        self.assertAlmostEqual(kpoints["Γ"][2], 0)
100
101        self.assertAlmostEqual(kpoints["e"][0], 0.0)
102        self.assertAlmostEqual(kpoints["e"][1], 0.49999999999999956)
103        self.assertAlmostEqual(kpoints["e"][2], 0.5000000000000002)
104
105        d = False
106        if np.allclose(kpoints["d_{1}"], [0.2530864197530836, 0.25308641975308915, 0.0], atol=1e-5) or np.allclose(
107            kpoints["d"], [0.2530864197530836, 0.25308641975308915, 0.0], atol=1e-5
108        ):
109            d = True
110
111        self.assertTrue(d)
112
113        q = False
114        if np.allclose(kpoints["q_{1}"], [0.2530864197530836, 0.25308641975308915, 0.5], atol=1e-5) or np.allclose(
115            kpoints["q"], [0.2530864197530836, 0.25308641975308915, 0.5], atol=1e-5
116        ):
117            q = True
118
119        self.assertTrue(q)
120
121    def test_magnetic_kpath_generation(self):
122        struct_file_path = os.path.join(test_dir_structs, "LaMnO3_magnetic.mcif")
123        struct = Structure.from_file(struct_file_path)
124        mga = CollinearMagneticStructureAnalyzer(struct)
125        col_spin_orig = mga.get_structure_with_spin()
126        col_spin_orig.add_spin_by_site([0.0] * 20)
127        col_spin_sym = SpacegroupAnalyzer(col_spin_orig)
128        col_spin_prim = col_spin_sym.get_primitive_standard_structure(international_monoclinic=False)
129
130        magmom_vec_list = [np.zeros(3) for site in col_spin_prim]
131        magmom_vec_list[4:8] = [
132            np.array([3.87, 3.87, 0.0]),
133            np.array([3.87, 3.87, 0.0]),
134            np.array([-3.87, -3.87, 0.0]),
135            np.array([-3.87, -3.87, 0.0]),
136        ]
137        col_spin_prim.add_site_property("magmom", magmom_vec_list)
138
139        kpath = KPathLatimerMunro(col_spin_prim, has_magmoms=True)
140
141        kpoints = kpath._kpath["kpoints"]
142        labels = list(kpoints.keys())
143
144        self.assertEqual(
145            sorted(labels),
146            sorted(["a", "b", "c", "d", "d_{1}", "e", "f", "g", "g_{1}", "Γ"]),
147        )
148
149        self.assertAlmostEqual(kpoints["e"][0], -0.4999999999999998)
150        self.assertAlmostEqual(kpoints["e"][1], 0.0)
151        self.assertAlmostEqual(kpoints["e"][2], 0.5000000000000002)
152
153        self.assertAlmostEqual(kpoints["g"][0], -0.4999999999999999)
154        self.assertAlmostEqual(kpoints["g"][1], -0.49999999999999994)
155        self.assertAlmostEqual(kpoints["g"][2], 0.5000000000000002)
156
157        self.assertAlmostEqual(kpoints["a"][0], -0.4999999999999999)
158        self.assertAlmostEqual(kpoints["a"][1], 0.0)
159        self.assertAlmostEqual(kpoints["a"][2], 0.0)
160
161        self.assertAlmostEqual(kpoints["g_{1}"][0], 0.4999999999999999)
162        self.assertAlmostEqual(kpoints["g_{1}"][1], -0.5)
163        self.assertAlmostEqual(kpoints["g_{1}"][2], 0.5000000000000001)
164
165        self.assertAlmostEqual(kpoints["f"][0], 0.0)
166        self.assertAlmostEqual(kpoints["f"][1], -0.5)
167        self.assertAlmostEqual(kpoints["f"][2], 0.5000000000000002)
168
169        self.assertAlmostEqual(kpoints["c"][0], 0.0)
170        self.assertAlmostEqual(kpoints["c"][1], 0.0)
171        self.assertAlmostEqual(kpoints["c"][2], 0.5000000000000001)
172
173        self.assertAlmostEqual(kpoints["b"][0], 0.0)
174        self.assertAlmostEqual(kpoints["b"][1], -0.5)
175        self.assertAlmostEqual(kpoints["b"][2], 0.0)
176
177        self.assertAlmostEqual(kpoints["Γ"][0], 0)
178        self.assertAlmostEqual(kpoints["Γ"][1], 0)
179        self.assertAlmostEqual(kpoints["Γ"][2], 0)
180
181        d = False
182        if np.allclose(kpoints["d_{1}"], [-0.5, -0.5, 0.0], atol=1e-5) or np.allclose(
183            kpoints["d"], [-0.5, -0.5, 0.0], atol=1e-5
184        ):
185            d = True
186
187        self.assertTrue(d)
188
189        g = False
190        if np.allclose(kpoints["g_{1}"], [-0.5, -0.5, 0.5], atol=1e-5) or np.allclose(
191            kpoints["g"], [-0.5, -0.5, 0.5], atol=1e-5
192        ):
193            g = True
194
195        self.assertTrue(g)
196
197
198if __name__ == "__main__":
199    unittest.main()
200