Skip to content

Commit

Permalink
Merge 12ceeb2 into bba5a44
Browse files Browse the repository at this point in the history
  • Loading branch information
janosh committed Oct 13, 2022
2 parents bba5a44 + 12ceeb2 commit a5f3121
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 5 deletions.
30 changes: 25 additions & 5 deletions pymatgen/analysis/phase_diagram.py
Expand Up @@ -16,7 +16,7 @@
import re
import warnings
from functools import lru_cache
from typing import Any, Literal, Sequence
from typing import Any, Iterator, Literal, Sequence

import numpy as np
import plotly.graph_objs as go
Expand Down Expand Up @@ -480,7 +480,7 @@ def _compute(self):
qhull_entries=qhull_entries,
)

def pd_coords(self, comp):
def pd_coords(self, comp: Composition) -> np.ndarray:
"""
The phase diagram is generated in a reduced dimensional space
(n_elements - 1). This function returns the coordinates in that space.
Expand Down Expand Up @@ -579,7 +579,7 @@ def __repr__(self):
output = [
f"{'-'.join(symbols)} phase diagram",
f"{len(self.stable_entries)} stable phases: ",
", ".join([entry.name for entry in self.stable_entries]),
", ".join([entry.name for entry in sorted(self.stable_entries, key=str)]),
]
return "\n".join(output)

Expand Down Expand Up @@ -1499,7 +1499,6 @@ def __init__(
elements: Sequence[Element] = None,
keep_all_spaces: bool = False,
verbose: bool = False,
computed_data: dict[str, Any] = None,
) -> None:
"""
Args:
Expand All @@ -1512,6 +1511,7 @@ def __init__(
is preserved.
keep_all_spaces (bool): Boolean control on whether to keep chemical spaces
that are subspaces of other spaces.
verbose (bool): Whether to show progress bar during convex hull construction.
"""
if elements is None:
elements = sorted({els for e in entries for els in e.composition.elements})
Expand Down Expand Up @@ -1551,6 +1551,8 @@ def __init__(
inds.extend([min_entries.index(el) for el in el_refs.values()])

self.qhull_entries = tuple(min_entries[i] for i in inds)
# make qhull spaces frozensets since they become keys to self.pds dict and frozensets are hashable
# prevent repeating elements in chemical space and avoid the ordering problem (i.e. Fe-O == O-Fe automatically)
self._qhull_spaces = tuple(frozenset(e.composition.elements) for e in self.qhull_entries)

# Get all unique chemical spaces
Expand Down Expand Up @@ -1585,6 +1587,24 @@ def __init__(
def __repr__(self):
return f"{type(self).__name__} covering {len(self.spaces)} sub-spaces"

def __len__(self):
return len(self.spaces)

def __getitem__(self, item: frozenset[Element]) -> PhaseDiagram:
return self.pds[item]

def __setitem__(self, key: frozenset[Element], value: PhaseDiagram) -> None:
self.pds[key] = value

def __delitem__(self, key: frozenset[Element]) -> None:
del self.pds[key]

def __iter__(self) -> Iterator[PhaseDiagram]:
return iter(self.pds.values())

def __contains__(self, item: frozenset[Element]) -> bool:
return item in self.pds

def as_dict(self) -> dict[str, Any]:
"""
Returns:
Expand Down Expand Up @@ -1646,7 +1666,7 @@ def get_pd_for_entry(self, entry: Entry | Composition) -> PhaseDiagram:
if space.issuperset(entry_space):
return pd

raise ValueError(f"No suitable PhaseDiagrams found for {entry}.")
raise ValueError(f"No suitable PhaseDiagrams found for {entry}.")

def get_decomposition(self, comp: Composition) -> dict[PDEntry, float]:
"""
Expand Down
42 changes: 42 additions & 0 deletions pymatgen/analysis/tests/test_phase_diagram.py
@@ -1,6 +1,7 @@
# Copyright (c) Pymatgen Development Team.
# Distributed under the terms of the MIT License.

import collections
import os
import unittest
import warnings
Expand Down Expand Up @@ -165,6 +166,12 @@ def test_init(self):
)
self.assertRaises(ValueError, PhaseDiagram, entries)

def test_repr(self):
assert (
str(self.pd) == "Li-Fe-O phase diagram\n11 stable phases: \nFe, FeO, "
"Fe2O3, Fe3O4, LiFeO2, Li, Li2O, LiO, Li5FeO4, Li2FeO3, O"
)

def test_dim1(self):
# Ensure that dim 1 PDs can be generated.
for el in ["Li", "Fe", "O2"]:
Expand Down Expand Up @@ -749,6 +756,10 @@ def test_get_form_energy(self):
def test_dimensionality(self):
assert self.pd.dim == self.ppd.dim

# test dims of sub PDs
dim_counts = collections.Counter(pd.dim for pd in self.ppd.pds.values())
assert dim_counts == {3: 7, 2: 6, 4: 2}

def test_get_hull_energy(self):
for comp in self.novel_comps:
e_hull_pd = self.pd.get_hull_energy(comp)
Expand Down Expand Up @@ -790,6 +801,37 @@ def test_raises_on_missing_terminal_entries(self):
with pytest.raises(ValueError, match=r"Missing terminal entries for elements \['Fe', 'O'\]"):
PatchedPhaseDiagram(entries=[entry])

def test_contains(self):
for space in self.ppd.spaces:
assert space in self.ppd
unlikely_chem_space = frozenset(map(Element, "HBCNOFPS"))
assert unlikely_chem_space not in self.ppd

def test_getitem(self):
chem_space = self.ppd.spaces[0]
pd = self.ppd[chem_space]
assert isinstance(pd, PhaseDiagram)
assert chem_space in pd._qhull_spaces
assert str(pd) == "V-C phase diagram\n4 stable phases: \nC, V, V6C5, V2C"

with pytest.raises(KeyError):
self.ppd[frozenset(map(Element, "HBCNOFPS"))]

def test_iter(self):
for pd in self.ppd:
assert isinstance(pd, PhaseDiagram)
assert len(self.ppd) == len(self.ppd.pds)

def test_len(self):
assert len(self.ppd) == len(self.ppd.pds)

def test_setitem_and_delitem(self):
unlikely_chem_space = frozenset(map(Element, "HBCNOFPS"))
self.ppd[unlikely_chem_space] = self.pd
assert unlikely_chem_space in self.ppd
assert self.ppd[unlikely_chem_space] == self.pd
del self.ppd[unlikely_chem_space] # test __delitem__() and restore original state


class ReactionDiagramTest(unittest.TestCase):
def setUp(self):
Expand Down

0 comments on commit a5f3121

Please sign in to comment.