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.
Files changed (25) hide show
  1. {surface_construct-0.8.2/surface_construct.egg-info → surface_construct-0.9}/PKG-INFO +12 -6
  2. {surface_construct-0.8.2 → surface_construct-0.9}/setup.py +1 -5
  3. surface_construct-0.9/surface_construct/__init__.py +12 -0
  4. {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct/db.py +1 -1
  5. surface_construct-0.9/surface_construct/sg_sampler.py +314 -0
  6. {surface_construct-0.8.2 → surface_construct-0.9/surface_construct.egg-info}/PKG-INFO +12 -6
  7. {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct.egg-info/SOURCES.txt +6 -7
  8. {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct.egg-info/requires.txt +0 -3
  9. surface_construct-0.9/tests/test_sampling1.py +38 -0
  10. surface_construct-0.9/tests/test_sampling2.py +44 -0
  11. surface_construct-0.9/tests/test_surface_grid.py +105 -0
  12. surface_construct-0.9/tests/test_task.py +83 -0
  13. surface_construct-0.8.2/surface_construct/__init__.py +0 -4
  14. surface_construct-0.8.2/surface_construct/atoms.py +0 -564
  15. surface_construct-0.8.2/surface_construct/sampling.py +0 -318
  16. surface_construct-0.8.2/surface_construct/structure.py +0 -536
  17. surface_construct-0.8.2/surface_construct/surface.py +0 -738
  18. surface_construct-0.8.2/surface_construct/surface_grid.py +0 -705
  19. surface_construct-0.8.2/surface_construct/utils.py +0 -361
  20. {surface_construct-0.8.2 → surface_construct-0.9}/LICENSE +0 -0
  21. {surface_construct-0.8.2 → surface_construct-0.9}/README.md +0 -0
  22. {surface_construct-0.8.2 → surface_construct-0.9}/setup.cfg +0 -0
  23. {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct/default_parameter.py +0 -0
  24. {surface_construct-0.8.2 → surface_construct-0.9}/surface_construct.egg-info/dependency_links.txt +0 -0
  25. {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
1
+ Metadata-Version: 2.4
2
2
  Name: surface_construct
3
- Version: 0.8.2
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.8.2',
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
1
+ Metadata-Version: 2.4
2
2
  Name: surface_construct
3
- Version: 0.8.2
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/sampling.py
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
@@ -1,10 +1,7 @@
1
1
  ase
2
2
  networkx
3
- numpy
4
3
  spglib
5
4
  pandas
6
5
  tqdm
7
- matplotlib
8
- scipy
9
6
  scikit-learn
10
7
  scikit-image
@@ -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)