Skip to content

Commit 4b6c994

Browse files
committed
Fix reading/writing xyz file when PBC specified as str
1 parent 1736637 commit 4b6c994

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

kliff/dataset/extxyz.py

+27-5
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,22 @@ def read_extxyz(
4646
cell = _parse_key_value(line, "Lattice", "float", 9, filename)
4747
cell = np.reshape(cell, (3, 3))
4848

49-
# PBC
50-
PBC = _parse_key_value(line, "PBC", "int", 3, filename)
49+
# PBC integer (0, 1) or str ("T", "F")
50+
PBC = _parse_key_value(line, "PBC", "str", 3, filename)
51+
try:
52+
PBC = [bool(int(i)) for i in PBC]
53+
except ValueError:
54+
tmp = []
55+
for p in PBC:
56+
if p.lower() == "t":
57+
tmp.append(True)
58+
elif p.lower() == "f":
59+
tmp.append(False)
60+
else:
61+
raise InputError(
62+
f"Invalid PBC value {p} at line 2 of file {filename}."
63+
)
64+
PBC = tmp
5165

5266
# energy is optional
5367
try:
@@ -125,6 +139,7 @@ def write_extxyz(
125139
energy: Optional[float] = None,
126140
forces: Optional[np.ndarray] = None,
127141
stress: Optional[List[float]] = None,
142+
bool_as_str: bool = False,
128143
):
129144
"""
130145
Write configuration info to a file in extended xyz file_format.
@@ -139,6 +154,8 @@ def write_extxyz(
139154
forces: Nx3 array, forces on atoms; If `None`, not write to file
140155
stress: 1D array of size 6, stress on the cell in Voigt notation; If `None`,
141156
not write to file
157+
bool_as_str: If `True`, write PBC as "T" or "F"; otherwise, write PBC as 1 or 0.
158+
142159
"""
143160

144161
with open(filename, "w") as fout:
@@ -155,7 +172,10 @@ def write_extxyz(
155172
else:
156173
fout.write("{:.15g} ".format(item))
157174

158-
PBC = [int(i) for i in PBC]
175+
if bool_as_str:
176+
PBC = ["T" if i else "F" for i in PBC]
177+
else:
178+
PBC = [int(i) for i in PBC]
159179
fout.write('PBC="{} {} {}" '.format(PBC[0], PBC[1], PBC[2]))
160180

161181
if energy is not None:
@@ -204,7 +224,7 @@ def _parse_key_value(
204224
Args:
205225
line: The string line.
206226
key: Keyword to parse.
207-
dtype: Expected data type of value, `int` or `float`.
227+
dtype: Expected data type of value, `int`, `float` or `str`.
208228
size: Expected size of value.
209229
filename: File name where the line comes from.
210230
@@ -221,7 +241,7 @@ def _parse_key_value(
221241
else:
222242
value = value[value.index("=") + 1 :]
223243
value = value.lstrip(" ")
224-
value += " " # add an whitespace at end in case this is the last key
244+
value += " " # add a whitespace at end in case this is the last key
225245
value = value[: value.index(" ")]
226246
value = value.split()
227247
except Exception as e:
@@ -237,6 +257,8 @@ def _parse_key_value(
237257
value = [float(i) for i in value]
238258
elif dtype == "int":
239259
value = [int(i) for i in value]
260+
elif dtype == "str":
261+
pass
240262
except Exception as e:
241263
raise InputError(f"{e}.\nCorrupted {key} data at line 2 of file {filename}.")
242264

tests/dataset/test_extxyz.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,34 @@
11
import numpy as np
22
import pytest
33

4-
from kliff.dataset.dataset import Configuration, Dataset
4+
from kliff.dataset.dataset import Configuration, Dataset, read_extxyz, write_extxyz
5+
6+
7+
def test_read_write_extxyz(test_data_dir, tmp_dir):
8+
path = test_data_dir.joinpath("configs/MoS2/MoS2_energy_forces_stress.xyz")
9+
cell, species, coords, PBC, energy, forces, stress = read_extxyz(path)
10+
11+
fname = "test.xyz"
12+
write_extxyz(
13+
fname,
14+
cell,
15+
species,
16+
coords,
17+
PBC,
18+
energy,
19+
forces,
20+
stress,
21+
bool_as_str=True,
22+
)
23+
cell1, species1, coords1, PBC1, energy1, forces1, stress1 = read_extxyz(fname)
24+
25+
assert np.allclose(cell, cell1)
26+
assert species == species1
27+
assert np.allclose(coords, coords1)
28+
assert PBC == PBC1
29+
assert energy == energy1
30+
assert np.allclose(forces, forces1)
31+
assert stress == stress1
532

633

734
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)