Skip to content

Commit 769ccf4

Browse files
authored
Merge pull request #353 from deepmodeling/devel
merge recent development on devel to master
2 parents f8d70a4 + b73a49e commit 769ccf4

Some content is hidden

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

89 files changed

+43115
-4877
lines changed

.github/workflows/test.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Python package
2+
3+
on:
4+
- push
5+
- pull_request
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
strategy:
11+
matrix:
12+
python-version: [3.7, 3.8]
13+
PYMATGEN_VERSION: [2019.1.13, 2019.7.30]
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- name: Set up Python ${{ matrix.python-version }}
18+
uses: actions/setup-python@v2
19+
with:
20+
python-version: ${{ matrix.python-version }}
21+
- name: Install dependencies
22+
run: pip install coverage codecov pymatgen==${{ matrix.PYMATGEN_VERSION }} .
23+
- name: Test
24+
run: coverage run --source=./dpgen -m unittest -v && coverage report
25+
- run: codecov

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ dpgen.egg-info
3737
.eggs
3838
.coverage
3939
dbconfig.json
40-
.vscode/*
40+
.vscode/*
41+
.idea/*

.travis.yml

Lines changed: 0 additions & 19 deletions
This file was deleted.

README.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,8 @@ The bold notation of key (such aas **type_map**) means that it's a necessary key
571571
|**fp_params["mixingweight"]** | Float| 0.05 | Proportion a of output Density Matrix to be used for the input Density Matrix of next SCF cycle (linear mixing).
572572
|**fp_params["NumberPulay"]** | Integer| 5 | Controls the Pulay convergence accelerator.
573573
| *fp_style == cp2k*
574-
| **fp_params** | Dict | |Parameters for cp2k calculation. find detail in manual.cp2k.org. only the kind section must be set before use. we assume that you have basic knowledge for cp2k input.
574+
| **user_fp_params** | Dict | |Parameters for cp2k calculation. find detail in manual.cp2k.org. only the kind section must be set before use. we assume that you have basic knowledge for cp2k input.
575+
| **external_input_path** | String | | Conflict with key:user_fp_params, use the template input provided by user, some rules should be followed, read the following text in detail.
575576

576577

577578
#### Rules for cp2k input at dictionary form
@@ -609,9 +610,54 @@ Here are examples for setting:
609610
}
610611
}
611612
}
613+
```
614+
615+
#### Rules for use cp2k template input provided by user
616+
617+
See Full example template.inp and dpgen input parameter file in
618+
619+
`tests/generator/cp2k_make_fp_files/exinput/template.inp` and `tests/generator/param-mgo-cp2k-exinput.json`
620+
621+
Here is example for provide external input
622+
623+
```python
624+
{
625+
"_comment": " 02.fp ",
626+
"fp_style": "cp2k",
627+
"shuffle_poscar": false,
628+
"fp_task_max": 100,
629+
"fp_task_min": 10,
630+
"fp_pp_path": ".",
631+
"fp_pp_files": [],
632+
"external_input_path": "./cp2k_make_fp_files/exinput/template.inp",
633+
"_comment": " that's all
634+
}
612635
```
613636

637+
the following essential section should be provided in user template
614638

639+
```
640+
641+
&FORCE_EVAL
642+
# add this line if you need to fit virial
643+
STRESS_TENSOR ANALYTICAL
644+
&PRINT
645+
&FORCES ON
646+
&END FORCES
647+
# add this line if you need to fit virial
648+
&STRESS_TENSOR ON
649+
&END FORCES
650+
&END PRINT
651+
&SUBSYS
652+
&CELL
653+
ABC LEFT FOR DPGEN
654+
&END CELL
655+
&COORD
656+
@include coord.xyz
657+
&END COORD
658+
&END SUBSYS
659+
&END FORCE_EVAL
660+
```
615661

616662
## Test: Auto-test for Deep Generator
617663
### configure and param.json

dpgen/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
SHORT_CMD="dpgen"
99
dlog = logging.getLogger(__name__)
1010
dlog.setLevel(logging.INFO)
11-
dlogf = logging.FileHandler(os.getcwd()+os.sep+SHORT_CMD+'.log')
11+
dlogf = logging.FileHandler(os.getcwd()+os.sep+SHORT_CMD+'.log', delay=True)
1212
dlogf_formatter=logging.Formatter('%(asctime)s - %(levelname)s : %(message)s')
1313
#dlogf_formatter=logging.Formatter('%(asctime)s - %(name)s - [%(filename)s:%(funcName)s - %(lineno)d ] - %(levelname)s \n %(message)s')
1414
dlogf.setFormatter(dlogf_formatter)

dpgen/auto_test/EOS.py

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import glob
2+
import json
3+
import os
4+
import re
5+
6+
import numpy as np
7+
from monty.serialization import loadfn, dumpfn
8+
9+
import dpgen.auto_test.lib.vasp as vasp
10+
from dpgen import dlog
11+
from dpgen.auto_test.Property import Property
12+
from dpgen.auto_test.refine import make_refine
13+
from dpgen.auto_test.reproduce import make_repro
14+
from dpgen.auto_test.reproduce import post_repro
15+
16+
17+
class EOS(Property):
18+
def __init__(self,
19+
parameter):
20+
parameter['reproduce'] = parameter.get('reproduce', False)
21+
self.reprod = parameter['reproduce']
22+
if not self.reprod:
23+
if not ('init_from_suffix' in parameter and 'output_suffix' in parameter):
24+
self.vol_start = parameter['vol_start']
25+
self.vol_end = parameter['vol_end']
26+
self.vol_step = parameter['vol_step']
27+
parameter['cal_type'] = parameter.get('cal_type', 'relaxation')
28+
self.cal_type = parameter['cal_type']
29+
default_cal_setting = {"relax_pos": True,
30+
"relax_shape": True,
31+
"relax_vol": False}
32+
if 'cal_setting' not in parameter:
33+
parameter['cal_setting'] = default_cal_setting
34+
else:
35+
if "relax_pos" not in parameter['cal_setting']:
36+
parameter['cal_setting']['relax_pos'] = default_cal_setting['relax_pos']
37+
if "relax_shape" not in parameter['cal_setting']:
38+
parameter['cal_setting']['relax_shape'] = default_cal_setting['relax_shape']
39+
if "relax_vol" not in parameter['cal_setting']:
40+
parameter['cal_setting']['relax_vol'] = default_cal_setting['relax_vol']
41+
self.cal_setting = parameter['cal_setting']
42+
else:
43+
parameter['cal_type'] = 'static'
44+
self.cal_type = parameter['cal_type']
45+
default_cal_setting = {"relax_pos": False,
46+
"relax_shape": False,
47+
"relax_vol": False}
48+
if 'cal_setting' not in parameter:
49+
parameter['cal_setting'] = default_cal_setting
50+
else:
51+
if "relax_pos" not in parameter['cal_setting']:
52+
parameter['cal_setting']['relax_pos'] = default_cal_setting['relax_pos']
53+
if "relax_shape" not in parameter['cal_setting']:
54+
parameter['cal_setting']['relax_shape'] = default_cal_setting['relax_shape']
55+
if "relax_vol" not in parameter['cal_setting']:
56+
parameter['cal_setting']['relax_vol'] = default_cal_setting['relax_vol']
57+
self.cal_setting = parameter['cal_setting']
58+
parameter['init_from_suffix'] = parameter.get('init_from_suffix', '00')
59+
self.init_from_suffix = parameter['init_from_suffix']
60+
self.parameter = parameter
61+
62+
def make_confs(self,
63+
path_to_work,
64+
path_to_equi,
65+
refine=False):
66+
path_to_work = os.path.abspath(path_to_work)
67+
if os.path.exists(path_to_work):
68+
dlog.warning('%s already exists' % path_to_work)
69+
else:
70+
os.makedirs(path_to_work)
71+
path_to_equi = os.path.abspath(path_to_equi)
72+
73+
if 'start_confs_path' in self.parameter and os.path.exists(self.parameter['start_confs_path']):
74+
init_path_list = glob.glob(os.path.join(self.parameter['start_confs_path'], '*'))
75+
struct_init_name_list = []
76+
for ii in init_path_list:
77+
struct_init_name_list.append(ii.split('/')[-1])
78+
struct_output_name = path_to_work.split('/')[-2]
79+
assert struct_output_name in struct_init_name_list
80+
path_to_equi = os.path.abspath(os.path.join(self.parameter['start_confs_path'],
81+
struct_output_name, 'relaxation', 'relax_task'))
82+
83+
cwd = os.getcwd()
84+
task_list = []
85+
if self.reprod:
86+
print('eos reproduce starts')
87+
if 'init_data_path' not in self.parameter:
88+
raise RuntimeError("please provide the initial data path to reproduce")
89+
init_data_path = os.path.abspath(self.parameter['init_data_path'])
90+
task_list = make_repro(init_data_path, self.init_from_suffix,
91+
path_to_work, self.parameter.get('reprod_last_frame', True))
92+
os.chdir(cwd)
93+
94+
else:
95+
if refine:
96+
print('eos refine starts')
97+
task_list = make_refine(self.parameter['init_from_suffix'],
98+
self.parameter['output_suffix'],
99+
path_to_work)
100+
os.chdir(cwd)
101+
102+
init_from_path = re.sub(self.parameter['output_suffix'][::-1],
103+
self.parameter['init_from_suffix'][::-1],
104+
path_to_work[::-1], count=1)[::-1]
105+
task_list_basename = list(map(os.path.basename, task_list))
106+
107+
for ii in task_list_basename:
108+
init_from_task = os.path.join(init_from_path, ii)
109+
output_task = os.path.join(path_to_work, ii)
110+
os.chdir(output_task)
111+
if os.path.isfile('eos.json'):
112+
os.remove('eos.json')
113+
if os.path.islink('eos.json'):
114+
os.remove('eos.json')
115+
os.symlink(os.path.relpath(os.path.join(init_from_task, 'eos.json')), 'eos.json')
116+
os.chdir(cwd)
117+
118+
else:
119+
print('gen eos from ' + str(self.vol_start) + ' to ' + str(self.vol_end) + ' by every ' + str(self.vol_step))
120+
equi_contcar = os.path.join(path_to_equi, 'CONTCAR')
121+
if not os.path.exists(equi_contcar):
122+
raise RuntimeError("please do relaxation first")
123+
vol_to_poscar = vasp.poscar_vol(equi_contcar) / vasp.poscar_natoms(equi_contcar)
124+
self.parameter['scale2equi'] = []
125+
126+
task_num = 0
127+
while self.vol_start + self.vol_step * task_num < self.vol_end:
128+
# for vol in np.arange(int(self.vol_start * 100), int(self.vol_end * 100), int(self.vol_step * 100)):
129+
# vol = vol / 100.0
130+
vol = self.vol_start + task_num * self.vol_step
131+
#task_num = int((vol - self.vol_start) / self.vol_step)
132+
output_task = os.path.join(path_to_work, 'task.%06d' % task_num)
133+
os.makedirs(output_task, exist_ok=True)
134+
os.chdir(output_task)
135+
for ii in ['INCAR', 'POTCAR', 'POSCAR.orig', 'POSCAR', 'conf.lmp', 'in.lammps']:
136+
if os.path.exists(ii):
137+
os.remove(ii)
138+
task_list.append(output_task)
139+
os.symlink(os.path.relpath(equi_contcar), 'POSCAR.orig')
140+
# scale = (vol / vol_to_poscar) ** (1. / 3.)
141+
scale = vol ** (1. / 3.)
142+
eos_params = {'volume': vol * vol_to_poscar, 'scale': scale}
143+
dumpfn(eos_params, 'eos.json', indent=4)
144+
self.parameter['scale2equi'].append(scale) # 06/22
145+
vasp.poscar_scale('POSCAR.orig', 'POSCAR', scale)
146+
task_num += 1
147+
os.chdir(cwd)
148+
return task_list
149+
150+
def post_process(self, task_list):
151+
pass
152+
153+
def task_type(self):
154+
return self.parameter['type']
155+
156+
def task_param(self):
157+
return self.parameter
158+
159+
def _compute_lower(self,
160+
output_file,
161+
all_tasks,
162+
all_res):
163+
output_file = os.path.abspath(output_file)
164+
res_data = {}
165+
ptr_data = "conf_dir: " + os.path.dirname(output_file) + "\n"
166+
if not self.reprod:
167+
ptr_data += ' VpA(A^3) EpA(eV)\n'
168+
for ii in range(len(all_tasks)):
169+
# vol = self.vol_start + ii * self.vol_step
170+
vol = loadfn(os.path.join(all_tasks[ii], 'eos.json'))['volume']
171+
task_result = loadfn(all_res[ii])
172+
res_data[vol] = task_result['energies'][-1] / task_result['atom_numbs'][0]
173+
ptr_data += '%7.3f %8.4f \n' % (vol, task_result['energies'][-1] / task_result['atom_numbs'][0])
174+
# res_data[vol] = all_res[ii]['energy'] / len(all_res[ii]['force'])
175+
# ptr_data += '%7.3f %8.4f \n' % (vol, all_res[ii]['energy'] / len(all_res[ii]['force']))
176+
177+
else:
178+
if 'init_data_path' not in self.parameter:
179+
raise RuntimeError("please provide the initial data path to reproduce")
180+
init_data_path = os.path.abspath(self.parameter['init_data_path'])
181+
res_data, ptr_data = post_repro(init_data_path, self.parameter['init_from_suffix'],
182+
all_tasks, ptr_data, self.parameter.get('reprod_last_frame', True))
183+
184+
with open(output_file, 'w') as fp:
185+
json.dump(res_data, fp, indent=4)
186+
187+
return res_data, ptr_data

0 commit comments

Comments
 (0)