surface-construct 0.11__tar.gz → 0.12.1__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 (38) hide show
  1. {surface_construct-0.11/surface_construct.egg-info → surface_construct-0.12.1}/PKG-INFO +16 -25
  2. {surface_construct-0.11 → surface_construct-0.12.1}/README.md +14 -23
  3. {surface_construct-0.11 → surface_construct-0.12.1}/setup.py +2 -2
  4. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/structures/adsorbate.py +17 -5
  5. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/structures/combiner.py +5 -0
  6. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/structures/surface_grid.py +4 -3
  7. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/tasks/__init__.py +2 -1
  8. surface_construct-0.12.1/surface_construct/tasks/afm.py +120 -0
  9. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/tasks/sitesampling.py +1 -4
  10. {surface_construct-0.11 → surface_construct-0.12.1/surface_construct.egg-info}/PKG-INFO +16 -25
  11. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct.egg-info/SOURCES.txt +1 -0
  12. {surface_construct-0.11 → surface_construct-0.12.1}/tests/test_surface_grid.py +9 -1
  13. {surface_construct-0.11 → surface_construct-0.12.1}/tests/test_task.py +39 -3
  14. {surface_construct-0.11 → surface_construct-0.12.1}/LICENSE +0 -0
  15. {surface_construct-0.11 → surface_construct-0.12.1}/setup.cfg +0 -0
  16. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/__init__.py +0 -0
  17. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/db.py +0 -0
  18. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/default_parameter.py +0 -0
  19. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/sg_sampler.py +0 -0
  20. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/structures/__init__.py +0 -0
  21. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/structures/pymsym_test.py +0 -0
  22. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/structures/surface.py +0 -0
  23. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/tasks/taskbase.py +0 -0
  24. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/tasks/terminations.py +0 -0
  25. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/utils/__init__.py +0 -0
  26. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/utils/atoms.py +0 -0
  27. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/utils/geometry.py +0 -0
  28. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/utils/pymsym_wrapper.py +0 -0
  29. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/utils/spglib_wrapper.py +0 -0
  30. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct/utils/weight_functions.py +0 -0
  31. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct.egg-info/dependency_links.txt +0 -0
  32. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct.egg-info/requires.txt +0 -0
  33. {surface_construct-0.11 → surface_construct-0.12.1}/surface_construct.egg-info/top_level.txt +0 -0
  34. {surface_construct-0.11 → surface_construct-0.12.1}/tests/test_adsorbate.py +0 -0
  35. {surface_construct-0.11 → surface_construct-0.12.1}/tests/test_combiner.py +0 -0
  36. {surface_construct-0.11 → surface_construct-0.12.1}/tests/test_sampling1.py +0 -0
  37. {surface_construct-0.11 → surface_construct-0.12.1}/tests/test_sampling2.py +0 -0
  38. {surface_construct-0.11 → surface_construct-0.12.1}/tests/test_simple_surface.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: surface_construct
3
- Version: 0.11
4
- Summary: Surface termination construction especially for complex model, such as oxides or carbides.
3
+ Version: 0.12.1
4
+ Summary: Surface construction and surface reaction sampling tools.
5
5
  Home-page: https://gitee.com/pjren/surface_construct/
6
6
  Author: ren
7
7
  Author-email: 0403114076@163.com
@@ -32,7 +32,9 @@ Dynamic: summary
32
32
 
33
33
  催化剂构效关系是建立表面位点结构和反应过程势能面的关联关系,这依赖对表面上各种可能位点的充分分析和采样,找到这些位点对关键反应步骤的影响情况。从催化剂的角度看,研究的目标是从表面上存在的位点中找到表面最适合反应的位点,即使反应势能面最低的位点;从反应的角度看,研究目标是对于一系列反应通道,找到反应势能面上的卡点,找到能够突破卡点的催化环境。
34
34
 
35
- 本软件同时进行表面位点的构建、采样、计算、分析,和反应过程的分析采样,即过渡态和分子构象,由此可以实现分子在表面反应的全过程采样。其中的技术关键是采样的效率,我们针对性地使用综合使用了多样化的采样策略,保证表面各类型位点和关键位点的充分采样。
35
+ 本软件同时进行表面位点的构建、采样、计算、分析,和反应过程的分析采样,即过渡态和分子构象,由此可以实现分子在表面反应的全过程采样。不仅包括平板模型的表面,还包括分子筛孔道內、团簇表面等。
36
+
37
+ 表面反应过程采样的技术关键是采样的效率,我们针对性地使用综合使用了多样化的采样策略,保证表面各类型位点和关键位点的充分采样。
36
38
 
37
39
  ### 应用场景
38
40
  * 催化剂表面最可能反应位点采样
@@ -41,15 +43,17 @@ Dynamic: summary
41
43
  * 优化 C、R、Z (z方向,距离表面的距离)空间,固定COM
42
44
  * 返回所采结构中最低能量和对应的结构和能量
43
45
 
44
- * 催化剂表面全势能面采样
46
+ * 催化剂表面全势能面采样(位点、分子构象、旋转)
45
47
  * 适用于催化剂位点全局考察
46
48
  * 适用于表面分子全局的构象和姿态
47
49
  * 适用于反应全过程采样
48
50
  * 不优化,或者仅优化Z空间
49
51
  * 返回全部能量和结构,以及全局的fitting结果
50
52
  * 使用能量截断(dEmax<2eV)
53
+ * 原子力显微镜(AFM)谱图模拟
54
+ * 分子筛孔道內分子构象采样
55
+
51
56
 
52
- <img src="docs/birds_view.png" alt="表面位点全局分析" style="zoom:50%;" />
53
57
 
54
58
  ## 程序流程图 Program Workflow
55
59
 
@@ -96,24 +100,6 @@ Dynamic: summary
96
100
  * MDMin
97
101
  * FIRE
98
102
 
99
- 各种优化算法的对比,参考[链接](https://wiki.fysik.dtu.dk/gpaw/devel/ase_optimize/ase_optimize.html)
100
-
101
- **使用方法**
102
-
103
- 修改 `surface_reaction_sample.py` 其中的一行
104
-
105
- ```
106
- from ase.optimize import BFGS
107
- ```
108
-
109
- 改为
110
-
111
- ```
112
- from ase.optimize import XXX as BFGS
113
- ```
114
-
115
- 注意:目前这只是权宜之计,后面会把相应的设置加入到 `parameter.py`
116
-
117
103
  ### Gaussian Process Regression 方法
118
104
 
119
105
  高斯过程回归 GPR 的优点:
@@ -166,6 +152,8 @@ $$
166
152
  * v 0.9.2: debug 支持三斜晶系的表面格点化
167
153
  * v 0.9.3: debug GridGenerator
168
154
  * v 0.10: 表面终结生成完整并入
155
+ * v0.11:分子构象和旋转采样
156
+ * v0.12:AFM 模拟
169
157
 
170
158
  **TODO**
171
159
 
@@ -174,13 +162,16 @@ $$
174
162
  * Low-Energy Region Explorer 方法借鉴[^LoreX]: 划分能量区域, 进行 Delaunay 划分,合并较小的区域为较大的区域。然后针对低能的区域进行额外采样。也可以适用不同的方法,低精度进行低能高能区域识别,然后高精度方法加强。
175
163
  * 表面格点使用对称性进行降维。在最初期就引入对称性。参考 adsorbate rotation 思路
176
164
  * 表面位点数据库
177
- * 多原子体系(内坐标受限体系)
165
+ * 覆盖度问题
166
+ * 表面上每增加一个吸附分子,就更新一次格点(可以仅仅更新 vip points,或者dock points)
167
+ * 表面上新增 dock points 属性,根据吸附能、位点类型或者用户进行定义。默认是所有的位点,根据能量分析或者用户更新
168
+ * sg 增加 del_grid(indices), 删除对应的 points, vectors,Dga 等等
178
169
  * 完善用户界面、例子、教程
179
170
 
180
171
 
181
172
  ## Reference
182
173
 
183
- [^Duvenaud]: [The Kernel Cookbook: Advice on Covariance functions](https://www.cs.toronto.edu/~duvenaud/)]
174
+ [^Duvenaud]: [The Kernel Cookbook: Advice on Covariance functions](https://www.cs.toronto.edu/~duvenaud/)
184
175
  [^BASC]: Shane Carr, Roman Garnett, Cynthia LoBASC: Applying Bayesian Optimization to the Search for Global Minima on Potential Energy Surfaces.
185
176
 
186
177
  [^向量空间转化]: 计算实空间和向量空间的相邻格点距离的映射系数,根据此系数将实空间的距离转化为向量空间距离。
@@ -2,7 +2,9 @@
2
2
 
3
3
  催化剂构效关系是建立表面位点结构和反应过程势能面的关联关系,这依赖对表面上各种可能位点的充分分析和采样,找到这些位点对关键反应步骤的影响情况。从催化剂的角度看,研究的目标是从表面上存在的位点中找到表面最适合反应的位点,即使反应势能面最低的位点;从反应的角度看,研究目标是对于一系列反应通道,找到反应势能面上的卡点,找到能够突破卡点的催化环境。
4
4
 
5
- 本软件同时进行表面位点的构建、采样、计算、分析,和反应过程的分析采样,即过渡态和分子构象,由此可以实现分子在表面反应的全过程采样。其中的技术关键是采样的效率,我们针对性地使用综合使用了多样化的采样策略,保证表面各类型位点和关键位点的充分采样。
5
+ 本软件同时进行表面位点的构建、采样、计算、分析,和反应过程的分析采样,即过渡态和分子构象,由此可以实现分子在表面反应的全过程采样。不仅包括平板模型的表面,还包括分子筛孔道內、团簇表面等。
6
+
7
+ 表面反应过程采样的技术关键是采样的效率,我们针对性地使用综合使用了多样化的采样策略,保证表面各类型位点和关键位点的充分采样。
6
8
 
7
9
  ### 应用场景
8
10
  * 催化剂表面最可能反应位点采样
@@ -11,15 +13,17 @@
11
13
  * 优化 C、R、Z (z方向,距离表面的距离)空间,固定COM
12
14
  * 返回所采结构中最低能量和对应的结构和能量
13
15
 
14
- * 催化剂表面全势能面采样
16
+ * 催化剂表面全势能面采样(位点、分子构象、旋转)
15
17
  * 适用于催化剂位点全局考察
16
18
  * 适用于表面分子全局的构象和姿态
17
19
  * 适用于反应全过程采样
18
20
  * 不优化,或者仅优化Z空间
19
21
  * 返回全部能量和结构,以及全局的fitting结果
20
22
  * 使用能量截断(dEmax<2eV)
23
+ * 原子力显微镜(AFM)谱图模拟
24
+ * 分子筛孔道內分子构象采样
25
+
21
26
 
22
- <img src="docs/birds_view.png" alt="表面位点全局分析" style="zoom:50%;" />
23
27
 
24
28
  ## 程序流程图 Program Workflow
25
29
 
@@ -66,24 +70,6 @@
66
70
  * MDMin
67
71
  * FIRE
68
72
 
69
- 各种优化算法的对比,参考[链接](https://wiki.fysik.dtu.dk/gpaw/devel/ase_optimize/ase_optimize.html)
70
-
71
- **使用方法**
72
-
73
- 修改 `surface_reaction_sample.py` 其中的一行
74
-
75
- ```
76
- from ase.optimize import BFGS
77
- ```
78
-
79
- 改为
80
-
81
- ```
82
- from ase.optimize import XXX as BFGS
83
- ```
84
-
85
- 注意:目前这只是权宜之计,后面会把相应的设置加入到 `parameter.py`
86
-
87
73
  ### Gaussian Process Regression 方法
88
74
 
89
75
  高斯过程回归 GPR 的优点:
@@ -136,6 +122,8 @@ $$
136
122
  * v 0.9.2: debug 支持三斜晶系的表面格点化
137
123
  * v 0.9.3: debug GridGenerator
138
124
  * v 0.10: 表面终结生成完整并入
125
+ * v0.11:分子构象和旋转采样
126
+ * v0.12:AFM 模拟
139
127
 
140
128
  **TODO**
141
129
 
@@ -144,13 +132,16 @@ $$
144
132
  * Low-Energy Region Explorer 方法借鉴[^LoreX]: 划分能量区域, 进行 Delaunay 划分,合并较小的区域为较大的区域。然后针对低能的区域进行额外采样。也可以适用不同的方法,低精度进行低能高能区域识别,然后高精度方法加强。
145
133
  * 表面格点使用对称性进行降维。在最初期就引入对称性。参考 adsorbate rotation 思路
146
134
  * 表面位点数据库
147
- * 多原子体系(内坐标受限体系)
135
+ * 覆盖度问题
136
+ * 表面上每增加一个吸附分子,就更新一次格点(可以仅仅更新 vip points,或者dock points)
137
+ * 表面上新增 dock points 属性,根据吸附能、位点类型或者用户进行定义。默认是所有的位点,根据能量分析或者用户更新
138
+ * sg 增加 del_grid(indices), 删除对应的 points, vectors,Dga 等等
148
139
  * 完善用户界面、例子、教程
149
140
 
150
141
 
151
142
  ## Reference
152
143
 
153
- [^Duvenaud]: [The Kernel Cookbook: Advice on Covariance functions](https://www.cs.toronto.edu/~duvenaud/)]
144
+ [^Duvenaud]: [The Kernel Cookbook: Advice on Covariance functions](https://www.cs.toronto.edu/~duvenaud/)
154
145
  [^BASC]: Shane Carr, Roman Garnett, Cynthia LoBASC: Applying Bayesian Optimization to the Search for Global Minima on Potential Energy Surfaces.
155
146
 
156
147
  [^向量空间转化]: 计算实空间和向量空间的相邻格点距离的映射系数,根据此系数将实空间的距离转化为向量空间距离。
@@ -15,13 +15,13 @@ install_requires = [
15
15
 
16
16
  setup(
17
17
  name='surface_construct',
18
- version='0.11',
18
+ version='0.12.1',
19
19
  packages=find_packages(),
20
20
  url='https://gitee.com/pjren/surface_construct/',
21
21
  license='GPL',
22
22
  author='ren',
23
23
  author_email='0403114076@163.com',
24
- description='Surface termination construction especially for complex model, such as oxides or carbides.',
24
+ description='Surface construction and surface reaction sampling tools.',
25
25
  long_description=long_description,
26
26
  long_description_content_type="text/markdown",
27
27
  install_requires=install_requires,
@@ -5,7 +5,7 @@ from ase.geometry.analysis import Analysis as ase_Analysis
5
5
  from ase.geometry.distance import distance as ase_distance
6
6
  from scipy.spatial import cKDTree
7
7
 
8
- from surface_construct.utils.atoms import atoms2graph, atoms_regulate, set_dihedrals
8
+ from surface_construct.utils.atoms import atoms2graph, atoms_regulate, set_dihedrals, topodist_matrix, topo_identity
9
9
  from surface_construct.utils.geometry import dih_grid, sample_rotations_with_symmetry, view_samples, \
10
10
  estimate_rotation_samples
11
11
  from surface_construct.utils.pymsym_wrapper import get_pure_rotations, get_point_group, get_Cn
@@ -64,9 +64,12 @@ class Adsorbate:
64
64
  f" Point Group: {self.point_group}",
65
65
  f" Radius: {self.rads}",
66
66
  f" Principal axis: [{px:8.3f}, {py:8.3f}, {pz:8.3f}] ",
67
- f" Number of dihedral: {len(self.all_dihedrals)}"]
67
+ ]
68
68
  if self.dihedral_delta:
69
- info.append(f" Number of dihedral grid: {len(self.dihedral_grid)}",)
69
+ info+=[
70
+ f" Number of dihedral grid: {len(self.dihedral_grid)}",
71
+ f" Number of dihedral: {len(self.all_dihedrals)}",
72
+ ]
70
73
  info += [f" Number of symmetry rotation operations: {len(self.symmetry_rotation_operations)}",
71
74
  f" Number of symmetry rotations: {len(self._symmetry_rotations)}",]
72
75
  if self.rotation_delta:
@@ -90,11 +93,14 @@ class Adsorbate:
90
93
  将分子旋转到主轴 = z, 次主轴=x, 第三轴 = y
91
94
  """
92
95
  # com to 0,0,0
96
+ constraints = self.atoms.constraints.copy() # 需要先消除限制,因为会影响set_com 和旋转
97
+ self.atoms.constraints = []
93
98
  if len(self.atoms) > 1:
94
99
  atoms_regulate(self.atoms)
95
100
  else:
96
101
  self.atoms.set_center_of_mass([0.,0.,0.])
97
102
  self.is_regulated = True
103
+ self.atoms.constraints = constraints
98
104
 
99
105
  @property
100
106
  def com(self):
@@ -106,8 +112,8 @@ class Adsorbate:
106
112
  @property
107
113
  def principal_axis(self):
108
114
  # 分子主轴向量
109
- if not self.is_regulated:
110
- self.regulate()
115
+ #if not self.is_regulated:
116
+ # self.regulate()
111
117
  evals, evecs = self.atoms.get_moments_of_inertia(vectors=True)
112
118
  return evecs[np.argmin(np.abs(evals))]
113
119
 
@@ -216,6 +222,12 @@ class Adsorbate:
216
222
 
217
223
  return self._atoms_graph
218
224
 
225
+ @property
226
+ def topo_id(self):
227
+ dm = topodist_matrix(self._adj_matrix)
228
+ ids = topo_identity(dm)
229
+ return ids
230
+
219
231
  def get_dihedral_mask(self, dihedral: Tuple[int, int, int, int]) -> set:
220
232
  """
221
233
  为二面角生成移动的 mask indices
@@ -120,6 +120,10 @@ class AdsGridCombiner:
120
120
  rotation:Sequence=None,
121
121
  dock_point:int=None) -> ase.Atoms:
122
122
  from scipy.spatial.transform import Rotation as R
123
+
124
+ atoms = self.ads_obj.atoms.copy()
125
+ constraints = atoms.constraints.copy() # 需要先消除限制,因为会影响set_com 和旋转
126
+ atoms.constraints = []
123
127
  if dih_value is not None:
124
128
  dih_dict = self.ads_obj.get_dihedrals(dih_value=dih_value)
125
129
  atoms = set_dihedrals(self.ads_obj.atoms,dih_dict)
@@ -134,6 +138,7 @@ class AdsGridCombiner:
134
138
  atoms.positions = R.from_quat(rotation, scalar_first=True).apply(atoms.positions)
135
139
 
136
140
  atoms.positions += xyz # move atoms
141
+ atoms.constraints = constraints # 重新找回 constraints
137
142
  return atoms
138
143
 
139
144
  def get_vip_rot(self)->Sequence:
@@ -98,11 +98,12 @@ class MLATVectorGen:
98
98
  index_array = grid_dist.argsort(axis=-1)
99
99
  grid_dist = np.take_along_axis(grid_dist, index_array, axis=-1)
100
100
  # 设定距离向量长度
101
- vlen = self.vlen
102
101
  r0 = self.kwargs.get('r0_dict')[atomnum] # r0_dict 是一个字典,放着 r0 值
103
- v = grid_dist[:, :vlen]
104
102
  kwargs.update({'r0': r0})
105
- v_w = self.weight_func(v, **kwargs)
103
+ vlen = min(self.vlen,grid_dist.shape[-1])
104
+ rt = grid_dist[:, :vlen]
105
+ v_w = np.zeros((grid_dist.shape[0],self.vlen))
106
+ v_w[:,:vlen] = self.weight_func(rt, **kwargs)
106
107
  vector.append(v_w)
107
108
  vector = np.concatenate(vector, axis=1)
108
109
  return vector
@@ -11,4 +11,5 @@
11
11
  3. obj.run 运行任务
12
12
  4. 分析和作图
13
13
  """
14
- from .sitesampling import SurfaceSiteSampleTask
14
+ from .sitesampling import SurfaceSiteSampleTask
15
+ from .afm import AFMTask
@@ -0,0 +1,120 @@
1
+ import datetime
2
+
3
+ import ase.io
4
+ import numpy as np
5
+ from ase import Atoms
6
+ from ase.constraints import FixAtoms, dict2constraint
7
+ from .sitesampling import SurfaceSiteSampleTask
8
+
9
+ def update_fixatoms_index(atoms:Atoms, idx:int):
10
+ c_list = []
11
+ for c in atoms.constraints:
12
+ if isinstance(c, FixAtoms):
13
+ dct = c.todict()
14
+ dct['kwargs']['indices'] = [i+idx for i in dct['kwargs']['indices']]
15
+ new_c = dict2constraint(dct)
16
+ c_list.append(new_c)
17
+ return c_list
18
+
19
+ def get_topo_id(A,nl=None): # 替代老的
20
+ from ase.geometry.analysis import Analysis as ase_Analysis
21
+ from surface_construct.utils.atoms import topodist_matrix, topo_identity
22
+ analysis = ase_Analysis(A, nl=nl)
23
+ adj_matrix = analysis.adjacency_matrix[0].toarray()
24
+ dm = topodist_matrix(adj_matrix)
25
+ ids = topo_identity(dm)
26
+ return ids
27
+
28
+ class AFMTask(SurfaceSiteSampleTask):
29
+
30
+ def irun(self,grid_idx=None, **kwargs):
31
+ # 采样单元运行
32
+ self.grid_idx = grid_idx
33
+ x,y,z = self.sg_obj.points[grid_idx]
34
+ dock_point = self.combiner.ads_obj.dock_points[0] # tip must define the dock_point
35
+ dz_range = (np.linspace(2.0,0.75,self.kwargs.get('nz',10)) *
36
+ (max(self.sg_obj.rsub)+self.sg_obj.rads)) # from far to near
37
+ z0 = max(self.sg_obj.atoms.positions[:,2])
38
+ e0_list = []
39
+ dz_list = []
40
+ atoms_list = []
41
+ ads_topo_id0 = self.combiner.ads_obj.topo_id
42
+ for dz in dz_range:
43
+ ads_atoms = self.combiner.docking(
44
+ xyz=[x,y,z0+dz],
45
+ dock_point=dock_point,
46
+ )
47
+ atoms = self.sg_obj.atoms.copy()
48
+ atoms += ads_atoms
49
+ atoms.calc = self.combiner.calc
50
+
51
+ if self.optimizer is not None:
52
+ # 设置 constraint
53
+ idx0 = len(self.sg_obj.atoms)
54
+ new_constraint = (update_fixatoms_index(self.combiner.ads_obj.atoms, idx0)
55
+ + atoms.constraints)
56
+ atoms.constraints = new_constraint
57
+ opt_kwargs = self.kwargs.get('optimizer',dict())
58
+ output_name = f"opt_{grid_idx}-{dz:.2f}"
59
+ if 'logfile' not in opt_kwargs:
60
+ opt_kwargs['logfile'] = f"{output_name}.log"
61
+ if 'trajectory' not in opt_kwargs:
62
+ opt_kwargs['trajectory'] = f"{output_name}.traj"
63
+ if 'fmax' in opt_kwargs:
64
+ fmax = opt_kwargs.pop('fmax')
65
+ else:
66
+ fmax = 0.1
67
+ if 'steps' in opt_kwargs:
68
+ steps = opt_kwargs.pop('steps')
69
+ else:
70
+ steps = 100
71
+ opt = self.optimizer(atoms, **opt_kwargs)
72
+ converged = opt.run(fmax=fmax, steps=steps)
73
+ if converged:
74
+ new_ads_atoms = atoms[len(self.sg_obj.atoms):]
75
+ topo_id = get_topo_id(new_ads_atoms,nl=self.combiner.ads_obj.nl)
76
+ if topo_id != ads_topo_id0:
77
+ msg=f"Warning: The connectivity of tip is broken for dz={dz}"
78
+ self.log(msg+'\n')
79
+ converged = False
80
+ else:
81
+ converged = True
82
+
83
+ if converged:
84
+ e0=atoms.get_potential_energy()
85
+ e0_list.append(e0)
86
+ dz_list.append(dz)
87
+ atoms_list.append(atoms.copy())
88
+
89
+ if len(e0_list) == 0:
90
+ e0 = np.nan
91
+ converged = False # re-define converged
92
+ else:
93
+ converged = True
94
+ e0_min_idx = np.argmin(e0_list)
95
+ e0 = e0_list[e0_min_idx]
96
+ dz = dz_list[e0_min_idx]
97
+ z = z0 + dz
98
+
99
+ # 打印信息到 log file:
100
+ used_time = (datetime.datetime.now() - self.stime).seconds
101
+ h = used_time // 3600
102
+ m = (used_time % 3600) // 60
103
+ s = (used_time % 60)
104
+ msg = (f"SAMPLE {h:02}:{m:02}:{s:02} {grid_idx:7} "
105
+ f"{x:8.3f} {y:8.3f} {z:8.3f} {e0:.4f} {str(converged)[0]}")
106
+ self.log(msg+'\n')
107
+ # 输出 优化完的结构
108
+ if converged:
109
+ ase.io.write(f"atoms_{grid_idx}.traj", atoms_list)
110
+ # 更新 sg_obj
111
+ self.sg_obj.set_energy(grid_idx, e0)
112
+ for iz, ie in zip(dz_list, e0_list):
113
+ self.sg_obj.set_property(grid_idx, ie, key=iz)
114
+ self.to_pkl()
115
+ # 是否画图?
116
+ if kwargs.get('fit', False):
117
+ self.sg_obj.fit()
118
+ self.sg_obj.plot_energy()
119
+ else:
120
+ self.sg_obj.del_sample(grid_idx)
@@ -81,7 +81,6 @@ class SurfaceSiteSampleTask(TaskBase):
81
81
  msg.append(f" Size: {s.get('size')}")
82
82
  msg.append(f" Surface Sampler: {s.get('surface')}")
83
83
  msg.append(f" Surface Sampler weight: {s.get('weight',1.0)}")
84
- msg.append(f" Conformation Sampler: {s.get('conformation')}")
85
84
  msg.append("Other kwargs:")
86
85
  for k,v in self.kwargs.items():
87
86
  msg.append(f' {k} : {v}')
@@ -113,8 +112,7 @@ class SurfaceSiteSampleTask(TaskBase):
113
112
  cidx=cidx,
114
113
  ridx=ridx,
115
114
  dp_idx=dp_idx,
116
- opt_z=True,
117
- **kwargs)
115
+ opt_z=True)
118
116
  if atoms is None:
119
117
  continue
120
118
  if self.optimizer is not None:
@@ -181,7 +179,6 @@ class SurfaceSiteSampleTask(TaskBase):
181
179
  sg_sampler = isampler.get("surface")
182
180
  if type(sg_sampler) in (tuple, list) and len(sg_sampler) == 1:
183
181
  sg_sampler = sg_sampler[0]
184
- conf_sampler = isampler.get("conformation", None) # TODO: 这个需要重新设计和调试
185
182
  if type(sg_sampler) == str:
186
183
  sg_sampler_obj = name2sampler(sg_sampler)
187
184
  if sg_sampler in ('InitialSGSampler', 'KeyPointSGSampler'): # 一次性采N样,其余都是一次一个点
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: surface_construct
3
- Version: 0.11
4
- Summary: Surface termination construction especially for complex model, such as oxides or carbides.
3
+ Version: 0.12.1
4
+ Summary: Surface construction and surface reaction sampling tools.
5
5
  Home-page: https://gitee.com/pjren/surface_construct/
6
6
  Author: ren
7
7
  Author-email: 0403114076@163.com
@@ -32,7 +32,9 @@ Dynamic: summary
32
32
 
33
33
  催化剂构效关系是建立表面位点结构和反应过程势能面的关联关系,这依赖对表面上各种可能位点的充分分析和采样,找到这些位点对关键反应步骤的影响情况。从催化剂的角度看,研究的目标是从表面上存在的位点中找到表面最适合反应的位点,即使反应势能面最低的位点;从反应的角度看,研究目标是对于一系列反应通道,找到反应势能面上的卡点,找到能够突破卡点的催化环境。
34
34
 
35
- 本软件同时进行表面位点的构建、采样、计算、分析,和反应过程的分析采样,即过渡态和分子构象,由此可以实现分子在表面反应的全过程采样。其中的技术关键是采样的效率,我们针对性地使用综合使用了多样化的采样策略,保证表面各类型位点和关键位点的充分采样。
35
+ 本软件同时进行表面位点的构建、采样、计算、分析,和反应过程的分析采样,即过渡态和分子构象,由此可以实现分子在表面反应的全过程采样。不仅包括平板模型的表面,还包括分子筛孔道內、团簇表面等。
36
+
37
+ 表面反应过程采样的技术关键是采样的效率,我们针对性地使用综合使用了多样化的采样策略,保证表面各类型位点和关键位点的充分采样。
36
38
 
37
39
  ### 应用场景
38
40
  * 催化剂表面最可能反应位点采样
@@ -41,15 +43,17 @@ Dynamic: summary
41
43
  * 优化 C、R、Z (z方向,距离表面的距离)空间,固定COM
42
44
  * 返回所采结构中最低能量和对应的结构和能量
43
45
 
44
- * 催化剂表面全势能面采样
46
+ * 催化剂表面全势能面采样(位点、分子构象、旋转)
45
47
  * 适用于催化剂位点全局考察
46
48
  * 适用于表面分子全局的构象和姿态
47
49
  * 适用于反应全过程采样
48
50
  * 不优化,或者仅优化Z空间
49
51
  * 返回全部能量和结构,以及全局的fitting结果
50
52
  * 使用能量截断(dEmax<2eV)
53
+ * 原子力显微镜(AFM)谱图模拟
54
+ * 分子筛孔道內分子构象采样
55
+
51
56
 
52
- <img src="docs/birds_view.png" alt="表面位点全局分析" style="zoom:50%;" />
53
57
 
54
58
  ## 程序流程图 Program Workflow
55
59
 
@@ -96,24 +100,6 @@ Dynamic: summary
96
100
  * MDMin
97
101
  * FIRE
98
102
 
99
- 各种优化算法的对比,参考[链接](https://wiki.fysik.dtu.dk/gpaw/devel/ase_optimize/ase_optimize.html)
100
-
101
- **使用方法**
102
-
103
- 修改 `surface_reaction_sample.py` 其中的一行
104
-
105
- ```
106
- from ase.optimize import BFGS
107
- ```
108
-
109
- 改为
110
-
111
- ```
112
- from ase.optimize import XXX as BFGS
113
- ```
114
-
115
- 注意:目前这只是权宜之计,后面会把相应的设置加入到 `parameter.py`
116
-
117
103
  ### Gaussian Process Regression 方法
118
104
 
119
105
  高斯过程回归 GPR 的优点:
@@ -166,6 +152,8 @@ $$
166
152
  * v 0.9.2: debug 支持三斜晶系的表面格点化
167
153
  * v 0.9.3: debug GridGenerator
168
154
  * v 0.10: 表面终结生成完整并入
155
+ * v0.11:分子构象和旋转采样
156
+ * v0.12:AFM 模拟
169
157
 
170
158
  **TODO**
171
159
 
@@ -174,13 +162,16 @@ $$
174
162
  * Low-Energy Region Explorer 方法借鉴[^LoreX]: 划分能量区域, 进行 Delaunay 划分,合并较小的区域为较大的区域。然后针对低能的区域进行额外采样。也可以适用不同的方法,低精度进行低能高能区域识别,然后高精度方法加强。
175
163
  * 表面格点使用对称性进行降维。在最初期就引入对称性。参考 adsorbate rotation 思路
176
164
  * 表面位点数据库
177
- * 多原子体系(内坐标受限体系)
165
+ * 覆盖度问题
166
+ * 表面上每增加一个吸附分子,就更新一次格点(可以仅仅更新 vip points,或者dock points)
167
+ * 表面上新增 dock points 属性,根据吸附能、位点类型或者用户进行定义。默认是所有的位点,根据能量分析或者用户更新
168
+ * sg 增加 del_grid(indices), 删除对应的 points, vectors,Dga 等等
178
169
  * 完善用户界面、例子、教程
179
170
 
180
171
 
181
172
  ## Reference
182
173
 
183
- [^Duvenaud]: [The Kernel Cookbook: Advice on Covariance functions](https://www.cs.toronto.edu/~duvenaud/)]
174
+ [^Duvenaud]: [The Kernel Cookbook: Advice on Covariance functions](https://www.cs.toronto.edu/~duvenaud/)
184
175
  [^BASC]: Shane Carr, Roman Garnett, Cynthia LoBASC: Applying Bayesian Optimization to the Search for Global Minima on Potential Energy Surfaces.
185
176
 
186
177
  [^向量空间转化]: 计算实空间和向量空间的相邻格点距离的映射系数,根据此系数将实空间的距离转化为向量空间距离。
@@ -17,6 +17,7 @@ surface_construct/structures/pymsym_test.py
17
17
  surface_construct/structures/surface.py
18
18
  surface_construct/structures/surface_grid.py
19
19
  surface_construct/tasks/__init__.py
20
+ surface_construct/tasks/afm.py
20
21
  surface_construct/tasks/sitesampling.py
21
22
  surface_construct/tasks/taskbase.py
22
23
  surface_construct/tasks/terminations.py
@@ -118,4 +118,12 @@ class TestSurfaceGrid:
118
118
  atoms = ase.io.read('atoms_files/Fe28C12_115_12_POSCAR')
119
119
  sg_obj = SurfaceGrid(atoms, interval=0.1, ads_num=6, lpca=False)
120
120
  sg_obj.gridize(subtype='slab')
121
- print(sg_obj.points.shape)
121
+ print(sg_obj.points.shape)
122
+
123
+ def test_ads_C4H4O(self):
124
+ atoms = ase.io.read('atoms_files/C4H4O_Cu.vasp')
125
+ sg_obj = SurfaceGrid(atoms, interval=0.2, ads_num=6, lpca=False)
126
+ sg_obj.gridize(subtype='slab')
127
+ sg_obj.vectorize()
128
+ assert sg_obj.vector.shape==(6582, 40)
129
+ pass
@@ -4,17 +4,18 @@ from random import randint
4
4
 
5
5
  import ase.io
6
6
  import pytest
7
- from ase import Atom
7
+ from ase import Atom, Atoms
8
+ from ase.constraints import FixAtoms
8
9
  from ase.visualize import view
9
10
  from lasp_ase.lasp import Lasp
10
11
  from surface_construct import SurfaceGrid
11
12
  from surface_construct import AdsGridCombiner
12
13
  from surface_construct import Adsorbate
13
- from surface_construct.tasks import SurfaceSiteSampleTask
14
+ from surface_construct.tasks import SurfaceSiteSampleTask, AFMTask
14
15
  from ase.optimize import LBFGS, BFGS
15
16
 
16
17
 
17
- class TestSurfaceSiteSampling:
18
+ class TestTask:
18
19
  """
19
20
  Simple Ru 0001 suface
20
21
  """
@@ -110,4 +111,39 @@ class TestSurfaceSiteSampling:
110
111
  ]
111
112
  task_obj = SurfaceSiteSampleTask(combiner=com_obj, sampler=sampler, optimizer=None)
112
113
  task_obj.run()
114
+ print('Done')
115
+
116
+ def test_afm(self):
117
+ tip_atoms = Atoms('Ru4CO',positions=[
118
+ [4.96420026, 5.33360004, 5.96179962],
119
+ [2.98259974, 6.51570022, 6.69340014],
120
+ [6.93529963, 6.55210018, 6.65879965],
121
+ [4.97309983, 3.62199992, 6.84219956],
122
+ [4.93830025, 5.30839980, 3.98790002],
123
+ [4.91949975, 5.28810024, 2.48350024],
124
+ ])
125
+
126
+ tip_atoms.constraints = FixAtoms(mask=tip_atoms.symbols == 'Ru')
127
+ tip_obj = Adsorbate(tip_atoms)
128
+ tip_obj.dock_point_indices = [[5]] # O atom as docker_point
129
+ shutil.copyfile('../atoms_files/RuCHO_lasp.in', 'lasp.in')
130
+ shutil.copyfile('../atoms_files/RuCHO_pf2.pot', 'RuCHO.pot')
131
+ satoms = ase.io.read('../atoms_files/ru_0001_POSCAR')
132
+ satoms.calc = Lasp()
133
+ sg_obj = SurfaceGrid(satoms, interval=0.1, rads=tip_obj.rads, lpca=False, subtype='slab')
134
+ sg_obj.gridize()
135
+ com_obj = AdsGridCombiner(sg_obj, tip_obj)
136
+
137
+ sampler =[
138
+ {
139
+ 'surface': "KeyPointSGSampler", # 表面采样方法
140
+ }, # 第一步采样
141
+ {
142
+ 'size': 2, # 采样大小
143
+ 'surface': ("MaxDiversitySGSampler", "MaxSigmaSGSampler"), # 表面采样方法
144
+ 'weight': (0.5, 0.5), # 表面采样方法的权重
145
+ } # 第二步采样
146
+ ]
147
+ task_obj = AFMTask(combiner=com_obj, sampler=sampler, optimizer=LBFGS, nz=10) # nz 定义 z方向采多少样
148
+ task_obj.run()
113
149
  print('Done')