Skip to content

Commit

Permalink
Reading spin densities from CHGCAR (#754)
Browse files Browse the repository at this point in the history
* bugfix for reading spin densities from CHGCAR

Signed-off-by: Nick Papior <[email protected]>
Co-authored-by: Nick Papior <[email protected]>
  • Loading branch information
tfrederiksen and zerothi authored Apr 22, 2024
1 parent 71360c5 commit f2d61b1
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ we hit release version 1.0.0.
- A new `AtomicMatrixPlot` to plot sparse matrices, #668

### Fixed
- fixed `CHGCAR` spin-polarized density reads, #754
- dispatch methods now searches the mro for best matches, #721
- all `eps` arguments has changed to `atol`
- methods with `axis` arguments now accepts the str equivalent 0==a
Expand Down
31 changes: 25 additions & 6 deletions src/sisl/io/vasp/chg.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,36 @@ class chgSileVASP(carSileVASP):

@sile_fh_open(True)
def read_grid(self, index=0, dtype=np.float64, **kwargs) -> Grid:
"""Reads the charge density from the file and returns with a grid (plus geometry)
r"""Reads the charge density from the file and returns with a grid (plus geometry)
Parameters
----------
index : int or array_like, optional
the index of the grid to read. For a spin-polarized VASP calculation 0 and 1 are
allowed, UP/DOWN. For non-collinear 0, 1, 2 or 3 is allowed which equals,
the index of the grid to read.
For spin-polarized calculations, 0 and 1 refer to the charge (spin-up plus spin-down) and
magnetitization (spin-up minus spin-down), respectively.
For non-collinear calculations, 0 refers to the charge while 1, 2 and 3 to
the magnetization in the :math:`\sigma_x`, :math:`\sigma_y`, and :math:`\sigma_z` directions, respectively.
TOTAL, x, y, z charge density with the Cartesian directions equal to the charge
magnetization. For array-like they refer to the fractional
contributions for each corresponding index.
magnetization.
For array-like they refer to the fractional contributions for each corresponding index.
dtype : numpy.dtype, optional
grid stored dtype
spin : optional
same as `index` argument. `spin` argument has precedence.
Examples
--------
Read the spin polarization from a spin-polarized CHGCAR file
>>> fh = sisl.get_sile('CHGCAR')
>>> charge = fh.read_grid()
>>> spin = fh.read_grid(1)
>>> up_density = fh.read_grid([0.5, 0.5])
>>> assert np.allclose((charge + spin).grid / 2, up_density.grid)
>>> down_density = fh.read_grid([0.5, -0.5])
>>> assert np.allclose((charge - spin).grid / 2, down_density.grid)
Returns
-------
Grid
Expand Down Expand Up @@ -90,8 +105,12 @@ def read_grid(self, index=0, dtype=np.float64, **kwargs) -> Grid:
while j < occ:
j += len(rl().split())
line = rl()
# read over an additional block with geom.na entries???
j = len(line.split())
while j < geom.na:
j += len(rl().split())
# one line of nx, ny, nz
rl()
assert np.allclose(list(map(int, rl().split())), [nx, ny, nz])

# Cut size before proceeding (otherwise it *may* fail)
vals = np.array(vals).astype(dtype, copy=False)
Expand Down
38 changes: 36 additions & 2 deletions src/sisl/io/vasp/tests/test_chg.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,47 @@ def test_nitric_oxide_pol(sisl_files, chg_type, np_dtype):

assert grid.grid.sum() * grid.dvolume == pytest.approx(1, rel=1e-3)
assert geom == grid.geometry
# check against first raw datapoint on grid
if chg_type == "CHG":
assert grid.grid[0, 0, 0] * grid.volume == pytest.approx(0.33228e-03)
elif chg_type == "CHGCAR":
assert grid.grid[0, 0, 0] * grid.volume == pytest.approx(0.49880745183e-03)

# construct up-spin density
chg = chgSileVASP(f).read_grid(0, dtype=np_dtype)
grid.grid += chg.grid
grid.grid /= 2
up_spin = chgSileVASP(f).read_grid([0.5, 0.5], dtype=np_dtype)
assert np.allclose(grid.grid, up_spin.grid)


def test_nitric_oxide_soi(sisl_files, chg_type, np_dtype):
f = sisl_files(_dir, "nitric_oxide/soi", chg_type + ".gz")
grids = []
for i in range(4):
grid = chgSileVASP(f).read_grid(i, dtype=np_dtype)
grids.append(grid)
# check against first raw datapoint on grid
if chg_type == "CHG":
val = [0.12505, 0.26118e-03, 0.26791e-03, 0.27440e-03][i]
assert grid.grid[0, 0, 0] * grid.volume == pytest.approx(val)
elif chg_type == "CHGCAR":
val = [
0.12504989341e00,
0.26117671499e-03,
0.26791165124e-03,
0.27440440526e-03,
][i]
assert grid.grid[0, 0, 0] * grid.volume == pytest.approx(val)

s = 0
for i in range(1, 4):
grid = chgSileVASP(f).read_grid(i, dtype=np_dtype)
grid = grids[i]
s += (grid.grid.sum() * grid.dvolume) ** 2

assert s == pytest.approx(1, rel=1e-3)

# construct up-spin density
grid.grid += grids[0].grid
grid.grid /= 2
up_spin = chgSileVASP(f).read_grid([0.5, 0, 0, 0.5], dtype=np_dtype)
assert np.allclose(grid.grid, up_spin.grid)

0 comments on commit f2d61b1

Please sign in to comment.