Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support of all lammps dump coordinate style #179

Merged
merged 9 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 29 additions & 36 deletions dpdata/lammps/dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,45 +51,38 @@ def get_natoms_vec(lines) :
assert (sum(natoms_vec) == get_natoms(lines))
return natoms_vec

def get_posi(lines) :
def get_coordtype_and_scalefactor(keys):
# 4 types in total,with different scaling factor
key_pc=['x','y','z'] # plain cartesian, sf = 1
key_uc=['xu','yu','zu'] # unwraped cartesian, sf = 1
key_s=['xs','ys','zs'] # scaled by lattice parameter, sf = lattice parameter
key_su = ['xsu','ysu','zsu'] #scaled and unfolded,sf = lattice parameter
lmp_coor_type = [key_pc,key_uc,key_s,key_su]
sf = [0,0,1,1]
for k in range(4):
if all(i in keys for i in lmp_coor_type[k]):
return lmp_coor_type[k],sf[k]

def safe_get_posi(lines,cell,orig=np.zeros(3)) :
blk, head = _get_block(lines, 'ATOMS')
keys = head.split()
coord_tp_and_sf = get_coordtype_and_scalefactor(keys)
assert coord_tp_and_sf is not None, 'Dump file does not contain atomic coordinates!'
coordtype, sf = coord_tp_and_sf
id_idx = keys.index('id') - 2
xidx = keys.index('x') - 2
yidx = keys.index('y') - 2
zidx = keys.index('z') - 2
xidx = keys.index(coordtype[0])-2
yidx = keys.index(coordtype[1])-2
zidx = keys.index(coordtype[2])-2
sel = (xidx, yidx, zidx)
posis = []
for ii in blk :
words = ii.split()
posis.append([float(words[id_idx]), float(words[xidx]), float(words[yidx]), float(words[zidx])])
posis.sort()
posis = np.array(posis)
return posis[:,1:4]

def get_posi_frac(lines) :
blk, head = _get_block(lines, 'ATOMS')
keys = head.split()
id_idx = keys.index('id') - 2
xidx = keys.index('xs') - 2
yidx = keys.index('ys') - 2
zidx = keys.index('zs') - 2
sel = (xidx, yidx, zidx)
posis = []
for ii in blk :
words = ii.split()
posis.append([float(words[id_idx]), float(words[xidx]), float(words[yidx]), float(words[zidx])])
posis.sort()
posis = np.array(posis)
return posis[:,1:4]

def safe_get_posi(lines, cell, orig = np.zeros(3)):
try:
posis = get_posi(lines) - orig
except ValueError:
fposis = get_posi_frac(lines)
posis = fposis @ cell
return posis
posis = np.array(posis)[:,1:4]
if not sf:
posis = (posis-orig)@np.linalg.inv(cell)# Convert to scaled coordinates for unscaled coordinates
return (posis%1)@cell # Convert scaled coordinates back to Cartesien coordinates
Comment on lines +83 to +85
Copy link
Member

@amcadmus amcadmus Aug 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@y1xiaoc The scaled coordinates are converted to Cartesian coordinates, is it the expected behavior?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For orig equals to zero this should be correct.

For a Cartesian and folded coordinates (with keys x, y and z, i.e. the originally supported one) with a non-zero orig, this will change the behavior by forcing the shifted coordinate fit into the cell. For example, for a coord orginally range in (0,10) and a orig = 5, original version will lead to a coord range in (-5,5) but current version (due to the %1 operation) will warp the coord back into range (0, 10) again.

I'm not sure what is the orig parameter used for (and it seems to be ignored for scaled coordinates in both original and current version) so I cannot tell this change of behavior is problematic or not.


def get_dumpbox(lines) :
blk, h = _get_block(lines, 'BOX BOUNDS')
Expand Down Expand Up @@ -211,16 +204,16 @@ def split_traj(dump_lines) :
# # print(get_natomtypes(lines))
# # print(get_natoms_vec(lines))
# posi = get_posi(lines)
# dbox, tilt = get_dumpbox(lines)
# orig, box = dumpbox2box(dbox, tilt)
# dbox1, tilt1 = box2dumpbox(orig, box)
# print(dbox - dbox1)
# print(tilt - tilt1)
# print(orig)
# print(box)
# np.savetxt('tmp.out', posi - orig, fmt='%.6f')
# print(system_data(lines))

lines = load_file('conf.5.dump', begin = 0, step = 2)
with open('tmp.out', 'w') as fp:
fp.write('\n'.join(lines))
lines = load_file('conf_unfold.dump', begin = 0, step = 1)
al = split_traj(lines)
s = system_data(lines,['O','H'])
#l = np.linalg.norm(s['cells'][1],axis=1)
#p = s['coords'][0] + l
#np.savetxt('p',p,fmt='%1.10f')
22 changes: 22 additions & 0 deletions tests/poscars/conf_s_su.dump
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ITEM: TIMESTEP
0
ITEM: NUMBER OF ATOMS
2
ITEM: BOX BOUNDS xy xz yz pp pp pp
0.0 5.0739861 1.2621856
0.0 2.7916155 1.2874292
0.0 2.2254033 0.7485898
ITEM: ATOMS id type xs ys zs
1 1 0.0 0.0 0.0
2 2 0.2472745002 0.2527254533 0.2477701458
ITEM: TIMESTEP
1
ITEM: NUMBER OF ATOMS
2
ITEM: BOX BOUNDS xy xz yz pp pp pp
0.0 5.0739861 1.2621856
0.0 2.7916155 1.2874292
0.0 2.2254033 0.7485898
ITEM: ATOMS id type xsu ysu zsu
1 1 0.0 0.0 0.0
2 2 1.2472745002 1.2527254533 1.2477701458
22 changes: 22 additions & 0 deletions tests/poscars/conf_unfold.dump
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ITEM: TIMESTEP
0
ITEM: NUMBER OF ATOMS
2
ITEM: BOX BOUNDS xy xz yz pp pp pp
0.0 5.0739861 1.2621856
0.0 2.7916155 1.2874292
0.0 2.2254033 0.7485898
ITEM: ATOMS id type xu yu zu
1 1 5.073986099999999944e+00 2.791615499999999805e+00 2.225403299999999973e+00
2 2 6.336171700000000406e+00 3.493418300000000087e+00 2.776791800099999818e+00
ITEM: TIMESTEP
0
ITEM: NUMBER OF ATOMS
2
ITEM: BOX BOUNDS xy xz yz pp pp pp
0.0 5.0739861 1.2621856
0.0 2.7916155 1.2874292
1.0 3.2254033 0.7485898
ITEM: ATOMS id type xu yu zu
1 1 5.073986099999999944e+00 2.791615499999999805e+00 3.225403299999999973e+00
2 2 6.336171700000000406e+00 3.493418300000000087e+00 3.776791800099999818e+00
26 changes: 26 additions & 0 deletions tests/poscars/test_lammps_dump_s_su.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os
import numpy as np
import unittest
from context import dpdata
from poscars.poscar_ref_oh import TestPOSCARoh

class TestDump(unittest.TestCase, TestPOSCARoh):

def setUp(self):
self.system = dpdata.System(os.path.join('poscars', 'conf_s_su.dump'),
type_map = ['O', 'H'])

class TestDump2(unittest.TestCase, TestPOSCARoh):

def setUp(self):
self.tmp_system = dpdata.System(os.path.join('poscars', 'conf_s_su.dump'),
type_map = ['O', 'H'])
self.system = self.tmp_system.sub_system([1])

def test_nframes (self) :
self.assertEqual(self.tmp_system.get_nframes(), 2)


if __name__ == '__main__':
unittest.main()

26 changes: 26 additions & 0 deletions tests/test_lammps_dump_unfold.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os
import numpy as np
import unittest
from context import dpdata
from poscars.poscar_ref_oh import TestPOSCARoh

class TestDump(unittest.TestCase, TestPOSCARoh):

def setUp(self):
self.system = dpdata.System(os.path.join('poscars', 'conf_unfold.dump'),
type_map = ['O', 'H'])

class TestDump2(unittest.TestCase, TestPOSCARoh):

def setUp(self):
self.tmp_system = dpdata.System(os.path.join('poscars', 'conf_unfold.dump'),
type_map = ['O', 'H'])
self.system = self.tmp_system.sub_system([1])

def test_nframes (self) :
self.assertEqual(self.tmp_system.get_nframes(), 2)


if __name__ == '__main__':
unittest.main()