surface-construct 0.8.2__tar.gz → 0.9__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.8.2/surface_construct.egg-info → surface_construct-0.9}/PKG-INFO +12 -6
- {surface_construct-0.8.2 → surface_construct-0.9}/setup.py +1 -5
- surface_construct-0.9/surface_construct/__init__.py +12 -0
- {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct/db.py +1 -1
- surface_construct-0.9/surface_construct/sg_sampler.py +314 -0
- {surface_construct-0.8.2 → surface_construct-0.9/surface_construct.egg-info}/PKG-INFO +12 -6
- {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct.egg-info/SOURCES.txt +6 -7
- {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct.egg-info/requires.txt +0 -3
- surface_construct-0.9/tests/test_sampling1.py +38 -0
- surface_construct-0.9/tests/test_sampling2.py +44 -0
- surface_construct-0.9/tests/test_surface_grid.py +105 -0
- surface_construct-0.9/tests/test_task.py +83 -0
- surface_construct-0.8.2/surface_construct/__init__.py +0 -4
- surface_construct-0.8.2/surface_construct/atoms.py +0 -564
- surface_construct-0.8.2/surface_construct/sampling.py +0 -318
- surface_construct-0.8.2/surface_construct/structure.py +0 -536
- surface_construct-0.8.2/surface_construct/surface.py +0 -738
- surface_construct-0.8.2/surface_construct/surface_grid.py +0 -705
- surface_construct-0.8.2/surface_construct/utils.py +0 -361
- {surface_construct-0.8.2 → surface_construct-0.9}/LICENSE +0 -0
- {surface_construct-0.8.2 → surface_construct-0.9}/README.md +0 -0
- {surface_construct-0.8.2 → surface_construct-0.9}/setup.cfg +0 -0
- {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct/default_parameter.py +0 -0
- {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct.egg-info/dependency_links.txt +0 -0
- {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct.egg-info/top_level.txt +0 -0
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: surface_construct
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9
|
|
4
4
|
Summary: Surface termination construction especially for complex model, such as oxides or carbides.
|
|
5
5
|
Home-page: https://gitee.com/pjren/surface_construct/
|
|
6
6
|
Author: ren
|
|
7
7
|
Author-email: 0403114076@163.com
|
|
8
8
|
License: GPL
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
11
10
|
Classifier: Operating System :: OS Independent
|
|
12
11
|
Description-Content-Type: text/markdown
|
|
13
12
|
License-File: LICENSE
|
|
14
13
|
Requires-Dist: ase
|
|
15
14
|
Requires-Dist: networkx
|
|
16
|
-
Requires-Dist: numpy
|
|
17
15
|
Requires-Dist: spglib
|
|
18
16
|
Requires-Dist: pandas
|
|
19
17
|
Requires-Dist: tqdm
|
|
20
|
-
Requires-Dist: matplotlib
|
|
21
|
-
Requires-Dist: scipy
|
|
22
18
|
Requires-Dist: scikit-learn
|
|
23
19
|
Requires-Dist: scikit-image
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: requires-dist
|
|
29
|
+
Dynamic: summary
|
|
24
30
|
|
|
25
31
|
# 基于分层采样策略的催化剂表面位点全局分析
|
|
26
32
|
|
|
@@ -6,19 +6,16 @@ with open("README.md", "r", encoding='utf-8') as f:
|
|
|
6
6
|
install_requires = [
|
|
7
7
|
'ase',
|
|
8
8
|
'networkx',
|
|
9
|
-
'numpy',
|
|
10
9
|
'spglib',
|
|
11
10
|
'pandas',
|
|
12
11
|
'tqdm',
|
|
13
|
-
'matplotlib',
|
|
14
|
-
'scipy',
|
|
15
12
|
'scikit-learn',
|
|
16
13
|
'scikit-image'
|
|
17
14
|
]
|
|
18
15
|
|
|
19
16
|
setup(
|
|
20
17
|
name='surface_construct',
|
|
21
|
-
version='0.
|
|
18
|
+
version='0.9',
|
|
22
19
|
packages=['surface_construct'],
|
|
23
20
|
url='https://gitee.com/pjren/surface_construct/',
|
|
24
21
|
license='GPL',
|
|
@@ -30,7 +27,6 @@ setup(
|
|
|
30
27
|
install_requires=install_requires,
|
|
31
28
|
classifiers=[
|
|
32
29
|
"Programming Language :: Python :: 3",
|
|
33
|
-
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
|
34
30
|
"Operating System :: OS Independent",
|
|
35
31
|
],
|
|
36
32
|
)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from surface_construct.structures.surface import Crystal, Surface, Slab, Termination
|
|
2
|
+
from surface_construct.structures.surface import get_terminations_score
|
|
3
|
+
from surface_construct.structures.surface_grid import SurfaceGrid, GridGenerator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
__all__ = ['SurfaceGrid',
|
|
7
|
+
'GridGenerator',
|
|
8
|
+
'Crystal',
|
|
9
|
+
'Surface',
|
|
10
|
+
'Slab',
|
|
11
|
+
'Termination',
|
|
12
|
+
]
|
|
@@ -6,7 +6,7 @@ from ase.db.core import now
|
|
|
6
6
|
from ase.io.jsonio import write_json, read_json
|
|
7
7
|
import os
|
|
8
8
|
from ase.db.row import AtomsRow, row2dct
|
|
9
|
-
from surface_construct.atoms import get_atoms_topo_id
|
|
9
|
+
from surface_construct.utils.atoms import get_atoms_topo_id
|
|
10
10
|
from surface_construct.utils import calc_hull_vertices, get_calc_info
|
|
11
11
|
|
|
12
12
|
"""
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy.spatial import cKDTree
|
|
3
|
+
from scipy.spatial.distance import cdist
|
|
4
|
+
from sklearn.cluster import KMeans as Cluster
|
|
5
|
+
import random
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def name2sampler(name):
|
|
9
|
+
return globals()[name]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def addition_samples(sg_obj, size=None, probability=None, **kwargs):
|
|
13
|
+
if 'seed' in kwargs:
|
|
14
|
+
seed = kwargs['seed']
|
|
15
|
+
else:
|
|
16
|
+
seed = None
|
|
17
|
+
if probability is None:
|
|
18
|
+
probability = {
|
|
19
|
+
"max_sigma": 0.2, # 采样方法的概率
|
|
20
|
+
"max_diversity": 0.8,
|
|
21
|
+
}
|
|
22
|
+
if size is None:
|
|
23
|
+
size = 1
|
|
24
|
+
|
|
25
|
+
# 归一化
|
|
26
|
+
total = sum(probability.values())
|
|
27
|
+
if total != 1.0:
|
|
28
|
+
probability = {k: v / total for k, v in probability.items()}
|
|
29
|
+
|
|
30
|
+
rng = np.random.default_rng(seed)
|
|
31
|
+
method_list = rng.choice(list(probability.keys()), size=size, p=list(probability.values()))
|
|
32
|
+
|
|
33
|
+
point_idx = np.array([], dtype=int)
|
|
34
|
+
for method in method_list:
|
|
35
|
+
method_lower = method.lower()
|
|
36
|
+
if method_lower == 'max_sigma':
|
|
37
|
+
sampling_obj = MaxSigmaSGSampler(sg_obj)
|
|
38
|
+
elif method_lower == 'max_diversity':
|
|
39
|
+
sampling_obj = MaxDiversitySGSampler(sg_obj)
|
|
40
|
+
else:
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
point_idx = np.concatenate([point_idx, sampling_obj.samples(size=1, **kwargs)]) # 每种方法只采一个
|
|
43
|
+
|
|
44
|
+
return point_idx
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SGSamplerBase:
|
|
48
|
+
def __init__(self, sg_obj, **kwargs):
|
|
49
|
+
self.sg_obj = sg_obj
|
|
50
|
+
self.threshold = kwargs.get('threshold', 0.37) # 0.37 is half of H-H bond
|
|
51
|
+
self.weight = kwargs.get('weight', 1.0) # 采样的几率,最后进行归一化处理
|
|
52
|
+
self.kwargs = kwargs
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def _pop_size(self):
|
|
56
|
+
return len(self.sg_obj.points)
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def _population(self):
|
|
60
|
+
"""
|
|
61
|
+
默认的全体是 sg_obj.points 的 index
|
|
62
|
+
:return:
|
|
63
|
+
"""
|
|
64
|
+
return range(self._pop_size)
|
|
65
|
+
|
|
66
|
+
def _append_sample_to_sg(self, point_idx=None):
|
|
67
|
+
"""
|
|
68
|
+
将采样点加入到 sg_obj.sample_points 和相应的 vector
|
|
69
|
+
|
|
70
|
+
:return:
|
|
71
|
+
"""
|
|
72
|
+
if point_idx is None:
|
|
73
|
+
point_idx = []
|
|
74
|
+
elif type(point_idx) is int:
|
|
75
|
+
point_idx = [point_idx]
|
|
76
|
+
|
|
77
|
+
for p in point_idx:
|
|
78
|
+
self.sg_obj.sample_idx = p
|
|
79
|
+
|
|
80
|
+
def _samples(self, size, **kwargs):
|
|
81
|
+
raise NotImplementedError
|
|
82
|
+
|
|
83
|
+
def samples(self, size=1, **kwargs):
|
|
84
|
+
result = []
|
|
85
|
+
curr_size = size
|
|
86
|
+
loop = 0
|
|
87
|
+
while len(result) < size and loop < 10:
|
|
88
|
+
point_idx = self._samples(size=curr_size, **kwargs)
|
|
89
|
+
filtered_idx = self.exclude_too_close_sample(point_idx)
|
|
90
|
+
self._append_sample_to_sg(point_idx=filtered_idx)
|
|
91
|
+
result += filtered_idx
|
|
92
|
+
curr_size = size - len(filtered_idx)
|
|
93
|
+
loop += 1
|
|
94
|
+
return result
|
|
95
|
+
|
|
96
|
+
def exclude_too_close_sample(self, idx_list, threshold=None):
|
|
97
|
+
if threshold is None:
|
|
98
|
+
threshold = self.threshold
|
|
99
|
+
if self.sg_obj.sample_idx is not None:
|
|
100
|
+
unique_idx_list = [i for i in idx_list if i not in self.sg_obj.sample_idx]
|
|
101
|
+
points = list(self.sg_obj.sample_points)
|
|
102
|
+
else:
|
|
103
|
+
unique_idx_list = idx_list[:]
|
|
104
|
+
points = []
|
|
105
|
+
new_idx_list = []
|
|
106
|
+
for idx in unique_idx_list:
|
|
107
|
+
p = self.sg_obj.points[idx]
|
|
108
|
+
if len(points) == 0:
|
|
109
|
+
points.append(p)
|
|
110
|
+
new_idx_list.append(idx)
|
|
111
|
+
continue
|
|
112
|
+
tree = cKDTree(points)
|
|
113
|
+
if len(tree.query_ball_point(x=p, r=threshold,p=2))==0:
|
|
114
|
+
points.append(p)
|
|
115
|
+
new_idx_list.append(idx)
|
|
116
|
+
|
|
117
|
+
if len(new_idx_list) != len(idx_list):
|
|
118
|
+
print(f"Exclude too close sample {set(idx_list)-set(new_idx_list)}")
|
|
119
|
+
return new_idx_list
|
|
120
|
+
|
|
121
|
+
class KeyPointSGSampler(SGSamplerBase):
|
|
122
|
+
"""
|
|
123
|
+
关键点采样,使用 vip_id
|
|
124
|
+
"""
|
|
125
|
+
def _samples(self, **kwargs):
|
|
126
|
+
sample_idx = self.sg_obj.unique_vip_id
|
|
127
|
+
clusters = Cluster(n_clusters=len(sample_idx)).fit(self.sg_obj.vector)
|
|
128
|
+
self.sg_obj._clusters = clusters
|
|
129
|
+
return sample_idx
|
|
130
|
+
|
|
131
|
+
def samples(self, size=None, **kwargs):
|
|
132
|
+
point_idx = self._samples(**kwargs)
|
|
133
|
+
filtered_idx = self.exclude_too_close_sample(point_idx)
|
|
134
|
+
self._append_sample_to_sg(point_idx=filtered_idx)
|
|
135
|
+
return filtered_idx
|
|
136
|
+
|
|
137
|
+
class RandomSGSampler(SGSamplerBase):
|
|
138
|
+
"""
|
|
139
|
+
完全随机的选择点,仅用于测试,效率太低。
|
|
140
|
+
"""
|
|
141
|
+
def __init__(self, sg_obj, **kwargs):
|
|
142
|
+
super().__init__(sg_obj, **kwargs)
|
|
143
|
+
if 'seed' in kwargs:
|
|
144
|
+
self.seed = kwargs['seed']
|
|
145
|
+
else:
|
|
146
|
+
self.seed = None
|
|
147
|
+
|
|
148
|
+
def _samples(self, size, **kwargs):
|
|
149
|
+
idx = random.sample(self._population, size)
|
|
150
|
+
return idx
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class MaxSigmaSGSampler(SGSamplerBase):
|
|
154
|
+
"""
|
|
155
|
+
对最大误差的点进行采样
|
|
156
|
+
"""
|
|
157
|
+
def _samples(self, size, **kwargs):
|
|
158
|
+
if 'energy' in self.sg_obj.grid_property:
|
|
159
|
+
# 如果已经读入了一些能量,则返回误差最大的点
|
|
160
|
+
sigma_array = self.sg_obj.grid_property['energy']
|
|
161
|
+
sigma0 = sigma_array.max()
|
|
162
|
+
idx_list = np.argwhere(sigma_array <= sigma0-0.1).flatten().tolist()
|
|
163
|
+
idx = random.sample(idx_list, size)
|
|
164
|
+
return idx
|
|
165
|
+
else:
|
|
166
|
+
raise "No energy for all population, pls do initial sampling first!"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class MinEnergySGSampler(SGSamplerBase):
|
|
170
|
+
"""
|
|
171
|
+
对最大误差的点进行采样
|
|
172
|
+
"""
|
|
173
|
+
def _samples(self, size, **kwargs):
|
|
174
|
+
if 'energy' in self.sg_obj.grid_property:
|
|
175
|
+
E_array = self.sg_obj.grid_property['energy']
|
|
176
|
+
# 如果已经读入了一些能量,则返回能量最低的点 (<0.1eV 以内,然后随机选一个)
|
|
177
|
+
E0 = E_array.min()
|
|
178
|
+
idx_list = np.argwhere(E_array <= E0+0.1).flatten().tolist()
|
|
179
|
+
idx = random.sample(idx_list, size)
|
|
180
|
+
return idx
|
|
181
|
+
else:
|
|
182
|
+
raise "No energy for all population, pls do initial sampling first!"
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class InitialSGSampler(SGSamplerBase):
|
|
186
|
+
"""
|
|
187
|
+
结合使用 KeyPointSampling 和 MaxDiversitySampling
|
|
188
|
+
"""
|
|
189
|
+
def _samples(self, size=None, **kwargs):
|
|
190
|
+
# 先进行 KeyPoint sampling,数量不够再进行 Max diversity sampling
|
|
191
|
+
vip_idx = self.sg_obj.unique_vip_id
|
|
192
|
+
if size is None:
|
|
193
|
+
size = len(vip_idx)
|
|
194
|
+
|
|
195
|
+
if size == len(vip_idx):
|
|
196
|
+
# 已经排除了距离过近的点,而且已经加入到了sg_obj
|
|
197
|
+
sample_idx = KeyPointSGSampler(self.sg_obj, **self.kwargs).samples(**kwargs)
|
|
198
|
+
elif size < len(vip_idx):
|
|
199
|
+
print(f"The initial sampling size {size} is smaller than the number of key points {len(vip_idx)}.")
|
|
200
|
+
sample_idx = random.sample(vip_idx, size)
|
|
201
|
+
self._append_sample_to_sg(point_idx=sample_idx)
|
|
202
|
+
else:
|
|
203
|
+
sample_idx = KeyPointSGSampler(self.sg_obj, **self.kwargs).samples(**kwargs)
|
|
204
|
+
while len(sample_idx) < size:
|
|
205
|
+
adding_sample = MaxDiversitySGSampler(self.sg_obj).samples(size=size-len(sample_idx),**kwargs)
|
|
206
|
+
sample_idx = np.concatenate([sample_idx, adding_sample])
|
|
207
|
+
return sample_idx
|
|
208
|
+
|
|
209
|
+
def samples(self, size=1, **kwargs):
|
|
210
|
+
return self._samples(size=size, **kwargs)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class MaxDiversitySGSampler(SGSamplerBase):
|
|
214
|
+
"""
|
|
215
|
+
对当前采样结构差异最大的点进行采样
|
|
216
|
+
基本思路是这样的:
|
|
217
|
+
* 重新进行聚类,
|
|
218
|
+
* 判断已经采样点属于的类别,找出没有点的类别,空类
|
|
219
|
+
* 如果空类不止一个,比较这些空类中心与旧点的距离,选择距离最大的点。
|
|
220
|
+
"""
|
|
221
|
+
def _samples(self, size, center=True, **kwargs):
|
|
222
|
+
"""
|
|
223
|
+
:param size:
|
|
224
|
+
:param center: 是否取中心。如果不是,则取能量最小值的点。如果没有能量则报错。
|
|
225
|
+
:param kwargs:
|
|
226
|
+
:return:
|
|
227
|
+
"""
|
|
228
|
+
# 判断是否有过往的采样点,如果没有,调用 InitialSampling
|
|
229
|
+
if len(self.sg_obj.sample_idx) == 0:
|
|
230
|
+
clusters = Cluster(n_clusters=size).fit(self.sg_obj.vector)
|
|
231
|
+
virgin = list(set(clusters.labels_))
|
|
232
|
+
else:
|
|
233
|
+
cluster_size = len(self.sg_obj.sample_idx) + size
|
|
234
|
+
nvirgin = 0
|
|
235
|
+
larger_clusters = None
|
|
236
|
+
larger_virgin = None
|
|
237
|
+
virgin = None
|
|
238
|
+
clusters = None
|
|
239
|
+
# 如果等于则停止,并保存 cluster
|
|
240
|
+
while nvirgin != size:
|
|
241
|
+
# 以 len(sample_idx) + size 作为新的聚类的size
|
|
242
|
+
clusters = Cluster(n_clusters=cluster_size).fit(self.sg_obj.vector)
|
|
243
|
+
labels = clusters.labels_[self.sg_obj.sample_idx]
|
|
244
|
+
labels_set = set(labels)
|
|
245
|
+
virgin = set(range(cluster_size)) - labels_set
|
|
246
|
+
nvirgin = len(virgin)
|
|
247
|
+
# 判断分类以后空类数目与size的大小
|
|
248
|
+
# 如果大于size,则减小size,并记录空类的数目
|
|
249
|
+
if nvirgin > size:
|
|
250
|
+
cluster_size -= 1
|
|
251
|
+
larger_clusters = clusters
|
|
252
|
+
larger_virgin = virgin
|
|
253
|
+
# 如果小于 size 则增大size,检查上一个size是否有记录,如果有记录则使用上个size 的记录。从中随机选择size个点作为采样点。
|
|
254
|
+
elif nvirgin < size:
|
|
255
|
+
cluster_size += 1
|
|
256
|
+
if larger_clusters is not None:
|
|
257
|
+
clusters = larger_clusters
|
|
258
|
+
virgin = larger_virgin
|
|
259
|
+
break
|
|
260
|
+
# 从 virgin 里面选取 size 个点
|
|
261
|
+
cluster_idx = random.sample(list(virgin), size)
|
|
262
|
+
if (not center) and 'energy' not in self.sg_obj.grid_property:
|
|
263
|
+
center = True
|
|
264
|
+
print("Warning: Can't get cluster minimum energy, use cluster center instead!")
|
|
265
|
+
if center:
|
|
266
|
+
# 取中心位置的格点
|
|
267
|
+
centers = clusters.cluster_centers_[cluster_idx]
|
|
268
|
+
center_dist = cdist(centers, self.sg_obj.vector) # 计算每个点到中心的距离
|
|
269
|
+
point_idx = np.argmin(center_dist, axis=-1)
|
|
270
|
+
else:
|
|
271
|
+
# 取这些 clusters 中能量最小值点
|
|
272
|
+
point_idx = []
|
|
273
|
+
for c_id in cluster_idx:
|
|
274
|
+
p_idx = np.arange(len(self.sg_obj.points))[clusters.labels_ == c_id]
|
|
275
|
+
# 求这些点的能量最小值
|
|
276
|
+
p_energy = self.sg_obj.grid_energy[p_idx]
|
|
277
|
+
point_idx.append(p_idx[p_energy.argmin()])
|
|
278
|
+
# assign cluster to sg_obj
|
|
279
|
+
self.sg_obj._clusters = clusters
|
|
280
|
+
return point_idx
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class NewtonSGSampler(SGSamplerBase):
|
|
284
|
+
"""
|
|
285
|
+
沿着受力方向进行采样
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
def _samples(self, size, **kwargs):
|
|
289
|
+
raise NotImplementedError
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class RandomWalk(SGSamplerBase):
|
|
293
|
+
"""
|
|
294
|
+
从给定点出发随机行走进行采样
|
|
295
|
+
"""
|
|
296
|
+
def _samples(self, size, **kwargs):
|
|
297
|
+
raise NotImplementedError
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class SystematicSGSampler(SGSamplerBase):
|
|
301
|
+
"""
|
|
302
|
+
等距采样。主要用于测试。
|
|
303
|
+
"""
|
|
304
|
+
def _samples(self, size, **kwargs):
|
|
305
|
+
if 'start' in kwargs:
|
|
306
|
+
start = kwargs['start']
|
|
307
|
+
else:
|
|
308
|
+
start = random.randint(0, self._pop_size)
|
|
309
|
+
stop = self._pop_size
|
|
310
|
+
indices = list(range(start, stop)) + list(range(0, start))
|
|
311
|
+
step = int(self._pop_size / size)
|
|
312
|
+
point_idx = [indices[i + n * step] for n, i in enumerate(range(size))]
|
|
313
|
+
|
|
314
|
+
return point_idx
|
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: surface_construct
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9
|
|
4
4
|
Summary: Surface termination construction especially for complex model, such as oxides or carbides.
|
|
5
5
|
Home-page: https://gitee.com/pjren/surface_construct/
|
|
6
6
|
Author: ren
|
|
7
7
|
Author-email: 0403114076@163.com
|
|
8
8
|
License: GPL
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
11
10
|
Classifier: Operating System :: OS Independent
|
|
12
11
|
Description-Content-Type: text/markdown
|
|
13
12
|
License-File: LICENSE
|
|
14
13
|
Requires-Dist: ase
|
|
15
14
|
Requires-Dist: networkx
|
|
16
|
-
Requires-Dist: numpy
|
|
17
15
|
Requires-Dist: spglib
|
|
18
16
|
Requires-Dist: pandas
|
|
19
17
|
Requires-Dist: tqdm
|
|
20
|
-
Requires-Dist: matplotlib
|
|
21
|
-
Requires-Dist: scipy
|
|
22
18
|
Requires-Dist: scikit-learn
|
|
23
19
|
Requires-Dist: scikit-image
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: requires-dist
|
|
29
|
+
Dynamic: summary
|
|
24
30
|
|
|
25
31
|
# 基于分层采样策略的催化剂表面位点全局分析
|
|
26
32
|
|
|
@@ -2,16 +2,15 @@ LICENSE
|
|
|
2
2
|
README.md
|
|
3
3
|
setup.py
|
|
4
4
|
surface_construct/__init__.py
|
|
5
|
-
surface_construct/atoms.py
|
|
6
5
|
surface_construct/db.py
|
|
7
6
|
surface_construct/default_parameter.py
|
|
8
|
-
surface_construct/
|
|
9
|
-
surface_construct/structure.py
|
|
10
|
-
surface_construct/surface.py
|
|
11
|
-
surface_construct/surface_grid.py
|
|
12
|
-
surface_construct/utils.py
|
|
7
|
+
surface_construct/sg_sampler.py
|
|
13
8
|
surface_construct.egg-info/PKG-INFO
|
|
14
9
|
surface_construct.egg-info/SOURCES.txt
|
|
15
10
|
surface_construct.egg-info/dependency_links.txt
|
|
16
11
|
surface_construct.egg-info/requires.txt
|
|
17
|
-
surface_construct.egg-info/top_level.txt
|
|
12
|
+
surface_construct.egg-info/top_level.txt
|
|
13
|
+
tests/test_sampling1.py
|
|
14
|
+
tests/test_sampling2.py
|
|
15
|
+
tests/test_surface_grid.py
|
|
16
|
+
tests/test_task.py
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import ase.io
|
|
3
|
+
|
|
4
|
+
from surface_construct.sg_sampler import InitialSGSampler, KeyPointSGSampler, MaxDiversitySGSampler
|
|
5
|
+
from surface_construct import SurfaceGrid
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestSampling1:
|
|
9
|
+
"""
|
|
10
|
+
Simple Ru 0001 suface
|
|
11
|
+
"""
|
|
12
|
+
def setup_method(self):
|
|
13
|
+
self.atoms = ase.io.read('atoms_files/ru_0001_POSCAR')
|
|
14
|
+
self.sg_obj = SurfaceGrid(self.atoms, interval=0.1, ads_num=6, lpca=True)
|
|
15
|
+
self.sg_obj.initialize()
|
|
16
|
+
|
|
17
|
+
def teardown_method(self):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
def test_initial_sampling(self):
|
|
21
|
+
for size in range(1, 6):
|
|
22
|
+
sample_obj = InitialSGSampler(self.sg_obj)
|
|
23
|
+
samples = sample_obj.samples(size=size)
|
|
24
|
+
self.sg_obj.plot_cluster(figname=f'sampling_{size}')
|
|
25
|
+
self.sg_obj.del_sample()
|
|
26
|
+
|
|
27
|
+
def test_keypoint_sampling(self):
|
|
28
|
+
sample_obj = KeyPointSGSampler(self.sg_obj)
|
|
29
|
+
samples = sample_obj.samples()
|
|
30
|
+
self.sg_obj.plot_cluster(figname=f'KeyPoint_sampling')
|
|
31
|
+
|
|
32
|
+
def test_max_diversity_sampling(self):
|
|
33
|
+
sample_obj = MaxDiversitySGSampler(self.sg_obj)
|
|
34
|
+
samples = sample_obj.samples(size=4)
|
|
35
|
+
self.sg_obj.plot_cluster(figname=f'MaxDiversity_sampling')
|
|
36
|
+
|
|
37
|
+
def test_max_sigma_sampling(self):
|
|
38
|
+
pass
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import ase.io
|
|
3
|
+
|
|
4
|
+
from surface_construct import SurfaceGrid
|
|
5
|
+
from surface_construct.sg_sampler import InitialSGSampler, KeyPointSGSampler, MaxDiversitySGSampler
|
|
6
|
+
|
|
7
|
+
class TestSampling2:
|
|
8
|
+
"""
|
|
9
|
+
Cu-CuO interface
|
|
10
|
+
"""
|
|
11
|
+
def setup_method(self):
|
|
12
|
+
atoms = ase.io.read('atoms_files/CuOx-Cu100-CONTCAR')
|
|
13
|
+
self.sg_obj = SurfaceGrid(atoms, interval=0.2, ads_num=6, lpca=False)
|
|
14
|
+
self.sg_obj.initialize()
|
|
15
|
+
|
|
16
|
+
def teardown_method(self):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
def test_initial_sampling(self):
|
|
20
|
+
for size in [4, 8, 16]:
|
|
21
|
+
sample_obj = InitialSGSampler(self.sg_obj)
|
|
22
|
+
samples = sample_obj.samples(size=size)
|
|
23
|
+
self.sg_obj.plot_cluster(figname=f'sampling_{size}')
|
|
24
|
+
self.sg_obj.del_sample()
|
|
25
|
+
|
|
26
|
+
def test_keypoint_sampling(self):
|
|
27
|
+
sample_obj = KeyPointSGSampler(self.sg_obj)
|
|
28
|
+
samples = sample_obj.samples()
|
|
29
|
+
self.sg_obj.plot_cluster(figname=f'KeyPoint_sampling')
|
|
30
|
+
|
|
31
|
+
def test_max_diversity_sampling(self):
|
|
32
|
+
sample_obj = MaxDiversitySGSampler(self.sg_obj)
|
|
33
|
+
samples = sample_obj.samples(size=10)
|
|
34
|
+
self.sg_obj.plot_cluster(figname=f'MaxDiversity_sampling')
|
|
35
|
+
|
|
36
|
+
def test_max_sigma_sampling(self):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
def test_exclude_too_close_sampling(self):
|
|
40
|
+
samples = [0,1,2,3]
|
|
41
|
+
sample_obj = KeyPointSGSampler(self.sg_obj)
|
|
42
|
+
result_sample = sample_obj.exclude_too_close_sample(samples)
|
|
43
|
+
print(self.sg_obj.points[samples])
|
|
44
|
+
print(result_sample)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import ase.io
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from ase.visualize import view
|
|
6
|
+
from ase import Atoms
|
|
7
|
+
import ase
|
|
8
|
+
from surface_construct import GridGenerator
|
|
9
|
+
from ase.cluster.cubic import FaceCenteredCubic
|
|
10
|
+
from surface_construct import SurfaceGrid
|
|
11
|
+
|
|
12
|
+
class TestSurfaceGrid:
|
|
13
|
+
def test_Cu_cluster(self):
|
|
14
|
+
"""
|
|
15
|
+
GridGenerator.
|
|
16
|
+
Runtime is about 9s
|
|
17
|
+
:return:
|
|
18
|
+
"""
|
|
19
|
+
surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)]
|
|
20
|
+
layers = [4, 4, 4]
|
|
21
|
+
lc = 3.61000
|
|
22
|
+
atoms = FaceCenteredCubic('Cu', surfaces, layers, latticeconstant=lc)
|
|
23
|
+
|
|
24
|
+
atoms.cell = [35, 35, 35]
|
|
25
|
+
atoms.pbc = False # True is very slow
|
|
26
|
+
atoms.center()
|
|
27
|
+
|
|
28
|
+
gridgen = GridGenerator(atoms, interval=0.1)
|
|
29
|
+
grid = gridgen.grid
|
|
30
|
+
print(len(grid))
|
|
31
|
+
|
|
32
|
+
def test_Ag_cluster(self):
|
|
33
|
+
# Ag55
|
|
34
|
+
# Time: 4.23s
|
|
35
|
+
atoms = ase.io.read('atoms_files/Ag.xyz')
|
|
36
|
+
gridgen = GridGenerator(atoms, interval=0.2, subtype='cluster')
|
|
37
|
+
grid = gridgen.grid
|
|
38
|
+
print(len(grid))
|
|
39
|
+
|
|
40
|
+
def test_Ru0001_slab(self):
|
|
41
|
+
# Ru(0001)
|
|
42
|
+
# Time: 4.23s
|
|
43
|
+
atoms = ase.io.read('atoms_files/ru_0001_POSCAR')
|
|
44
|
+
gridgen = GridGenerator(atoms, interval=0.1, subtype='slab')
|
|
45
|
+
grid = gridgen.grid
|
|
46
|
+
print(len(grid))
|
|
47
|
+
|
|
48
|
+
def test_Ru0001_grid_graph(self):
|
|
49
|
+
# Ru(0001)
|
|
50
|
+
atoms = ase.io.read('atoms_files/ru_0001_POSCAR')
|
|
51
|
+
sg_obj = SurfaceGrid(atoms, interval=0.1, ads_num=6, lpca=False)
|
|
52
|
+
sg_obj.gridize(subtype='slab')
|
|
53
|
+
sg_obj.vectorize()
|
|
54
|
+
graph = sg_obj.grid_graph
|
|
55
|
+
vip = sg_obj.vip_id
|
|
56
|
+
print(len(vip))
|
|
57
|
+
print(sg_obj.vector_unit)
|
|
58
|
+
print(len(sg_obj.vector))
|
|
59
|
+
|
|
60
|
+
def test_In2O3_slab(self):
|
|
61
|
+
# In2O3. Should use larger scale.
|
|
62
|
+
atoms = ase.io.read('atoms_files/POSCAR_In2O3_110')
|
|
63
|
+
sg_obj = SurfaceGrid(atoms, interval=0.1, ads_num=6, lpca=False)
|
|
64
|
+
sg_obj.gridize(subtype='slab')
|
|
65
|
+
sg_obj.vectorize()
|
|
66
|
+
graph = sg_obj.grid_graph
|
|
67
|
+
vip = sg_obj.vip_id
|
|
68
|
+
print(len(vip))
|
|
69
|
+
print(sg_obj.vector_unit)
|
|
70
|
+
|
|
71
|
+
def test_Fe3C_slab(self):
|
|
72
|
+
atoms = ase.io.read('atoms_files/Fe3C001_07_CONTCAR')
|
|
73
|
+
sg_obj = SurfaceGrid(atoms, interval=0.1, ads_num=6, lpca=False)
|
|
74
|
+
sg_obj.gridize(subtype='slab')
|
|
75
|
+
sg_obj.vectorize()
|
|
76
|
+
graph = sg_obj.grid_graph
|
|
77
|
+
grid_site_label, site_dict = sg_obj.get_grid_site_type()
|
|
78
|
+
grid_index_label, index_dict = sg_obj.get_grid_index_type()
|
|
79
|
+
vip = sg_obj.vip_id
|
|
80
|
+
print(len(vip))
|
|
81
|
+
print(list(site_dict.keys()))
|
|
82
|
+
|
|
83
|
+
def test_ZSM5(self):
|
|
84
|
+
atoms = ase.io.read('atoms_files/zsm5.cif')
|
|
85
|
+
gridgen = GridGenerator(atoms, interval=0.2, subtype='bulk', rsub='vdw_radii', scale=1.0)
|
|
86
|
+
grid = gridgen.grid
|
|
87
|
+
print(len(grid))
|
|
88
|
+
|
|
89
|
+
def test_interface1(self):
|
|
90
|
+
atoms = ase.io.read('atoms_files/CuOx-Cu100-CONTCAR')
|
|
91
|
+
sg_obj = SurfaceGrid(atoms, interval=0.2, ads_num=6, lpca=False)
|
|
92
|
+
sg_obj.gridize(subtype='slab')
|
|
93
|
+
sg_obj.vectorize()
|
|
94
|
+
vip = sg_obj.vip_id
|
|
95
|
+
uvip = sg_obj.unique_vip_id
|
|
96
|
+
print(len(vip), len(uvip))
|
|
97
|
+
|
|
98
|
+
def test_In2O3_4x4(self):
|
|
99
|
+
# This a large surface, contain about 75K points.
|
|
100
|
+
atoms = ase.io.read('atoms_files/POSCAR_In2O3_110')
|
|
101
|
+
superatoms = atoms.repeat([2,2,1])
|
|
102
|
+
sg_obj = SurfaceGrid(superatoms, interval=0.1, ads_num=6, lpca=False)
|
|
103
|
+
sg_obj.gridize(subtype='slab')
|
|
104
|
+
Lga = sg_obj._Lga
|
|
105
|
+
print(Lga.shape)
|