Skip to content

Commit 44db168

Browse files
author
Han Wang
committed
Merge branch 'devel'
2 parents 64805b9 + 94368f8 commit 44db168

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+4793
-49
lines changed

.github/workflows/pub-pypi.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Publish Python distributions to PyPI
2+
3+
on: push
4+
5+
jobs:
6+
build-n-publish:
7+
if: github.repository_owner == 'deepmodeling'
8+
name: Build and publish Python distributions to PyPI
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@master
12+
13+
- name: Set up Python 3.9
14+
uses: actions/setup-python@master
15+
with:
16+
python-version: 3.9
17+
18+
- name: Install pypa/build
19+
run: >-
20+
python -m
21+
pip install
22+
build
23+
--user
24+
25+
- name: Build a binary wheel and a source tarball
26+
run: >-
27+
python -m
28+
build
29+
--sdist
30+
--wheel
31+
--outdir dist/
32+
.
33+
34+
- name: Publish distribution to PyPI
35+
if: startsWith(github.ref, 'refs/tags')
36+
uses: pypa/gh-action-pypi-publish@master
37+
with:
38+
password: ${{ secrets.PYPI_API_TOKEN }}
39+

.github/workflows/test.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,15 @@ jobs:
1515
- uses: actions/checkout@v2
1616
# set up conda
1717
- name: Set up Python ${{ matrix.python-version }}
18-
uses: conda-incubator/setup-miniconda@v2
18+
uses: actions/setup-python@v4
1919
with:
20-
auto-activate-base: true
21-
activate-environment: ""
20+
python-version: ${{ matrix.python-version }}
2221
# install rdkit and openbabel
2322
- name: Install rdkit
24-
run: conda create -c conda-forge -n my-rdkit-env python=${{ matrix.python-version }} rdkit openbabel;
23+
run: python -m pip install rdkit openbabel-wheel
2524
- name: Install dependencies
26-
run: source $CONDA/bin/activate my-rdkit-env && pip install .[amber,ase,pymatgen] coverage codecov
25+
run: python -m pip install .[amber,ase,pymatgen] coverage codecov
2726
- name: Test
28-
run: source $CONDA/bin/activate my-rdkit-env && cd tests && coverage run --source=../dpdata -m unittest && cd .. && coverage combine tests/.coverage && coverage report
27+
run: cd tests && coverage run --source=../dpdata -m unittest && cd .. && coverage combine tests/.coverage && coverage report
2928
- name: Run codecov
30-
run: source $CONDA/bin/activate my-rdkit-env && codecov
29+
run: codecov

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ The `System` or `LabeledSystem` can be constructed from the following file forma
8282
| Gromacs | gro | True | False | System | 'gromacs/gro' |
8383
| ABACUS | STRU | False | True | LabeledSystem | 'abacus/scf' |
8484
| ABACUS | cif | True | True | LabeledSystem | 'abacus/md' |
85+
| ABACUS | STRU | True | True | LabeledSystem | 'abacus/relax' |
8586
| ase | structure | True | True | MultiSystems | 'ase/structure' |
8687

8788

docs/cli.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Command line interface
2+
======================
3+
4+
.. argparse::
5+
:module: dpdata.cli
6+
:func: dpdata_parser
7+
:prog: dpdata

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
'sphinx.ext.intersphinx',
4949
'numpydoc',
5050
'm2r2',
51+
'sphinxarg.ext',
5152
]
5253

5354
# Add any paths that contain templates here, relative to this directory.

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Welcome to dpdata's documentation!
1010
:maxdepth: 2
1111
:caption: Contents:
1212

13+
cli
1314
formats
1415
api/api
1516

dpdata/abacus/relax.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import os,sys
2+
import numpy as np
3+
from .scf import bohr2ang, kbar2evperang3, get_geometry_in, get_cell, get_coords
4+
5+
# Read in geometries from an ABACUS RELAX(CELL-RELAX) trajectory in OUT.XXXX/runnning_relax/cell-relax.log.
6+
7+
def get_log_file(fname, inlines):
8+
suffix = "ABACUS"
9+
calculation = "scf"
10+
for line in inlines:
11+
if "suffix" in line and "suffix"==line.split()[0]:
12+
suffix = line.split()[1]
13+
elif "calculation" in line and "calculation" == line.split()[0]:
14+
calculation = line.split()[1]
15+
logf = os.path.join(fname, "OUT.%s/running_%s.log"%(suffix,calculation))
16+
return logf
17+
18+
def get_coords_from_log(loglines,natoms):
19+
'''
20+
NOTICE: unit of coords and cells is Angstrom
21+
'''
22+
natoms_log = 0
23+
for line in loglines:
24+
if line[13:41] == "number of atom for this type":
25+
natoms_log += int(line.split()[-1])
26+
27+
assert(natoms_log>0 and natoms_log == natoms),"ERROR: detected atom number in log file is %d" % natoms
28+
29+
energy = []
30+
cells = []
31+
coords = []
32+
force = []
33+
stress = []
34+
35+
for i in range(len(loglines)):
36+
line = loglines[i]
37+
if line[18:41] == "lattice constant (Bohr)":
38+
a0 = float(line.split()[-1])
39+
elif len(loglines[i].split()) >=2 and loglines[i].split()[1] == 'COORDINATES':
40+
coords.append([])
41+
direct_coord = False
42+
if loglines[i].split()[0] == 'DIRECT':
43+
direct_coord = True
44+
for k in range(2,2+natoms):
45+
coords[-1].append(list(map(lambda x: float(x),loglines[i+k].split()[1:4])))
46+
elif loglines[i].split()[0] == 'CARTESIAN':
47+
for k in range(2,2+natoms):
48+
coords[-1].append(list(map(lambda x: float(x)*a0,loglines[i+k].split()[1:4])))
49+
else:
50+
assert(False),"Unrecongnized coordinate type, %s, line:%d" % (loglines[i].split()[0],i)
51+
52+
converg = True
53+
for j in range(i):
54+
if loglines[i-j-1][1:36] == 'Ion relaxation is not converged yet':
55+
converg = False
56+
break
57+
elif loglines[i-j-1][1:29] == 'Ion relaxation is converged!':
58+
converg = True
59+
break
60+
61+
if converg:
62+
for j in range(i+1,len(loglines)):
63+
if loglines[j][1:56] == "Lattice vectors: (Cartesian coordinate: in unit of a_0)":
64+
cells.append([])
65+
for k in range(1,4):
66+
cells[-1].append(list(map(lambda x:float(x)*a0,loglines[j+k].split()[0:3])))
67+
break
68+
else:
69+
cells.append(cells[-1])
70+
71+
if direct_coord:
72+
coords[-1] = coords[-1].dot(cells[-1])
73+
74+
elif line[4:15] == "TOTAL-FORCE":
75+
force.append([])
76+
for j in range(5,5+natoms):
77+
force[-1].append(list(map(lambda x:float(x),loglines[i+j].split()[1:4])))
78+
elif line[1:13] == "TOTAL-STRESS":
79+
stress.append([])
80+
for j in range(4,7):
81+
stress[-1].append(list(map(lambda x:float(x),loglines[i+j].split()[0:3])))
82+
elif line[1:14] == "final etot is":
83+
energy.append(float(line.split()[-2]))
84+
85+
assert(len(cells) == len(coords) or len(cells)+1 == len(coords)),"ERROR: detected %d coordinates and %d cells" % (len(coords),len(cells))
86+
if len(cells)+1 == len(coords): del(coords[-1])
87+
88+
energy = np.array(energy)
89+
cells = np.array(cells)
90+
coords = np.array(coords)
91+
stress = np.array(stress)
92+
force = np.array(force)
93+
94+
cells *= bohr2ang
95+
coords *= bohr2ang
96+
97+
virial = np.zeros([len(cells), 3, 3])
98+
for i in range(len(cells)):
99+
volume = np.linalg.det(cells[i, :, :].reshape([3, 3]))
100+
virial[i] = stress[i] * kbar2evperang3 * volume
101+
102+
return energy,cells,coords,force,stress,virial
103+
104+
def get_frame (fname):
105+
if type(fname) == str:
106+
# if the input parameter is only one string, it is assumed that it is the
107+
# base directory containing INPUT file;
108+
path_in = os.path.join(fname, "INPUT")
109+
else:
110+
raise RuntimeError('invalid input')
111+
with open(path_in, 'r') as fp:
112+
inlines = fp.read().split('\n')
113+
geometry_path_in = get_geometry_in(fname, inlines) # base dir of STRU
114+
with open(geometry_path_in, 'r') as fp:
115+
geometry_inlines = fp.read().split('\n')
116+
celldm, cell = get_cell(geometry_inlines)
117+
atom_names, natoms, types, coord_tmp = get_coords(celldm, cell, geometry_inlines, inlines)
118+
119+
logf = get_log_file(fname, inlines)
120+
assert(os.path.isfile(logf)),"Error: can not find %s" % logf
121+
with open(logf) as f1: lines = f1.readlines()
122+
123+
atomnumber = 0
124+
for i in natoms: atomnumber += i
125+
energy,cells,coords,force,stress,virial = get_coords_from_log(lines,atomnumber)
126+
127+
data = {}
128+
data['atom_names'] = atom_names
129+
data['atom_numbs'] = natoms
130+
data['atom_types'] = types
131+
data['cells'] = cells
132+
data['coords'] = coords
133+
data['energies'] = energy
134+
data['forces'] = force
135+
data['virials'] = virial
136+
data['stress'] = stress
137+
data['orig'] = np.zeros(3)
138+
139+
return data

dpdata/abacus/scf.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def get_block (lines, keyword, skip = 0, nlines = None):
3333
def get_geometry_in(fname, inlines):
3434
geometry_path_in = os.path.join(fname, "STRU")
3535
for line in inlines:
36-
if "atom_file" in line and "atom_file"==line.split()[0]:
36+
if "stru_file" in line and "stru_file"==line.split()[0]:
3737
atom_file = line.split()[1]
3838
geometry_path_in = os.path.join(fname, atom_file)
3939
break
@@ -148,7 +148,6 @@ def get_frame (fname):
148148

149149
geometry_path_in = get_geometry_in(fname, inlines)
150150
path_out = get_path_out(fname, inlines)
151-
152151
with open(geometry_path_in, 'r') as fp:
153152
geometry_inlines = fp.read().split('\n')
154153
with open(path_out, 'r') as fp:
@@ -233,7 +232,7 @@ def make_unlabeled_stru(data, frame_idx, pp_file=None, numerical_orbital=None, n
233232
for iele in range(len(data['atom_names'])):
234233
out += data['atom_names'][iele] + " "
235234
if mass is not None:
236-
out += "%d "%mass[iele]
235+
out += "%.3f "%mass[iele]
237236
else:
238237
out += "1 "
239238
if pp_file is not None:
@@ -280,4 +279,4 @@ def make_unlabeled_stru(data, frame_idx, pp_file=None, numerical_orbital=None, n
280279

281280
#if __name__ == "__main__":
282281
# path = "/home/lrx/work/12_ABACUS_dpgen_interface/dpdata/dpdata/tests/abacus.scf"
283-
# data = get_frame(path)
282+
# data = get_frame(path)

dpdata/amber/sqm.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ def make_sqm_in(data, fname=None, frame_idx=0, **kwargs):
9494
ret += " verbosity=4\n"
9595
ret += " /\n"
9696
for ii in range(len(data['atom_types'])):
97-
ret += "{:>4s}{:>6s}{:>14s}{:>14s}{:>14s}\n".format(
97+
ret += "{:>4s}{:>6s}{:>16s}{:>16s}{:>16s}\n".format(
9898
str(atomic_numbers[ii]),
9999
str(symbols[ii]),
100-
f"{data['coords'][frame_idx][ii, 0]:.4f}",
101-
f"{data['coords'][frame_idx][ii, 1]:.4f}",
102-
f"{data['coords'][frame_idx][ii, 2]:.4f}"
100+
f"{data['coords'][frame_idx][ii, 0]:.6f}",
101+
f"{data['coords'][frame_idx][ii, 1]:.6f}",
102+
f"{data['coords'][frame_idx][ii, 2]:.6f}"
103103
)
104104
if fname is not None:
105105
with open(fname, 'w') as fp:

dpdata/cli.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
from .system import System, LabeledSystem, MultiSystems
66

77

8-
def dpdata_cli():
9-
"""dpdata cli.
8+
def dpdata_parser() -> argparse.ArgumentParser:
9+
"""Returns dpdata cli parser.
1010
11-
Examples
12-
--------
13-
.. code-block:: bash
14-
15-
$ dpdata -iposcar POSCAR -odeepmd/npy -O data -n
11+
Returns
12+
-------
13+
argparse.ArgumentParser
14+
dpdata cli parser
1615
"""
1716
parser = argparse.ArgumentParser(
1817
description="dpdata: Manipulating multiple atomic simulation data formats",
@@ -28,7 +27,19 @@ def dpdata_cli():
2827
parser.add_argument("--type-map", "-t", type=str, nargs="+", help="type map")
2928

3029
parser.add_argument('--version', action='version', version='dpdata v%s' % __version__)
30+
return parser
3131

32+
33+
def dpdata_cli():
34+
"""dpdata cli.
35+
36+
Examples
37+
--------
38+
.. code-block:: bash
39+
40+
$ dpdata -iposcar POSCAR -odeepmd/npy -O data -n
41+
"""
42+
parser = dpdata_parser()
3243
parsed_args = parser.parse_args()
3344
convert(**vars(parsed_args))
3445

0 commit comments

Comments
 (0)