Skip to content

Commit da48136

Browse files
add unwrap support for lammps dump (#339)
* add unwarp support for lammps dump * let user choose to unwrap and add unittest case * temp to revert format changes * clean up * add warning for unwrap * add UnwrapWarning class
1 parent 1056b0b commit da48136

File tree

4 files changed

+41
-15
lines changed

4 files changed

+41
-15
lines changed

dpdata/lammps/dump.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
lib_path = os.path.dirname(os.path.realpath(__file__))
66
sys.path.append(lib_path)
77
import lmp
8+
import warnings
9+
class UnwrapWarning(UserWarning):
10+
pass
11+
warnings.simplefilter('once', UnwrapWarning)
12+
813

914
def _get_block (lines, key) :
1015
for idx in range(len(lines)) :
@@ -59,16 +64,17 @@ def get_coordtype_and_scalefactor(keys):
5964
key_su = ['xsu','ysu','zsu'] #scaled and unfolded,sf = lattice parameter
6065
lmp_coor_type = [key_pc,key_uc,key_s,key_su]
6166
sf = [0,0,1,1]
67+
uw = [0,1,0,1] # unwraped or not
6268
for k in range(4):
6369
if all(i in keys for i in lmp_coor_type[k]):
64-
return lmp_coor_type[k],sf[k]
70+
return lmp_coor_type[k], sf[k], uw[k]
6571

66-
def safe_get_posi(lines,cell,orig=np.zeros(3)) :
72+
def safe_get_posi(lines,cell,orig=np.zeros(3), unwrap=False) :
6773
blk, head = _get_block(lines, 'ATOMS')
6874
keys = head.split()
6975
coord_tp_and_sf = get_coordtype_and_scalefactor(keys)
7076
assert coord_tp_and_sf is not None, 'Dump file does not contain atomic coordinates!'
71-
coordtype, sf = coord_tp_and_sf
77+
coordtype, sf, uw = coord_tp_and_sf
7278
id_idx = keys.index('id') - 2
7379
xidx = keys.index(coordtype[0])-2
7480
yidx = keys.index(coordtype[1])-2
@@ -81,8 +87,13 @@ def safe_get_posi(lines,cell,orig=np.zeros(3)) :
8187
posis.sort()
8288
posis = np.array(posis)[:,1:4]
8389
if not sf:
84-
posis = (posis-orig)@np.linalg.inv(cell)# Convert to scaled coordinates for unscaled coordinates
85-
return (posis%1)@cell # Convert scaled coordinates back to Cartesien coordinates
90+
posis = (posis - orig) @ np.linalg.inv(cell) # Convert to scaled coordinates for unscaled coordinates
91+
if uw and unwrap:
92+
return posis @ cell # convert scaled coordinates back to Cartesien coordinates unwrap at the periodic boundaries
93+
else:
94+
if uw and not unwrap:
95+
warnings.warn(message='Your dump file contains unwrapped coordinates, but you did not specify unwrapping (unwrap = True). The default is wrapping at periodic boundaries (unwrap = False).\n',category=UnwrapWarning)
96+
return (posis % 1) @ cell # Convert scaled coordinates back to Cartesien coordinates with wraping at periodic boundary conditions
8697

8798
def get_dumpbox(lines) :
8899
blk, h = _get_block(lines, 'BOX BOUNDS')
@@ -145,9 +156,9 @@ def load_file(fname, begin = 0, step = 1) :
145156
cc += 1
146157
if cc >= begin and (cc - begin) % step == 0 :
147158
buff.append(line)
148-
149159

150-
def system_data(lines, type_map = None, type_idx_zero = True) :
160+
161+
def system_data(lines, type_map = None, type_idx_zero = True, unwrap=False) :
151162
array_lines = split_traj(lines)
152163
lines = array_lines[0]
153164
system = {}
@@ -166,12 +177,12 @@ def system_data(lines, type_map = None, type_idx_zero = True) :
166177
system['cells'] = [np.array(cell)]
167178
natoms = sum(system['atom_numbs'])
168179
system['atom_types'] = get_atype(lines, type_idx_zero = type_idx_zero)
169-
system['coords'] = [safe_get_posi(lines, cell, np.array(orig))]
180+
system['coords'] = [safe_get_posi(lines, cell, np.array(orig), unwrap)]
170181
for ii in range(1, len(array_lines)) :
171182
bounds, tilt = get_dumpbox(array_lines[ii])
172183
orig, cell = dumpbox2box(bounds, tilt)
173184
system['cells'].append(cell)
174-
system['coords'].append(safe_get_posi(array_lines[ii], cell, np.array(orig)))
185+
system['coords'].append(safe_get_posi(array_lines[ii], cell, np.array(orig), unwrap))
175186
system['cells'] = np.array(system['cells'])
176187
system['coords'] = np.array(system['coords'])
177188
return system
@@ -181,7 +192,7 @@ def split_traj(dump_lines) :
181192
marks = []
182193
for idx,ii in enumerate(dump_lines) :
183194
if 'ITEM: TIMESTEP' in ii :
184-
marks.append(idx)
195+
marks.append(idx)
185196
if len(marks) == 0 :
186197
return None
187198
elif len(marks) == 1 :
@@ -191,9 +202,9 @@ def split_traj(dump_lines) :
191202
ret = []
192203
for ii in marks :
193204
ret.append(dump_lines[ii:ii+block_size])
194-
# for ii in range(len(marks)-1):
205+
# for ii in range(len(marks)-1):
195206
# assert(marks[ii+1] - marks[ii] == block_size)
196-
return ret
207+
return ret
197208
return None
198209

199210

dpdata/plugins/lammps.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def from_system(self,
4040
type_map=None,
4141
begin=0,
4242
step=1,
43+
unwrap=False,
4344
**kwargs):
4445
lines = dpdata.lammps.dump.load_file(file_name, begin=begin, step=step)
45-
return dpdata.lammps.dump.system_data(lines, type_map)
46+
return dpdata.lammps.dump.system_data(lines, type_map, unwrap=unwrap)

tests/poscars/poscar_ref_oh.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@ def test_cell(self):
2727
places = 6,
2828
msg = 'cell[%d][%d] failed' % (ii,jj))
2929

30-
def test_frame(self):
31-
ovito_posis = np.array([[0, 0, 0],
30+
def test_frame(self):
31+
if hasattr(self, "unwrap") and self.unwrap is True:
32+
ovito_posis = np.array([[5.0739861, 2.7916155, 2.2254033],
33+
[6.3361717, 3.4934183, 2.7767918]])
34+
else:
35+
ovito_posis = np.array([[0, 0, 0],
3236
[1.2621856, 0.7018028, 0.5513885]])
3337
for ii in range(2) :
3438
for jj in range(3) :

tests/test_lammps_dump_unfold.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ def test_nframes (self) :
2121
self.assertEqual(self.tmp_system.get_nframes(), 2)
2222

2323

24+
class TestDumpUnwrap(unittest.TestCase, TestPOSCARoh):
25+
def setUp(self):
26+
self.unwrap = True
27+
self.system = dpdata.System(
28+
os.path.join('poscars', 'conf_unfold.dump'),
29+
type_map=['O', 'H'],
30+
unwrap=self.unwrap,
31+
)
32+
33+
2434
if __name__ == '__main__':
2535
unittest.main()
2636

0 commit comments

Comments
 (0)