5
5
from pathlib import Path
6
6
7
7
import numpy as np
8
+ import pytest
8
9
from plotly .graph_objects import Figure
9
10
10
11
from pymatgen .analysis .chempot_diagram import (
23
24
class ChemicalPotentialDiagramTest (PymatgenTest ):
24
25
def setUp (self ):
25
26
self .entries = EntrySet .from_csv (str (module_dir / "pdentries_test.csv" ))
26
- self .cpd_ternary = ChemicalPotentialDiagram (entries = self .entries , default_min_limit = - 25 )
27
+ self .cpd_ternary = ChemicalPotentialDiagram (entries = self .entries , default_min_limit = - 25 , formal_chempots = False )
28
+ self .cpd_ternary_formal = ChemicalPotentialDiagram (
29
+ entries = self .entries , default_min_limit = - 25 , formal_chempots = True
30
+ )
27
31
elements = [Element ("Fe" ), Element ("O" )]
28
32
binary_entries = list (
29
33
filter (
30
34
lambda e : set (e .composition .elements ).issubset (elements ),
31
35
self .entries ,
32
36
)
33
37
)
34
- self .cpd_binary = ChemicalPotentialDiagram (entries = binary_entries , default_min_limit = - 25 )
38
+ self .cpd_binary = ChemicalPotentialDiagram (entries = binary_entries , default_min_limit = - 25 , formal_chempots = False )
35
39
warnings .simplefilter ("ignore" )
36
40
37
41
def tearDown (self ):
@@ -40,6 +44,7 @@ def tearDown(self):
40
44
def test_dim (self ):
41
45
assert self .cpd_binary .dim == 2
42
46
assert self .cpd_ternary .dim == 3
47
+ assert self .cpd_ternary_formal .dim == 3
43
48
44
49
def test_el_refs (self ):
45
50
el_refs = {elem : entry .energy for elem , entry in self .cpd_ternary .el_refs .items ()}
@@ -48,17 +53,26 @@ def test_el_refs(self):
48
53
energies = [- 1.91301487 , - 6.5961471 , - 25.54966885 ]
49
54
correct_el_refs = dict (zip (elems , energies ))
50
55
51
- self .assertDictsAlmostEqual (el_refs , correct_el_refs )
56
+ assert el_refs == pytest .approx (correct_el_refs )
57
+
58
+ def test_el_refs_formal (self ):
59
+ el_refs = {elem : entry .energy for elem , entry in self .cpd_ternary_formal .el_refs .items ()}
60
+ elems = [Element ("Li" ), Element ("Fe" ), Element ("O" )]
61
+ energies = [0 , 0 , 0 ]
62
+ correct_el_refs = dict (zip (elems , energies ))
63
+ assert el_refs == pytest .approx (correct_el_refs )
52
64
53
65
def test_border_hyperplanes (self ):
54
66
desired = np .array (
55
67
[[- 1 , 0 , 0 , - 25 ], [1 , 0 , 0 , 0 ], [0 , - 1 , 0 , - 25 ], [0 , 1 , 0 , 0 ], [0 , 0 , - 1 , - 25 ], [0 , 0 , 1 , 0 ]]
56
68
)
57
- self .assertArrayAlmostEqual (self .cpd_ternary .border_hyperplanes , desired )
69
+ assert self .cpd_ternary .border_hyperplanes == pytest .approx (desired )
70
+ assert self .cpd_ternary_formal .border_hyperplanes == pytest .approx (desired )
58
71
59
72
def test_lims (self ):
60
73
desired_lims = np .array ([[- 25 , 0 ], [- 25 , 0 ], [- 25 , 0 ]])
61
- self .assertArrayAlmostEqual (self .cpd_ternary .lims , desired_lims )
74
+ assert self .cpd_ternary .lims == pytest .approx (desired_lims )
75
+ assert self .cpd_ternary_formal .lims == pytest .approx (desired_lims )
62
76
63
77
def test_pca (self ):
64
78
points_3d = np .array (
@@ -80,7 +94,7 @@ def test_pca(self):
80
94
81
95
points_2d , _ , _ = simple_pca (points_3d , k = 2 )
82
96
83
- self . assertArrayAlmostEqual ( points_2d , points_2d_desired )
97
+ assert points_2d == pytest . approx ( points_2d_desired )
84
98
85
99
def test_centroid (self ):
86
100
vertices = np .array (
@@ -97,7 +111,7 @@ def test_centroid(self):
97
111
centroid = get_centroid_2d (vertices )
98
112
centroid_desired = np .array ([- 0.00069433 , - 0.00886174 ])
99
113
100
- self . assertArrayAlmostEqual ( centroid , centroid_desired )
114
+ assert centroid == pytest . approx ( centroid_desired , abs = 1e-6 )
101
115
102
116
def test_get_2d_orthonormal_vector (self ):
103
117
pts_1 = np .array ([[1 , 1 ], [2 , 2 ]])
@@ -109,18 +123,25 @@ def test_get_2d_orthonormal_vector(self):
109
123
vec_1_desired = np .array ([0.70710678 , 0.70710678 ])
110
124
vec_2_desired = np .array ([0.98386991 , 0.17888544 ])
111
125
112
- self . assertArrayAlmostEqual ( vec_1 , vec_1_desired )
113
- self . assertArrayAlmostEqual ( vec_2 , vec_2_desired )
126
+ assert vec_1 == pytest . approx ( vec_1_desired )
127
+ assert vec_2 == pytest . approx ( vec_2_desired )
114
128
115
129
def test_get_plot (self ):
116
130
fig_2d = self .cpd_binary .get_plot ()
117
131
fig_3d = self .cpd_ternary .get_plot ()
132
+ fig_3d_formal = self .cpd_ternary_formal .get_plot ()
118
133
119
134
assert isinstance (fig_2d , Figure )
120
- assert fig_2d [ " data" ] [0 ][ " type" ] == "scatter"
135
+ assert fig_2d . data [0 ]. type == "scatter"
121
136
122
137
assert isinstance (fig_3d , Figure )
123
- assert fig_3d ["data" ][0 ]["type" ] == "scatter3d"
138
+ assert fig_3d .data [0 ].type == "scatter3d"
139
+
140
+ assert isinstance (fig_3d_formal , Figure )
141
+ assert fig_3d_formal .data [0 ].type == "scatter3d"
142
+ assert fig_3d_formal .data [0 ].mode == "lines"
143
+ assert fig_3d_formal .layout .plot_bgcolor == "rgba(0,0,0,0)"
144
+ assert fig_3d_formal .layout .scene .annotations [0 ].text == "FeO"
124
145
125
146
def test_domains (self ):
126
147
correct_domains = {
@@ -229,7 +250,114 @@ def test_domains(self):
229
250
d = self .cpd_ternary .domains [formula ]
230
251
d = d .round (6 ) # to get rid of numerical errors from qhull
231
252
actual_domain_sorted = d [np .lexsort ((d [:, 2 ], d [:, 1 ], d [:, 0 ]))]
232
- self .assertArrayAlmostEqual (actual_domain_sorted , domain )
253
+ assert actual_domain_sorted == pytest .approx (domain )
254
+
255
+ formal_domains = {
256
+ "FeO" : np .array (
257
+ [
258
+ [- 2.50000000e01 , 3.55271368e-15 , - 2.85707600e00 ],
259
+ [- 2.01860032e00 , 3.55271368e-15 , - 2.85707600e00 ],
260
+ [- 2.50000000e01 , - 1.45446765e-01 , - 2.71162923e00 ],
261
+ [- 2.16404709e00 , - 1.45446765e-01 , - 2.71162923e00 ],
262
+ ]
263
+ ),
264
+ "Fe2O3" : np .array (
265
+ [
266
+ [- 25.0 , - 4.14354109 , 0.0 ],
267
+ [- 3.637187 , - 4.14354108 , 0.0 ],
268
+ [- 3.49325969 , - 3.85568646 , - 0.19190308 ],
269
+ [- 25.0 , - 0.70024301 , - 2.29553205 ],
270
+ [- 2.44144521 , - 0.70024301 , - 2.29553205 ],
271
+ ]
272
+ ),
273
+ "Fe3O4" : np .array (
274
+ [
275
+ [- 25.0 , - 0.70024301 , - 2.29553205 ],
276
+ [- 25.0 , - 0.14544676 , - 2.71162923 ],
277
+ [- 2.44144521 , - 0.70024301 , - 2.29553205 ],
278
+ [- 2.16404709 , - 0.14544676 , - 2.71162923 ],
279
+ ]
280
+ ),
281
+ "LiFeO2" : np .array (
282
+ [
283
+ [- 3.49325969e00 , - 3.85568646e00 , - 1.91903083e-01 ],
284
+ [- 2.01860032e00 , 3.55271368e-15 , - 2.85707600e00 ],
285
+ [- 2.44144521e00 , - 7.00243005e-01 , - 2.29553205e00 ],
286
+ [- 2.16404709e00 , - 1.45446765e-01 , - 2.71162923e00 ],
287
+ [- 1.71198739e00 , 3.55271368e-15 , - 3.01038246e00 ],
288
+ [- 2.74919447e00 , - 3.11162124e00 , - 9.35968300e-01 ],
289
+ ]
290
+ ),
291
+ "Li2O" : np .array (
292
+ [
293
+ [0.00000000e00 , - 2.50000000e01 , - 6.22930387e00 ],
294
+ [- 2.69949567e00 , - 2.50000000e01 , - 8.30312528e-01 ],
295
+ [3.55271368e-15 , 3.55271368e-15 , - 6.22930387e00 ],
296
+ [- 1.43858289e00 , 3.55271368e-15 , - 3.35213809e00 ],
297
+ [- 2.69949567e00 , - 3.78273835e00 , - 8.30312528e-01 ],
298
+ ]
299
+ ),
300
+ "Li2O2" : np .array (
301
+ [
302
+ [- 3.52980820e00 , - 2.50000000e01 , 0.00000000e00 ],
303
+ [- 2.69949567e00 , - 2.50000000e01 , - 8.30312528e-01 ],
304
+ [- 3.52980820e00 , - 4.35829869e00 , 3.55271368e-15 ],
305
+ [- 2.69949567e00 , - 3.78273835e00 , - 8.30312528e-01 ],
306
+ [- 2.82687176e00 , - 3.65536226e00 , - 7.02936437e-01 ],
307
+ ]
308
+ ),
309
+ "Li2FeO3" : np .array (
310
+ [
311
+ [- 3.52980820e00 , - 4.35829869e00 , 3.55271368e-15 ],
312
+ [- 3.63718700e00 , - 4.14354108e00 , 0.00000000e00 ],
313
+ [- 3.49325969e00 , - 3.85568646e00 , - 1.91903083e-01 ],
314
+ [- 2.74919447e00 , - 3.11162124e00 , - 9.35968300e-01 ],
315
+ [- 2.82687176e00 , - 3.65536226e00 , - 7.02936437e-01 ],
316
+ ]
317
+ ),
318
+ "Li5FeO4" : np .array (
319
+ [
320
+ [- 1.43858289e00 , 3.55271368e-15 , - 3.35213809e00 ],
321
+ [- 1.71198739e00 , 3.55271368e-15 , - 3.01038246e00 ],
322
+ [- 2.74919447e00 , - 3.11162124e00 , - 9.35968300e-01 ],
323
+ [- 2.69949567e00 , - 3.78273835e00 , - 8.30312528e-01 ],
324
+ [- 2.82687176e00 , - 3.65536226e00 , - 7.02936437e-01 ],
325
+ ]
326
+ ),
327
+ "O2" : np .array (
328
+ [
329
+ [- 2.50000000e01 , - 2.50000000e01 , 3.55271368e-15 ],
330
+ [- 3.52980820e00 , - 2.50000000e01 , 0.00000000e00 ],
331
+ [- 2.50000000e01 , - 4.14354109e00 , 0.00000000e00 ],
332
+ [- 3.52980820e00 , - 4.35829869e00 , 3.55271368e-15 ],
333
+ [- 3.63718700e00 , - 4.14354108e00 , 0.00000000e00 ],
334
+ ]
335
+ ),
336
+ "Fe" : np .array (
337
+ [
338
+ [0.00000000e00 , 0.00000000e00 , - 2.50000000e01 ],
339
+ [- 2.50000000e01 , 0.00000000e00 , - 2.50000000e01 ],
340
+ [3.55271368e-15 , 3.55271368e-15 , - 6.22930387e00 ],
341
+ [- 2.50000000e01 , 3.55271368e-15 , - 2.85707600e00 ],
342
+ [- 2.01860032e00 , 3.55271368e-15 , - 2.85707600e00 ],
343
+ [- 1.43858289e00 , 3.55271368e-15 , - 3.35213809e00 ],
344
+ [- 1.71198739e00 , 3.55271368e-15 , - 3.01038246e00 ],
345
+ ]
346
+ ),
347
+ "Li" : np .array (
348
+ [
349
+ [3.55271368e-15 , - 2.50000000e01 , - 2.50000000e01 ],
350
+ [0.00000000e00 , - 2.50000000e01 , - 6.22930387e00 ],
351
+ [0.00000000e00 , 0.00000000e00 , - 2.50000000e01 ],
352
+ [3.55271368e-15 , 3.55271368e-15 , - 6.22930387e00 ],
353
+ ]
354
+ ),
355
+ }
356
+
357
+ for formula , domain in formal_domains .items ():
358
+ d = self .cpd_ternary_formal .domains [formula ]
359
+ d = d .round (6 ) # to get rid of numerical errors from qhull
360
+ assert d == pytest .approx (domain , abs = 1e-5 )
233
361
234
362
235
363
if __name__ == "__main__" :
0 commit comments