mdkits 0.1.27__tar.gz → 0.1.29__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.
- {mdkits-0.1.27 → mdkits-0.1.29}/PKG-INFO +1 -1
- {mdkits-0.1.27 → mdkits-0.1.29}/pyproject.toml +1 -1
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/cut_surface.py +1 -1
- mdkits-0.1.29/src/mdkits/dft_cli/dft_cli.py +19 -0
- mdkits-0.1.29/src/mdkits/md_cli/angle.py +127 -0
- {mdkits-0.1.27/src/mdkits/cli → mdkits-0.1.29/src/mdkits/md_cli}/density.py +1 -1
- mdkits-0.1.29/src/mdkits/md_cli/hb_distribution.py +185 -0
- mdkits-0.1.29/src/mdkits/md_cli/md_cli.py +21 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/mdkits.py +5 -7
- mdkits-0.1.29/src/mdkits/util/.fig_operation.py.swp +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/arg_type.py +0 -2
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/encapsulated_mda.py +4 -1
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/numpy_geo.py +7 -5
- mdkits-0.1.29/src/mdkits/util/out_err.py +29 -0
- mdkits-0.1.27/src/mdkits/cli/hb_distribution.py +0 -126
- mdkits-0.1.27/src/mdkits/util/out_err.py +0 -26
- {mdkits-0.1.27 → mdkits-0.1.29}/LICENSE +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/README.md +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/__init__.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/__init__.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/adsorbate.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/build_bulk.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/build_cli.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/build_interface.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/build_solution.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/build_surface.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/supercell.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/build_cli/water.xyz +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/,hb_distribution_down.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/convert.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/data.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/extract.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/hartree_potential.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/hartree_potential_ave.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/hb.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/packmol_input.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/plot.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/cli/wrap.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/config/__init__.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/config/settings.yml +0 -0
- {mdkits-0.1.27/src/mdkits/cli → mdkits-0.1.29/src/mdkits/dft_cli}/cube.py +0 -0
- {mdkits-0.1.27/src/mdkits/cli → mdkits-0.1.29/src/mdkits/dft_cli}/pdos.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/__init__.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/cp2k_input_parsing.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/encapsulated_ase.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/fig_operation.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/os_operation.py +0 -0
- {mdkits-0.1.27 → mdkits-0.1.29}/src/mdkits/util/structure_parsing.py +0 -0
|
@@ -70,7 +70,7 @@ def main(atoms, face, vacuum, size, cell, orth):
|
|
|
70
70
|
super_surface = supercell.supercell(surface, size[0], size[1], 1)
|
|
71
71
|
|
|
72
72
|
super_surface.write(o)
|
|
73
|
-
out_err.cell_output(super_surface
|
|
73
|
+
out_err.cell_output(super_surface)
|
|
74
74
|
out_err.path_output(o)
|
|
75
75
|
|
|
76
76
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from mdkits.dft_cli import (
|
|
3
|
+
cube,
|
|
4
|
+
pdos,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group(name='dft')
|
|
9
|
+
@click.pass_context
|
|
10
|
+
def main(ctx):
|
|
11
|
+
"""kits for dft analysis"""
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
main.add_command(cube.main)
|
|
16
|
+
main.add_command(pdos.main)
|
|
17
|
+
|
|
18
|
+
if __name__ == '__main__':
|
|
19
|
+
main()
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from MDAnalysis import Universe
|
|
3
|
+
from MDAnalysis.analysis.base import AnalysisBase
|
|
4
|
+
import MDAnalysis
|
|
5
|
+
import sys
|
|
6
|
+
from mdkits.util import numpy_geo, encapsulated_mda, arg_type
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Angle_distribution(AnalysisBase):
|
|
11
|
+
def __init__(self, filename, cell, water_height, update_water, surface, distance_judg=None, angle_judg=(None, None), dt=0.001, bin_size=5):
|
|
12
|
+
u = Universe(filename)
|
|
13
|
+
u.trajectory.ts.dt = dt
|
|
14
|
+
u.dimensions = cell
|
|
15
|
+
|
|
16
|
+
self.u = u
|
|
17
|
+
self.atomgroup = u.select_atoms("all")
|
|
18
|
+
self.bin_size = bin_size
|
|
19
|
+
self.frame_count = 0
|
|
20
|
+
self.surface = surface
|
|
21
|
+
self.update_water = update_water
|
|
22
|
+
self.mid_z = u.dimensions[2]/2
|
|
23
|
+
|
|
24
|
+
self.normal_up = np.array([0, 0, 1])
|
|
25
|
+
self.normal_down = np.array([0, 0, -1])
|
|
26
|
+
self.total_angle = 180
|
|
27
|
+
|
|
28
|
+
if water_height is None:
|
|
29
|
+
sys.exit("Please specify the water height")
|
|
30
|
+
else:
|
|
31
|
+
self.water_height = water_height
|
|
32
|
+
|
|
33
|
+
if self.update_water:
|
|
34
|
+
self.distance_judg = distance_judg
|
|
35
|
+
self.angle_judg = angle_judg
|
|
36
|
+
|
|
37
|
+
if surface is not None:
|
|
38
|
+
self.surface_group = self.atomgroup.select_atoms(f"{surface}")
|
|
39
|
+
if self.surface_group.n_atoms == 0:
|
|
40
|
+
sys.exit("Please specify the correct surface group")
|
|
41
|
+
else:
|
|
42
|
+
sys.exit("Please specify a surface group")
|
|
43
|
+
|
|
44
|
+
super(Angle_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
|
|
45
|
+
|
|
46
|
+
def _prepare(self):
|
|
47
|
+
self.bin_num = int(self.total_angle / self.bin_size) + 2
|
|
48
|
+
self.angle_w_distribution = np.zeros(self.bin_num, dtype=np.float64)
|
|
49
|
+
self.angle_oh_distribution = np.zeros(self.bin_num, dtype=np.float64)
|
|
50
|
+
|
|
51
|
+
def _append(self, angle, anglew=True):
|
|
52
|
+
bins = np.floor(angle / self.bin_size).astype(int) + 1
|
|
53
|
+
|
|
54
|
+
if anglew:
|
|
55
|
+
bins = bins[bins < len(self.angle_w_distribution)]
|
|
56
|
+
np.add.at(self.angle_w_distribution, bins, 1)
|
|
57
|
+
else:
|
|
58
|
+
bins = bins[bins < len(self.angle_oh_distribution)]
|
|
59
|
+
np.add.at(self.angle_oh_distribution, bins, 1)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _single_frame(self):
|
|
63
|
+
surface = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
64
|
+
|
|
65
|
+
if len(surface) == 1:
|
|
66
|
+
o_group = self.atomgroup.select_atoms(f"name O and prop z < {surface[0]+self.water_height}", updating=True)
|
|
67
|
+
else:
|
|
68
|
+
o_group = self.atomgroup.select_atoms(f"name O and (prop z < {surface[0]+self.water_height} or prop z > {surface[1]-self.water_height})", updating=True)
|
|
69
|
+
|
|
70
|
+
h_group = self.atomgroup.select_atoms("name H")
|
|
71
|
+
|
|
72
|
+
if self.update_water:
|
|
73
|
+
o, oh1, oh2 = encapsulated_mda.update_water(self, o_group=o_group, h_group=h_group, distance_judg=self.distance_judg, angle_judg=self.angle_judg, return_index=False)
|
|
74
|
+
else:
|
|
75
|
+
o = o_group
|
|
76
|
+
oh1 = self.atomgroup[o_group.indices + 1]
|
|
77
|
+
oh2 = self.atomgroup[o_group.indices + 2]
|
|
78
|
+
|
|
79
|
+
vec1 = MDAnalysis.lib.distances.minimize_vectors(oh1.positions - o.positions, self.u.dimensions)
|
|
80
|
+
vec2 = MDAnalysis.lib.distances.minimize_vectors(oh2.positions - o.positions, self.u.dimensions)
|
|
81
|
+
|
|
82
|
+
bisector = numpy_geo.vector_between_two_vector(vec1, vec2)
|
|
83
|
+
|
|
84
|
+
angle_vec1 = np.hstack((numpy_geo.vector_vector_angle(vec1[o.positions[:, 2] < self.mid_z], self.normal_up), numpy_geo.vector_vector_angle(vec1[o.positions[:, 2] > self.mid_z], self.normal_down)))
|
|
85
|
+
|
|
86
|
+
angle_vec2 = np.hstack((numpy_geo.vector_vector_angle(vec2[o.positions[:, 2] < self.mid_z], self.normal_up), numpy_geo.vector_vector_angle(vec2[o.positions[:, 2] > self.mid_z], self.normal_down)))
|
|
87
|
+
|
|
88
|
+
angle_bisector = np.hstack((numpy_geo.vector_vector_angle(bisector[o.positions[:, 2] < self.mid_z], self.normal_up), numpy_geo.vector_vector_angle(bisector[o.positions[:, 2] > self.mid_z], self.normal_down)))
|
|
89
|
+
|
|
90
|
+
self._append(angle_vec1, anglew=False)
|
|
91
|
+
self._append(angle_vec2, anglew=False)
|
|
92
|
+
self._append(angle_bisector)
|
|
93
|
+
|
|
94
|
+
self.frame_count += 1
|
|
95
|
+
|
|
96
|
+
def _conclude(self):
|
|
97
|
+
if self.frame_count > 0:
|
|
98
|
+
average_angle_w = self.angle_w_distribution / self.frame_count
|
|
99
|
+
average_angle_oh = self.angle_oh_distribution / (self.frame_count*2)
|
|
100
|
+
bins_z = np.arange(len(average_angle_w)) * self.bin_size
|
|
101
|
+
conbined_data = np.column_stack((bins_z, average_angle_w, average_angle_oh))
|
|
102
|
+
np.savetxt("angle_distribution.dat", conbined_data, header="angle\tw_suf_dist\toh_suf_dist", fmt='%.5f', delimiter='\t')
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@click.command(name="angle")
|
|
106
|
+
@click.argument("filename", type=click.Path(exists=True))
|
|
107
|
+
@click.option('--cell', type=arg_type.Cell, help="set cell, a list of lattice, --cell x,y,z or x,y,z,a,b,c")
|
|
108
|
+
@click.option("--water_height", type=float, help="water height from surface")
|
|
109
|
+
@click.option("--surface", type=str, help="surface group")
|
|
110
|
+
@click.option('--update_water', is_flag=True, help='update water with distance or angle judgment')
|
|
111
|
+
@click.option('--distance', type=float, help='update water distance judgment', default=1.2, show_default=True)
|
|
112
|
+
@click.option('--angle', type=(float, float), help='update water angle judgment')
|
|
113
|
+
@click.option('-r', type=arg_type.FrameRange, help='range of frame to analysis')
|
|
114
|
+
def main(filename, cell, water_height, update_water, distance, angle, surface, r):
|
|
115
|
+
"""analysis angle between normal vectors and OH vector or bisector"""
|
|
116
|
+
a = Angle_distribution(filename, cell, water_height, update_water, distance_judg=distance, angle_judg=angle, surface=surface)
|
|
117
|
+
if r is not None:
|
|
118
|
+
if len(r) == 2:
|
|
119
|
+
a.run(start=r[0], stop=r[1])
|
|
120
|
+
elif len(r) == 3:
|
|
121
|
+
a.run(start=r[0], stop=r[1], step=r[2])
|
|
122
|
+
else:
|
|
123
|
+
a.run()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
if __name__ == "__main__":
|
|
127
|
+
main()
|
|
@@ -75,7 +75,7 @@ class Density_distribution(AnalysisBase):
|
|
|
75
75
|
self._append(o.positions[:, 2])
|
|
76
76
|
|
|
77
77
|
else:
|
|
78
|
-
group = self.atomgroup.select_atoms(f"{self.element}")
|
|
78
|
+
group = self.atomgroup.select_atoms(f"{self.element}", updating=True)
|
|
79
79
|
self._append(group.positions[:, 2])
|
|
80
80
|
|
|
81
81
|
if self.surface_group:
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import click
|
|
5
|
+
import MDAnalysis
|
|
6
|
+
from MDAnalysis import Universe
|
|
7
|
+
from MDAnalysis.analysis.base import AnalysisBase
|
|
8
|
+
from mdkits.util import arg_type, os_operation, numpy_geo, encapsulated_mda
|
|
9
|
+
import warnings, sys
|
|
10
|
+
warnings.filterwarnings("ignore")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Hb_distribution(AnalysisBase):
|
|
14
|
+
def __init__(self, filename, cell, surface, update_water, distance_judg, angle_judg, hb_distance, hb_angle, bin_size=0.2, dt=0.001, index=None):
|
|
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.update_water = update_water
|
|
25
|
+
self.frame_count = 0
|
|
26
|
+
np.set_printoptions(threshold=np.inf)
|
|
27
|
+
|
|
28
|
+
if surface is not None:
|
|
29
|
+
self.surface_group = self.atomgroup.select_atoms(f"{surface}")
|
|
30
|
+
if self.surface_group.n_atoms == 0:
|
|
31
|
+
sys.exit("Please specify the correct surface group")
|
|
32
|
+
else:
|
|
33
|
+
self.surface_group = False
|
|
34
|
+
|
|
35
|
+
if self.update_water:
|
|
36
|
+
self.distance_judg = distance_judg
|
|
37
|
+
self.angle_judg = angle_judg
|
|
38
|
+
|
|
39
|
+
if index is not None:
|
|
40
|
+
self.index = index
|
|
41
|
+
self.hb_d_index = 0
|
|
42
|
+
self.hb_a_index = 0
|
|
43
|
+
else:
|
|
44
|
+
self.index = None
|
|
45
|
+
|
|
46
|
+
super(Hb_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
|
|
47
|
+
|
|
48
|
+
def _prepare(self):
|
|
49
|
+
bin_num = int(self.u.dimensions[2] / self.bin_size) + 2
|
|
50
|
+
self.accepter = np.zeros(bin_num, dtype=np.float64)
|
|
51
|
+
self.donor = np.zeros(bin_num, dtype=np.float64)
|
|
52
|
+
self.od = np.zeros(bin_num, dtype=np.float64)
|
|
53
|
+
if self.surface_group:
|
|
54
|
+
self.surface_pos = np.zeros(2)
|
|
55
|
+
|
|
56
|
+
def _append(self, hb_d, hb_a, o):
|
|
57
|
+
bins_d = np.floor(hb_d / self.bin_size).astype(int) + 1
|
|
58
|
+
bins_a = np.floor(hb_a / self.bin_size).astype(int) + 1
|
|
59
|
+
bins_o = np.floor(o / self.bin_size).astype(int) + 1
|
|
60
|
+
|
|
61
|
+
bins_d = bins_d[bins_d < len(self.donor)]
|
|
62
|
+
bins_a = bins_a[bins_a < len(self.accepter)]
|
|
63
|
+
bins_o = bins_o[bins_o < len(self.od)]
|
|
64
|
+
|
|
65
|
+
np.add.at(self.donor, bins_d, 1)
|
|
66
|
+
np.add.at(self.accepter, bins_a, 1)
|
|
67
|
+
np.add.at(self.od, bins_o, 1)
|
|
68
|
+
|
|
69
|
+
def _single_frame(self):
|
|
70
|
+
if self.update_water:
|
|
71
|
+
o = self.atomgroup.select_atoms("name O")
|
|
72
|
+
h = self.atomgroup.select_atoms("name H")
|
|
73
|
+
|
|
74
|
+
o_group, oh1, oh2 = encapsulated_mda.update_water(self, o, h, distance_judg=self.distance_judg, angle_judg=self.angle_judg, return_index=False)
|
|
75
|
+
|
|
76
|
+
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)
|
|
77
|
+
|
|
78
|
+
o0 = o_group[o_pair[:, 0]]
|
|
79
|
+
o1 = o_group[o_pair[:, 1]]
|
|
80
|
+
|
|
81
|
+
o0h1 = oh1[o_pair[:, 0]]
|
|
82
|
+
o0h2 = oh2[o_pair[:, 0]]
|
|
83
|
+
o1h1 = oh1[o_pair[:, 1]]
|
|
84
|
+
o1h2 = oh2[o_pair[:, 1]]
|
|
85
|
+
else:
|
|
86
|
+
o_group = self.atomgroup.select_atoms("name O")
|
|
87
|
+
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)
|
|
88
|
+
|
|
89
|
+
o0 = o_group[o_pair[:, 0]]
|
|
90
|
+
o1 = o_group[o_pair[:, 1]]
|
|
91
|
+
|
|
92
|
+
o0h1 = self.atomgroup[o0.indices + 1]
|
|
93
|
+
o0h2 = self.atomgroup[o0.indices + 2]
|
|
94
|
+
o1h1 = self.atomgroup[o1.indices + 1]
|
|
95
|
+
o1h2 = self.atomgroup[o1.indices + 2]
|
|
96
|
+
|
|
97
|
+
angle_o0h1_o0_o1 = np.degrees(
|
|
98
|
+
MDAnalysis.lib.distances.calc_angles(o0h1.positions, o0.positions, o1.positions, box=self.u.dimensions)
|
|
99
|
+
)
|
|
100
|
+
angle_o0h2_o0_o1 = np.degrees(
|
|
101
|
+
MDAnalysis.lib.distances.calc_angles(o0h2.positions, o0.positions, o1.positions, box=self.u.dimensions)
|
|
102
|
+
)
|
|
103
|
+
angle_o1h1_o1_o0 = np.degrees(
|
|
104
|
+
MDAnalysis.lib.distances.calc_angles(o1h1.positions, o1.positions, o0.positions, box=self.u.dimensions)
|
|
105
|
+
)
|
|
106
|
+
angle_o1h2_o1_o0 = np.degrees(
|
|
107
|
+
MDAnalysis.lib.distances.calc_angles(o1h2.positions, o1.positions, o0.positions, box=self.u.dimensions)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
condition_d = (angle_o0h1_o0_o1 < self.hb_angle) | (angle_o0h2_o0_o1 < self.hb_angle)
|
|
111
|
+
condition_a = (angle_o1h1_o1_o0 < self.hb_angle) | (angle_o1h2_o1_o0 < self.hb_angle)
|
|
112
|
+
|
|
113
|
+
if self.index is not None:
|
|
114
|
+
self.hb_d_index += o0.positions[:, 2][condition_d & (o0.indices == self.index)].shape[0]
|
|
115
|
+
self.hb_a_index += o0.positions[:, 2][condition_a & (o0.indices == self.index)].shape[0]
|
|
116
|
+
else:
|
|
117
|
+
hb_d = o0.positions[:, 2][condition_d]
|
|
118
|
+
hb_a = o0.positions[:, 2][condition_a]
|
|
119
|
+
|
|
120
|
+
self._append(hb_d, hb_a, o_group.positions[:, 2])
|
|
121
|
+
|
|
122
|
+
if self.surface_group:
|
|
123
|
+
lower_z, upper_z = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
124
|
+
self.surface_pos[0] += lower_z
|
|
125
|
+
self.surface_pos[1] += upper_z
|
|
126
|
+
|
|
127
|
+
self.frame_count += 1
|
|
128
|
+
|
|
129
|
+
def _conclude(self):
|
|
130
|
+
if self.frame_count > 0 and self.index is None:
|
|
131
|
+
average_od = self.od / self.frame_count
|
|
132
|
+
average_donor = (self.donor / self.frame_count) / average_od
|
|
133
|
+
average_accepter = (self.accepter / self.frame_count) / average_od
|
|
134
|
+
average_sum = average_donor + average_accepter
|
|
135
|
+
|
|
136
|
+
bins_z = np.arange(len(self.donor)) * self.bin_size
|
|
137
|
+
|
|
138
|
+
if self.surface:
|
|
139
|
+
lower_z, upper_z = self.surface_pos/self.frame_count
|
|
140
|
+
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
141
|
+
filtered_bins_z = bins_z[mask] - lower_z
|
|
142
|
+
filtered_average_accepter = average_accepter[mask]
|
|
143
|
+
filtered_average_donor = average_donor[mask]
|
|
144
|
+
filtered_average_sum = average_sum[mask]
|
|
145
|
+
|
|
146
|
+
combined_data = np.column_stack((filtered_bins_z, filtered_average_accepter, filtered_average_donor, filtered_average_sum))
|
|
147
|
+
else:
|
|
148
|
+
combined_data = np.column_stack((bins_z, average_accepter, average_donor, average_sum))
|
|
149
|
+
|
|
150
|
+
np.savetxt("hb_distribution.dat", combined_data, header="Z\tAccepter\tDonor\tAccepter+Donor", fmt='%.5f', delimiter='\t')
|
|
151
|
+
|
|
152
|
+
if self.index is not None and self.frame_count > 0:
|
|
153
|
+
self.hb_d_index /= self.frame_count
|
|
154
|
+
self.hb_a_index /= self.frame_count
|
|
155
|
+
output = f"# {self.index}\naccepter : {self.hb_a_index}\ndonor : {self.hb_d_index}\ntotal : {self.hb_a_index + self.hb_d_index}"
|
|
156
|
+
with open(f"hb_{self.index}.dat", "a") as f:
|
|
157
|
+
f.write(output)
|
|
158
|
+
print(output)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@click.command(name="hb")
|
|
162
|
+
@click.argument('filename', type=click.Path(exists=True), default=os_operation.default_file_name('*-pos-1.xyz', last=True))
|
|
163
|
+
@click.option('--hb_param', type=click.Tuple([float, float]), help='parameter for hydrogen bond', default=(3.5, 35), show_default=True)
|
|
164
|
+
@click.option('--cell', type=arg_type.Cell, help='set cell, a list of lattice, --cell x,y,z or x,y,z,a,b,c')
|
|
165
|
+
@click.option('--surface', type=str, help='surface element')
|
|
166
|
+
@click.option('-r', type=arg_type.FrameRange, help='range of frame to analysis')
|
|
167
|
+
@click.option('--update_water', is_flag=True, help='update water with distance or angle judgment')
|
|
168
|
+
@click.option('--distance', type=float, help='update water distance judgment', default=1.2, show_default=True)
|
|
169
|
+
@click.option('--angle', type=(float, float), help='update water angle judgment')
|
|
170
|
+
@click.option('--index', type=int, help='index of an atom')
|
|
171
|
+
def main(filename, hb_param, cell, surface, r, update_water, distance, angle, index):
|
|
172
|
+
"""analysis hydrogen bond distribution along z-axis"""
|
|
173
|
+
hb_dist = Hb_distribution(filename, cell, surface, update_water=update_water, distance_judg=distance, angle_judg=angle, hb_distance=hb_param[0], hb_angle=hb_param[1], index=index)
|
|
174
|
+
|
|
175
|
+
if r is not None:
|
|
176
|
+
if len(r) == 2:
|
|
177
|
+
hb_dist.run(start=r[0], stop=r[1])
|
|
178
|
+
elif len(r) == 3:
|
|
179
|
+
hb_dist.run(start=r[0], stop=r[1], step=r[2])
|
|
180
|
+
else:
|
|
181
|
+
hb_dist.run()
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if __name__ == '__main__':
|
|
185
|
+
main()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from mdkits.md_cli import (
|
|
3
|
+
density,
|
|
4
|
+
hb_distribution,
|
|
5
|
+
angle,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group(name='md')
|
|
10
|
+
@click.pass_context
|
|
11
|
+
def main(ctx):
|
|
12
|
+
"""kits for MD analysis"""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
main.add_command(density.main)
|
|
16
|
+
main.add_command(hb_distribution.main)
|
|
17
|
+
main.add_command(angle.main)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
if __name__ == '__main__':
|
|
21
|
+
main()
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import click
|
|
2
2
|
from mdkits.build_cli import build_cli
|
|
3
|
+
from mdkits.dft_cli import dft_cli
|
|
4
|
+
from mdkits.md_cli import md_cli
|
|
3
5
|
from mdkits.cli import (
|
|
4
6
|
convert,
|
|
5
7
|
wrap,
|
|
6
8
|
extract,
|
|
7
9
|
data,
|
|
8
10
|
plot,
|
|
9
|
-
density,
|
|
10
|
-
cube,
|
|
11
|
-
pdos,
|
|
12
11
|
)
|
|
13
12
|
|
|
14
13
|
|
|
@@ -20,15 +19,14 @@ def cli(ctx):
|
|
|
20
19
|
pass
|
|
21
20
|
|
|
22
21
|
|
|
22
|
+
cli.add_command(md_cli.main)
|
|
23
|
+
cli.add_command(dft_cli.main)
|
|
24
|
+
cli.add_command(build_cli.cli_build)
|
|
23
25
|
cli.add_command(convert.main)
|
|
24
26
|
cli.add_command(wrap.main)
|
|
25
27
|
cli.add_command(extract.main)
|
|
26
28
|
cli.add_command(data.main)
|
|
27
29
|
cli.add_command(plot.main)
|
|
28
|
-
cli.add_command(density.main)
|
|
29
|
-
cli.add_command(cube.main)
|
|
30
|
-
cli.add_command(pdos.main)
|
|
31
|
-
cli.add_command(build_cli.cli_build)
|
|
32
30
|
|
|
33
31
|
|
|
34
32
|
if __name__ == '__main__':
|
|
Binary file
|
|
@@ -14,10 +14,8 @@ class CellType(click.ParamType):
|
|
|
14
14
|
|
|
15
15
|
if len(cell) == 3:
|
|
16
16
|
cell += [90, 90, 90]
|
|
17
|
-
out_err.cell_output(cell)
|
|
18
17
|
return cell
|
|
19
18
|
elif len(cell) == 6:
|
|
20
|
-
out_err.cell_output(cell)
|
|
21
19
|
return cell
|
|
22
20
|
else:
|
|
23
21
|
self.fail(f"{value} is not a valid cell parameter", param, ctx)
|
|
@@ -3,7 +3,7 @@ import numpy as np
|
|
|
3
3
|
from . import numpy_geo
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def update_water(self, o_group, h_group, distance_judg=1.2, angle_judg:tuple[float, float]=None, return_index=False):
|
|
6
|
+
def update_water(self, o_group, h_group, distance_judg=1.2, angle_judg:tuple[float, float]=(None, None), return_index=False):
|
|
7
7
|
"""
|
|
8
8
|
input: o and h atom
|
|
9
9
|
output: o and two h in this frame
|
|
@@ -53,6 +53,9 @@ def update_water(self, o_group, h_group, distance_judg=1.2, angle_judg:tuple[flo
|
|
|
53
53
|
if return_index:
|
|
54
54
|
return o_index, oh1_index, oh2_index
|
|
55
55
|
else:
|
|
56
|
+
if len(o_index) == 0:
|
|
57
|
+
raise ValueError("No water found in this atom group")
|
|
58
|
+
|
|
56
59
|
o = o_group[o_index]
|
|
57
60
|
oh1 = h_group[oh1_index]
|
|
58
61
|
oh2 = h_group[oh2_index]
|
|
@@ -45,7 +45,7 @@ def vector_between_two_vector(vector1, vector2):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def vector_vector_angle(vector, surface_vector):
|
|
48
|
-
cos = np.dot(vector, surface_vector) / (np.linalg.norm(vector) * np.linalg.norm(surface_vector))
|
|
48
|
+
cos = np.dot(vector, surface_vector) / (np.linalg.norm(vector, axis=1) * np.linalg.norm(surface_vector))
|
|
49
49
|
vector_vector_angle = np.arccos(np.clip(cos, -1.0, 1.0))
|
|
50
50
|
vector_vector_angle = np.degrees(vector_vector_angle)
|
|
51
51
|
return vector_vector_angle
|
|
@@ -96,7 +96,7 @@ def unwrap(atom1, atom2, coefficients, max=0, total=False):
|
|
|
96
96
|
return min_dist, closest_point
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
def find_surface(surface_group:np.ndarray, layer_tolerance=
|
|
99
|
+
def find_surface(surface_group:np.ndarray, layer_tolerance=0.05, surface_tolerance=5):
|
|
100
100
|
sort_group = np.sort(surface_group)
|
|
101
101
|
layer_mean = []
|
|
102
102
|
current_layer = [sort_group[0]]
|
|
@@ -108,12 +108,14 @@ def find_surface(surface_group:np.ndarray, layer_tolerance=1, surface_tolerance=
|
|
|
108
108
|
current_layer = [sort_group[i]]
|
|
109
109
|
layer_mean.append(np.mean(current_layer))
|
|
110
110
|
|
|
111
|
-
if len(
|
|
112
|
-
return layer_mean[0]
|
|
111
|
+
if len(layer_mean) == 1:
|
|
112
|
+
return [layer_mean[0]]
|
|
113
113
|
|
|
114
114
|
diff = np.diff(layer_mean)
|
|
115
115
|
if np.any(diff > surface_tolerance):
|
|
116
|
-
index = np.argmax(diff >
|
|
116
|
+
index = np.argmax(diff > surface_tolerance)
|
|
117
117
|
return (layer_mean[index], layer_mean[index + 1])
|
|
118
118
|
else:
|
|
119
|
+
if layer_mean[-1] > layer_mean[0]:
|
|
120
|
+
return [layer_mean[-1]]
|
|
119
121
|
return (layer_mean[-1], layer_mean[0])
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
output and error for cli
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import sys, os
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def cell_output(atoms):
|
|
10
|
+
cell = atoms.cell.cellpar()
|
|
11
|
+
if not hasattr(atoms, "name"):
|
|
12
|
+
atoms.name = "present"
|
|
13
|
+
print(f"{atoms.name} cell: x = {cell[0]}, y = {cell[1]}, z = {cell[2]}, a = {cell[3]}\u00B0, b = {cell[4]}\u00B0, c = {cell[5]}\u00B0")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def path_output(file: str):
|
|
17
|
+
print(os.path.abspath(file))
|
|
18
|
+
|
|
19
|
+
def check_cell(atoms, cell=None):
|
|
20
|
+
if cell is not None:
|
|
21
|
+
atoms.set_cell(cell)
|
|
22
|
+
cell_output(atoms)
|
|
23
|
+
elif not np.array_equal(atoms.cell.cellpar(), np.array([0., 0., 0., 90., 90., 90.])):
|
|
24
|
+
cell_output(atoms)
|
|
25
|
+
elif np.array_equal(atoms.cell.cellpar(), np.array([0., 0., 0., 90., 90., 90.])) and cell is not None:
|
|
26
|
+
atoms.set_cell(cell)
|
|
27
|
+
cell_output(atoms)
|
|
28
|
+
else:
|
|
29
|
+
raise ValueError("can't parse cell please use --cell set cell")
|
|
@@ -1,126 +0,0 @@
|
|
|
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()
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
output and error for cli
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import numpy as np
|
|
6
|
-
import sys, os
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def cell_output(cell):
|
|
10
|
-
print(f"system cell: x = {cell[0]}, y = {cell[1]}, z = {cell[2]}, a = {cell[3]}\u00B0, b = {cell[4]}\u00B0, c = {cell[5]}\u00B0")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def path_output(file: str):
|
|
14
|
-
print(os.path.abspath(file))
|
|
15
|
-
|
|
16
|
-
def check_cell(atoms, cell=None):
|
|
17
|
-
if cell is not None:
|
|
18
|
-
atoms.set_cell(cell)
|
|
19
|
-
cell_output(atoms.cell.cellpar())
|
|
20
|
-
if not np.array_equal(atoms.cell.cellpar(), np.array([0., 0., 0., 90., 90., 90.])):
|
|
21
|
-
cell_output(atoms.cell.cellpar())
|
|
22
|
-
elif np.array_equal(atoms.cell.cellpar(), np.array([0., 0., 0., 90., 90., 90.])) and cell is not None:
|
|
23
|
-
atoms.set_cell(cell)
|
|
24
|
-
cell_output(atoms.cell.cellpar())
|
|
25
|
-
else:
|
|
26
|
-
raise ValueError("can't parse cell please use --cell set cell")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|