surface-construct 0.5.14__tar.gz → 0.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {surface_construct-0.5.14/surface_construct.egg-info → surface_construct-0.6}/PKG-INFO +1 -1
- {surface_construct-0.5.14 → surface_construct-0.6}/README.md +259 -259
- {surface_construct-0.5.14 → surface_construct-0.6}/setup.py +35 -35
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct/surface_grid.py +100 -79
- surface_construct-0.6/surface_construct/utils.py +255 -0
- {surface_construct-0.5.14 → surface_construct-0.6/surface_construct.egg-info}/PKG-INFO +1 -1
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct.egg-info/SOURCES.txt +1 -3
- surface_construct-0.5.14/surface_construct/utils.py +0 -37
- surface_construct-0.5.14/tests/test_surface_grid.py +0 -35
- surface_construct-0.5.14/tests/test_systematic_opt.py +0 -16
- {surface_construct-0.5.14 → surface_construct-0.6}/LICENSE +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/setup.cfg +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct/__init__.py +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct/atoms.py +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct/db.py +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct/default_parameter.py +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct/sampling.py +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct/structure.py +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct/surface.py +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct.egg-info/dependency_links.txt +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct.egg-info/requires.txt +0 -0
- {surface_construct-0.5.14 → surface_construct-0.6}/surface_construct.egg-info/top_level.txt +0 -0
|
@@ -1,259 +1,259 @@
|
|
|
1
|
-
# 基于分层采样策略的催化剂表面位点全局分析
|
|
2
|
-
|
|
3
|
-
A Method with Stratified Sampling Strategy for Comprehensive Analysis of Catalyst Surface Composed of Multiple Sites
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## 程序流程图 Program Workflow
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-

|
|
16
|
-
|
|
17
|
-
## 重要的概念 Glossary
|
|
18
|
-
|
|
19
|
-
* 表面格点 Grid:以范德华或者共价键长等值面进行离散化得到,表现为 (xi, yi, zi) 三维坐标。
|
|
20
|
-
|
|
21
|
-

|
|
22
|
-
|
|
23
|
-
* 表面向量 Vector:用来表征格点局部化学环境的向量表示方法,表现形式为 N 维的向量。
|
|
24
|
-
|
|
25
|
-
* 本方法中我们使用正则化的距离向量表达,其中距离是与N个最近邻原子之间的距离。
|
|
26
|
-
* 正则化是为了保证不同化学环境格点的区分度尽量大。我们这里使用距离的倒数作为正则化方法,即距离越远对化学环境的描述贡献越小。
|
|
27
|
-
* 为了减小计算量,在进行向量操作之前要对向量进行降维。降维的标准是保证保留尽可能多的信息,默认信息丢失不超过 5%。
|
|
28
|
-
|
|
29
|
-
* 向量化 Vectorization: 将格点转化为向量的过程
|
|
30
|
-
|
|
31
|
-
* 当前我们使用多点定位 Multilateration 进行向量化
|
|
32
|
-
|
|
33
|
-

|
|
34
|
-
|
|
35
|
-
* 分层采样 Stratified sampling。根据“相似结构具有相似性质”的原理采样分层采样的策略对表面位点进行采样,降低计算量。
|
|
36
|
-
|
|
37
|
-

|
|
38
|
-
|
|
39
|
-
* 吸附结构
|
|
40
|
-
|
|
41
|
-

|
|
42
|
-
|
|
43
|
-
## 安装
|
|
44
|
-
|
|
45
|
-
`pip install -U surface-construct`
|
|
46
|
-
|
|
47
|
-
## 发布新版本 (only for 管理员)
|
|
48
|
-
|
|
49
|
-
python -m build
|
|
50
|
-
twine upload --verbose dist/*
|
|
51
|
-
|
|
52
|
-
## 使用方法 Manual
|
|
53
|
-
|
|
54
|
-
### 所需文件 Required Files
|
|
55
|
-
|
|
56
|
-
* `surface_reaction_sample.py`: 主流程文件
|
|
57
|
-
|
|
58
|
-
* `parameter.py`: 参数定义文件
|
|
59
|
-
|
|
60
|
-
* `POSCAR.0`: 表面结构文件
|
|
61
|
-
|
|
62
|
-
* 注意:名字可以修改,与 `parameter.py` 设置一致
|
|
63
|
-
* 设置需要固定的原子
|
|
64
|
-
|
|
65
|
-
* bsub 文件。在公司集群上提交,以下面的为例
|
|
66
|
-
|
|
67
|
-
```Bash
|
|
68
|
-
#/bin/bash
|
|
69
|
-
#BSUB -J Sampling
|
|
70
|
-
#BSUB -q short
|
|
71
|
-
#BSUB -n 28
|
|
72
|
-
#BSUB -o out.%J.txt
|
|
73
|
-
#BSUB -e error.%J.txt
|
|
74
|
-
#BSUB -R span[ptile=28]
|
|
75
|
-
module load old/intel18u4
|
|
76
|
-
export OMP_NUM_THREADS=1
|
|
77
|
-
export I_MPI_ADJUST_REDUCE=3
|
|
78
|
-
workdir=`pwd`
|
|
79
|
-
date
|
|
80
|
-
|
|
81
|
-
export PATH="/export/home/renpengju/miniconda3/bin:$PATH"
|
|
82
|
-
export VASP_PP_PATH=$HOME/vasp/mypps
|
|
83
|
-
export VASP_SCRIPT=$workdir/run_vasp.py
|
|
84
|
-
|
|
85
|
-
cat > run_vasp.py << EOF
|
|
86
|
-
import os
|
|
87
|
-
exitcode = os.system('mpirun -PSM2 /export/soft_old/vasp541/vasp.5.4.1/bin/vasp_gam')
|
|
88
|
-
EOF
|
|
89
|
-
|
|
90
|
-
python surface_reaction_sample.py > surface_reaction_sample.py.log
|
|
91
|
-
|
|
92
|
-
date
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### 参数设置
|
|
96
|
-
|
|
97
|
-
注意:所有的参数均在 `parameter.py` 进行设置
|
|
98
|
-
|
|
99
|
-
```python
|
|
100
|
-
from ase.calculators.vasp import Vasp
|
|
101
|
-
import numpy as np
|
|
102
|
-
|
|
103
|
-
# 用户参数,以下参数必须设定,没有默认值
|
|
104
|
-
poscar = 'ru_0001_POSCAR'
|
|
105
|
-
atomnum = [7, 7] # 吸附的原子序号, 第一个原子靠近表面
|
|
106
|
-
bondlength = 1.65 # 初始的键长
|
|
107
|
-
angle = [np.pi / 2, 0.0] # 分子吸附的角度,[theta, phi_x]: [与 z 轴的角度,绕 z 轴的旋转角度(相对于x)]
|
|
108
|
-
|
|
109
|
-
# 以下参数可选,具有默认值
|
|
110
|
-
calc = Vasp(
|
|
111
|
-
xc='PBE',
|
|
112
|
-
gga='PE',
|
|
113
|
-
kpts=(1, 1, 1),
|
|
114
|
-
encut=400,
|
|
115
|
-
setups='recommended',
|
|
116
|
-
ncore=4,
|
|
117
|
-
gamma=True,
|
|
118
|
-
nelm=200,
|
|
119
|
-
algo='fast',
|
|
120
|
-
ismear=0,
|
|
121
|
-
sigma=0.05,
|
|
122
|
-
ibrion=-1, # 不使用 vasp 自身的优化,必须是 -1
|
|
123
|
-
ediff=1e-4,
|
|
124
|
-
prec='normal',
|
|
125
|
-
nsw=0, # 不使用 vasp 优化,必须是 0
|
|
126
|
-
lreal='Auto',
|
|
127
|
-
lwave=True, # 保存 WAVECAR 可以加速
|
|
128
|
-
lcharg=False,
|
|
129
|
-
ispin=1)
|
|
130
|
-
|
|
131
|
-
scan_type = 'transition_state' # 扫描类型:'optimization','transition_state'
|
|
132
|
-
grid_interval = 0.1 # angstrom, 格点的间距
|
|
133
|
-
Nsample = 5 # 第一次采样的点
|
|
134
|
-
Niter = 3 # 最大迭代次数
|
|
135
|
-
fmax = 0.1 # 结构优化 force 的收敛标准
|
|
136
|
-
max_error = 0.01 # 表面采样的收敛标准
|
|
137
|
-
radii_type = 'covalent_radii' # 半径选项:'vdw_radii','covalent_radii'
|
|
138
|
-
radii_factor = 1.1 # 原子半径系数
|
|
139
|
-
sampleproperty = {'phi_x': np.linspace(0, np.pi/3, 2, endpoint=False)}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### 手动添加格点能量信息
|
|
143
|
-
|
|
144
|
-
通过脚本 `append_sample.py`实现,打开之后,修改以下信息
|
|
145
|
-
|
|
146
|
-
```python
|
|
147
|
-
pkl_filename = 'surface_grid.pkl'
|
|
148
|
-
keep_old_sample = True # 判断是否保留原有的采样的点
|
|
149
|
-
results = [
|
|
150
|
-
'0_opt.traj', # 支持 ase.traj, vasprun.xml 文件,仅读取最后优化后的结果
|
|
151
|
-
'1_opt.traj',
|
|
152
|
-
'2_opt.traj',
|
|
153
|
-
'3_opt.traj',
|
|
154
|
-
'4_opt.traj',
|
|
155
|
-
'5_opt.traj',
|
|
156
|
-
'6_opt.traj',
|
|
157
|
-
'7_opt.traj',
|
|
158
|
-
'8_opt.traj',
|
|
159
|
-
'9_opt.traj',
|
|
160
|
-
]
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
运行: `python append_sample.py`
|
|
164
|
-
|
|
165
|
-
注意:文件夹下必须有 `parameter.py` 和相应的表面结构文件
|
|
166
|
-
|
|
167
|
-
注意:为了避免失误,再运行前对 `surface_grid.pkl` 进行备份
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
### [其他 ASE 优化算法](https://wiki.fysik.dtu.dk/ase/ase/optimize.html)
|
|
172
|
-
|
|
173
|
-
* BFGS, BFGSLineSearch, LBFGS, LBFGSLineSearch
|
|
174
|
-
* GPMin
|
|
175
|
-
* MDMin
|
|
176
|
-
* FIRE
|
|
177
|
-
|
|
178
|
-
各种优化算法的对比,参考[链接](https://wiki.fysik.dtu.dk/gpaw/devel/ase_optimize/ase_optimize.html)
|
|
179
|
-
|
|
180
|
-
**使用方法**
|
|
181
|
-
|
|
182
|
-
修改 `surface_reaction_sample.py` 其中的一行
|
|
183
|
-
|
|
184
|
-
```
|
|
185
|
-
from ase.optimize import BFGS
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
改为
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
from ase.optimize import XXX as BFGS
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
注意:目前这只是权宜之计,后面会把相应的设置加入到 `parameter.py`
|
|
195
|
-
|
|
196
|
-
### Gaussian Process Regression 方法
|
|
197
|
-
|
|
198
|
-
高斯过程回归 GPR 的优点:
|
|
199
|
-
|
|
200
|
-
* 不仅可以返回回归函数,可以给出拟合的置信度。根据置信度,可以进行进一步差点,迭代进行可以系统地降低整个拟合误差。
|
|
201
|
-
* 可以灵活地选择 kernel 函数来适用于不同的场景。
|
|
202
|
-
|
|
203
|
-
GPR 最重要的参数是kernel的选择。根据格点向量的特点,我们使用添加噪音的 (RBF) (aka Gassian kernel, Squared Exponetial Kernel) kernel 函数:
|
|
204
|
-
$$
|
|
205
|
-
k(x_i,x_j)=\sigma^2 \exp(-{d(x_i,x_j)^2\over 2l^2}) + {noise\_level}
|
|
206
|
-
$$
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
其中 $l$ 代表 length scale, $\sigma ^2$ 是 output variance。 使用 scikit-learn 中的类进行构造,
|
|
210
|
-
$$
|
|
211
|
-
\text{Kernel = ConstantKernel}\times \text{RBF} + \text{WhiteKernel}
|
|
212
|
-
$$
|
|
213
|
-
其中 ConstantKernel 代表 output variance $\sigma^2$, 因为 scikit-learn 内置的 RBF kernel 不包含这一项,WhiteKernel 将 noise_level 考虑进去,RBF 是 Radial Basis Function kernel。
|
|
214
|
-
|
|
215
|
-
**重要的参数**
|
|
216
|
-
|
|
217
|
-
* RBF kernel
|
|
218
|
-
* Length Scale $l$:determines the length of the 'wiggles' in your function. In general, you won't be able to extrapolate more than ℓ units away from your data. [^Duvenaud]
|
|
219
|
-
|
|
220
|
-
参考 [^BASC] 文献,此处我们设置实空间的 $l_{grid}=1 \text{\AA}$ ,变化范围[0.5, 2.0],转化为向量空间的长度[^向量空间转化]。根据实际情况,我们使用非对称 anisotropic 的 RBF。
|
|
221
|
-
* Constant kernel
|
|
222
|
-
|
|
223
|
-
* GPR 在训练之前将 y 数值进行正则化,因而此处设置为 1.0,且训练过程中不变化。
|
|
224
|
-
|
|
225
|
-
* White kernel
|
|
226
|
-
|
|
227
|
-
* noise level 是一个经验的参数。根据 DFT 吸附和过渡态的常见误差的量级为 0.1 eV,将此数值绝对值定为 0.1。设置时需要根据 y 正则化的系数进行缩放。在拟合过程中,keep fixed。
|
|
228
|
-
|
|
229
|
-
* GPR
|
|
230
|
-
|
|
231
|
-
* $\alpha$:参数用于防止过拟合,根据经验设置为 $10^{-5}$。
|
|
232
|
-
* n_restarts_optimizer:9,经验选择。
|
|
233
|
-
* 其他数值使用默认值。
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
## 路线图 Roadmap
|
|
239
|
-
|
|
240
|
-
* v 0.4.1: 单原子和双原子分子表面吸附
|
|
241
|
-
* v 0.4.2: 双原子过渡态计算,扫描 phi 角度
|
|
242
|
-
* v 0.5: 多种表面采样方法
|
|
243
|
-
* v 0.6: 表面位点数据库
|
|
244
|
-
* v 0.7: 颗粒体系表面格点构造
|
|
245
|
-
* v 0.8: 多原子体系(内坐标受限体系)
|
|
246
|
-
* v 0.9: 完善用户界面、例子、教程
|
|
247
|
-
* v 1.0: 发布第一个正式版
|
|
248
|
-
* v 1.1: 孔材料体系格点构造
|
|
249
|
-
* v 1.2: 多原子体系(复杂内坐标体系)
|
|
250
|
-
* v 1.3: 团簇体系
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
## Reference
|
|
255
|
-
|
|
256
|
-
[^Duvenaud]: [The Kernel Cookbook: Advice on Covariance functions](https://www.cs.toronto.edu/~duvenaud/)]
|
|
257
|
-
[^BASC]: Shane Carr, Roman Garnett, Cynthia LoBASC: Applying Bayesian Optimization to the Search for Global Minima on Potential Energy Surfaces.
|
|
258
|
-
[^向量空间转化]: 计算实空间和向量空间的相邻格点距离的映射系数,根据此系数将实空间的距离转化为向量空间距离。
|
|
259
|
-
|
|
1
|
+
# 基于分层采样策略的催化剂表面位点全局分析
|
|
2
|
+
|
|
3
|
+
A Method with Stratified Sampling Strategy for Comprehensive Analysis of Catalyst Surface Composed of Multiple Sites
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## 程序流程图 Program Workflow
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
## 重要的概念 Glossary
|
|
18
|
+
|
|
19
|
+
* 表面格点 Grid:以范德华或者共价键长等值面进行离散化得到,表现为 (xi, yi, zi) 三维坐标。
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
* 表面向量 Vector:用来表征格点局部化学环境的向量表示方法,表现形式为 N 维的向量。
|
|
24
|
+
|
|
25
|
+
* 本方法中我们使用正则化的距离向量表达,其中距离是与N个最近邻原子之间的距离。
|
|
26
|
+
* 正则化是为了保证不同化学环境格点的区分度尽量大。我们这里使用距离的倒数作为正则化方法,即距离越远对化学环境的描述贡献越小。
|
|
27
|
+
* 为了减小计算量,在进行向量操作之前要对向量进行降维。降维的标准是保证保留尽可能多的信息,默认信息丢失不超过 5%。
|
|
28
|
+
|
|
29
|
+
* 向量化 Vectorization: 将格点转化为向量的过程
|
|
30
|
+
|
|
31
|
+
* 当前我们使用多点定位 Multilateration 进行向量化
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
* 分层采样 Stratified sampling。根据“相似结构具有相似性质”的原理采样分层采样的策略对表面位点进行采样,降低计算量。
|
|
36
|
+
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
* 吸附结构
|
|
40
|
+
|
|
41
|
+

|
|
42
|
+
|
|
43
|
+
## 安装
|
|
44
|
+
|
|
45
|
+
`pip install -U surface-construct`
|
|
46
|
+
|
|
47
|
+
## 发布新版本 (only for 管理员)
|
|
48
|
+
|
|
49
|
+
python -m build
|
|
50
|
+
twine upload --verbose dist/*
|
|
51
|
+
|
|
52
|
+
## 使用方法 Manual
|
|
53
|
+
|
|
54
|
+
### 所需文件 Required Files
|
|
55
|
+
|
|
56
|
+
* `surface_reaction_sample.py`: 主流程文件
|
|
57
|
+
|
|
58
|
+
* `parameter.py`: 参数定义文件
|
|
59
|
+
|
|
60
|
+
* `POSCAR.0`: 表面结构文件
|
|
61
|
+
|
|
62
|
+
* 注意:名字可以修改,与 `parameter.py` 设置一致
|
|
63
|
+
* 设置需要固定的原子
|
|
64
|
+
|
|
65
|
+
* bsub 文件。在公司集群上提交,以下面的为例
|
|
66
|
+
|
|
67
|
+
```Bash
|
|
68
|
+
#/bin/bash
|
|
69
|
+
#BSUB -J Sampling
|
|
70
|
+
#BSUB -q short
|
|
71
|
+
#BSUB -n 28
|
|
72
|
+
#BSUB -o out.%J.txt
|
|
73
|
+
#BSUB -e error.%J.txt
|
|
74
|
+
#BSUB -R span[ptile=28]
|
|
75
|
+
module load old/intel18u4
|
|
76
|
+
export OMP_NUM_THREADS=1
|
|
77
|
+
export I_MPI_ADJUST_REDUCE=3
|
|
78
|
+
workdir=`pwd`
|
|
79
|
+
date
|
|
80
|
+
|
|
81
|
+
export PATH="/export/home/renpengju/miniconda3/bin:$PATH"
|
|
82
|
+
export VASP_PP_PATH=$HOME/vasp/mypps
|
|
83
|
+
export VASP_SCRIPT=$workdir/run_vasp.py
|
|
84
|
+
|
|
85
|
+
cat > run_vasp.py << EOF
|
|
86
|
+
import os
|
|
87
|
+
exitcode = os.system('mpirun -PSM2 /export/soft_old/vasp541/vasp.5.4.1/bin/vasp_gam')
|
|
88
|
+
EOF
|
|
89
|
+
|
|
90
|
+
python surface_reaction_sample.py > surface_reaction_sample.py.log
|
|
91
|
+
|
|
92
|
+
date
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 参数设置
|
|
96
|
+
|
|
97
|
+
注意:所有的参数均在 `parameter.py` 进行设置
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from ase.calculators.vasp import Vasp
|
|
101
|
+
import numpy as np
|
|
102
|
+
|
|
103
|
+
# 用户参数,以下参数必须设定,没有默认值
|
|
104
|
+
poscar = 'ru_0001_POSCAR'
|
|
105
|
+
atomnum = [7, 7] # 吸附的原子序号, 第一个原子靠近表面
|
|
106
|
+
bondlength = 1.65 # 初始的键长
|
|
107
|
+
angle = [np.pi / 2, 0.0] # 分子吸附的角度,[theta, phi_x]: [与 z 轴的角度,绕 z 轴的旋转角度(相对于x)]
|
|
108
|
+
|
|
109
|
+
# 以下参数可选,具有默认值
|
|
110
|
+
calc = Vasp(
|
|
111
|
+
xc='PBE',
|
|
112
|
+
gga='PE',
|
|
113
|
+
kpts=(1, 1, 1),
|
|
114
|
+
encut=400,
|
|
115
|
+
setups='recommended',
|
|
116
|
+
ncore=4,
|
|
117
|
+
gamma=True,
|
|
118
|
+
nelm=200,
|
|
119
|
+
algo='fast',
|
|
120
|
+
ismear=0,
|
|
121
|
+
sigma=0.05,
|
|
122
|
+
ibrion=-1, # 不使用 vasp 自身的优化,必须是 -1
|
|
123
|
+
ediff=1e-4,
|
|
124
|
+
prec='normal',
|
|
125
|
+
nsw=0, # 不使用 vasp 优化,必须是 0
|
|
126
|
+
lreal='Auto',
|
|
127
|
+
lwave=True, # 保存 WAVECAR 可以加速
|
|
128
|
+
lcharg=False,
|
|
129
|
+
ispin=1)
|
|
130
|
+
|
|
131
|
+
scan_type = 'transition_state' # 扫描类型:'optimization','transition_state'
|
|
132
|
+
grid_interval = 0.1 # angstrom, 格点的间距
|
|
133
|
+
Nsample = 5 # 第一次采样的点
|
|
134
|
+
Niter = 3 # 最大迭代次数
|
|
135
|
+
fmax = 0.1 # 结构优化 force 的收敛标准
|
|
136
|
+
max_error = 0.01 # 表面采样的收敛标准
|
|
137
|
+
radii_type = 'covalent_radii' # 半径选项:'vdw_radii','covalent_radii'
|
|
138
|
+
radii_factor = 1.1 # 原子半径系数
|
|
139
|
+
sampleproperty = {'phi_x': np.linspace(0, np.pi/3, 2, endpoint=False)}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 手动添加格点能量信息
|
|
143
|
+
|
|
144
|
+
通过脚本 `append_sample.py`实现,打开之后,修改以下信息
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
pkl_filename = 'surface_grid.pkl'
|
|
148
|
+
keep_old_sample = True # 判断是否保留原有的采样的点
|
|
149
|
+
results = [
|
|
150
|
+
'0_opt.traj', # 支持 ase.traj, vasprun.xml 文件,仅读取最后优化后的结果
|
|
151
|
+
'1_opt.traj',
|
|
152
|
+
'2_opt.traj',
|
|
153
|
+
'3_opt.traj',
|
|
154
|
+
'4_opt.traj',
|
|
155
|
+
'5_opt.traj',
|
|
156
|
+
'6_opt.traj',
|
|
157
|
+
'7_opt.traj',
|
|
158
|
+
'8_opt.traj',
|
|
159
|
+
'9_opt.traj',
|
|
160
|
+
]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
运行: `python append_sample.py`
|
|
164
|
+
|
|
165
|
+
注意:文件夹下必须有 `parameter.py` 和相应的表面结构文件
|
|
166
|
+
|
|
167
|
+
注意:为了避免失误,再运行前对 `surface_grid.pkl` 进行备份
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
### [其他 ASE 优化算法](https://wiki.fysik.dtu.dk/ase/ase/optimize.html)
|
|
172
|
+
|
|
173
|
+
* BFGS, BFGSLineSearch, LBFGS, LBFGSLineSearch
|
|
174
|
+
* GPMin
|
|
175
|
+
* MDMin
|
|
176
|
+
* FIRE
|
|
177
|
+
|
|
178
|
+
各种优化算法的对比,参考[链接](https://wiki.fysik.dtu.dk/gpaw/devel/ase_optimize/ase_optimize.html)
|
|
179
|
+
|
|
180
|
+
**使用方法**
|
|
181
|
+
|
|
182
|
+
修改 `surface_reaction_sample.py` 其中的一行
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
from ase.optimize import BFGS
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
改为
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
from ase.optimize import XXX as BFGS
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
注意:目前这只是权宜之计,后面会把相应的设置加入到 `parameter.py`
|
|
195
|
+
|
|
196
|
+
### Gaussian Process Regression 方法
|
|
197
|
+
|
|
198
|
+
高斯过程回归 GPR 的优点:
|
|
199
|
+
|
|
200
|
+
* 不仅可以返回回归函数,可以给出拟合的置信度。根据置信度,可以进行进一步差点,迭代进行可以系统地降低整个拟合误差。
|
|
201
|
+
* 可以灵活地选择 kernel 函数来适用于不同的场景。
|
|
202
|
+
|
|
203
|
+
GPR 最重要的参数是kernel的选择。根据格点向量的特点,我们使用添加噪音的 (RBF) (aka Gassian kernel, Squared Exponetial Kernel) kernel 函数:
|
|
204
|
+
$$
|
|
205
|
+
k(x_i,x_j)=\sigma^2 \exp(-{d(x_i,x_j)^2\over 2l^2}) + {noise\_level}
|
|
206
|
+
$$
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
其中 $l$ 代表 length scale, $\sigma ^2$ 是 output variance。 使用 scikit-learn 中的类进行构造,
|
|
210
|
+
$$
|
|
211
|
+
\text{Kernel = ConstantKernel}\times \text{RBF} + \text{WhiteKernel}
|
|
212
|
+
$$
|
|
213
|
+
其中 ConstantKernel 代表 output variance $\sigma^2$, 因为 scikit-learn 内置的 RBF kernel 不包含这一项,WhiteKernel 将 noise_level 考虑进去,RBF 是 Radial Basis Function kernel。
|
|
214
|
+
|
|
215
|
+
**重要的参数**
|
|
216
|
+
|
|
217
|
+
* RBF kernel
|
|
218
|
+
* Length Scale $l$:determines the length of the 'wiggles' in your function. In general, you won't be able to extrapolate more than ℓ units away from your data. [^Duvenaud]
|
|
219
|
+
|
|
220
|
+
参考 [^BASC] 文献,此处我们设置实空间的 $l_{grid}=1 \text{\AA}$ ,变化范围[0.5, 2.0],转化为向量空间的长度[^向量空间转化]。根据实际情况,我们使用非对称 anisotropic 的 RBF。
|
|
221
|
+
* Constant kernel
|
|
222
|
+
|
|
223
|
+
* GPR 在训练之前将 y 数值进行正则化,因而此处设置为 1.0,且训练过程中不变化。
|
|
224
|
+
|
|
225
|
+
* White kernel
|
|
226
|
+
|
|
227
|
+
* noise level 是一个经验的参数。根据 DFT 吸附和过渡态的常见误差的量级为 0.1 eV,将此数值绝对值定为 0.1。设置时需要根据 y 正则化的系数进行缩放。在拟合过程中,keep fixed。
|
|
228
|
+
|
|
229
|
+
* GPR
|
|
230
|
+
|
|
231
|
+
* $\alpha$:参数用于防止过拟合,根据经验设置为 $10^{-5}$。
|
|
232
|
+
* n_restarts_optimizer:9,经验选择。
|
|
233
|
+
* 其他数值使用默认值。
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
## 路线图 Roadmap
|
|
239
|
+
|
|
240
|
+
* v 0.4.1: 单原子和双原子分子表面吸附
|
|
241
|
+
* v 0.4.2: 双原子过渡态计算,扫描 phi 角度
|
|
242
|
+
* v 0.5: 多种表面采样方法
|
|
243
|
+
* v 0.6: 表面位点数据库
|
|
244
|
+
* v 0.7: 颗粒体系表面格点构造
|
|
245
|
+
* v 0.8: 多原子体系(内坐标受限体系)
|
|
246
|
+
* v 0.9: 完善用户界面、例子、教程
|
|
247
|
+
* v 1.0: 发布第一个正式版
|
|
248
|
+
* v 1.1: 孔材料体系格点构造
|
|
249
|
+
* v 1.2: 多原子体系(复杂内坐标体系)
|
|
250
|
+
* v 1.3: 团簇体系
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
## Reference
|
|
255
|
+
|
|
256
|
+
[^Duvenaud]: [The Kernel Cookbook: Advice on Covariance functions](https://www.cs.toronto.edu/~duvenaud/)]
|
|
257
|
+
[^BASC]: Shane Carr, Roman Garnett, Cynthia LoBASC: Applying Bayesian Optimization to the Search for Global Minima on Potential Energy Surfaces.
|
|
258
|
+
[^向量空间转化]: 计算实空间和向量空间的相邻格点距离的映射系数,根据此系数将实空间的距离转化为向量空间距离。
|
|
259
|
+
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
from setuptools import setup
|
|
2
|
-
|
|
3
|
-
with open("README.md", "r", encoding='utf-8') as f:
|
|
4
|
-
long_description = f.read()
|
|
5
|
-
|
|
6
|
-
install_requires = [
|
|
7
|
-
'ase',
|
|
8
|
-
'networkx',
|
|
9
|
-
'numpy',
|
|
10
|
-
'spglib',
|
|
11
|
-
'pandas',
|
|
12
|
-
'tqdm',
|
|
13
|
-
'matplotlib',
|
|
14
|
-
'scipy',
|
|
15
|
-
'scikit-learn',
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
setup(
|
|
19
|
-
name='surface_construct',
|
|
20
|
-
version='0.
|
|
21
|
-
packages=['surface_construct'],
|
|
22
|
-
url='https://gitee.com/pjren/surface_construct/',
|
|
23
|
-
license='GPL',
|
|
24
|
-
author='ren',
|
|
25
|
-
author_email='0403114076@163.com',
|
|
26
|
-
description='Surface termination construction especially for complex model, such as oxides or carbides.',
|
|
27
|
-
long_description=long_description,
|
|
28
|
-
long_description_content_type="text/markdown",
|
|
29
|
-
install_requires=install_requires,
|
|
30
|
-
classifiers=[
|
|
31
|
-
"Programming Language :: Python :: 3",
|
|
32
|
-
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
|
33
|
-
"Operating System :: OS Independent",
|
|
34
|
-
],
|
|
35
|
-
)
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding='utf-8') as f:
|
|
4
|
+
long_description = f.read()
|
|
5
|
+
|
|
6
|
+
install_requires = [
|
|
7
|
+
'ase',
|
|
8
|
+
'networkx',
|
|
9
|
+
'numpy',
|
|
10
|
+
'spglib',
|
|
11
|
+
'pandas',
|
|
12
|
+
'tqdm',
|
|
13
|
+
'matplotlib',
|
|
14
|
+
'scipy',
|
|
15
|
+
'scikit-learn',
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
setup(
|
|
19
|
+
name='surface_construct',
|
|
20
|
+
version='0.6',
|
|
21
|
+
packages=['surface_construct'],
|
|
22
|
+
url='https://gitee.com/pjren/surface_construct/',
|
|
23
|
+
license='GPL',
|
|
24
|
+
author='ren',
|
|
25
|
+
author_email='0403114076@163.com',
|
|
26
|
+
description='Surface termination construction especially for complex model, such as oxides or carbides.',
|
|
27
|
+
long_description=long_description,
|
|
28
|
+
long_description_content_type="text/markdown",
|
|
29
|
+
install_requires=install_requires,
|
|
30
|
+
classifiers=[
|
|
31
|
+
"Programming Language :: Python :: 3",
|
|
32
|
+
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
|
33
|
+
"Operating System :: OS Independent",
|
|
34
|
+
],
|
|
35
|
+
)
|
|
@@ -16,19 +16,21 @@ import ase
|
|
|
16
16
|
import numpy as np
|
|
17
17
|
import pickle
|
|
18
18
|
from ase.data import covalent_radii, vdw_radii
|
|
19
|
-
from ase.geometry import
|
|
19
|
+
from ase.geometry import find_mic
|
|
20
20
|
from ase.visualize import view
|
|
21
21
|
from matplotlib import pyplot as plt
|
|
22
|
+
import matplotlib.tri as mtri
|
|
22
23
|
from scipy.interpolate import griddata
|
|
23
24
|
from scipy.spatial import ConvexHull
|
|
24
25
|
from scipy.spatial.distance import cdist, euclidean
|
|
26
|
+
from scipy.stats import triang
|
|
25
27
|
from sklearn.cluster import KMeans as Cluster
|
|
26
28
|
from sklearn.decomposition import PCA
|
|
27
29
|
from sklearn.gaussian_process import GaussianProcessRegressor
|
|
28
30
|
from sklearn.gaussian_process.kernels import RBF, ConstantKernel, WhiteKernel
|
|
29
31
|
from sklearn.preprocessing import StandardScaler
|
|
30
32
|
|
|
31
|
-
from surface_construct.utils import get_calc_info
|
|
33
|
+
from surface_construct.utils import get_calc_info, GridGenerator, get_distances
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
def no_weight(v, **kwargs):
|
|
@@ -52,19 +54,19 @@ def linear_weight(v, **kwargs):
|
|
|
52
54
|
def vb_r_weight(v, **kwargs):
|
|
53
55
|
r0 = kwargs['r0']
|
|
54
56
|
if 'b' not in kwargs:
|
|
55
|
-
b = 0.
|
|
57
|
+
b = 0.618 # 较大的数值衰减较慢,能够将更远的原子作用考虑进来。不建议大于此数
|
|
56
58
|
else:
|
|
57
59
|
b = kwargs['b']
|
|
58
60
|
weight = np.exp((r0 - v) / b)
|
|
59
61
|
weight[weight > 1.0] = 1.0
|
|
60
|
-
v_w = v * weight
|
|
62
|
+
v_w = v / r0 * weight
|
|
61
63
|
return v_w
|
|
62
64
|
|
|
63
65
|
|
|
64
66
|
def vb_weight(v, **kwargs):
|
|
65
67
|
r0 = kwargs['r0']
|
|
66
68
|
if 'b' not in kwargs:
|
|
67
|
-
b = 0
|
|
69
|
+
b = 1.0 # 较大的数值衰减较慢,能够将更远的原子作用考虑进来
|
|
68
70
|
else:
|
|
69
71
|
b = kwargs['b']
|
|
70
72
|
weight = np.exp((r0 - v) / b)
|
|
@@ -119,7 +121,7 @@ class SurfaceGrid:
|
|
|
119
121
|
|
|
120
122
|
self.points = None # 格点 xyz 坐标
|
|
121
123
|
self._Dga = None # grid_atoms 距离矩阵
|
|
122
|
-
self._DAga = None # grid_atoms 距离向量矩阵,保存是为了求角度
|
|
124
|
+
# self._DAga = None # grid_atoms 距离向量矩阵,保存是为了求角度
|
|
123
125
|
self.vector = None
|
|
124
126
|
self.lpca = lpca
|
|
125
127
|
self._pca = None
|
|
@@ -165,7 +167,7 @@ class SurfaceGrid:
|
|
|
165
167
|
result[dim, int((sign+1)/2)] = v
|
|
166
168
|
return np.concatenate(result) # [xmin, xmax, ymin, ymax, zmin, zmax]
|
|
167
169
|
|
|
168
|
-
def gridize(self,
|
|
170
|
+
def gridize(self, **kwargs):
|
|
169
171
|
"""
|
|
170
172
|
格点化。
|
|
171
173
|
这种方法仅仅适用于无孔的材料,表面为z方向,且方向向上。
|
|
@@ -173,6 +175,8 @@ class SurfaceGrid:
|
|
|
173
175
|
* surface_index: 表面原子的序号
|
|
174
176
|
:return:
|
|
175
177
|
"""
|
|
178
|
+
|
|
179
|
+
""" ### Old code
|
|
176
180
|
if gridxy is None:
|
|
177
181
|
nx, ny = self.grid_nx, self.grid_ny
|
|
178
182
|
|
|
@@ -225,9 +229,25 @@ class SurfaceGrid:
|
|
|
225
229
|
if surface_index is not None: # grid_dist should contain all atoms
|
|
226
230
|
grid_dist_array, grid_dist = get_distances(
|
|
227
231
|
self.points, self.atoms.positions, cell=self.atoms.cell, pbc=self.atoms.pbc)
|
|
232
|
+
"""
|
|
233
|
+
subtype = kwargs.get('subtype', None)
|
|
234
|
+
rsub = [self.radii[atomnum] for atomnum in self.atoms.numbers]
|
|
235
|
+
gridgen = GridGenerator(self.atoms, interval=self.interval, subtype=subtype, rads=self.rads, rsub=rsub)
|
|
236
|
+
self.points = gridgen.grid.copy()
|
|
237
|
+
self._gridgen = gridgen
|
|
238
|
+
|
|
239
|
+
#self._Dga = grid_dist
|
|
240
|
+
#self._DAga = grid_dist_array
|
|
241
|
+
|
|
242
|
+
def _calc_Dga(self):
|
|
243
|
+
# TODO: add cutoff to kwargs or as self attr
|
|
244
|
+
cutoff = 10
|
|
245
|
+
if self.points is None:
|
|
246
|
+
self.gridize()
|
|
247
|
+
_, Dga = get_distances(self.points, self.atoms.positions, cutoff=cutoff,
|
|
248
|
+
use_ase=False, cell=self.atoms.cell)
|
|
249
|
+
self._Dga = Dga
|
|
228
250
|
|
|
229
|
-
self._Dga = grid_dist
|
|
230
|
-
self._DAga = grid_dist_array
|
|
231
251
|
|
|
232
252
|
def grid_NN_array(self, grid_idx):
|
|
233
253
|
"""
|
|
@@ -235,46 +255,30 @@ class SurfaceGrid:
|
|
|
235
255
|
:param grid_idx:
|
|
236
256
|
:return:
|
|
237
257
|
"""
|
|
238
|
-
if self.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
else:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
"""
|
|
258
|
-
if self._DAga is not None:
|
|
259
|
-
order = np.argsort(self._Dga[grid_idx])
|
|
260
|
-
weight = self._Dga[grid_idx, order] ** (-4)
|
|
261
|
-
force_array = np.atleast_2d(weight).T * self._DAga[grid_idx, order]
|
|
262
|
-
force = force_array.sum(axis=0)
|
|
263
|
-
return force
|
|
264
|
-
else:
|
|
265
|
-
raise NotImplementedError
|
|
258
|
+
#if self._Dga is not None:
|
|
259
|
+
# # 一般使用表面格点与最近邻原子的向量, 效果不好,在顶位会出现混乱。放弃
|
|
260
|
+
# # v = self._DAga[grid_idx][self._Dga[grid_idx].argmin()]
|
|
261
|
+
# # if v[0] < 0.1 and v[1] < 0.1:
|
|
262
|
+
# if True:
|
|
263
|
+
# # 对于顶位,即向量x,y为0,0 的情况,使用最近邻原子和次紧邻原子的向量
|
|
264
|
+
# order = np.argsort(self._Dga[grid_idx])
|
|
265
|
+
# p1, p2 = self.atoms.positions[order[0:2]]
|
|
266
|
+
# v, vlen = get_distances(p1, p2, cell=self.atoms.cell, pbc=self.atoms.pbc)
|
|
267
|
+
# v = v[0, 0]
|
|
268
|
+
# return v
|
|
269
|
+
#else:
|
|
270
|
+
# raise NotImplementedError
|
|
271
|
+
if self._Dga is None:
|
|
272
|
+
self._calc_Dga()
|
|
273
|
+
order = np.argsort(self._Dga[grid_idx])
|
|
274
|
+
p1, p2 = self.atoms.positions[order[0:2]]
|
|
275
|
+
v, _ = find_mic(p2-p1, cell=self.atoms.cell, pbc=self.atoms.pbc)
|
|
276
|
+
return v
|
|
266
277
|
|
|
267
278
|
def view_grid(self):
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
def set_grid(self, points):
|
|
272
|
-
"""
|
|
273
|
-
TODO: 手动设置格点
|
|
274
|
-
:param points:
|
|
275
|
-
:return:
|
|
276
|
-
"""
|
|
277
|
-
pass
|
|
279
|
+
if self._gridgen is None:
|
|
280
|
+
self.gridize()
|
|
281
|
+
self._gridgen.view()
|
|
278
282
|
|
|
279
283
|
@property
|
|
280
284
|
def grid_energy(self):
|
|
@@ -285,39 +289,46 @@ class SurfaceGrid:
|
|
|
285
289
|
|
|
286
290
|
def filter_grid_z(self, z=None):
|
|
287
291
|
"""
|
|
288
|
-
过滤 z 方向不合理的格点,默认原子坐标 zmax
|
|
292
|
+
过滤 z 方向不合理的格点,默认原子坐标 zmax. 对于孔材料和cluster 已经不合时宜了
|
|
289
293
|
:param z:
|
|
290
294
|
:return:
|
|
291
295
|
"""
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
self.
|
|
297
|
-
self.
|
|
298
|
-
|
|
299
|
-
|
|
296
|
+
pass
|
|
297
|
+
# if z is None:
|
|
298
|
+
# z = self.atoms.positions[:, 2].max()
|
|
299
|
+
# index = self.points[:, 2] > z
|
|
300
|
+
# self.points = self.points[index]
|
|
301
|
+
# self._Dga = self._Dga[index]
|
|
302
|
+
# self._DAga = self._DAga[index]
|
|
303
|
+
|
|
304
|
+
def vectorize(self, Dga=None, return_vector=False, wf=vb_weight, pca=True, pca_ratio=0.90, **kwargs):
|
|
300
305
|
"""
|
|
301
306
|
TODO: 使用 DScribe 来进行向量化,并进行测试。如何测试?测试什么内容?
|
|
302
307
|
使用 distance matrix 来进行向量化
|
|
303
308
|
使用衰减函数对 vector 加权重。备选函数:S型,指数型(键价),1/sqrt,1/x,线性。倾向使用指数型,键价理论支持。 1/x,或者 1/sqrt,衰减更慢。
|
|
304
|
-
这种方法类似于多点地位方法(Multilateration),因而暂时称其为 Multilateration vectorization.
|
|
309
|
+
这种方法类似于多点地位方法(Multilateration),因而暂时称其为 Multilateration vectorization.
|
|
310
|
+
:param wf:
|
|
311
|
+
:param Dga: grid-atoms distance matrix
|
|
312
|
+
:param return_vector: 是否返回 vector 向量
|
|
305
313
|
"""
|
|
306
314
|
if Dga is None:
|
|
315
|
+
if self._Dga is None:
|
|
316
|
+
self._calc_Dga()
|
|
307
317
|
Dga = self._Dga
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
318
|
+
|
|
319
|
+
Natoms = Dga.shape[1] / len(self.atoms) # Dga is multiple of atoms
|
|
320
|
+
assert Natoms == int(Natoms) # Natoms should be int
|
|
321
|
+
numbers = np.concatenate([self.atoms.numbers]*int(Natoms)) # multiply atoms.number
|
|
311
322
|
|
|
312
323
|
vector = []
|
|
313
324
|
for atomnum, atomcount in self.species:
|
|
314
|
-
grid_dist = Dga[:,
|
|
325
|
+
grid_dist = Dga[:, numbers == atomnum]
|
|
315
326
|
# 排序,返回排序后的序号
|
|
316
327
|
index_array = grid_dist.argsort(axis=-1)
|
|
317
328
|
grid_dist = np.take_along_axis(grid_dist, index_array, axis=-1)
|
|
318
329
|
# grid_dist_array = np.take_along_axis(grid_dist_array, index_array, axis=-1)
|
|
319
330
|
# 设定距离向量长度
|
|
320
|
-
vlen =
|
|
331
|
+
vlen = self.vlen
|
|
321
332
|
r0 = self.rads + self.radii[atomnum]
|
|
322
333
|
v = grid_dist[:, :vlen]
|
|
323
334
|
kwargs.update({'r0': r0})
|
|
@@ -374,6 +385,7 @@ class SurfaceGrid:
|
|
|
374
385
|
def grid_sample(self, N=10, include_vertex=False):
|
|
375
386
|
"""
|
|
376
387
|
Warning: Obsoleted, replaced by Sampling class
|
|
388
|
+
TODO: 使用vertex 点作为分类的中心点
|
|
377
389
|
:param include_vertex: 是否对边界额外采样
|
|
378
390
|
:param N:
|
|
379
391
|
:return:
|
|
@@ -572,20 +584,24 @@ class SurfaceGrid:
|
|
|
572
584
|
:return:
|
|
573
585
|
"""
|
|
574
586
|
assert key in self.grid_property
|
|
575
|
-
|
|
576
|
-
print("Plot {} ...".format(key))
|
|
577
|
-
X = self.points[:, 0].reshape((self.grid_ny, self.grid_nx))
|
|
578
|
-
Y = self.points[:, 1].reshape((self.grid_ny, self.grid_nx))
|
|
579
|
-
Z = self.grid_property[key].reshape((self.grid_ny, self.grid_nx))
|
|
580
|
-
|
|
581
587
|
fig, ax = plt.subplots()
|
|
582
588
|
ax.set_aspect('equal')
|
|
583
589
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
590
|
+
print("Plot {} ...".format(key))
|
|
591
|
+
#X = self.points[:, 0].reshape((self.grid_ny, self.grid_nx))
|
|
592
|
+
#Y = self.points[:, 1].reshape((self.grid_ny, self.grid_nx))
|
|
593
|
+
#Z = self.grid_property[key].reshape((self.grid_ny, self.grid_nx))
|
|
594
|
+
#if vmax is None:
|
|
595
|
+
# vmax = Z.max() + (Z.max() - Z.min()) * 0.2
|
|
596
|
+
#if vmin is None:
|
|
597
|
+
# vmin = Z.min() - (Z.max() - Z.min()) * 0.2
|
|
598
|
+
#contourf0 = ax.contourf(X, Y, Z, levels=50, cmap="jet", vmin=vmin, vmax=vmax)
|
|
599
|
+
x = self.points[:, 0]
|
|
600
|
+
y = self.points[:, 1]
|
|
601
|
+
z = self.grid_property[key]
|
|
602
|
+
triang = mtri.Triangulation(x, y)
|
|
603
|
+
contourf0 = ax.tricontourf(triang, z, levels=50, cmap="jet", vmin=vmin, vmax=vmax)
|
|
604
|
+
|
|
589
605
|
# 画上 sample 点,采过的点用黑色,下一步采的点用白色
|
|
590
606
|
if sample:
|
|
591
607
|
sample_points = self.sample_points
|
|
@@ -664,15 +680,20 @@ class SurfaceGrid:
|
|
|
664
680
|
def plot_sigma(self, key='energy', figname=None, vmax=None, vmin=None):
|
|
665
681
|
# TODO: 支持 cluster 作图。保存原始 meshgrid 和 id?或者重新插值?
|
|
666
682
|
assert key in self.grid_property_sigma
|
|
667
|
-
|
|
668
|
-
X = self.points[:, 0].reshape((self.grid_ny, self.grid_nx))
|
|
669
|
-
Y = self.points[:, 1].reshape((self.grid_ny, self.grid_nx))
|
|
670
|
-
Z = self.grid_property_sigma[key].reshape((self.grid_ny, self.grid_nx))
|
|
671
|
-
|
|
672
683
|
fig, ax = plt.subplots()
|
|
673
684
|
ax.set_aspect('equal')
|
|
674
685
|
|
|
675
|
-
|
|
686
|
+
#X = self.points[:, 0].reshape((self.grid_ny, self.grid_nx))
|
|
687
|
+
#Y = self.points[:, 1].reshape((self.grid_ny, self.grid_nx))
|
|
688
|
+
#Z = self.grid_property_sigma[key].reshape((self.grid_ny, self.grid_nx))
|
|
689
|
+
#contourf0 = ax.contourf(X, Y, Z, levels=50, cmap="RdPu", vmax=vmax, vmin=vmin)
|
|
690
|
+
|
|
691
|
+
x = self.points[:, 0]
|
|
692
|
+
y = self.points[:, 1]
|
|
693
|
+
z = self.grid_property_sigma[key]
|
|
694
|
+
triang = mtri.Triangulation(x, y)
|
|
695
|
+
contourf0 = ax.tricontourf(triang, z, levels=50, cmap="RdPu", vmin=vmin, vmax=vmax)
|
|
696
|
+
|
|
676
697
|
# sigma 最大值标注
|
|
677
698
|
max_sigma_point = self.points[self.grid_property_sigma[key].argmax()]
|
|
678
699
|
ax.scatter(max_sigma_point[0], max_sigma_point[1], marker="+", s=100, linewidths=2,
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
from distutils.command.sdist import sdist
|
|
3
|
+
from enum import unique
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from ase.data import covalent_radii, vdw_radii, chemical_symbols
|
|
7
|
+
from ase.neighborlist import natural_cutoffs
|
|
8
|
+
from numpy import dtype
|
|
9
|
+
from numpy.ma.core import nonzero
|
|
10
|
+
from scipy.spatial import ConvexHull, cKDTree
|
|
11
|
+
from skimage.measure import marching_cubes
|
|
12
|
+
import ase
|
|
13
|
+
from ase.visualize import view
|
|
14
|
+
import ase.geometry
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def calc_hull_vertices(v):
|
|
18
|
+
shape = v.shape
|
|
19
|
+
if len(shape) != 2:
|
|
20
|
+
print("Warning: The vector should be 2D, however {}D vector was provided!)".format(len(shape)))
|
|
21
|
+
print("The Convex Hull Vertices won't be calculated.")
|
|
22
|
+
return None
|
|
23
|
+
if shape[1] > 5:
|
|
24
|
+
print("Warning: The vector.shape[1]={} is too large to be calculated!)".format(shape[1]))
|
|
25
|
+
print("The Convex Hull Vertices won't be calculated.")
|
|
26
|
+
return None
|
|
27
|
+
try:
|
|
28
|
+
print("Calculate Convex Hull Vertices ...")
|
|
29
|
+
hull = ConvexHull(v)
|
|
30
|
+
vertices = hull.vertices
|
|
31
|
+
return vertices
|
|
32
|
+
except ValueError:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_calc_info(calc=None):
|
|
37
|
+
if calc is None:
|
|
38
|
+
return {}
|
|
39
|
+
calc_name = calc.name
|
|
40
|
+
calc_para = dict()
|
|
41
|
+
if calc_name in ('vasp',):
|
|
42
|
+
calc_para['xc'] = calc.parameters['xc']
|
|
43
|
+
calc_para['encut'] = calc.parameters['encut']
|
|
44
|
+
|
|
45
|
+
calc_info = {
|
|
46
|
+
'name': calc_name,
|
|
47
|
+
'para': calc_para,
|
|
48
|
+
}
|
|
49
|
+
return calc_info
|
|
50
|
+
|
|
51
|
+
def get_distances(p1, p2=None, cutoff=10, cell=None, use_ase=False):
|
|
52
|
+
"""
|
|
53
|
+
计算位点周围原子的距离,参考 ase.geometry.get_distances. 对于更大的体系使用 cDTree 来计算。
|
|
54
|
+
:param p1: grid positions
|
|
55
|
+
:param p2: atoms.positions
|
|
56
|
+
:param cutoff: 截断半径,只考虑距离之内的距离,超过该距离的定为 np.inf
|
|
57
|
+
:param cell:
|
|
58
|
+
:param use_ase: 如果 use_ase is True,则使用 ase.geometry.get_distances,即周期性条件等价的原子只考虑一次
|
|
59
|
+
:return:
|
|
60
|
+
"""
|
|
61
|
+
pbc = cell.lengths() < (cutoff * 2)
|
|
62
|
+
if not np.any(pbc):
|
|
63
|
+
use_ase = True
|
|
64
|
+
|
|
65
|
+
if use_ase:
|
|
66
|
+
return ase.geometry.get_distances(p1, p2, cell, pbc)
|
|
67
|
+
|
|
68
|
+
if p2 is None:
|
|
69
|
+
p2 = p1.copy()
|
|
70
|
+
|
|
71
|
+
ranges = [np.arange(-1 * p, p + 1) for p in pbc]
|
|
72
|
+
hkls = np.array(list(itertools.product(*ranges)))
|
|
73
|
+
hkls = np.concatenate([hkls, np.zeros([hkls.shape[0], 3-hkls.shape[1]], dtype=int)], axis=1)
|
|
74
|
+
vrvecs = hkls @ cell
|
|
75
|
+
p2 = np.concatenate(p2 + vrvecs[:, None], axis=0)
|
|
76
|
+
tree1 = cKDTree(p1, copy_data=True)
|
|
77
|
+
tree2 = cKDTree(p2, copy_data=True)
|
|
78
|
+
sdm = tree1.sparse_distance_matrix(tree2, max_distance=cutoff)
|
|
79
|
+
# set 0 to np.inf
|
|
80
|
+
s = sdm.copy()
|
|
81
|
+
for k in s.keys():
|
|
82
|
+
s[k] = np.inf
|
|
83
|
+
np.seterr(divide='ignore')
|
|
84
|
+
s = np.divide(1, s.toarray())
|
|
85
|
+
dist = sdm.toarray() + s
|
|
86
|
+
return None, dist
|
|
87
|
+
|
|
88
|
+
class GridGenerator:
|
|
89
|
+
def __init__(self, atoms,
|
|
90
|
+
rads=0.76,
|
|
91
|
+
rsub='natural_cutoff',
|
|
92
|
+
subtype=None,
|
|
93
|
+
interval=0.1,
|
|
94
|
+
scale=None,
|
|
95
|
+
):
|
|
96
|
+
"""
|
|
97
|
+
:param atoms: 基底结构 ase.Atoms
|
|
98
|
+
:param rads: 吸附原子的半径, 默认是 C 的共价半径
|
|
99
|
+
:param rsub: 基底的原子半径
|
|
100
|
+
type: str, 'covalent_radii' or 'vdw_radii'
|
|
101
|
+
type: list or tuple or numpy.array, [r1, r2, ... rN], N=len(atoms)
|
|
102
|
+
:param subtype: 基底的类型,slab, cluster, bulk (porous material)
|
|
103
|
+
:param interval:
|
|
104
|
+
:param scale: scale factor of rsub and rads. For covalent_radii, the default is 1.1, otherwise it is 1.0
|
|
105
|
+
"""
|
|
106
|
+
self.atoms = atoms
|
|
107
|
+
self._grid = None
|
|
108
|
+
self.atoms_num_type = set(atoms.numbers)
|
|
109
|
+
self.interval = interval
|
|
110
|
+
|
|
111
|
+
if subtype is None:
|
|
112
|
+
if not np.all(atoms.pbc):
|
|
113
|
+
self.subtype = 'cluster'
|
|
114
|
+
else:
|
|
115
|
+
self.subtype = 'bulk'
|
|
116
|
+
elif subtype.lower() in ['slab', 'bulk', 'cluster']:
|
|
117
|
+
self.subtype = subtype.lower()
|
|
118
|
+
else:
|
|
119
|
+
raise NotImplementedError('Only slab, cluster, bulk and slab are implemented.')
|
|
120
|
+
self._generator = getattr(self, self.subtype+'_grid')
|
|
121
|
+
|
|
122
|
+
if type(rsub) in (list, tuple, np.ndarray):
|
|
123
|
+
assert len(rsub) == len(atoms)
|
|
124
|
+
self.rsub = rsub
|
|
125
|
+
elif type(rsub) == dict:
|
|
126
|
+
self.rsub = [rsub.get(n) or rsub.get(chemical_symbols(n)) for n in atoms.numbers]
|
|
127
|
+
elif type(rsub) == str:
|
|
128
|
+
if rsub == 'covalent_radii' or rsub == 'natural_cutoff':
|
|
129
|
+
self.rsub = natural_cutoffs(atoms)
|
|
130
|
+
if scale is None:
|
|
131
|
+
scale = 1.1
|
|
132
|
+
elif rsub == 'vdw_radii':
|
|
133
|
+
self.rsub = [vdw_radii[n] for n in atoms.numbers]
|
|
134
|
+
else:
|
|
135
|
+
raise ValueError("rsub must be 'covalent_radii', 'natural_cutoff' or 'vdw_radii' or a list.")
|
|
136
|
+
|
|
137
|
+
if scale is None:
|
|
138
|
+
scale = 1.0
|
|
139
|
+
self.scale = scale
|
|
140
|
+
self.rsub = np.asarray(self.rsub) * scale
|
|
141
|
+
self.rads = rads * scale
|
|
142
|
+
|
|
143
|
+
def cluster_grid(self):
|
|
144
|
+
atoms = self.atoms
|
|
145
|
+
if np.all(atoms.pbc):
|
|
146
|
+
atoms.center()
|
|
147
|
+
interval = self.interval
|
|
148
|
+
pos = atoms.positions
|
|
149
|
+
# 找到团簇格点的边界
|
|
150
|
+
posx, posy, posz = pos[:,0], pos[:,1], pos[:,2]
|
|
151
|
+
xmin = (posx - self.rsub).min() - interval * 2 - self.rads
|
|
152
|
+
xmax = (posx + self.rsub).max() + interval * 2 + self.rads
|
|
153
|
+
ymin = (posy - self.rsub).min() - interval * 2 - self.rads
|
|
154
|
+
ymax = (posy + self.rsub).max() + interval * 2 + self.rads
|
|
155
|
+
zmin = (posz - self.rsub).min() - interval * 2 - self.rads
|
|
156
|
+
zmax = (posz + self.rsub).max() + interval * 2 + self.rads
|
|
157
|
+
xarray = np.arange(xmin, xmax, interval)
|
|
158
|
+
yarray = np.arange(ymin, ymax, interval)
|
|
159
|
+
zarray = np.arange(zmin, zmax, interval)
|
|
160
|
+
nx,ny,nz = map(len, [xarray, yarray, zarray])
|
|
161
|
+
# 格点生成
|
|
162
|
+
grid_x, grid_y, grid_z = np.meshgrid(xarray, yarray, zarray, indexing='ij')
|
|
163
|
+
xyz = np.asarray([grid_x.ravel(), grid_y.ravel(), grid_z.ravel()]).T
|
|
164
|
+
grid_tree = cKDTree(xyz, copy_data=True)
|
|
165
|
+
|
|
166
|
+
dist_sum = 0
|
|
167
|
+
atoms_num_type = set(atoms.numbers)
|
|
168
|
+
# 对于不同的原子类型取不同的半径
|
|
169
|
+
for num_type in atoms_num_type:
|
|
170
|
+
pos = atoms.positions[atoms.numbers == num_type]
|
|
171
|
+
atoms_tree = cKDTree(pos, copy_data=True)
|
|
172
|
+
max_distance = self.rads + self.rsub[atoms.numbers == num_type][0]
|
|
173
|
+
sdm = atoms_tree.sparse_distance_matrix(grid_tree, max_distance=max_distance)
|
|
174
|
+
# TODO: 此处可以加上 mask 参数,过滤掉一部分格点,从而加速计算
|
|
175
|
+
# 保证没有格点的坐标跟grid 完全重合,如果有的话,需要标识出来,赋予它们另外的值,保证在后面识别中不为0。
|
|
176
|
+
sdm0 = atoms_tree.sparse_distance_matrix(grid_tree, max_distance=0)
|
|
177
|
+
for k in sdm0.keys():
|
|
178
|
+
sdm[k] = 1
|
|
179
|
+
dist_sum = sdm.toarray().sum(axis=0).reshape((nx, ny, nz)) + dist_sum
|
|
180
|
+
|
|
181
|
+
verts, faces, normals, values = marching_cubes(dist_sum, 0, allow_degenerate=False)
|
|
182
|
+
verts = np.asarray(verts, dtype=int)
|
|
183
|
+
unique_verts = np.unique(verts,axis=0) # exclude some repeat points
|
|
184
|
+
# _points = np.asarray([[grid_x[i,j,k],grid_y[i,j,k],grid_z[i,j,k]] for i, j, k in unique_verts[:]]) # 校验数值
|
|
185
|
+
points = np.asarray([grid_x[unique_verts[:,0], unique_verts[:,1], unique_verts[:,2]],
|
|
186
|
+
grid_y[unique_verts[:,0], unique_verts[:,1], unique_verts[:,2]],
|
|
187
|
+
grid_z[unique_verts[:,0], unique_verts[:,1], unique_verts[:,2]]]).T
|
|
188
|
+
self._grid = points
|
|
189
|
+
|
|
190
|
+
def slab_grid(self):
|
|
191
|
+
# TODO: exclude the grid inside bulk
|
|
192
|
+
atoms = self.atoms
|
|
193
|
+
pos = atoms.positions
|
|
194
|
+
interval = self.interval
|
|
195
|
+
posz = pos[:,2]
|
|
196
|
+
zmax = (posz + np.asarray(self.rsub)).max() + self.rads + interval * 2
|
|
197
|
+
zmin = (posz.max() + posz.min())/2 # 从层中心开始
|
|
198
|
+
lenx, leny, lenz = atoms.cell.lengths()
|
|
199
|
+
ifx, ify, ifz = interval / lenx, interval / leny, interval / lenz
|
|
200
|
+
fx_list = np.arange(0, 1, ifx)
|
|
201
|
+
fy_list = np.arange(0, 1, ify)
|
|
202
|
+
fz_list = np.arange(zmin/lenz, zmax/lenz, ifz)
|
|
203
|
+
nx, ny, nz = map(len, [fx_list, fy_list, fz_list])
|
|
204
|
+
fgrid_x, fgrid_y, fgrid_z = np.meshgrid(fx_list, fy_list, fz_list, indexing='ij')
|
|
205
|
+
fxyz = np.asarray([fgrid_x.ravel(), fgrid_y.ravel(), fgrid_z.ravel()]).T
|
|
206
|
+
xyz = atoms.cell.cartesian_positions(fxyz)
|
|
207
|
+
grid_tree = cKDTree(xyz, copy_data=True)
|
|
208
|
+
|
|
209
|
+
# 对atoms 在 xy 方向超胞. Adapt from ase.geometry.geometry.general_find_mic
|
|
210
|
+
ranges = [np.arange(-1 * p, p + 1) for p in atoms.pbc[:2]]
|
|
211
|
+
hkls = np.concatenate([np.array(list(itertools.product(*ranges))),
|
|
212
|
+
np.zeros([9, 1], dtype=int)], axis=1)
|
|
213
|
+
vrvecs = hkls @ atoms.cell
|
|
214
|
+
super_pos = np.concatenate(atoms.positions + vrvecs[:,None], axis=0)
|
|
215
|
+
super_num = np.concatenate([atoms.numbers] * 9)
|
|
216
|
+
rsub = np.concatenate([self.rsub] * 9)
|
|
217
|
+
|
|
218
|
+
dist_sum = 0
|
|
219
|
+
atoms_num_type = set(atoms.numbers)
|
|
220
|
+
# 对于不同的原子类型取不同的半径
|
|
221
|
+
for num_type in atoms_num_type:
|
|
222
|
+
pos = super_pos[super_num == num_type]
|
|
223
|
+
atoms_tree = cKDTree(pos, copy_data=True)
|
|
224
|
+
max_distance = self.rads + rsub[super_num == num_type][0]
|
|
225
|
+
sdm = atoms_tree.sparse_distance_matrix(grid_tree, max_distance=max_distance)
|
|
226
|
+
# TODO: 此处可以加上 mask 参数,过滤掉一部分格点,从而加速计算
|
|
227
|
+
# 保证没有格点的坐标跟grid 完全重合,如果有的话,需要标识出来,赋予它们另外的值,保证在后面识别中不为0。
|
|
228
|
+
sdm0 = atoms_tree.sparse_distance_matrix(grid_tree, max_distance=0)
|
|
229
|
+
for k in sdm0.keys():
|
|
230
|
+
sdm[k] = 1
|
|
231
|
+
dist_sum = sdm.toarray().sum(axis=0).reshape((nx, ny, nz)) + dist_sum
|
|
232
|
+
|
|
233
|
+
verts, faces, normals, values = marching_cubes(dist_sum, 0, allow_degenerate=False)
|
|
234
|
+
verts = np.asarray(verts, dtype=int)
|
|
235
|
+
unique_verts = np.unique(verts,axis=0) # exclude some repeat points
|
|
236
|
+
fpoints = np.asarray([fgrid_x[unique_verts[:,0], unique_verts[:,1], unique_verts[:,2]],
|
|
237
|
+
fgrid_y[unique_verts[:,0], unique_verts[:,1], unique_verts[:,2]],
|
|
238
|
+
fgrid_z[unique_verts[:,0], unique_verts[:,1], unique_verts[:,2]]]).T
|
|
239
|
+
points = atoms.cell.cartesian_positions(fpoints)
|
|
240
|
+
self._grid = points
|
|
241
|
+
|
|
242
|
+
def bulk_grid(self):
|
|
243
|
+
raise NotImplementedError
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def grid(self):
|
|
247
|
+
if self._grid is None:
|
|
248
|
+
self._generator()
|
|
249
|
+
|
|
250
|
+
return self._grid
|
|
251
|
+
|
|
252
|
+
def view(self):
|
|
253
|
+
if len(self.grid) > 10000:
|
|
254
|
+
print("Too much grid number, it will be very slow.")
|
|
255
|
+
view(self.atoms + ase.Atoms(symbols=['X'] * len(self.grid), positions=self.grid))
|
|
@@ -14,6 +14,4 @@ surface_construct.egg-info/PKG-INFO
|
|
|
14
14
|
surface_construct.egg-info/SOURCES.txt
|
|
15
15
|
surface_construct.egg-info/dependency_links.txt
|
|
16
16
|
surface_construct.egg-info/requires.txt
|
|
17
|
-
surface_construct.egg-info/top_level.txt
|
|
18
|
-
tests/test_surface_grid.py
|
|
19
|
-
tests/test_systematic_opt.py
|
|
17
|
+
surface_construct.egg-info/top_level.txt
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
from scipy.spatial import ConvexHull
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def calc_hull_vertices(v):
|
|
5
|
-
shape = v.shape
|
|
6
|
-
if len(shape) != 2:
|
|
7
|
-
print("Warning: The vector should be 2D, however {}D vector was provided!)".format(len(shape)))
|
|
8
|
-
print("The Convex Hull Vertices won't be calculated.")
|
|
9
|
-
return None
|
|
10
|
-
if shape[1] > 5:
|
|
11
|
-
print("Warning: The vector.shape[1]={} is too large to be calculated!)".format(shape[1]))
|
|
12
|
-
print("The Convex Hull Vertices won't be calculated.")
|
|
13
|
-
return None
|
|
14
|
-
try:
|
|
15
|
-
print("Calculate Convex Hull Vertices ...")
|
|
16
|
-
hull = ConvexHull(v)
|
|
17
|
-
vertices = hull.vertices
|
|
18
|
-
return vertices
|
|
19
|
-
except ValueError:
|
|
20
|
-
return None
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def get_calc_info(calc=None):
|
|
24
|
-
if calc is None:
|
|
25
|
-
return {}
|
|
26
|
-
calc_name = calc.name
|
|
27
|
-
calc_para = dict()
|
|
28
|
-
if calc_name in ('vasp',):
|
|
29
|
-
calc_para['xc'] = calc.parameters['xc']
|
|
30
|
-
calc_para['encut'] = calc.parameters['encut']
|
|
31
|
-
|
|
32
|
-
calc_info = {
|
|
33
|
-
'name': calc_name,
|
|
34
|
-
'para': calc_para,
|
|
35
|
-
}
|
|
36
|
-
return calc_info
|
|
37
|
-
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import ase.io
|
|
2
|
-
import matplotlib.pyplot as plt
|
|
3
|
-
import numpy as np
|
|
4
|
-
from ase.visualize import view
|
|
5
|
-
from sklearn.decomposition import PCA
|
|
6
|
-
|
|
7
|
-
from surface_construct.surface_grid import SurfaceGrid
|
|
8
|
-
|
|
9
|
-
atoms = ase.io.read('ru_0001_POSCAR')
|
|
10
|
-
# atoms = ase.io.read('In2O3_011.cif')
|
|
11
|
-
sg = SurfaceGrid(atoms, interval=0.2)
|
|
12
|
-
sg.gridize()
|
|
13
|
-
sg.vectorize()
|
|
14
|
-
|
|
15
|
-
energy_file = 'energy.dat'
|
|
16
|
-
with open(energy_file, 'r+') as f:
|
|
17
|
-
content = f.readlines()
|
|
18
|
-
|
|
19
|
-
points = []
|
|
20
|
-
values = []
|
|
21
|
-
for l in content[1:]:
|
|
22
|
-
x1, y1, z1, x2, y2, z2, e = list(map(float, l.split()[1:]))
|
|
23
|
-
values.append(e)
|
|
24
|
-
points.append([(x1 + x2) / 2.0, (y1 + y2) / 2.0, (z1 + z2) / 2.0])
|
|
25
|
-
points = np.asarray(points)
|
|
26
|
-
values = np.asarray(values)
|
|
27
|
-
|
|
28
|
-
sg.set_energy(points, values, ignore_z=True)
|
|
29
|
-
|
|
30
|
-
sg.plot_energy()
|
|
31
|
-
sg.plot_sigma()
|
|
32
|
-
|
|
33
|
-
points_sample = sg.grid_sample()
|
|
34
|
-
|
|
35
|
-
view(sg.atoms + ase.Atoms(symbols=['X'] * len(points_sample), positions=points_sample))
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import ase
|
|
2
|
-
import numpy as np
|
|
3
|
-
from ase.visualize import view
|
|
4
|
-
from surface_construct.systematic_opt import SystematicOpt
|
|
5
|
-
|
|
6
|
-
atoms = ase.Atoms('CO', positions=[[0, 0, 0], [0, 0, 1.4]])
|
|
7
|
-
coordinate = {
|
|
8
|
-
'phi_x': {'indices': [0, 1], 'values': [0, 90]},
|
|
9
|
-
'theta': {'indices': [0, 1], 'values': [0, 90]},
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
sysopt = SystematicOpt(atoms, coordinate)
|
|
13
|
-
A = sysopt.rotate_theta(0, 1, 0)
|
|
14
|
-
A1 = sysopt.rotate_phi_x(0, 1, 90)
|
|
15
|
-
atomslst = sysopt.get_initial_atomslst()
|
|
16
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{surface_construct-0.5.14 → surface_construct-0.6}/surface_construct.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|