mdkits 0.1a1__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.

Potentially problematic release.


This version of mdkits might be problematic. Click here for more details.

Files changed (42) hide show
  1. mdkits-0.1a1/LICENSE +21 -0
  2. mdkits-0.1a1/PKG-INFO +161 -0
  3. mdkits-0.1a1/README.md +136 -0
  4. mdkits-0.1a1/pyproject.toml +46 -0
  5. mdkits-0.1a1/src/mdkits/__init__.py +0 -0
  6. mdkits-0.1a1/src/mdkits/cli/,hb_distribution.py +126 -0
  7. mdkits-0.1a1/src/mdkits/cli/,hb_distribution_down.py +114 -0
  8. mdkits-0.1a1/src/mdkits/cli/adsorbate.py +84 -0
  9. mdkits-0.1a1/src/mdkits/cli/build_bulk.py +55 -0
  10. mdkits-0.1a1/src/mdkits/cli/build_interface.py +86 -0
  11. mdkits-0.1a1/src/mdkits/cli/build_surface.py +134 -0
  12. mdkits-0.1a1/src/mdkits/cli/cmdline.py +41 -0
  13. mdkits-0.1a1/src/mdkits/cli/convert.py +63 -0
  14. mdkits-0.1a1/src/mdkits/cli/cp2k_input.py +479 -0
  15. mdkits-0.1a1/src/mdkits/cli/cube.py +59 -0
  16. mdkits-0.1a1/src/mdkits/cli/cut_surface.py +38 -0
  17. mdkits-0.1a1/src/mdkits/cli/data.py +80 -0
  18. mdkits-0.1a1/src/mdkits/cli/density.py +89 -0
  19. mdkits-0.1a1/src/mdkits/cli/density2.py +91 -0
  20. mdkits-0.1a1/src/mdkits/cli/extract.py +80 -0
  21. mdkits-0.1a1/src/mdkits/cli/hartree_potential.py +59 -0
  22. mdkits-0.1a1/src/mdkits/cli/hartree_potential_ave.py +84 -0
  23. mdkits-0.1a1/src/mdkits/cli/hb.py +101 -0
  24. mdkits-0.1a1/src/mdkits/cli/log.py +64 -0
  25. mdkits-0.1a1/src/mdkits/cli/matplot.py +60 -0
  26. mdkits-0.1a1/src/mdkits/cli/packmol_input.py +76 -0
  27. mdkits-0.1a1/src/mdkits/cli/pdos.py +36 -0
  28. mdkits-0.1a1/src/mdkits/cli/plot.py +289 -0
  29. mdkits-0.1a1/src/mdkits/cli/supercell.py +72 -0
  30. mdkits-0.1a1/src/mdkits/cli/wrap.py +36 -0
  31. mdkits-0.1a1/src/mdkits/config/__init__.py +35 -0
  32. mdkits-0.1a1/src/mdkits/config/settings.yml +4 -0
  33. mdkits-0.1a1/src/mdkits/mdtool.py +28 -0
  34. mdkits-0.1a1/src/mdkits/util/__init__.py +0 -0
  35. mdkits-0.1a1/src/mdkits/util/arg_type.py +41 -0
  36. mdkits-0.1a1/src/mdkits/util/cp2k_input_parsing.py +46 -0
  37. mdkits-0.1a1/src/mdkits/util/encapsulated_ase.py +134 -0
  38. mdkits-0.1a1/src/mdkits/util/encapsulated_mda.py +59 -0
  39. mdkits-0.1a1/src/mdkits/util/fig_operation.py +28 -0
  40. mdkits-0.1a1/src/mdkits/util/numpy_geo.py +118 -0
  41. mdkits-0.1a1/src/mdkits/util/os_operation.py +35 -0
  42. mdkits-0.1a1/src/mdkits/util/structure_parsing.py +147 -0
mdkits-0.1a1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 jxxcr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
mdkits-0.1a1/PKG-INFO ADDED
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.3
2
+ Name: mdkits
3
+ Version: 0.1a1
4
+ Summary: tools for md or dft
5
+ License: MIT
6
+ Keywords: molecular dynamics,density functional theory
7
+ Author: jxxcr
8
+ Author-email: jixxcr@qq.com
9
+ Requires-Python: >=3.11,<4.0
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Requires-Dist: MDAnalysis (>=2.8.0,<3.0.0)
17
+ Requires-Dist: ase (>=3.22.1,<4.0.0)
18
+ Requires-Dist: click (>=8.1.3,<9.0.0)
19
+ Requires-Dist: dynaconf (>=3.1.12,<4.0.0)
20
+ Requires-Dist: matplotlib (>=3.9.0,<4.0.0)
21
+ Requires-Dist: numpy (>=1.26.4,<2.0.0)
22
+ Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
23
+ Project-URL: Repository, https://github.com/jxxcr/mdkits
24
+ Description-Content-Type: text/markdown
25
+
26
+ # MD 轨迹分析脚本
27
+ `mdtool` 提供了多种工具, 安装脚本:
28
+ ```bash
29
+ pip install mdtool --upgrade
30
+ ```
31
+ ### 密度分布
32
+
33
+ ### 氢键
34
+
35
+ #### 单个水分子
36
+
37
+ #### 氢键分布
38
+
39
+ ### 角度
40
+
41
+ #### 与表面法向量夹角分布
42
+
43
+ #### ion - O - ion 夹角分布
44
+
45
+ #### $\cos \phi \rho_{H_2 O}$ 分布
46
+
47
+ ### RDF
48
+
49
+ ### 位置归一化
50
+ `wrap`用于将轨迹文件中的原子位置进行归一化处理, 如将`[FILENAME]`中的原子位置归一化到晶胞中, 并输出为`wrapped.xyz`, 默认从`cp2k`的输出文件`input_inp`中读取`ABC`和`ALPHA_BETA_GAMMA`信息作为晶胞参数:
51
+ ```bash
52
+ mdtool wrap [FILENAME]
53
+ ```
54
+ 或指定`cp2k`的输入文件:
55
+ ```bash
56
+ mdtool wrap [FILENAME] --cp2k_input_file setting.inp
57
+ ```
58
+ 或指定晶胞参数:
59
+ ```bash
60
+ mdtool wrap [FILENAME] --cell 10,10,10
61
+ ```
62
+ 默认的`[FILENAME]`为`*-pos-1.xyz`
63
+
64
+ ## DFT 性质分析脚本
65
+ ### PDOS
66
+
67
+ ### 静电势
68
+
69
+ ### 电荷差分
70
+
71
+ ## 其他
72
+ ### 轨迹提取
73
+ `extract`用于提取轨迹文件中的特定的帧, 如从`frames.xyz`中提取第 1000 帧到第 2000 帧的轨迹文件, 并输出为`1000-2000.xyz`, `-r`选项的参数与`Python`的切片语法一致:
74
+ ```bash
75
+ mdtool extract frames.xyz -r 1000:2000 -o 1000-2000.xyz
76
+ ```
77
+ 或从`cp2k`的默认输出的轨迹文件`*-pos-1.xyz`文件中提取最后一帧输出为`extracted.xyz`(`extract`的默认行为):
78
+ ```bash
79
+ mdtool extract
80
+ ```
81
+ 或每50帧输出一个结构到`./coord`目录中, 同时调整输出格式为`cp2k`的`@INCLUDE coord.xyz`的形式:
82
+ ```bash
83
+ mdtool extract -cr ::50
84
+ ```
85
+
86
+ ### 结构文件转换
87
+ `convert`用于将结构文件从一种格式转换为另一种格式, 如将`structure.xyz`转换为`out.cif`(默认文件名为`out`), 对于不储存周期性边界条件的文件, 可以使用`--cell`选项指定`PBC`:
88
+ ```bash
89
+ mdtool convert -c structure.xyz --cell 10,10,10
90
+ ```
91
+ 将`structure.cif`转换为`POSCAR`:
92
+ ```bash
93
+ mdtool convert -v structure.cif
94
+ ```
95
+ 将`structure.cif`转换为`structure_xyz.xyz`:
96
+ ```bash
97
+ mdtool convert -c structure.cif -o structure_xyz
98
+ ```
99
+
100
+ ### 数据处理
101
+ `data`用于对数据进行处理如:
102
+ 1. `--nor`: 对数据进行归一化处理
103
+ 2. `--gaus`: 对数据进行高斯过滤
104
+ 3. `--fold`: 堆数据进行折叠平均
105
+ 4. `--err`: 计算数据的误差棒
106
+
107
+
108
+ ### 绘图工具
109
+ `plot`用于绘制数据图, `plot`需要读取`yaml`格式的配置文件进行绘图, `yaml`文件的形式如下:
110
+ ```yaml
111
+ # plot mode 1
112
+ figure1:
113
+ data:
114
+ legend1: ./data1.dat
115
+ legend2: ./data2.dat
116
+ x:
117
+ 0: x-axis
118
+ y:
119
+ 1: y-axis
120
+ x_range:
121
+ - 5
122
+ - 15
123
+
124
+ # plot mode 2
125
+ figure2:
126
+ data:
127
+ y-xais: ./data.dat
128
+ x:
129
+ 0: x-axis
130
+ y:
131
+ 1: legend1
132
+ 2: legend2
133
+ 3: legend3
134
+ 4: legend4
135
+ 5: legend5
136
+ y_range:
137
+ - 0.5
138
+ - 6
139
+ legend_fontsize: 12
140
+
141
+ # plot mode error
142
+ 12_dp_e_error:
143
+ data:
144
+ legend: ./error.dat
145
+ x:
146
+ 0: x-axis
147
+ y:
148
+ 1: y-axis
149
+ fold: dp
150
+ legend_fontsize: 12
151
+ ```
152
+ 如上`plot`支持三种绘图模式, `mode 1`, `mode 2`和`mode error`. `mode 1`用于绘制多组数据文件的同一列数据对比, `mode 2`用于绘制同一数据文件的不同列数据对比, `mode error`用于绘制均方根误差图.
153
+
154
+ `plot`可以同时处理多个`yaml`文件, 每个`yaml`文件可以包含多个绘图配置, `mode 1`和`mode 2`的绘图配置可以自动识别, 但是`error`模式需要而外指定, 如:
155
+ ```bash
156
+ mdtool plot *.yaml
157
+ ```
158
+ 和:
159
+ ```bash
160
+ mdtool plot *.yaml --error
161
+ ```
mdkits-0.1a1/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # MD 轨迹分析脚本
2
+ `mdtool` 提供了多种工具, 安装脚本:
3
+ ```bash
4
+ pip install mdtool --upgrade
5
+ ```
6
+ ### 密度分布
7
+
8
+ ### 氢键
9
+
10
+ #### 单个水分子
11
+
12
+ #### 氢键分布
13
+
14
+ ### 角度
15
+
16
+ #### 与表面法向量夹角分布
17
+
18
+ #### ion - O - ion 夹角分布
19
+
20
+ #### $\cos \phi \rho_{H_2 O}$ 分布
21
+
22
+ ### RDF
23
+
24
+ ### 位置归一化
25
+ `wrap`用于将轨迹文件中的原子位置进行归一化处理, 如将`[FILENAME]`中的原子位置归一化到晶胞中, 并输出为`wrapped.xyz`, 默认从`cp2k`的输出文件`input_inp`中读取`ABC`和`ALPHA_BETA_GAMMA`信息作为晶胞参数:
26
+ ```bash
27
+ mdtool wrap [FILENAME]
28
+ ```
29
+ 或指定`cp2k`的输入文件:
30
+ ```bash
31
+ mdtool wrap [FILENAME] --cp2k_input_file setting.inp
32
+ ```
33
+ 或指定晶胞参数:
34
+ ```bash
35
+ mdtool wrap [FILENAME] --cell 10,10,10
36
+ ```
37
+ 默认的`[FILENAME]`为`*-pos-1.xyz`
38
+
39
+ ## DFT 性质分析脚本
40
+ ### PDOS
41
+
42
+ ### 静电势
43
+
44
+ ### 电荷差分
45
+
46
+ ## 其他
47
+ ### 轨迹提取
48
+ `extract`用于提取轨迹文件中的特定的帧, 如从`frames.xyz`中提取第 1000 帧到第 2000 帧的轨迹文件, 并输出为`1000-2000.xyz`, `-r`选项的参数与`Python`的切片语法一致:
49
+ ```bash
50
+ mdtool extract frames.xyz -r 1000:2000 -o 1000-2000.xyz
51
+ ```
52
+ 或从`cp2k`的默认输出的轨迹文件`*-pos-1.xyz`文件中提取最后一帧输出为`extracted.xyz`(`extract`的默认行为):
53
+ ```bash
54
+ mdtool extract
55
+ ```
56
+ 或每50帧输出一个结构到`./coord`目录中, 同时调整输出格式为`cp2k`的`@INCLUDE coord.xyz`的形式:
57
+ ```bash
58
+ mdtool extract -cr ::50
59
+ ```
60
+
61
+ ### 结构文件转换
62
+ `convert`用于将结构文件从一种格式转换为另一种格式, 如将`structure.xyz`转换为`out.cif`(默认文件名为`out`), 对于不储存周期性边界条件的文件, 可以使用`--cell`选项指定`PBC`:
63
+ ```bash
64
+ mdtool convert -c structure.xyz --cell 10,10,10
65
+ ```
66
+ 将`structure.cif`转换为`POSCAR`:
67
+ ```bash
68
+ mdtool convert -v structure.cif
69
+ ```
70
+ 将`structure.cif`转换为`structure_xyz.xyz`:
71
+ ```bash
72
+ mdtool convert -c structure.cif -o structure_xyz
73
+ ```
74
+
75
+ ### 数据处理
76
+ `data`用于对数据进行处理如:
77
+ 1. `--nor`: 对数据进行归一化处理
78
+ 2. `--gaus`: 对数据进行高斯过滤
79
+ 3. `--fold`: 堆数据进行折叠平均
80
+ 4. `--err`: 计算数据的误差棒
81
+
82
+
83
+ ### 绘图工具
84
+ `plot`用于绘制数据图, `plot`需要读取`yaml`格式的配置文件进行绘图, `yaml`文件的形式如下:
85
+ ```yaml
86
+ # plot mode 1
87
+ figure1:
88
+ data:
89
+ legend1: ./data1.dat
90
+ legend2: ./data2.dat
91
+ x:
92
+ 0: x-axis
93
+ y:
94
+ 1: y-axis
95
+ x_range:
96
+ - 5
97
+ - 15
98
+
99
+ # plot mode 2
100
+ figure2:
101
+ data:
102
+ y-xais: ./data.dat
103
+ x:
104
+ 0: x-axis
105
+ y:
106
+ 1: legend1
107
+ 2: legend2
108
+ 3: legend3
109
+ 4: legend4
110
+ 5: legend5
111
+ y_range:
112
+ - 0.5
113
+ - 6
114
+ legend_fontsize: 12
115
+
116
+ # plot mode error
117
+ 12_dp_e_error:
118
+ data:
119
+ legend: ./error.dat
120
+ x:
121
+ 0: x-axis
122
+ y:
123
+ 1: y-axis
124
+ fold: dp
125
+ legend_fontsize: 12
126
+ ```
127
+ 如上`plot`支持三种绘图模式, `mode 1`, `mode 2`和`mode error`. `mode 1`用于绘制多组数据文件的同一列数据对比, `mode 2`用于绘制同一数据文件的不同列数据对比, `mode error`用于绘制均方根误差图.
128
+
129
+ `plot`可以同时处理多个`yaml`文件, 每个`yaml`文件可以包含多个绘图配置, `mode 1`和`mode 2`的绘图配置可以自动识别, 但是`error`模式需要而外指定, 如:
130
+ ```bash
131
+ mdtool plot *.yaml
132
+ ```
133
+ 和:
134
+ ```bash
135
+ mdtool plot *.yaml --error
136
+ ```
@@ -0,0 +1,46 @@
1
+ [tool.poetry]
2
+ name = "mdkits"
3
+ version = "0.1.a1"
4
+ description = "tools for md or dft"
5
+ readme = "README.md"
6
+ authors = ["jxxcr <jixxcr@qq.com>"]
7
+ license = "MIT"
8
+ keywords = ["molecular dynamics", "density functional theory"]
9
+ classifiers = [
10
+ "Operating System :: OS Independent",
11
+ "Programming Language :: Python :: 3.11",
12
+ ]
13
+ repository = "https://github.com/jxxcr/mdkits"
14
+
15
+ [tool.poetry.dependencies]
16
+ python = "^3.11"
17
+ dynaconf = "^3.1.12"
18
+ click = "^8.1.3"
19
+ MDAnalysis = "^2.8.0"
20
+ ase = "^3.22.1"
21
+ matplotlib = "^3.9.0"
22
+ pyyaml = "^6.0.1"
23
+ numpy = "^1.26.4"
24
+
25
+ [tool.poetry.group.dev.dependencies]
26
+ pylint = "^2.17.4"
27
+ isort = "^5.12.0"
28
+ pytest = "^7.3.1"
29
+ tox = "^4.5.2"
30
+ mkdocs = "^1.4.3"
31
+ mkdocs-material = "^8.5.11"
32
+ pytest-pylint = "^0.19.0"
33
+ pre-commit = "^3.3.2"
34
+
35
+ [tool.poetry.scripts]
36
+ mdkits = "mdkits.mdkits:cli"
37
+
38
+ [build-system]
39
+ requires = ["poetry-core"]
40
+ build-backend = "poetry.core.masonry.api"
41
+ [tool.pytest.ini_options]
42
+ testpaths = "tests"
43
+ python_files = "tests.py test_*.py *_tests.py"
44
+
45
+ [tool.pylint.design]
46
+ max-line-length = 120
File without changes
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import numpy as np
4
+ import argparse
5
+ import MDAnalysis
6
+ from MDAnalysis import Universe
7
+ from MDAnalysis.analysis.base import AnalysisBase
8
+ from util import cp2k_input_parsing
9
+ import warnings
10
+ warnings.filterwarnings("ignore")
11
+
12
+
13
+ class Hb_distribution(AnalysisBase):
14
+ def __init__(self, filename, cell, surface, dt=0.001, hb_distance=3.5, hb_angle=35, bin_size=0.2):
15
+ u = Universe(filename)
16
+ u.trajectory.ts.dt = dt
17
+ u.dimensions = cell
18
+ self.u = u
19
+ self.atomgroup = u.select_atoms("all")
20
+ self.hb_distance = hb_distance
21
+ self.hb_angle = hb_angle
22
+ self.bin_size = bin_size
23
+ self.surface = surface
24
+ self.frame_count = 0
25
+ super(Hb_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
26
+
27
+ def _prepare(self):
28
+ bin_num = int(self.u.dimensions[2] / self.bin_size) + 2
29
+ self.accepter = np.zeros(bin_num, dtype=np.float64)
30
+ self.donor = np.zeros(bin_num, dtype=np.float64)
31
+
32
+ def _append(self, hb_d, hb_a):
33
+ bins_d = np.floor(hb_d / self.bin_size).astype(int) + 1
34
+ bins_a = np.floor(hb_a / self.bin_size).astype(int) + 1
35
+
36
+ bins_d = bins_d[bins_d < len(self.donor)]
37
+ bins_a = bins_a[bins_a < len(self.accepter)]
38
+
39
+ np.add.at(self.donor, bins_d, 1)
40
+ np.add.at(self.accepter, bins_a, 1)
41
+
42
+ self.frame_count += 1
43
+
44
+ def _single_frame(self):
45
+ o_group = self.atomgroup.select_atoms("name O")
46
+ o_pair = MDAnalysis.lib.distances.capped_distance(o_group.positions, o_group.positions, min_cutoff=0, max_cutoff=self.hb_distance, box=self.u.dimensions, return_distances=False)
47
+
48
+ o0 = o_group[o_pair[:, 0]]
49
+ o1 = o_group[o_pair[:, 1]]
50
+
51
+ o0h1 = self.atomgroup[o0.indices + 1]
52
+ o0h2 = self.atomgroup[o0.indices + 2]
53
+ o1h1 = self.atomgroup[o1.indices + 1]
54
+ o1h2 = self.atomgroup[o1.indices + 2]
55
+
56
+ angle_o0h1_o0_o1 = np.degrees(
57
+ MDAnalysis.lib.distances.calc_angles(o0h1.positions, o0.positions, o1.positions, box=self.u.dimensions)
58
+ )
59
+ angle_o0h2_o0_o1 = np.degrees(
60
+ MDAnalysis.lib.distances.calc_angles(o0h2.positions, o0.positions, o1.positions, box=self.u.dimensions)
61
+ )
62
+ angle_o1h1_o1_o0 = np.degrees(
63
+ MDAnalysis.lib.distances.calc_angles(o1h1.positions, o1.positions, o0.positions, box=self.u.dimensions)
64
+ )
65
+ angle_o1h2_o1_o0 = np.degrees(
66
+ MDAnalysis.lib.distances.calc_angles(o1h2.positions, o1.positions, o0.positions, box=self.u.dimensions)
67
+ )
68
+
69
+ condition_d = (angle_o0h1_o0_o1 < self.hb_angle) | (angle_o0h2_o0_o1 < self.hb_angle)
70
+ condition_a = (angle_o1h1_o1_o0 < self.hb_angle) | (angle_o1h2_o1_o0 < self.hb_angle)
71
+
72
+ hb_d = (o0.positions[:, 2][condition_d] + o1.positions[:, 2][condition_d]) / 2
73
+ hb_a = (o0.positions[:, 2][condition_a] + o1.positions[:, 2][condition_a]) / 2
74
+
75
+ self._append(hb_d, hb_a)
76
+
77
+ def _conclude(self):
78
+ if self.frame_count > 0:
79
+ average_donor = self.donor / self.frame_count
80
+ average_accepter = self.accepter / self.frame_count
81
+ average_sum = average_donor + average_accepter
82
+
83
+ bins_z = np.arange(len(self.donor)) * self.bin_size
84
+
85
+ lower_z, upper_z = self.surface
86
+ mask = (bins_z >= lower_z) & (bins_z <= upper_z)
87
+ filtered_bins_z = bins_z[mask] - lower_z
88
+ filtered_average_accepter = average_accepter[mask]
89
+ filtered_average_donor = average_donor[mask]
90
+ filtered_average_sum = average_sum[mask]
91
+
92
+ combined_data = np.column_stack((filtered_bins_z, filtered_average_accepter, filtered_average_donor, filtered_average_sum))
93
+
94
+ np.savetxt("hb_distribution.dat", combined_data, header="Z\tAccepter\tDonor\tAccepter+Donor", fmt='%.5f', delimiter='\t')
95
+
96
+
97
+ def parse_data(s):
98
+ return [float(x) for x in s.replace(',', ' ').split()]
99
+
100
+
101
+ def parse_r(s):
102
+ return [int(x) for x in s.replace(':', ' ').split()]
103
+
104
+
105
+ def parse_argument():
106
+ parser = argparse.ArgumentParser(description="analysis hb distribution")
107
+ parser.add_argument('filename', type=str, help='filename to analysis')
108
+ parser.add_argument('--cp2k_input_file', type=str, help='input file name of cp2k, default is "input.inp"', default='input.inp')
109
+ parser.add_argument('-r', type=parse_r, help='range of analysis', default=[0, -1, 1])
110
+ parser.add_argument('--cell', type=parse_data, help='set cell, a list of lattice, --cell x,y,z or x,y,z,a,b,c')
111
+ parser.add_argument('--surface', type=parse_data, help='[down_surface_z, up_surface_z]')
112
+ parser.add_argument('--hb_param', type=parse_data, help='[hb_distance, hb_angle], default is [3.5, 35]', default=[3.5, 35])
113
+
114
+ return parser.parse_args()
115
+
116
+
117
+ def main():
118
+ args = parse_argument()
119
+ cell = cp2k_input_parsing.get_cell(args.cp2k_input_file, args.cell)
120
+
121
+ hb_dist = Hb_distribution(args.filename, cell, args.surface, hb_distance=args.hb_param[0], hb_angle=args.hb_param[1])
122
+ hb_dist.run(start=args.r[0], stop=args.r[1], step=args.r[2])
123
+
124
+
125
+ if __name__ == '__main__':
126
+ main()
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import numpy as np
4
+ import argparse
5
+ import MDAnalysis
6
+ from MDAnalysis import Universe
7
+ from MDAnalysis.analysis.base import AnalysisBase
8
+ from util import cp2k_input_parsing
9
+ import warnings
10
+ warnings.filterwarnings("ignore")
11
+
12
+
13
+ class Hb_distribution(AnalysisBase):
14
+ def __init__(self, filename, cell, surface, dt=0.001, hb_distance=3.5, hb_angle=35, bin_size=0.2):
15
+ u = Universe(filename)
16
+ u.trajectory.ts.dt = dt
17
+ u.dimensions = cell
18
+ self.u = u
19
+ self.atomgroup = u.select_atoms("all")
20
+ self.hb_distance = hb_distance
21
+ self.hb_angle = hb_angle
22
+ self.bin_size = bin_size
23
+ self.surface = surface
24
+ self.frame_count = 0
25
+ super(Hb_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
26
+
27
+ def _prepare(self):
28
+ bin_num = int(self.u.dimensions[2] / self.bin_size) + 2
29
+ self.donor = np.zeros(bin_num, dtype=np.float64)
30
+
31
+ def _append(self, hb_d):
32
+ bins_d = np.floor(hb_d / self.bin_size).astype(int) + 1
33
+
34
+ bins_d = bins_d[bins_d < len(self.donor)]
35
+
36
+ np.add.at(self.donor, bins_d, 1)
37
+
38
+ self.frame_count += 1
39
+
40
+ def _single_frame(self):
41
+ o_group = self.atomgroup.select_atoms("name O")
42
+ o_pair = MDAnalysis.lib.distances.capped_distance(o_group.positions, o_group.positions, min_cutoff=0, max_cutoff=self.hb_distance, box=self.u.dimensions, return_distances=False)
43
+
44
+ o0 = o_group[o_pair[:, 0]]
45
+ o1 = o_group[o_pair[:, 1]]
46
+
47
+ o0h1 = self.atomgroup[o0.indices + 1]
48
+ o0h2 = self.atomgroup[o0.indices + 2]
49
+
50
+ angle_o0h1_o0_o1 = np.degrees(
51
+ MDAnalysis.lib.distances.calc_angles(o0h1.positions, o0.positions, o1.positions, box=self.u.dimensions)
52
+ )
53
+ angle_o0h2_o0_o1 = np.degrees(
54
+ MDAnalysis.lib.distances.calc_angles(o0h2.positions, o0.positions, o1.positions, box=self.u.dimensions)
55
+ )
56
+
57
+ mid_z = (self.surface[0] + self.surface[1]) / 2
58
+
59
+ condition_d = ((angle_o0h1_o0_o1 < self.hb_angle) | (angle_o0h2_o0_o1 < self.hb_angle)) & (o0.positions[:, 2] - o1.positions[:, 2] > 0)
60
+ #condition_d = ((angle_o0h1_o0_o1 < self.hb_angle) | (angle_o0h2_o0_o1 < self.hb_angle)) & (((o0.positions[:, 2] < mid_z) & (o0.positions[:, 2] - o1.positions[:, 2] > 0)) | ((o0.positions[:, 2] > mid_z) & (o0.positions[:, 2] - o1.positions[:, 2] < 0)))
61
+ #condition_a = ((angle_o1h1_o1_o0 < self.hb_angle) | (angle_o1h2_o1_o0 < self.hb_angle)) & (((o1.positions[:, 2] < mid_z) & (o1.positions[:, 2] - o0.positions[:, 2] > 1.5)) | ((o1.positions[:, 2] > mid_z) & (o1.positions[:, 2] - o0.positions[:, 2] < -1.5)))
62
+
63
+ hb_d = (o0.positions[:, 2][condition_d] + o1.positions[:, 2][condition_d]) / 2
64
+ #hb_a = (o0.positions[:, 2][condition_a] + o1.positions[:, 2][condition_a]) / 2
65
+
66
+ self._append(hb_d)
67
+
68
+ def _conclude(self):
69
+ if self.frame_count > 0:
70
+ average_donor = self.donor / self.frame_count
71
+
72
+ bins_z = np.arange(len(self.donor)) * self.bin_size
73
+
74
+ lower_z, upper_z = self.surface
75
+ mask = (bins_z >= lower_z) & (bins_z <= upper_z)
76
+ filtered_bins_z = bins_z[mask] - lower_z
77
+ filtered_average_donor = average_donor[mask]
78
+
79
+ combined_data = np.column_stack((filtered_bins_z, filtered_average_donor))
80
+
81
+ filename = 'hb_distribution_down.dat'
82
+ np.savetxt(filename, combined_data, header="Z\tDonor", fmt='%.5f', delimiter='\t')
83
+
84
+
85
+ def parse_data(s):
86
+ return [float(x) for x in s.replace(',', ' ').split()]
87
+
88
+
89
+ def parse_r(s):
90
+ return [int(x) for x in s.replace(':', ' ').split()]
91
+
92
+
93
+ def parse_argument():
94
+ parser = argparse.ArgumentParser(description="analysis hb distribution")
95
+ parser.add_argument('filename', type=str, help='filename to analysis')
96
+ parser.add_argument('--cp2k_input_file', type=str, help='input file name of cp2k, default is "input.inp"', default='input.inp')
97
+ parser.add_argument('-r', type=parse_r, help='range of analysis', default=[0, -1, 1])
98
+ parser.add_argument('--cell', type=parse_data, help='set cell, a list of lattice, --cell x,y,z or x,y,z,a,b,c')
99
+ parser.add_argument('--surface', type=parse_data, help='[down_surface_z, up_surface_z]')
100
+ parser.add_argument('--hb_param', type=parse_data, help='[hb_distance, hb_angle], default is [3.5, 35]', default=[3.5, 35])
101
+
102
+ return parser.parse_args()
103
+
104
+
105
+ def main():
106
+ args = parse_argument()
107
+ cell = cp2k_input_parsing.get_cell(args.cp2k_input_file, args.cell)
108
+
109
+ hb_dist = Hb_distribution(args.filename, cell, args.surface, hb_distance=args.hb_param[0], hb_angle=args.hb_param[1])
110
+ hb_dist.run(start=args.r[0], stop=args.r[1], step=args.r[2])
111
+
112
+
113
+ if __name__ == '__main__':
114
+ main()
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from ase import io, build
4
+ from ase.collections import g2
5
+ import argparse, os
6
+ import numpy as np
7
+ from util import encapsulated_ase
8
+
9
+
10
+ def parse_size(s):
11
+ if s == None:
12
+ return None
13
+ return [float(x) for x in s.replace(',', ' ').split()]
14
+
15
+
16
+ def parse_index(s):
17
+ return [int(x)-1 for x in s.replace(',', ' ').split()]
18
+
19
+
20
+ def parse_argument():
21
+ parser = argparse.ArgumentParser(description='add some adsorbate')
22
+ parser.add_argument('filename', type=str, help='init structure filename')
23
+ parser.add_argument('-m', type=str, help='atom or molecule to add')
24
+ parser.add_argument('--index', type=parse_index, help='index(list) of atom to add atom(top site)')
25
+ parser.add_argument('--offset', type=parse_size, help='adjust site, default is 0,0', default='0,0')
26
+ parser.add_argument('--height', type=float, help='designate vacuum of surface, default is None', default=0.0)
27
+ parser.add_argument('-x', type=float, help='rotate axis and angle')
28
+ parser.add_argument('-y', type=float, help='rotate axis and angle')
29
+ parser.add_argument('-z', type=float, help='rotate axis and angle')
30
+ parser.add_argument('-o', type=str, help='specify the output file name without suffix, default is "adsorbated.cif"', default='adsorbated.cif')
31
+ parser.add_argument('--coord', help='coord format', action='store_true')
32
+ parser.add_argument('--cell', type=parse_size, help='set xyz file cell, --cell x,y,z,a,b,c')
33
+ parser.add_argument('--cp2k', help='output cp2k format', action='store_true')
34
+
35
+ return parser.parse_args()
36
+
37
+ def main():
38
+ args = parse_argument()
39
+ atoms = encapsulated_ase.atoms_read_with_cell(args.filename, cell=args.cell, coord_mode=args.coord)
40
+
41
+ if len(args.offset) < 2:
42
+ args.offset.append(0)
43
+ offset = np.array(args.offset)
44
+
45
+ position_list = []
46
+ for atom in atoms:
47
+ if atom.index in args.index:
48
+ position_list.append(np.copy(atom.position[0:2])+offset)
49
+
50
+ if args.m in g2.names:
51
+ molecule = build.molecule(args.m)
52
+ if args.x:
53
+ molecule.rotate(args.x, 'x')
54
+ if args.y:
55
+ molecule.rotate(args.y, 'y')
56
+ if args.z:
57
+ molecule.rotate(args.z, 'z')
58
+ for position in position_list:
59
+ build.add_adsorbate(atoms, molecule, args.height, position=position)
60
+ else:
61
+ for position in position_list:
62
+ build.add_adsorbate(atoms, args.m, args.height, position=position)
63
+
64
+
65
+ if args.cp2k:
66
+ args.o = 'coord.xyz'
67
+ atoms.write(args.o, format='xyz')
68
+ with open(args.o, 'r') as f:
69
+ lines = f.readlines()
70
+ with open(args.o, 'w') as f:
71
+ f.writelines(lines[2:])
72
+ with open('cell.inc', 'w') as f:
73
+ cell = atoms.get_cell().cellpar()
74
+ f.write('ABC [angstrom] ' + str(cell[0]) + ' ' + str(cell[1]) + ' ' + str(cell[2]) + ' ' + '\n')
75
+ f.write('ALPHA_BETA_GAMMA ' + str(cell[3]) + ' ' + str(cell[4]) + ' ' + str(cell[5]) + '\n')
76
+ else:
77
+ atoms.write(args.o, format='cif')
78
+
79
+ print(os.path.abspath(args.o))
80
+
81
+
82
+ if __name__ == '__main__':
83
+ main()
84
+