Skip to content

Commit 98c5788

Browse files
authored
Adding Abinit magmoms from netCDF files to Structure.site_properties (materialsproject#3936)
* Added magmoms reading from nc files with Abinit. * Added tests. * Adding GSR files to tests setup. * Fixing test for collinear magmom. * Fixing test for noncollinear magmom. * Revert backward incompatible change introduced in #2a3608f and #565a8b4. * Added a test for PAW pseudopotentials with abinit. * Fix pseudo test. * Compressed large netCDF files for abinit. * Compressed pseudo file for abinit.
1 parent d464ad4 commit 98c5788

File tree

7 files changed

+82
-3
lines changed

7 files changed

+82
-3
lines changed

src/pymatgen/io/abinit/netcdf.py

+21
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from pymatgen.core.structure import Structure
1616
from pymatgen.core.units import ArrayWithUnit
1717
from pymatgen.core.xcfunc import XcFunc
18+
from pymatgen.electronic_structure.core import Magmom
1819

1920
if TYPE_CHECKING:
2021
from typing_extensions import Self
@@ -315,6 +316,23 @@ def structure_from_ncdata(ncdata, site_properties=None, cls=Structure):
315316
# type_atom[:natom] --> index Between 1 and number of atom species
316317
type_atom = ncdata.read_value("atom_species")
317318

319+
try:
320+
intgden = ncdata.read_value("intgden")
321+
nspden = intgden.shape[1]
322+
except NetcdfReaderError:
323+
intgden = None
324+
nspden = None
325+
326+
if intgden is not None:
327+
if nspden == 2:
328+
magmoms = Magmom(intgden[:, 1] - intgden[:, 0])
329+
elif nspden == 4:
330+
magmoms = [Magmom([intg_at[1], intg_at[2], intg_at[3]]) for intg_at in intgden]
331+
else:
332+
magmoms = None
333+
else:
334+
magmoms = None
335+
318336
# Fortran to C index and float --> int conversion.
319337
species = n_atom * [None]
320338
for atom in range(n_atom):
@@ -326,6 +344,9 @@ def structure_from_ncdata(ncdata, site_properties=None, cls=Structure):
326344
for prop in site_properties:
327345
dct[prop] = ncdata.read_value(prop)
328346

347+
if magmoms is not None and "magmom" not in dct:
348+
dct["magmom"] = magmoms
349+
329350
structure = cls(lattice, species, red_coords, site_properties=dct)
330351

331352
# Quick and dirty hack.

src/pymatgen/io/abinit/pseudos.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1078,8 +1078,8 @@ def read_ppdesc(self, filename):
10781078
# Assume file with the abinit header.
10791079
lines = _read_nlines(filename, 80)
10801080

1081-
for lineno, line in enumerate(lines, start=1):
1082-
if lineno == 3:
1081+
for lineno, line in enumerate(lines):
1082+
if lineno == 2:
10831083
try:
10841084
tokens = line.split()
10851085
pspcod, _pspxc = map(int, tokens[:2])
@@ -1095,7 +1095,7 @@ def read_ppdesc(self, filename):
10951095

10961096
if pspcod == 7:
10971097
# PAW -> need to know the format pspfmt
1098-
tokens = line.split()
1098+
tokens = lines[lineno + 1].split()
10991099
pspfmt, _creatorID = tokens[:2]
11001100

11011101
ppdesc = ppdesc._replace(format=pspfmt)

tests/files/io/abinit/28ni.paw.tar.xz

72.3 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.

tests/io/abinit/test_netcdf.py

+26
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
from __future__ import annotations
22

3+
import os
4+
import tarfile
5+
36
import numpy as np
47
import pytest
8+
from monty.tempfile import ScratchDir
59
from numpy.testing import assert_allclose, assert_array_equal
610
from pymatgen.core.structure import Structure
711
from pymatgen.io.abinit import EtsfReader
@@ -72,12 +76,34 @@ def test_read_si2(self):
7276
# Initialize pymatgen structure from GSR.
7377
structure = data.read_structure()
7478
assert isinstance(structure, Structure)
79+
assert "magmom" not in structure.site_properties
7580

7681
# Read ixc.
7782
# TODO: Upgrade GSR file.
7883
# xc = data.read_abinit_xcfunc()
7984
# assert xc == "LDA"
8085

86+
@pytest.mark.skipif(netCDF4 is None, reason="Requires Netcdf4")
87+
def test_read_fe(self):
88+
with ScratchDir(".") as tmp_dir:
89+
with tarfile.open(f"{TEST_DIR}/Fe_magmoms_collinear_GSR.tar.xz", mode="r:xz") as t:
90+
t.extractall(tmp_dir)
91+
ref_magmom_collinear = [-0.5069359730980665]
92+
path = os.path.join(tmp_dir, "Fe_magmoms_collinear_GSR.nc")
93+
94+
with EtsfReader(path) as data:
95+
structure = data.read_structure()
96+
assert structure.site_properties["magmom"] == ref_magmom_collinear
97+
98+
with tarfile.open(f"{TEST_DIR}/Fe_magmoms_noncollinear_GSR.tar.xz", mode="r:xz") as t:
99+
t.extractall(tmp_dir)
100+
ref_magmom_noncollinear = [[0.357939487, 0.357939487, 0]]
101+
path = os.path.join(tmp_dir, "Fe_magmoms_noncollinear_GSR.nc")
102+
103+
with EtsfReader(path) as data:
104+
structure = data.read_structure()
105+
assert structure.site_properties["magmom"] == ref_magmom_noncollinear
106+
81107

82108
class TestAbinitHeader(PymatgenTest):
83109
def test_api(self):

tests/io/abinit/test_pseudos.py

+32
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from __future__ import annotations
22

33
import os.path
4+
import tarfile
45
from collections import defaultdict
56

67
import pytest
8+
from monty.tempfile import ScratchDir
79
from pymatgen.io.abinit.pseudos import Pseudo, PseudoTable
810
from pymatgen.util.testing import TEST_FILES_DIR, PymatgenTest
911
from pytest import approx
@@ -17,6 +19,7 @@ def setUp(self):
1719
nc_pseudo_fnames["Si"] = [f"{TEST_DIR}/{file}" for file in ("14si.pspnc", "14si.4.hgh", "14-Si.LDA.fhi")]
1820

1921
self.nc_pseudos = defaultdict(list)
22+
self.paw_pseudos = defaultdict(list)
2023

2124
for symbol, file_names in nc_pseudo_fnames.items():
2225
for file_name in file_names:
@@ -90,6 +93,35 @@ def test_nc_pseudos(self):
9093
# Test pickle
9194
self.serialize_with_pickle(table, test_eq=False)
9295

96+
def test_paw_pseudos(self):
97+
"""Test 28ni.paw."""
98+
file_name = f"{TEST_DIR}/28ni.paw.tar.xz"
99+
symbol = "Ni"
100+
with ScratchDir(".") as tmp_dir, tarfile.open(file_name, mode="r:xz") as t:
101+
t.extractall(tmp_dir)
102+
path = os.path.join(tmp_dir, "28ni.paw")
103+
pseudo = Pseudo.from_file(path)
104+
105+
assert repr(pseudo)
106+
assert str(pseudo)
107+
assert not pseudo.isnc
108+
assert pseudo.ispaw
109+
assert pseudo.Z == 28
110+
assert pseudo.symbol == symbol
111+
assert pseudo.Z_val == 18
112+
assert pseudo.paw_radius >= 0.0
113+
114+
assert pseudo.l_max == 2
115+
assert pseudo.l_local == 0
116+
assert pseudo.supports_soc
117+
assert pseudo.md5 is not None
118+
119+
# Test pickle
120+
self.serialize_with_pickle(pseudo)
121+
122+
# Test MSONable
123+
self.assert_msonable(pseudo)
124+
93125
def test_pawxml_pseudos(self):
94126
"""Test O.GGA_PBE-JTH-paw.xml."""
95127
oxygen = Pseudo.from_file(f"{TEST_DIR}/O.GGA_PBE-JTH-paw.xml")

0 commit comments

Comments
 (0)