Skip to content

Commit b774c0b

Browse files
author
Han Wang
committed
fix: skip empty frame properties when dumping deepmd format
When an ABACUS SCF run converges but computes no forces/stress (e.g. cal_force/cal_stress disabled, as happens with some GPU/cusolver runs), dpdata produces a LabeledSystem with size-0 forces. Dumping it to deepmd/npy or deepmd/raw wrote a meaningless (nframes, 0) array, which then failed to reload with 'cannot reshape array of size 0 into shape (nframes, natoms, 3)'. Skip empty optional frame properties on dump instead. A missing force/virial file is already a supported state on load, so the round-trip is now consistent. Fixes deepmodeling#977
1 parent 7d75096 commit b774c0b

3 files changed

Lines changed: 41 additions & 0 deletions

File tree

dpdata/formats/deepmd/comp.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True):
152152
f"Shape of {dtype.name} is not (nframes, ...), but {dtype.shape}. This type of data will not converted to deepmd/npy format."
153153
)
154154
continue
155+
if nframes > 0 and np.asarray(data[dtype.name]).size == 0:
156+
# an optional frame property (e.g. forces/virials when
157+
# cal_force/cal_stress is disabled) may be empty while the
158+
# system still has frames. Skip it instead of writing a
159+
# meaningless (nframes, 0) array that cannot be reshaped on load.
160+
continue
155161
ddata = np.reshape(data[dtype.name], [nframes, -1])
156162
if np.issubdtype(ddata.dtype, np.floating):
157163
ddata = ddata.astype(comp_prec)

dpdata/formats/deepmd/raw.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,11 @@ def dump(folder, data):
136136
f"Shape of {dtype.name} is not (nframes, ...), but {dtype.shape}. This type of data will not converted to deepmd/raw format."
137137
)
138138
continue
139+
if nframes > 0 and np.asarray(data[dtype.name]).size == 0:
140+
# an optional frame property (e.g. forces/virials when
141+
# cal_force/cal_stress is disabled) may be empty while the
142+
# system still has frames. Skip it instead of writing a
143+
# meaningless (nframes, 0) array that cannot be reshaped on load.
144+
continue
139145
ddata = np.reshape(data[dtype.name], [nframes, -1])
140146
np.savetxt(os.path.join(folder, f"{dtype.deepmd_name}.raw"), ddata)

tests/test_abacus_pw_scf.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
import shutil
5+
import tempfile
56
import unittest
67

78
import numpy as np
@@ -163,6 +164,34 @@ def test_noforcestress_job(self):
163164
# test append self
164165
system_ch4.append(system_ch4)
165166

167+
def test_noforcestress_deepmd_roundtrip(self):
168+
# a converged scf without force/stress should survive a
169+
# round-trip through deepmd/npy without raising a reshape error
170+
system_ch4 = dpdata.LabeledSystem("abacus.scf", fmt="abacus/scf")
171+
tmp_dir = tempfile.mkdtemp()
172+
try:
173+
system_ch4.to("deepmd/npy", tmp_dir)
174+
reloaded = dpdata.LabeledSystem(tmp_dir, fmt="deepmd/npy")
175+
self.assertEqual(reloaded.get_nframes(), system_ch4.get_nframes())
176+
# empty force/virial should not be written as bogus data
177+
self.assertFalse(reloaded.data.get("forces", np.empty(0)).size)
178+
self.assertTrue("virials" not in reloaded.data)
179+
finally:
180+
shutil.rmtree(tmp_dir)
181+
182+
def test_noforcestress_deepmd_raw_roundtrip(self):
183+
# same as above but for the deepmd/raw format
184+
system_ch4 = dpdata.LabeledSystem("abacus.scf", fmt="abacus/scf")
185+
tmp_dir = tempfile.mkdtemp()
186+
try:
187+
system_ch4.to("deepmd/raw", tmp_dir)
188+
reloaded = dpdata.LabeledSystem(tmp_dir, fmt="deepmd/raw")
189+
self.assertEqual(reloaded.get_nframes(), system_ch4.get_nframes())
190+
self.assertFalse(reloaded.data.get("forces", np.empty(0)).size)
191+
self.assertTrue("virials" not in reloaded.data)
192+
finally:
193+
shutil.rmtree(tmp_dir)
194+
166195

167196
if __name__ == "__main__":
168197
unittest.main()

0 commit comments

Comments
 (0)