• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

materialsproject / pymatgen / 4075885785

pending completion
4075885785

push

github

Shyue Ping Ong
Merge branch 'master' of github.com:materialsproject/pymatgen

96 of 96 new or added lines in 27 files covered. (100.0%)

81013 of 102710 relevant lines covered (78.88%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.3
/pymatgen/analysis/tests/test_structure_analyzer.py
1
# Copyright (c) Pymatgen Development Team.
2
# Distributed under the terms of the MIT License.
3

4

5
from __future__ import annotations
1✔
6

7
import os
1✔
8
import unittest
1✔
9

10
import numpy as np
1✔
11
from pytest import approx
1✔
12

13
from pymatgen.analysis.structure_analyzer import (
1✔
14
    RelaxationAnalyzer,
15
    VoronoiAnalyzer,
16
    VoronoiConnectivity,
17
    average_coordination_number,
18
    contains_peroxide,
19
    oxide_type,
20
    solid_angle,
21
    sulfide_type,
22
)
23
from pymatgen.core.lattice import Lattice
1✔
24
from pymatgen.core.periodic_table import Element
1✔
25
from pymatgen.core.structure import Structure
1✔
26
from pymatgen.io.vasp.inputs import Poscar
1✔
27
from pymatgen.io.vasp.outputs import Xdatcar
1✔
28
from pymatgen.util.testing import PymatgenTest
1✔
29

30

31
class VoronoiAnalyzerTest(PymatgenTest):
1✔
32
    _multiprocess_shared_ = True
1✔
33

34
    def setUp(self):
1✔
35
        self.ss = Xdatcar(os.path.join(PymatgenTest.TEST_FILES_DIR, "XDATCAR.MD")).structures
1✔
36
        self.s = self.ss[1]
1✔
37
        self.va = VoronoiAnalyzer(cutoff=4.0)
1✔
38

39
    def test_analyze(self):
1✔
40
        # Check for the Voronoi index of site i in Structure
41
        single_structure = self.va.analyze(self.s, n=5)
1✔
42
        assert single_structure.view() in np.array([4, 3, 3, 4, 2, 2, 1, 0]).view(), "Cannot find the right polyhedron."
1✔
43
        # Check for the presence of a Voronoi index and its frequency in
44
        # a ensemble (list) of Structures
45
        ensemble = self.va.analyze_structures(self.ss, step_freq=2, most_frequent_polyhedra=10)
1✔
46
        assert ("[1 3 4 7 1 0 0 0]", 3) in ensemble, "Cannot find the right polyhedron in ensemble."
1✔
47

48

49
class RelaxationAnalyzerTest(unittest.TestCase):
1✔
50
    def setUp(self):
1✔
51
        p = Poscar.from_file(os.path.join(PymatgenTest.TEST_FILES_DIR, "POSCAR.Li2O"), check_for_POTCAR=False)
1✔
52
        s1 = p.structure
1✔
53
        p = Poscar.from_file(os.path.join(PymatgenTest.TEST_FILES_DIR, "CONTCAR.Li2O"), check_for_POTCAR=False)
1✔
54
        s2 = p.structure
1✔
55
        self.analyzer = RelaxationAnalyzer(s1, s2)
1✔
56

57
    def test_vol_and_para_changes(self):
1✔
58
        for v in self.analyzer.get_percentage_lattice_parameter_changes().values():
1✔
59
            assert -0.0092040921155279731 == approx(v)
1✔
60
            latt_change = v
1✔
61
        vol_change = self.analyzer.get_percentage_volume_change()
1✔
62
        assert -0.0273589101391 == approx(vol_change)
1✔
63
        # This is a simple cubic cell, so the latt and vol change are simply
64
        # Related. So let's test that.
65
        assert (1 + latt_change) ** 3 - 1 == approx(vol_change)
1✔
66

67
    def test_get_percentage_bond_dist_changes(self):
1✔
68
        for v in self.analyzer.get_percentage_bond_dist_changes().values():
1✔
69
            for v2 in v.values():
1✔
70
                assert -0.009204092115527862 == approx(v2)
1✔
71

72

73
class VoronoiConnectivityTest(PymatgenTest):
1✔
74
    def test_connectivity_array(self):
1✔
75
        vc = VoronoiConnectivity(self.get_structure("LiFePO4"))
1✔
76
        ca = vc.connectivity_array
1✔
77
        expected = np.array([0, 1.96338392, 0, 0.04594495])
1✔
78
        assert np.allclose(ca[15, :4, ca.shape[2] // 2], expected)
1✔
79

80
        expected = np.array([0, 0, 0])
1✔
81
        assert np.allclose(ca[1, -3:, 51], expected)
1✔
82

83
        site = vc.get_sitej(27, 51)
1✔
84
        assert site.specie == Element("O")
1✔
85
        expected = np.array([-0.29158, 0.74889, 0.95684])
1✔
86
        assert np.allclose(site.frac_coords, expected)
1✔
87

88

89
class MiscFunctionTest(PymatgenTest):
1✔
90
    def test_average_coordination_number(self):
1✔
91
        xdatcar = Xdatcar(os.path.join(PymatgenTest.TEST_FILES_DIR, "XDATCAR.MD"))
1✔
92
        coordination_numbers = average_coordination_number(xdatcar.structures, freq=1)
1✔
93
        assert coordination_numbers["Fe"] == approx(
1✔
94
            4.771903318390836, 5
95
        ), "Coordination number not calculated properly."
96

97
    def test_solid_angle(self):
1✔
98
        center = [2.294508207929496, 4.4078057081404, 2.299997773791287]
1✔
99
        coords = [
1✔
100
            [1.627286218099362, 3.081185538926995, 3.278749383217061],
101
            [1.776793751092763, 2.93741167455471, 3.058701096568852],
102
            [3.318412187495734, 2.997331084033472, 2.022167590167672],
103
            [3.874524708023352, 4.425301459451914, 2.771990305592935],
104
            [2.055778446743566, 4.437449313863041, 4.061046832034642],
105
        ]
106
        assert solid_angle(center, coords) == approx(1.83570965938, abs=1e-7), "Wrong result returned by solid_angle"
1✔
107

108
    def test_contains_peroxide(self):
1✔
109
        for f in ["LiFePO4", "NaFePO4", "Li3V2(PO4)3", "Li2O"]:
1✔
110
            assert not contains_peroxide(self.get_structure(f))
1✔
111

112
        for f in ["Li2O2", "K2O2"]:
1✔
113
            assert contains_peroxide(self.get_structure(f))
1✔
114

115
    def test_oxide_type(self):
1✔
116
        el_li = Element("Li")
1✔
117
        el_o = Element("O")
1✔
118
        latt = Lattice([[3.985034, 0.0, 0.0], [0.0, 4.881506, 0.0], [0.0, 0.0, 2.959824]])
1✔
119
        elts = [el_li, el_li, el_o, el_o, el_o, el_o]
1✔
120
        coords = []
1✔
121
        coords.append([0.500000, 0.500000, 0.500000])
1✔
122
        coords.append([0.0, 0.0, 0.0])
1✔
123
        coords.append([0.632568, 0.085090, 0.500000])
1✔
124
        coords.append([0.367432, 0.914910, 0.500000])
1✔
125
        coords.append([0.132568, 0.414910, 0.000000])
1✔
126
        coords.append([0.867432, 0.585090, 0.000000])
1✔
127
        struct = Structure(latt, elts, coords)
1✔
128
        assert oxide_type(struct, 1.1) == "superoxide"
1✔
129

130
        el_li = Element("Li")
1✔
131
        el_o = Element("O")
1✔
132
        elts = [el_li, el_o, el_o, el_o]
1✔
133
        latt = Lattice.from_parameters(3.999911, 3.999911, 3.999911, 133.847504, 102.228244, 95.477342)
1✔
134
        coords = [
1✔
135
            [0.513004, 0.513004, 1.000000],
136
            [0.017616, 0.017616, 0.000000],
137
            [0.649993, 0.874790, 0.775203],
138
            [0.099587, 0.874790, 0.224797],
139
        ]
140
        struct = Structure(latt, elts, coords)
1✔
141
        assert oxide_type(struct, 1.1) == "ozonide"
1✔
142

143
        latt = Lattice.from_parameters(3.159597, 3.159572, 7.685205, 89.999884, 89.999674, 60.000510)
1✔
144
        el_li = Element("Li")
1✔
145
        el_o = Element("O")
1✔
146
        elts = [el_li, el_li, el_li, el_li, el_o, el_o, el_o, el_o]
1✔
147
        coords = [
1✔
148
            [0.666656, 0.666705, 0.750001],
149
            [0.333342, 0.333378, 0.250001],
150
            [0.000001, 0.000041, 0.500001],
151
            [0.000001, 0.000021, 0.000001],
152
            [0.333347, 0.333332, 0.649191],
153
            [0.333322, 0.333353, 0.850803],
154
            [0.666666, 0.666686, 0.350813],
155
            [0.666665, 0.666684, 0.149189],
156
        ]
157
        struct = Structure(latt, elts, coords)
1✔
158
        assert oxide_type(struct, 1.1) == "peroxide"
1✔
159

160
        el_li = Element("Li")
1✔
161
        el_o = Element("O")
1✔
162
        el_h = Element("H")
1✔
163
        latt = Lattice.from_parameters(3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000)
1✔
164
        elts = [el_h, el_h, el_li, el_li, el_o, el_o]
1✔
165
        coords = [
1✔
166
            [0.000000, 0.500000, 0.413969],
167
            [0.500000, 0.000000, 0.586031],
168
            [0.000000, 0.000000, 0.000000],
169
            [0.500000, 0.500000, 0.000000],
170
            [0.000000, 0.500000, 0.192672],
171
            [0.500000, 0.000000, 0.807328],
172
        ]
173
        struct = Structure(latt, elts, coords)
1✔
174
        assert oxide_type(struct, 1.1) == "hydroxide"
1✔
175

176
        el_li = Element("Li")
1✔
177
        el_n = Element("N")
1✔
178
        el_h = Element("H")
1✔
179
        latt = Lattice.from_parameters(3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000)
1✔
180
        elts = [el_h, el_h, el_li, el_li, el_n, el_n]
1✔
181
        coords = [
1✔
182
            [0.000000, 0.500000, 0.413969],
183
            [0.500000, 0.000000, 0.586031],
184
            [0.000000, 0.000000, 0.000000],
185
            [0.500000, 0.500000, 0.000000],
186
            [0.000000, 0.500000, 0.192672],
187
            [0.500000, 0.000000, 0.807328],
188
        ]
189
        struct = Structure(latt, elts, coords)
1✔
190
        assert oxide_type(struct, 1.1) == "None"
1✔
191

192
        el_o = Element("O")
1✔
193
        latt = Lattice.from_parameters(4.389828, 5.369789, 5.369789, 70.786622, 69.244828, 69.244828)
1✔
194
        elts = [el_o, el_o, el_o, el_o, el_o, el_o, el_o, el_o]
1✔
195
        coords = [
1✔
196
            [0.844609, 0.273459, 0.786089],
197
            [0.155391, 0.213911, 0.726541],
198
            [0.155391, 0.726541, 0.213911],
199
            [0.844609, 0.786089, 0.273459],
200
            [0.821680, 0.207748, 0.207748],
201
            [0.178320, 0.792252, 0.792252],
202
            [0.132641, 0.148222, 0.148222],
203
            [0.867359, 0.851778, 0.851778],
204
        ]
205
        struct = Structure(latt, elts, coords)
1✔
206
        assert oxide_type(struct, 1.1) == "None"
1✔
207

208
    def test_sulfide_type(self):
1✔
209
        # NaS2 -> polysulfide
210
        latt = Lattice.tetragonal(9.59650, 11.78850)
1✔
211
        species = ["Na"] * 2 + ["S"] * 2
1✔
212
        coords = [
1✔
213
            [0.00000, 0.00000, 0.17000],
214
            [0.27600, 0.25000, 0.12500],
215
            [0.03400, 0.25000, 0.29600],
216
            [0.14700, 0.11600, 0.40000],
217
        ]
218
        struct = Structure.from_spacegroup(122, latt, species, coords)
1✔
219
        assert sulfide_type(struct) == "polysulfide"
1✔
220

221
        # NaCl type NaS -> sulfide
222
        latt = Lattice.cubic(5.75)
1✔
223
        species = ["Na", "S"]
1✔
224
        coords = [[0.00000, 0.00000, 0.00000], [0.50000, 0.50000, 0.50000]]
1✔
225
        struct = Structure.from_spacegroup(225, latt, species, coords)
1✔
226
        assert sulfide_type(struct) == "sulfide"
1✔
227

228
        # Na2S2O3 -> None (sulfate)
229
        latt = Lattice.monoclinic(6.40100, 8.10000, 8.47400, 96.8800)
1✔
230
        species = ["Na"] * 2 + ["S"] * 2 + ["O"] * 3
1✔
231
        coords = [
1✔
232
            [0.29706, 0.62396, 0.08575],
233
            [0.37673, 0.30411, 0.45416],
234
            [0.52324, 0.10651, 0.21126],
235
            [0.29660, -0.04671, 0.26607],
236
            [0.17577, 0.03720, 0.38049],
237
            [0.38604, -0.20144, 0.33624],
238
            [0.16248, -0.08546, 0.11608],
239
        ]
240
        struct = Structure.from_spacegroup(14, latt, species, coords)
1✔
241
        assert sulfide_type(struct) is None
1✔
242

243
        # Na3PS3O -> sulfide
244
        latt = Lattice.orthorhombic(9.51050, 11.54630, 5.93230)
1✔
245
        species = ["Na"] * 2 + ["S"] * 2 + ["P", "O"]
1✔
246
        coords = [
1✔
247
            [0.19920, 0.11580, 0.24950],
248
            [0.00000, 0.36840, 0.29380],
249
            [0.32210, 0.36730, 0.22530],
250
            [0.50000, 0.11910, 0.27210],
251
            [0.50000, 0.29400, 0.35500],
252
            [0.50000, 0.30300, 0.61140],
253
        ]
254
        struct = Structure.from_spacegroup(36, latt, species, coords)
1✔
255
        assert sulfide_type(struct) == "sulfide"
1✔
256

257
        # test for unphysical cells
258
        struct.scale_lattice(struct.volume * 10)
1✔
259
        assert sulfide_type(struct) == "sulfide"
1✔
260

261

262
if __name__ == "__main__":
1✔
263
    unittest.main()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc