Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 1028 structure to pymagen #1285

Merged
merged 17 commits into from
Mar 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
7fe80be
Updating docstrings in dataclasses tests (StructureData to/from ASE/p…
Mar 14, 2018
2657106
Adding two roundtrip tests ASE -> StructureData -> ASE
Mar 14, 2018
e669bef
Adding one additional roundtrip tests StructureData -> ASE -> Structu…
Mar 14, 2018
f036cb9
Adding two more roundtrip tests StructureData -> pymatgen -> Structur…
Mar 14, 2018
e6bb314
Adding a roundtrip test StructureData -> pymatgen -> StructureData fo…
Mar 14, 2018
b47fead
Adding a test to make sure the conversion from StructureData to pymat…
Mar 14, 2018
1722527
Adding a test pymatgen -> Structure, to check that an error is raised…
Mar 14, 2018
8067ac7
Adding a StructureData -> pymatgen -> StructureData conversion test t…
Mar 15, 2018
d7854e7
StructureData -> pymatgen conversion: adding properties -> kind_name …
Mar 15, 2018
faaa0b3
Minor change in TestPymatgenFromStructureData (test_roundtrip_kindnames)
Mar 15, 2018
2163105
Bug fixes in TestPymatgenFromStructureData (test_roundtrip_kindnames)
Mar 15, 2018
5184138
pymatgen -> Structure conversion: properties -> kind_name from pymatg…
Mar 15, 2018
4db539f
Adding support for StructureData -> pymatgen conversion with spins, u…
Mar 15, 2018
b966001
Merge branch 'develop' of github.com:aiidateam/aiida_core into fix_10…
Mar 15, 2018
f6b54a8
Fixing indentation in docstrings of StructureData -> get_pymatgen met…
Mar 15, 2018
cb8f98e
Fixing (again) the docstrings in StructureData.get_pymatgen, for Sphinx
Mar 15, 2018
cae4b24
Merge branch 'develop' into fix_1028_structure_to_pymagen
Mar 15, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
297 changes: 294 additions & 3 deletions aiida/backends/tests/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -1932,6 +1932,9 @@ class TestStructureDataFromAse(AiidaTestCase):

@unittest.skipIf(not has_ase(), "Unable to import ase")
def test_ase(self):
"""
Tests roundtrip ASE -> StructureData -> ASE
"""
from aiida.orm.data.structure import StructureData
import ase

Expand All @@ -1957,6 +1960,9 @@ def test_ase(self):

@unittest.skipIf(not has_ase(), "Unable to import ase")
def test_conversion_of_types_1(self):
"""
Tests roundtrip ASE -> StructureData -> ASE, with tags
"""
from aiida.orm.data.structure import StructureData
import ase

Expand Down Expand Up @@ -1987,6 +1993,10 @@ def test_conversion_of_types_1(self):

@unittest.skipIf(not has_ase(), "Unable to import ase")
def test_conversion_of_types_2(self):
"""
Tests roundtrip ASE -> StructureData -> ASE, with tags, and
changing the atomic masses
"""
from aiida.orm.data.structure import StructureData
import ase

Expand Down Expand Up @@ -2019,6 +2029,9 @@ def test_conversion_of_types_2(self):

@unittest.skipIf(not has_ase(), "Unable to import ase")
def test_conversion_of_types_3(self):
"""
Tests StructureData -> ASE, with all sorts of kind names
"""
from aiida.orm.data.structure import StructureData

a = StructureData()
Expand Down Expand Up @@ -2050,6 +2063,9 @@ def test_conversion_of_types_3(self):

@unittest.skipIf(not has_ase(), "Unable to import ase")
def test_conversion_of_types_4(self):
"""
Tests ASE -> StructureData -> ASE, in particular conversion tags / kind names
"""
from aiida.orm.data.structure import StructureData
import ase

Expand All @@ -2060,9 +2076,18 @@ def test_conversion_of_types_4(self):
s = StructureData(ase=atoms)
kindnames = set([k.name for k in s.kinds])
self.assertEquals(kindnames, set(['Fe', 'Fe1', 'Fe4']))
# check roundtrip ASE -> StructureData -> ASE
atoms2 = s.get_ase()
self.assertEquals(list(atoms2.get_tags()),list(atoms.get_tags()))
self.assertEquals(list(atoms2.get_chemical_symbols()),list(atoms.get_chemical_symbols()))
self.assertEquals(atoms2.get_chemical_formula(),'Fe5')

@unittest.skipIf(not has_ase(), "Unable to import ase")
def test_conversion_of_types_5(self):
"""
Tests ASE -> StructureData -> ASE, in particular conversion tags / kind names
(subtle variation of test_conversion_of_types_4)
"""
from aiida.orm.data.structure import StructureData
import ase

Expand All @@ -2073,6 +2098,34 @@ def test_conversion_of_types_5(self):
s = StructureData(ase=atoms)
kindnames = set([k.name for k in s.kinds])
self.assertEquals(kindnames, set(['Fe', 'Fe1', 'Fe4']))
# check roundtrip ASE -> StructureData -> ASE
atoms2 = s.get_ase()
self.assertEquals(list(atoms2.get_tags()),list(atoms.get_tags()))
self.assertEquals(list(atoms2.get_chemical_symbols()),list(atoms.get_chemical_symbols()))
self.assertEquals(atoms2.get_chemical_formula(),'Fe5')

@unittest.skipIf(not has_ase(), "Unable to import ase")
def test_conversion_of_types_6(self):
"""
Tests roundtrip StructureData -> ASE -> StructureData, with tags/kind names
"""
from aiida.orm.data.structure import StructureData

a = StructureData(cell=[[4,0,0],[0,4,0],[0,0,4]])
a.append_atom(position=(0,0,0), symbols='Ni', name='Ni1')
a.append_atom(position=(2,2,2), symbols='Ni', name='Ni2')
a.append_atom(position=(1,0,1), symbols='Cl', name='Cl')
a.append_atom(position=(1,3,1), symbols='Cl', name='Cl')

b = a.get_ase()
self.assertEquals(b.get_chemical_symbols(), ['Ni', 'Ni', 'Cl','Cl'])
self.assertEquals(list(b.get_tags()), [1, 2, 0, 0])

c = StructureData(ase=b)
self.assertEquals(c.get_site_kindnames(), ['Ni1', 'Ni2', 'Cl','Cl'])
self.assertEquals([k.symbol for k in c.kinds], ['Ni', 'Ni', 'Cl'])
self.assertEquals([s.position for s in c.sites],
[(0.,0.,0.),(2.,2.,2.),(1.,0.,1.),(1.,3.,1.)])


class TestStructureDataFromPymatgen(AiidaTestCase):
Expand All @@ -2090,7 +2143,8 @@ class TestStructureDataFromPymatgen(AiidaTestCase):
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_1(self):
"""
Test's imput is derived from COD entry 9011963, processed with
Tests roundtrip pymatgen -> StructureData -> pymatgen
Test's input is derived from COD entry 9011963, processed with
cif_mark_disorder (from cod-tools) and abbreviated.
"""
from aiida.orm.data.structure import StructureData
Expand Down Expand Up @@ -2162,6 +2216,7 @@ def test_1(self):
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_2(self):
"""
Tests xyz -> pymatgen -> StructureData
Input source: http://pymatgen.org/_static/Molecule.html
"""
from aiida.orm.data.structure import StructureData
Expand Down Expand Up @@ -2202,6 +2257,42 @@ def test_2(self):
[round(x, 2) for x in list(struct.sites[4].position)],
[5.77, 5.89, 5.73])

@unittest.skipIf(not has_pymatgen(), "Unable to import pymatgen")
@unittest.skipIf(has_pymatgen() and
StrictVersion(get_pymatgen_version()) !=
StrictVersion('4.5.3'),
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_partial_occ_and_spin(self):
"""
Tests pymatgen -> StructureData, with partial occupancies and spins.
This should raise a ValueError.
"""
from aiida.orm.data.structure import StructureData
import pymatgen

Fe_spin_up = pymatgen.structure.Specie('Fe',0,properties={'spin':1})
Mn_spin_up = pymatgen.structure.Specie('Mn',0,properties={'spin':1})
Fe_spin_down = pymatgen.structure.Specie('Fe',0,properties={'spin':-1})
Mn_spin_down = pymatgen.structure.Specie('Mn',0,properties={'spin':-1})
FeMn1 = pymatgen.Composition({Fe_spin_up:0.5,Mn_spin_up:0.5})
FeMn2 = pymatgen.Composition({Fe_spin_down:0.5,Mn_spin_down:0.5})
a = pymatgen.structure.Structure(lattice=[[4,0,0],[0,4,0],[0,0,4]],
species=[FeMn1,FeMn2],
coords=[[0,0,0],[0.5,0.5,0.5]])

with self.assertRaises(ValueError):
StructureData(pymatgen=a)

# same, with vacancies
Fe1 = pymatgen.Composition({Fe_spin_up:0.5})
Fe2 = pymatgen.Composition({Fe_spin_down:0.5})
a = pymatgen.structure.Structure(lattice=[[4,0,0],[0,4,0],[0,0,4]],
species=[Fe1,Fe2],
coords=[[0,0,0],[0.5,0.5,0.5]])

with self.assertRaises(ValueError):
StructureData(pymatgen=a)


class TestPymatgenFromStructureData(AiidaTestCase):
"""
Expand All @@ -2219,7 +2310,7 @@ class TestPymatgenFromStructureData(AiidaTestCase):
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_1(self):
"""
Test the check of periodic boundary conditions.
Tests the check of periodic boundary conditions.
"""
from aiida.orm.data.structure import StructureData

Expand All @@ -2239,6 +2330,9 @@ def test_1(self):
StrictVersion('4.5.3'),
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_2(self):
"""
Tests ASE -> StructureData -> pymatgen
"""
from aiida.orm.data.structure import StructureData
import ase

Expand Down Expand Up @@ -2274,7 +2368,8 @@ def test_2(self):
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_3(self):
"""
Test the conversion of StructureData to pymatgen's Molecule.
Tests the conversion of StructureData to pymatgen's Molecule
(ASE -> StructureData -> pymatgen)
"""
from aiida.orm.data.structure import StructureData
import ase
Expand All @@ -2299,7 +2394,203 @@ def test_3(self):
[2.0, 2.0, 2.0],
[3.0, 3.0, 3.0]])

@unittest.skipIf(not has_pymatgen(), "Unable to import pymatgen")
@unittest.skipIf(has_pymatgen() and
StrictVersion(get_pymatgen_version()) !=
StrictVersion('4.5.3'),
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_roundtrip(self):
"""
Tests roundtrip StructureData -> pymatgen -> StructureData
(no spins)
"""
from aiida.orm.data.structure import StructureData

a = StructureData(cell=[[5.6,0,0],[0,5.6,0],[0,0,5.6]])
a.append_atom(position=(0,0,0), symbols='Cl')
a.append_atom(position=(2.8,0,2.8), symbols='Cl')
a.append_atom(position=(0,2.8,2.8), symbols='Cl')
a.append_atom(position=(2.8,2.8,0), symbols='Cl')
a.append_atom(position=(2.8,2.8,2.8), symbols='Na')
a.append_atom(position=(2.8,0,0), symbols='Na')
a.append_atom(position=(0,2.8,0), symbols='Na')
a.append_atom(position=(0,0,2.8), symbols='Na')

b = a.get_pymatgen()
c = StructureData(pymatgen=b)
self.assertEquals(c.get_site_kindnames(), ['Cl','Cl','Cl','Cl','Na','Na','Na','Na'])
self.assertEquals([k.symbol for k in c.kinds], ['Cl','Na'])
self.assertEquals([s.position for s in c.sites],
[(0.,0.,0.),(2.8,0,2.8),(0,2.8,2.8),(2.8,2.8,0),(2.8,2.8,2.8),(2.8,0,0),(0,2.8,0),(0,0,2.8)])

@unittest.skipIf(not has_pymatgen(), "Unable to import pymatgen")
@unittest.skipIf(has_pymatgen() and
StrictVersion(get_pymatgen_version()) !=
StrictVersion('4.5.3'),
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_roundtrip_kindnames(self):
"""
Tests roundtrip StructureData -> pymatgen -> StructureData
(no spins, but with all kind of kind names)
"""
from aiida.orm.data.structure import StructureData

a = StructureData(cell=[[5.6,0,0],[0,5.6,0],[0,0,5.6]])
a.append_atom(position=(0,0,0), symbols='Cl',name='Cl')
a.append_atom(position=(2.8,0,2.8), symbols='Cl',name='Cl10')
a.append_atom(position=(0,2.8,2.8), symbols='Cl',name='Cla')
a.append_atom(position=(2.8,2.8,0), symbols='Cl',name='cl_x')
a.append_atom(position=(2.8,2.8,2.8), symbols='Na',name='Na1')
a.append_atom(position=(2.8,0,0), symbols='Na',name='Na2')
a.append_atom(position=(0,2.8,0), symbols='Na',name='Na_Na')
a.append_atom(position=(0,0,2.8), symbols='Na',name='Na4')

b = a.get_pymatgen()
self.assertEquals([site.properties['kind_name'] for site in b.sites],
['Cl','Cl10','Cla','cl_x','Na1','Na2','Na_Na','Na4'])

c = StructureData(pymatgen=b)
self.assertEquals(c.get_site_kindnames(), ['Cl','Cl10','Cla','cl_x','Na1','Na2','Na_Na','Na4'])
self.assertEquals(c.get_symbols_set(), set(['Cl','Na']))
self.assertEquals([s.position for s in c.sites],
[(0.,0.,0.),(2.8,0,2.8),(0,2.8,2.8),(2.8,2.8,0),(2.8,2.8,2.8),(2.8,0,0),(0,2.8,0),(0,0,2.8)])

@unittest.skipIf(not has_pymatgen(), "Unable to import pymatgen")
@unittest.skipIf(has_pymatgen() and
StrictVersion(get_pymatgen_version()) !=
StrictVersion('4.5.3'),
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_roundtrip_spins(self):
"""
Tests roundtrip StructureData -> pymatgen -> StructureData
(with spins)
"""
from aiida.orm.data.structure import StructureData

a = StructureData(cell=[[5.6,0,0],[0,5.6,0],[0,0,5.6]])
a.append_atom(position=(0,0,0), symbols='Mn',name='Mn1')
a.append_atom(position=(2.8,0,2.8), symbols='Mn',name='Mn1')
a.append_atom(position=(0,2.8,2.8), symbols='Mn',name='Mn1')
a.append_atom(position=(2.8,2.8,0), symbols='Mn',name='Mn1')
a.append_atom(position=(2.8,2.8,2.8), symbols='Mn',name='Mn2')
a.append_atom(position=(2.8,0,0), symbols='Mn',name='Mn2')
a.append_atom(position=(0,2.8,0), symbols='Mn',name='Mn2')
a.append_atom(position=(0,0,2.8), symbols='Mn',name='Mn2')

b = a.get_pymatgen(add_spin=True)
# check the spins
self.assertEquals([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)
self.assertEquals(c.get_site_kindnames(), ['Mn1','Mn1','Mn1','Mn1','Mn2','Mn2','Mn2','Mn2'])
self.assertEquals([k.symbol for k in c.kinds], ['Mn','Mn'])
self.assertEquals([s.position for s in c.sites],
[(0.,0.,0.),(2.8,0,2.8),(0,2.8,2.8),(2.8,2.8,0),(2.8,2.8,2.8),(2.8,0,0),(0,2.8,0),(0,0,2.8)])

@unittest.skipIf(not has_pymatgen(), "Unable to import pymatgen")
@unittest.skipIf(has_pymatgen() and
StrictVersion(get_pymatgen_version()) !=
StrictVersion('4.5.3'),
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_roundtrip_partial_occ(self):
"""
Tests roundtrip StructureData -> pymatgen -> StructureData
(with partial occupancies).
Structure initially from ICSD (id: 251993).
"""
from aiida.orm.data.structure import StructureData

a = StructureData(cell=[[3.9912, 0.0, 0.0],
[-1.9956, 3.456480591584452, 0.0],
[0.0, 0.0, 16.2958]])
a.append_atom(position=(0.0,0.0,13.49455198), symbols='Fe')
a.append_atom(position=(0.0,0.0,2.80124802), symbols='Fe')
a.append_atom(position=(0.0,0.0,5.34665198), symbols='Fe')
a.append_atom(position=(0.0,0.0,10.94914802), symbols='Fe')
a.append_atom(position=(1.9956,1.15239062923,12.22185), symbols='Fe',weights=0.9)
a.append_atom(position=(0.0,2.30408996235,4.07395), symbols='Fe',weights=0.9)
a.append_atom(position=(0.0,2.30408996235,12.22185),symbols='Ge')
a.append_atom(position=(1.9956,1.15239062923,4.07395),symbols='Ge')
a.append_atom(position=(1.9956,1.15239062923,14.8373259),symbols='Te')
a.append_atom(position=(0.0,2.30408996235,1.4584741),symbols='Te')
a.append_atom(position=(0.0,2.30408996235,6.6894259),symbols='Te')
a.append_atom(position=(1.9956,1.15239062923,9.6063741),symbols='Te')

# a few checks on the structure kinds and symbols
self.assertEquals(a.get_symbols_set(),set(['Fe', 'Ge', 'Te']))
self.assertEquals(a.get_site_kindnames(),
['Fe','Fe','Fe','Fe','FeX','FeX','Ge','Ge','Te','Te','Te','Te'])
self.assertEquals(a.get_formula(),'Fe4Ge2Te4{Fe0.90X0.10}2')

b = a.get_pymatgen()
# check the partial occupancies
self.assertEquals([s.as_dict() for s in b.species_and_occu],
[{'Fe':1.0},{'Fe':1.0},{'Fe':1.0},{'Fe':1.0},
{'Fe':0.9},{'Fe':0.9},{'Ge':1.0},{'Ge':1.0},
{'Te':1.0},{'Te':1.0},{'Te':1.0},{'Te':1.0}])

# back to StructureData
c = StructureData(pymatgen=b)
self.assertEquals(c.cell,[[3.9912, 0.0, 0.0],
[-1.9956, 3.456480591584452, 0.0],
[0.0, 0.0, 16.2958]])
self.assertEquals(c.get_symbols_set(),set(['Fe', 'Ge', 'Te']))
self.assertEquals(c.get_site_kindnames(),
['Fe','Fe','Fe','Fe','FeX','FeX','Ge','Ge','Te','Te','Te','Te'])
self.assertEquals(c.get_formula(),'Fe4Ge2Te4{Fe0.90X0.10}2')
self.assertEquals([s.position for s in c.sites],
[(0.0, 0.0, 13.49455198),
(0.0, 0.0, 2.80124802),
(0.0, 0.0, 5.34665198),
(0.0, 0.0, 10.94914802),
(1.9956, 1.15239062923, 12.22185),
(0.0, 2.30408996235, 4.07395),
(0.0, 2.30408996235, 12.22185),
(1.9956, 1.15239062923, 4.07395),
(1.9956, 1.15239062923, 14.8373259),
(0.0, 2.30408996235, 1.4584741),
(0.0, 2.30408996235, 6.6894259),
(1.9956, 1.15239062923, 9.6063741)])

@unittest.skipIf(not has_pymatgen(), "Unable to import pymatgen")
@unittest.skipIf(has_pymatgen() and
StrictVersion(get_pymatgen_version()) !=
StrictVersion('4.5.3'),
"Mismatch in the version of pymatgen (expected 4.5.3)")
def test_partial_occ_and_spin(self):
"""
Tests StructureData -> pymatgen, with partial occupancies and spins.
This should raise a ValueError.
"""
from aiida.orm.data.structure import StructureData

a = StructureData(cell=[[4,0,0],[0,4,0],[0,0,4]])
a.append_atom(position=(0,0,0), symbols=('Fe','Al'),weights=(0.8,0.2),name='FeAl1')
a.append_atom(position=(2,2,2), symbols=('Fe','Al'),weights=(0.8,0.2),name='FeAl2')

# a few checks on the structure kinds and symbols
self.assertEquals(a.get_symbols_set(),set(['Fe', 'Al']))
self.assertEquals(a.get_site_kindnames(),['FeAl1','FeAl2'])
self.assertEquals(a.get_formula(),'{Al0.20Fe0.80}2')

with self.assertRaises(ValueError):
a.get_pymatgen(add_spin=True)

# same, with vacancies
a = StructureData(cell=[[4,0,0],[0,4,0],[0,0,4]])
a.append_atom(position=(0,0,0), symbols='Fe',weights=0.8,name='FeX1')
a.append_atom(position=(2,2,2), symbols='Fe',weights=0.8,name='FeX2')

# a few checks on the structure kinds and symbols
self.assertEquals(a.get_symbols_set(),set(['Fe']))
self.assertEquals(a.get_site_kindnames(),['FeX1','FeX2'])
self.assertEquals(a.get_formula(),'{Fe0.80X0.20}2')

with self.assertRaises(ValueError):
a.get_pymatgen(add_spin=True)


class TestArrayData(AiidaTestCase):
"""
Tests the ArrayData objects.
Expand Down
Loading