Skip to content

Commit

Permalink
Dependencies: Add compatibility for pymatgen>=v2023.9.2 (#6109)
Browse files Browse the repository at this point in the history
As of v2023.9.2, the ``properties`` argument of the `Specie` class is
removed and the ``spin`` argument should be used instead. See:
materialsproject/pymatgen@118c245

The ``spin`` argument was introduced in v2023.6.28. See:
materialsproject/pymatgen@9f2b393

Instead of removing support for versions older than v2023.6.28 the code
is updated to be able to deal with the new version where `properties` is
no longer supported.

Cherry-pick: 4e0e7d8
  • Loading branch information
sphuber committed Nov 15, 2023
1 parent 093037d commit 1f6027f
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 15 deletions.
34 changes: 25 additions & 9 deletions aiida/orm/nodes/data/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,17 @@ def build_kind_name(species_and_occu):
species = list(species_and_occu.keys())
occupations = list(species_and_occu.values())

has_spin = any(specie.as_dict().get('properties', {}).get('spin', 0) != 0 for specie in species)
# As of v2023.9.2, the ``properties`` argument is removed and the ``spin`` argument should be used.
# See: https://github.com/materialsproject/pymatgen/commit/118c245d6082fe0b13e19d348fc1db9c0d512019
# The ``spin`` argument was introduced in v2023.6.28.
# See: https://github.com/materialsproject/pymatgen/commit/9f2b3939af45d5129e0778d371d814811924aeb6
has_spin_attribute = hasattr(species[0], '_spin')

if has_spin_attribute:
has_spin = any(specie.spin != 0 for specie in species)
else:
has_spin = any(specie.as_dict().get('properties', {}).get('spin', 0) != 0 for specie in species)

has_partial_occupancies = (len(occupations) != 1 or occupations[0] != 1.0)

if has_partial_occupancies and has_spin:
Expand All @@ -847,7 +857,10 @@ def build_kind_name(species_and_occu):

# If there is spin, we can only have a single specie, otherwise we would have raised above
specie = species[0]
spin = specie.as_dict().get('properties', {}).get('spin', 0)
if has_spin_attribute:
spin = specie.spin
else:
spin = specie.as_dict().get('properties', {}).get('spin', 0)

if spin < 0:
kind_name += '1'
Expand Down Expand Up @@ -1846,13 +1859,16 @@ def _get_object_pymatgen_structure(self, **kwargs):
kind = self.get_kind(site.kind_name)
if len(kind.symbols) != 1 or (len(kind.weights) != 1 or sum(kind.weights) < 1.):
raise ValueError('Cannot set partial occupancies and spins at the same time')
species.append(
Specie(
kind.symbols[0],
oxidation_state,
properties={'spin': -1 if kind.name.endswith('1') else 1 if kind.name.endswith('2') else 0}
)
)
spin = -1 if kind.name.endswith('1') else 1 if kind.name.endswith('2') else 0
try:
specie = Specie(kind.symbols[0], oxidation_state, properties={'spin': spin}) # pylint: disable=unexpected-keyword-arg
except TypeError:
# As of v2023.9.2, the ``properties`` argument is removed and the ``spin`` argument should be used.
# See: https://github.com/materialsproject/pymatgen/commit/118c245d6082fe0b13e19d348fc1db9c0d512019
# The ``spin`` argument was introduced in v2023.6.28.
# See: https://github.com/materialsproject/pymatgen/commit/9f2b3939af45d5129e0778d371d814811924aeb6
specie = Specie(kind.symbols[0], oxidation_state, spin=spin) # pylint: disable=unexpected-keyword-arg
species.append(specie)
else:
# case when no spin are defined
for site in self.sites:
Expand Down
2 changes: 1 addition & 1 deletion requirements/requirements-py-3.11.txt
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ pycparser==2.21
pydantic==1.10.9
pydata-sphinx-theme==0.8.1
pygments==2.15.1
pymatgen==2023.5.31
pymatgen==2023.9.2
pympler==0.9
pymysql==0.9.3
pynacl==1.5.0
Expand Down
19 changes: 14 additions & 5 deletions tests/test_dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -2247,10 +2247,16 @@ def test_partial_occ_and_spin(self):
from pymatgen.core.periodic_table import Specie
from pymatgen.core.structure import Structure

Fe_spin_up = Specie('Fe', 0, properties={'spin': 1})
Mn_spin_up = Specie('Mn', 0, properties={'spin': 1})
Fe_spin_down = Specie('Fe', 0, properties={'spin': -1})
Mn_spin_down = Specie('Mn', 0, properties={'spin': -1})
try:
Fe_spin_up = Specie('Fe', 0, spin=1) # pylint: disable=unexpected-keyword-arg
Mn_spin_up = Specie('Mn', 0, spin=1) # pylint: disable=unexpected-keyword-arg
Fe_spin_down = Specie('Fe', 0, spin=-1) # pylint: disable=unexpected-keyword-arg
Mn_spin_down = Specie('Mn', 0, spin=-1) # pylint: disable=unexpected-keyword-arg
except TypeError:
Fe_spin_up = Specie('Fe', 0, properties={'spin': 1}) # pylint: disable=unexpected-keyword-arg
Mn_spin_up = Specie('Mn', 0, properties={'spin': 1}) # pylint: disable=unexpected-keyword-arg
Fe_spin_down = Specie('Fe', 0, properties={'spin': -1}) # pylint: disable=unexpected-keyword-arg
Mn_spin_down = Specie('Mn', 0, properties={'spin': -1}) # pylint: disable=unexpected-keyword-arg
FeMn1 = Composition({Fe_spin_up: 0.5, Mn_spin_up: 0.5})
FeMn2 = Composition({Fe_spin_down: 0.5, Mn_spin_down: 0.5})
a = Structure(
Expand Down Expand Up @@ -2440,7 +2446,10 @@ def test_roundtrip_spins(self):

b = a.get_pymatgen(add_spin=True)
# check the spins
assert [s.as_dict()['properties']['spin'] for s in b.species] == [-1, -1, -1, -1, 1, 1, 1, 1]
try:
assert [s.as_dict()['spin'] for s in b.species] == [-1, -1, -1, -1, 1, 1, 1, 1]
except KeyError:
assert [s.as_dict()['properties']['spin'] for s in b.species] == [-1, -1, -1, -1, 1, 1, 1, 1]
# back to StructureData
c = StructureData(pymatgen=b)
assert c.get_site_kindnames() == ['Mn1', 'Mn1', 'Mn1', 'Mn1', 'Mn2', 'Mn2', 'Mn2', 'Mn2']
Expand Down

0 comments on commit 1f6027f

Please sign in to comment.