mdkits 0.1.13__py3-none-any.whl → 1.2.3__py3-none-any.whl
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.
- mdkits/build_cli/adsorbate.py +2 -1
- mdkits/build_cli/build_bulk.py +2 -1
- mdkits/build_cli/build_interface.py +5 -0
- mdkits/build_cli/build_solution.py +48 -4
- mdkits/build_cli/build_surface.py +2 -5
- mdkits/build_cli/cut_surface.py +1 -1
- mdkits/build_cli/supercell.py +1 -1
- mdkits/cli/convert.py +1 -1
- mdkits/cli/extract.py +29 -18
- mdkits/{cli → dft_cli/.back}/pdos.py +1 -0
- mdkits/dft_cli/check_neb.py +0 -0
- mdkits/{cli → dft_cli}/cube.py +3 -2
- mdkits/dft_cli/dft_cli.py +23 -0
- mdkits/dft_cli/fix.py +54 -0
- mdkits/dft_cli/pdos.py +119 -0
- mdkits/md_cli/angle.py +122 -0
- mdkits/{cli → md_cli}/density.py +24 -19
- mdkits/md_cli/dipole.py +124 -0
- mdkits/md_cli/hb_distribution.py +185 -0
- mdkits/md_cli/md_cli.py +32 -0
- mdkits/md_cli/monitor.py +104 -0
- mdkits/md_cli/msd.py +44 -0
- mdkits/md_cli/rdf.py +53 -0
- mdkits/md_cli/setting.py +14 -0
- mdkits/md_cli/vac.py +65 -0
- mdkits/{cli → md_cli}/wrap.py +4 -3
- mdkits/mdkits.py +5 -9
- mdkits/util/.fig_operation.py.swp +0 -0
- mdkits/util/arg_type.py +18 -8
- mdkits/util/cp2k_input_parsing.py +5 -1
- mdkits/util/encapsulated_ase.py +28 -7
- mdkits/util/encapsulated_mda.py +4 -1
- mdkits/util/numpy_geo.py +10 -5
- mdkits/util/os_operation.py +3 -1
- mdkits/util/out_err.py +18 -6
- mdkits-1.2.3.dist-info/METADATA +370 -0
- mdkits-1.2.3.dist-info/RECORD +51 -0
- mdkits/cli/,hb_distribution_down.py +0 -114
- mdkits/cli/hartree_potential.py +0 -59
- mdkits/cli/hartree_potential_ave.py +0 -84
- mdkits/cli/hb.py +0 -101
- mdkits/cli/hb_distribution.py +0 -126
- mdkits/cli/packmol_input.py +0 -76
- mdkits-0.1.13.dist-info/METADATA +0 -226
- mdkits-0.1.13.dist-info/RECORD +0 -43
- {mdkits-0.1.13.dist-info → mdkits-1.2.3.dist-info}/LICENSE +0 -0
- {mdkits-0.1.13.dist-info → mdkits-1.2.3.dist-info}/WHEEL +0 -0
- {mdkits-0.1.13.dist-info → mdkits-1.2.3.dist-info}/entry_points.txt +0 -0
mdkits/{cli → md_cli}/density.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
|
-
import click
|
|
4
|
+
import click, math
|
|
5
5
|
from MDAnalysis import Universe
|
|
6
6
|
from MDAnalysis.analysis.base import AnalysisBase
|
|
7
7
|
from mdkits.util import (
|
|
@@ -10,6 +10,7 @@ from mdkits.util import (
|
|
|
10
10
|
encapsulated_mda,
|
|
11
11
|
os_operation,
|
|
12
12
|
)
|
|
13
|
+
from .setting import common_setting
|
|
13
14
|
import warnings, sys
|
|
14
15
|
warnings.filterwarnings("ignore")
|
|
15
16
|
|
|
@@ -75,30 +76,33 @@ class Density_distribution(AnalysisBase):
|
|
|
75
76
|
self._append(o.positions[:, 2])
|
|
76
77
|
|
|
77
78
|
else:
|
|
78
|
-
group = self.atomgroup.select_atoms(f"{self.element}")
|
|
79
|
+
group = self.atomgroup.select_atoms(f"{self.element}", updating=True)
|
|
79
80
|
self._append(group.positions[:, 2])
|
|
80
81
|
|
|
81
82
|
if self.surface_group:
|
|
82
|
-
|
|
83
|
-
self.surface_pos[0] +=
|
|
84
|
-
self.surface_pos[1] +=
|
|
83
|
+
surface = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
84
|
+
self.surface_pos[0] += surface[0]
|
|
85
|
+
self.surface_pos[1] += surface[1]
|
|
85
86
|
|
|
86
87
|
self.frame_count += 1
|
|
87
88
|
|
|
88
89
|
def _conclude(self):
|
|
89
90
|
if self.frame_count > 0:
|
|
90
|
-
V = self.u.dimensions[0] * self.u.dimensions[1] * self.bin_size
|
|
91
|
+
V = self.u.dimensions[0] * self.u.dimensions[1] * math.sin(math.radians(180 - self.u.dimensions[-1])) * self.bin_size
|
|
91
92
|
|
|
92
93
|
if self.atomic_mass:
|
|
93
94
|
density_distribution = (self.density_distribution * self.atomic_mass * 1.660539 / V) / self.frame_count
|
|
94
95
|
else:
|
|
95
96
|
density_distribution = (self.density_distribution * (10000/6.02) / V) / self.frame_count
|
|
96
97
|
|
|
97
|
-
bins_z = np.arange(len(self.density_distribution)) * self.bin_size
|
|
98
|
+
bins_z = np.arange(len(self.density_distribution)) * self.bin_size + self.bin_size / 2
|
|
98
99
|
|
|
99
100
|
if self.surface:
|
|
100
101
|
lower_z = self.surface_pos[0] / self.frame_count
|
|
101
|
-
|
|
102
|
+
if self.surface_pos[1] == 0:
|
|
103
|
+
upper_z = np.inf
|
|
104
|
+
else:
|
|
105
|
+
upper_z = self.surface_pos[1] / self.frame_count
|
|
102
106
|
|
|
103
107
|
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
104
108
|
filtered_bins_z = bins_z[mask] - lower_z
|
|
@@ -110,24 +114,25 @@ class Density_distribution(AnalysisBase):
|
|
|
110
114
|
|
|
111
115
|
np.savetxt(self.o, conbined_data, header="Z\tdensity", fmt='%.5f', delimiter='\t')
|
|
112
116
|
|
|
113
|
-
@click.command(name='density')
|
|
114
|
-
@
|
|
115
|
-
@click.option('--
|
|
116
|
-
@click.option('--element', type=str, help='element to analysis')
|
|
117
|
+
@click.command(name='density', help="analysis density or concentration of element in a trajectory file")
|
|
118
|
+
@common_setting
|
|
119
|
+
@click.option('--group', type=str, help='group to analysis')
|
|
117
120
|
@click.option('--atomic_mass', type=float, help='output density unit (g/cm3), should give atomic mass of element, else is concentration unit (mol/L)')
|
|
118
121
|
@click.option('-o', type=str, help='output file name', default='density_{element}.dat', show_default=True)
|
|
119
|
-
|
|
120
|
-
@click.option('--distance', type=float, help='update water distance judgment', default=1.2, show_default=True)
|
|
121
|
-
@click.option('--angle', type=(float, float), help='update water angle judgment')
|
|
122
|
-
@click.option('--surface', type=str, help='surface element')
|
|
123
|
-
def main(filename, cell, o, element, atomic_mass, update_water, distance, angle, surface):
|
|
122
|
+
def main(filename, cell, o, group, atomic_mass, update_water, distance, angle, surface, r):
|
|
124
123
|
"""
|
|
125
124
|
analysis density or concentration of element in a trajectory file
|
|
126
125
|
"""
|
|
127
126
|
|
|
128
|
-
density_dist = Density_distribution(filename, cell, o=o, distance_judg=distance, angle_judg=angle, element=
|
|
127
|
+
density_dist = Density_distribution(filename, cell, o=o, distance_judg=distance, angle_judg=angle, element=group, atomic_mass=atomic_mass, update_water=update_water, surface=surface)
|
|
129
128
|
|
|
130
|
-
|
|
129
|
+
if r is not None:
|
|
130
|
+
if len(r) == 2:
|
|
131
|
+
density_dist.run(start=r[0], stop=r[1])
|
|
132
|
+
elif len(r) == 3:
|
|
133
|
+
density_dist.run(start=r[0], stop=r[1], step=r[2])
|
|
134
|
+
else:
|
|
135
|
+
density_dist.run()
|
|
131
136
|
|
|
132
137
|
|
|
133
138
|
if __name__ == '__main__':
|
mdkits/md_cli/dipole.py
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import click
|
|
3
|
+
import MDAnalysis
|
|
4
|
+
from MDAnalysis import Universe
|
|
5
|
+
from MDAnalysis.analysis.base import AnalysisBase
|
|
6
|
+
from mdkits.util import (
|
|
7
|
+
arg_type,
|
|
8
|
+
numpy_geo,
|
|
9
|
+
encapsulated_mda,
|
|
10
|
+
os_operation
|
|
11
|
+
)
|
|
12
|
+
from .setting import common_setting
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Dipole_distribution(AnalysisBase):
|
|
17
|
+
def __init__(self, filename, cell, update_water, distance_judg, angle_judg, surface, dt=0.001, bin_size=0.2):
|
|
18
|
+
u = Universe(filename)
|
|
19
|
+
u.trajectory.ts.dt = dt
|
|
20
|
+
u.dimensions = cell
|
|
21
|
+
|
|
22
|
+
self.u = u
|
|
23
|
+
self.atomgroup = u.select_atoms("all")
|
|
24
|
+
self.bin_size = bin_size
|
|
25
|
+
self.frame_count = 0
|
|
26
|
+
self.surface = surface
|
|
27
|
+
self.update_water = update_water
|
|
28
|
+
self.mid_z = u.dimensions[2] / 2
|
|
29
|
+
|
|
30
|
+
if self.update_water:
|
|
31
|
+
self.distance_judg = distance_judg
|
|
32
|
+
self.angle_judg = angle_judg
|
|
33
|
+
|
|
34
|
+
if surface is not None:
|
|
35
|
+
self.surface_group = self.atomgroup.select_atoms(f"{surface}")
|
|
36
|
+
if self.surface_group.n_atoms == 0:
|
|
37
|
+
sys.exit("Please specify the correct surface group")
|
|
38
|
+
else:
|
|
39
|
+
self.surface_group = False
|
|
40
|
+
|
|
41
|
+
super(Dipole_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
|
|
42
|
+
|
|
43
|
+
def _prepare(self):
|
|
44
|
+
self.bin_num = int(self.u.dimensions[2] / self.bin_size) + 2
|
|
45
|
+
self.dipole_distribution = np.zeros(self.bin_num, dtype=np.float64)
|
|
46
|
+
self.o_count = np.zeros(self.bin_num, dtype=np.float64)
|
|
47
|
+
|
|
48
|
+
if self.surface_group:
|
|
49
|
+
self.surface_pos = np.zeros(2)
|
|
50
|
+
|
|
51
|
+
def _append(self, angle, z):
|
|
52
|
+
bins = np.floor(z / self.bin_size).astype(int) + 1
|
|
53
|
+
np.add.at(self.dipole_distribution, bins, angle)
|
|
54
|
+
np.add.at(self.o_count, bins , 1)
|
|
55
|
+
|
|
56
|
+
def _single_frame(self):
|
|
57
|
+
o_group = self.atomgroup.select_atoms("name O")
|
|
58
|
+
|
|
59
|
+
if self.update_water:
|
|
60
|
+
h_group = self.atomgroup.select_atoms("name H")
|
|
61
|
+
o, oh1, oh2 = encapsulated_mda.update_water(self, o_group, h_group, distance_judg=self.distance_judg, angle_judg=self.angle_judg, return_index=False)
|
|
62
|
+
else:
|
|
63
|
+
o = o_group
|
|
64
|
+
oh1 = self.atomgroup[o.indices + 1]
|
|
65
|
+
oh2 = self.atomgroup[o.indices + 2]
|
|
66
|
+
|
|
67
|
+
if self.surface_group:
|
|
68
|
+
lower_z, upper_z = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
69
|
+
self.surface_pos[0] += lower_z
|
|
70
|
+
self.surface_pos[1] += upper_z
|
|
71
|
+
|
|
72
|
+
vec1 = MDAnalysis.lib.distances.minimize_vectors(oh1.positions - o.positions, self.u.dimensions)
|
|
73
|
+
vec2 = MDAnalysis.lib.distances.minimize_vectors(oh2.positions - o.positions, self.u.dimensions)
|
|
74
|
+
|
|
75
|
+
bisector = numpy_geo.vector_between_two_vector(vec1, vec2)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
angle_bisector = np.hstack((bisector[o.positions[:, 2] < self.mid_z][:, 2] / np.linalg.norm(bisector[o.positions[:, 2] < self.mid_z], axis=1), -bisector[o.positions[:, 2] > self.mid_z][:, 2] / np.linalg.norm(bisector[o.positions[:, 2] > self.mid_z], axis=1)))
|
|
79
|
+
|
|
80
|
+
self._append(angle_bisector, np.hstack((o.positions[:, 2][o.positions[:, 2] < self.mid_z], o.positions[:, 2][o.positions[:, 2] > self.mid_z])))
|
|
81
|
+
|
|
82
|
+
self.frame_count += 1
|
|
83
|
+
|
|
84
|
+
def _conclude(self):
|
|
85
|
+
if self.frame_count > 0:
|
|
86
|
+
average_dipole = self.dipole_distribution / self.o_count
|
|
87
|
+
water_density = (self.o_count * (15.999+1.0008*2) * 1.660539 / (self.u.dimensions[0] * self.u.dimensions[1] * self.bin_size)) / self.frame_count
|
|
88
|
+
average_dipole = average_dipole * water_density
|
|
89
|
+
bins_z = np.arange(len(average_dipole)) * self.bin_size + self.bin_size / 2
|
|
90
|
+
|
|
91
|
+
if self.surface:
|
|
92
|
+
lower_z = self.surface_pos[0] / self.frame_count
|
|
93
|
+
if self.surface_pos[1] == 0:
|
|
94
|
+
upper_z = np.inf
|
|
95
|
+
else:
|
|
96
|
+
upper_z = self.surface_pos[1] / self.frame_count
|
|
97
|
+
|
|
98
|
+
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
99
|
+
filtered_bins_z = bins_z[mask] - lower_z
|
|
100
|
+
filtered_dipole_distribution = average_dipole[mask]
|
|
101
|
+
|
|
102
|
+
conbined_data = np.column_stack((filtered_bins_z, filtered_dipole_distribution))
|
|
103
|
+
else:
|
|
104
|
+
conbined_data = np.column_stack((bins_z, average_dipole))
|
|
105
|
+
|
|
106
|
+
np.savetxt("dipole_distribution.dat", conbined_data, header="z\tDipole Z Positions\tWater Density", fmt='%.5f', delimiter='\t')
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@click.command(name="dipole")
|
|
110
|
+
@common_setting
|
|
111
|
+
def main(filename, cell, update_water, distance, angle, surface, r):
|
|
112
|
+
"""analysis dipole along z-axis"""
|
|
113
|
+
a = Dipole_distribution(filename, cell, update_water, distance_judg=distance, angle_judg=angle, surface=surface)
|
|
114
|
+
if r is not None:
|
|
115
|
+
if len(r) == 2:
|
|
116
|
+
a.run(start=r[0], stop=r[1])
|
|
117
|
+
elif len(r) == 3:
|
|
118
|
+
a.run(start=r[0], stop=r[1], step=r[2])
|
|
119
|
+
else:
|
|
120
|
+
a.run()
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
if __name__ == "__main__":
|
|
124
|
+
main()
|
|
@@ -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 numpy_geo, encapsulated_mda
|
|
9
|
+
import warnings, sys
|
|
10
|
+
from .setting import common_setting
|
|
11
|
+
warnings.filterwarnings("ignore")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Hb_distribution(AnalysisBase):
|
|
15
|
+
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):
|
|
16
|
+
u = Universe(filename)
|
|
17
|
+
u.trajectory.ts.dt = dt
|
|
18
|
+
u.dimensions = cell
|
|
19
|
+
self.u = u
|
|
20
|
+
self.atomgroup = u.select_atoms("all")
|
|
21
|
+
self.hb_distance = hb_distance
|
|
22
|
+
self.hb_angle = hb_angle
|
|
23
|
+
self.bin_size = bin_size
|
|
24
|
+
self.surface = surface
|
|
25
|
+
self.update_water = update_water
|
|
26
|
+
self.frame_count = 0
|
|
27
|
+
np.set_printoptions(threshold=np.inf)
|
|
28
|
+
|
|
29
|
+
if surface is not None:
|
|
30
|
+
self.surface_group = self.atomgroup.select_atoms(f"{surface}")
|
|
31
|
+
if self.surface_group.n_atoms == 0:
|
|
32
|
+
sys.exit("Please specify the correct surface group")
|
|
33
|
+
else:
|
|
34
|
+
self.surface_group = False
|
|
35
|
+
|
|
36
|
+
if self.update_water:
|
|
37
|
+
self.distance_judg = distance_judg
|
|
38
|
+
self.angle_judg = angle_judg
|
|
39
|
+
|
|
40
|
+
if index is not None:
|
|
41
|
+
self.index = index
|
|
42
|
+
self.hb_d_index = 0
|
|
43
|
+
self.hb_a_index = 0
|
|
44
|
+
else:
|
|
45
|
+
self.index = None
|
|
46
|
+
|
|
47
|
+
super(Hb_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
|
|
48
|
+
|
|
49
|
+
def _prepare(self):
|
|
50
|
+
bin_num = int(self.u.dimensions[2] / self.bin_size) + 2
|
|
51
|
+
self.accepter = np.zeros(bin_num, dtype=np.float64)
|
|
52
|
+
self.donor = np.zeros(bin_num, dtype=np.float64)
|
|
53
|
+
self.od = np.zeros(bin_num, dtype=np.float64)
|
|
54
|
+
if self.surface_group:
|
|
55
|
+
self.surface_pos = np.zeros(2)
|
|
56
|
+
|
|
57
|
+
def _append(self, hb_d, hb_a, o):
|
|
58
|
+
bins_d = np.floor(hb_d / self.bin_size).astype(int) + 1
|
|
59
|
+
bins_a = np.floor(hb_a / self.bin_size).astype(int) + 1
|
|
60
|
+
bins_o = np.floor(o / self.bin_size).astype(int) + 1
|
|
61
|
+
|
|
62
|
+
bins_d = bins_d[bins_d < len(self.donor)]
|
|
63
|
+
bins_a = bins_a[bins_a < len(self.accepter)]
|
|
64
|
+
bins_o = bins_o[bins_o < len(self.od)]
|
|
65
|
+
|
|
66
|
+
np.add.at(self.donor, bins_d, 1)
|
|
67
|
+
np.add.at(self.accepter, bins_a, 1)
|
|
68
|
+
np.add.at(self.od, bins_o, 1)
|
|
69
|
+
|
|
70
|
+
def _single_frame(self):
|
|
71
|
+
if self.update_water:
|
|
72
|
+
o = self.atomgroup.select_atoms("name O")
|
|
73
|
+
h = self.atomgroup.select_atoms("name H")
|
|
74
|
+
|
|
75
|
+
o_group, oh1, oh2 = encapsulated_mda.update_water(self, o, h, distance_judg=self.distance_judg, angle_judg=self.angle_judg, return_index=False)
|
|
76
|
+
|
|
77
|
+
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)
|
|
78
|
+
|
|
79
|
+
o0 = o_group[o_pair[:, 0]]
|
|
80
|
+
o1 = o_group[o_pair[:, 1]]
|
|
81
|
+
|
|
82
|
+
o0h1 = oh1[o_pair[:, 0]]
|
|
83
|
+
o0h2 = oh2[o_pair[:, 0]]
|
|
84
|
+
o1h1 = oh1[o_pair[:, 1]]
|
|
85
|
+
o1h2 = oh2[o_pair[:, 1]]
|
|
86
|
+
else:
|
|
87
|
+
o_group = self.atomgroup.select_atoms("name O")
|
|
88
|
+
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)
|
|
89
|
+
|
|
90
|
+
o0 = o_group[o_pair[:, 0]]
|
|
91
|
+
o1 = o_group[o_pair[:, 1]]
|
|
92
|
+
|
|
93
|
+
o0h1 = self.atomgroup[o0.indices + 1]
|
|
94
|
+
o0h2 = self.atomgroup[o0.indices + 2]
|
|
95
|
+
o1h1 = self.atomgroup[o1.indices + 1]
|
|
96
|
+
o1h2 = self.atomgroup[o1.indices + 2]
|
|
97
|
+
|
|
98
|
+
angle_o0h1_o0_o1 = np.degrees(
|
|
99
|
+
MDAnalysis.lib.distances.calc_angles(o0h1.positions, o0.positions, o1.positions, box=self.u.dimensions)
|
|
100
|
+
)
|
|
101
|
+
angle_o0h2_o0_o1 = np.degrees(
|
|
102
|
+
MDAnalysis.lib.distances.calc_angles(o0h2.positions, o0.positions, o1.positions, box=self.u.dimensions)
|
|
103
|
+
)
|
|
104
|
+
angle_o1h1_o1_o0 = np.degrees(
|
|
105
|
+
MDAnalysis.lib.distances.calc_angles(o1h1.positions, o1.positions, o0.positions, box=self.u.dimensions)
|
|
106
|
+
)
|
|
107
|
+
angle_o1h2_o1_o0 = np.degrees(
|
|
108
|
+
MDAnalysis.lib.distances.calc_angles(o1h2.positions, o1.positions, o0.positions, box=self.u.dimensions)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
condition_d = (angle_o0h1_o0_o1 < self.hb_angle) | (angle_o0h2_o0_o1 < self.hb_angle)
|
|
112
|
+
condition_a = (angle_o1h1_o1_o0 < self.hb_angle) | (angle_o1h2_o1_o0 < self.hb_angle)
|
|
113
|
+
|
|
114
|
+
if self.index is not None:
|
|
115
|
+
self.hb_d_index += o0.positions[:, 2][condition_d & (o0.indices == self.index)].shape[0]
|
|
116
|
+
self.hb_a_index += o0.positions[:, 2][condition_a & (o0.indices == self.index)].shape[0]
|
|
117
|
+
else:
|
|
118
|
+
hb_d = o0.positions[:, 2][condition_d]
|
|
119
|
+
hb_a = o0.positions[:, 2][condition_a]
|
|
120
|
+
|
|
121
|
+
self._append(hb_d, hb_a, o_group.positions[:, 2])
|
|
122
|
+
|
|
123
|
+
if self.surface_group:
|
|
124
|
+
surface = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
125
|
+
self.surface_pos[0] += surface[0]
|
|
126
|
+
self.surface_pos[1] += surface[1]
|
|
127
|
+
|
|
128
|
+
self.frame_count += 1
|
|
129
|
+
|
|
130
|
+
def _conclude(self):
|
|
131
|
+
if self.frame_count > 0 and self.index is None:
|
|
132
|
+
average_od = self.od / self.frame_count
|
|
133
|
+
average_donor = np.nan_to_num((self.donor / self.frame_count) / average_od, nan=0)
|
|
134
|
+
average_accepter = np.nan_to_num((self.accepter / self.frame_count) / average_od, nan=0)
|
|
135
|
+
average_sum = average_donor + average_accepter
|
|
136
|
+
|
|
137
|
+
bins_z = np.arange(len(self.donor)) * self.bin_size + self.bin_size / 2
|
|
138
|
+
|
|
139
|
+
if self.surface:
|
|
140
|
+
lower_z = self.surface_pos[0] / self.frame_count
|
|
141
|
+
if self.surface_pos[1] == 0:
|
|
142
|
+
upper_z = np.inf
|
|
143
|
+
else:
|
|
144
|
+
upper_z = self.surface_pos[1] / self.frame_count
|
|
145
|
+
|
|
146
|
+
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
147
|
+
filtered_bins_z = bins_z[mask] - lower_z
|
|
148
|
+
filtered_average_accepter = average_accepter[mask]
|
|
149
|
+
filtered_average_donor = average_donor[mask]
|
|
150
|
+
filtered_average_sum = average_sum[mask]
|
|
151
|
+
|
|
152
|
+
combined_data = np.column_stack((filtered_bins_z, filtered_average_accepter, filtered_average_donor, filtered_average_sum))
|
|
153
|
+
else:
|
|
154
|
+
combined_data = np.column_stack((bins_z, average_accepter, average_donor, average_sum))
|
|
155
|
+
|
|
156
|
+
np.savetxt("hb_distribution.dat", combined_data, header="Z\tAccepter\tDonor\tAccepter+Donor", fmt='%.5f', delimiter='\t')
|
|
157
|
+
|
|
158
|
+
if self.index is not None and self.frame_count > 0:
|
|
159
|
+
self.hb_d_index /= self.frame_count
|
|
160
|
+
self.hb_a_index /= self.frame_count
|
|
161
|
+
output = f"# {self.index}\naccepter : {self.hb_a_index}\ndonor : {self.hb_d_index}\ntotal : {self.hb_a_index + self.hb_d_index}"
|
|
162
|
+
with open(f"hb_{self.index}.dat", "a") as f:
|
|
163
|
+
f.write(output)
|
|
164
|
+
print(output)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@click.command(name="hb", help="analysis hydrogen bond distribution along z-axis")
|
|
168
|
+
@common_setting
|
|
169
|
+
@click.option('--hb_param', type=click.Tuple([float, float]), help='parameter for hydrogen bond', default=(3.5, 35), show_default=True)
|
|
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()
|
mdkits/md_cli/md_cli.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from mdkits.md_cli import (
|
|
3
|
+
wrap,
|
|
4
|
+
dipole,
|
|
5
|
+
angle,
|
|
6
|
+
density,
|
|
7
|
+
hb_distribution,
|
|
8
|
+
vac,
|
|
9
|
+
rdf,
|
|
10
|
+
msd,
|
|
11
|
+
monitor,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@click.group(name='md')
|
|
16
|
+
@click.pass_context
|
|
17
|
+
def cli(ctx):
|
|
18
|
+
"""kits for MD analysis"""
|
|
19
|
+
|
|
20
|
+
cli.add_command(wrap.main)
|
|
21
|
+
cli.add_command(density.main)
|
|
22
|
+
cli.add_command(dipole.main)
|
|
23
|
+
cli.add_command(angle.main)
|
|
24
|
+
cli.add_command(hb_distribution.main)
|
|
25
|
+
cli.add_command(vac.main)
|
|
26
|
+
cli.add_command(rdf.main)
|
|
27
|
+
cli.add_command(msd.main)
|
|
28
|
+
cli.add_command(monitor.main)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == '__main__':
|
|
32
|
+
cli()
|
mdkits/md_cli/monitor.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from .setting import common_setting
|
|
3
|
+
import MDAnalysis
|
|
4
|
+
from MDAnalysis import Universe
|
|
5
|
+
from MDAnalysis.analysis.base import AnalysisBase
|
|
6
|
+
from mdkits.util import arg_type, numpy_geo
|
|
7
|
+
import numpy as np
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Monitor(AnalysisBase):
|
|
12
|
+
def __init__(self, filename, cell, index, surface, dt=0.001):
|
|
13
|
+
u = Universe(filename)
|
|
14
|
+
u.trajectory.ts.dt = dt
|
|
15
|
+
u.dimensions = cell
|
|
16
|
+
|
|
17
|
+
self.u = u
|
|
18
|
+
self.atomgroup = self.u.select_atoms("all")
|
|
19
|
+
self.surface = surface
|
|
20
|
+
|
|
21
|
+
if index is None:
|
|
22
|
+
sys.exit("Please specify at least one atom to monitor")
|
|
23
|
+
else:
|
|
24
|
+
self.index = index
|
|
25
|
+
self.group = " or ".join([ f"index {i}" for i in self.index ])
|
|
26
|
+
|
|
27
|
+
if surface is not None:
|
|
28
|
+
self.surface_group = self.atomgroup.select_atoms(f"{surface}")
|
|
29
|
+
if self.surface_group.n_atoms == 0:
|
|
30
|
+
sys.exit("Please specify the correct surface group")
|
|
31
|
+
else:
|
|
32
|
+
self.surface_group = False
|
|
33
|
+
|
|
34
|
+
super(Monitor, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
|
|
35
|
+
|
|
36
|
+
def _prepare(self):
|
|
37
|
+
self.height = []
|
|
38
|
+
if len(self.index) == 2:
|
|
39
|
+
self.distance = []
|
|
40
|
+
elif len(self.index) == 3:
|
|
41
|
+
self.distance = []
|
|
42
|
+
self.angle = []
|
|
43
|
+
|
|
44
|
+
def _single_frame(self):
|
|
45
|
+
if self.surface_group:
|
|
46
|
+
surface = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
47
|
+
else:
|
|
48
|
+
surface = [0]
|
|
49
|
+
|
|
50
|
+
self.height.append(self.atomgroup.select_atoms(self.group).positions[:, 2] - surface[0])
|
|
51
|
+
|
|
52
|
+
if len(self.index) == 2:
|
|
53
|
+
vec = MDAnalysis.lib.distances.minimize_vectors(self.atomgroup[self.index[0]].position - self.atomgroup[self.index[1]].position, self.u.dimensions)
|
|
54
|
+
|
|
55
|
+
self.distance.append(np.linalg.norm(vec))
|
|
56
|
+
|
|
57
|
+
if len(self.index) == 3:
|
|
58
|
+
vec1 = MDAnalysis.lib.distances.minimize_vectors(self.atomgroup[self.index[0]].position - self.atomgroup[self.index[1]].position, self.u.dimensions)
|
|
59
|
+
vec2 = MDAnalysis.lib.distances.minimize_vectors(self.atomgroup[self.index[2]].position - self.atomgroup[self.index[1]].position, self.u.dimensions)
|
|
60
|
+
|
|
61
|
+
self.distance.append(np.array([np.linalg.norm(vec1), np.linalg.norm(vec2)]))
|
|
62
|
+
self.angle.append(numpy_geo.vector_vector_angle(vec1, vec2))
|
|
63
|
+
|
|
64
|
+
def _conclude(self):
|
|
65
|
+
frame_count = np.arange(self.u.trajectory.n_frames).reshape(-1, 1)
|
|
66
|
+
|
|
67
|
+
self.height = np.vstack(self.height)
|
|
68
|
+
|
|
69
|
+
np.savetxt("monitor.dat", np.hstack((frame_count, self.height)), fmt="%.5f", header=f"frame\t{' '.join(self.atomgroup.select_atoms(self.group).names)}")
|
|
70
|
+
|
|
71
|
+
if len(self.index) == 2:
|
|
72
|
+
self.distance = np.vstack(self.distance)
|
|
73
|
+
|
|
74
|
+
np.savetxt("monitor.dat", np.hstack((frame_count, self.height, self.distance)), fmt="%.5f", header=f"frame\t\t{' '.join(self.atomgroup.select_atoms(self.group).names)}\t{self.atomgroup.names[self.index[0]]}-{self.atomgroup.names[self.index[1]]}")
|
|
75
|
+
elif len(self.index) == 3:
|
|
76
|
+
self.distance = np.vstack(self.distance)
|
|
77
|
+
self.angle = np.vstack(self.angle)
|
|
78
|
+
|
|
79
|
+
np.savetxt("monitor.dat", np.hstack((frame_count, self.height, self.distance, self.angle)), fmt="%.5f", header=f"frame\t\t{' '.join(self.atomgroup.select_atoms(self.group).names)}\t{self.atomgroup.names[self.index[0]]}-{self.atomgroup.names[self.index[1]]}\t{self.atomgroup.names[self.index[2]]}-{self.atomgroup.names[self.index[1]]}\t{self.atomgroup.names[self.index[0]]}-{self.atomgroup.names[self.index[1]]}-{self.atomgroup.names[self.index[2]]}")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@click.command(name="monitor")
|
|
83
|
+
@click.argument("filename", type=click.Path(exists=True))
|
|
84
|
+
@click.option("--index", "-i", type=int, help="index of atom to monitor", multiple=True)
|
|
85
|
+
@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")
|
|
86
|
+
@click.option("--surface", type=str, help="surface group")
|
|
87
|
+
@click.option('-r', type=arg_type.FrameRange, help='range of frame to analysis')
|
|
88
|
+
def main(filename, cell, index, surface, r):
|
|
89
|
+
"""
|
|
90
|
+
monitor the property of between atoms
|
|
91
|
+
"""
|
|
92
|
+
a = Monitor(filename, cell, index, surface)
|
|
93
|
+
if r is not None:
|
|
94
|
+
if len(r) == 2:
|
|
95
|
+
a.run(start=r[0], stop=r[1])
|
|
96
|
+
elif len(r) == 3:
|
|
97
|
+
a.run(start=r[0], stop=r[1], step=r[2])
|
|
98
|
+
else:
|
|
99
|
+
a.run()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
main()
|
mdkits/md_cli/msd.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import MDAnalysis as mda
|
|
3
|
+
import MDAnalysis.analysis.msd as msd
|
|
4
|
+
import numpy as np
|
|
5
|
+
from mdkits.util import arg_type
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.command(name="msd")
|
|
9
|
+
@click.argument("filename", type=click.Path(exists=True))
|
|
10
|
+
@click.argument('type', type=click.Choice(['xyz', 'xy', 'yz', 'xz', 'x', 'y', 'z']))
|
|
11
|
+
@click.argument("group", type=str)
|
|
12
|
+
@click.option('-r', type=arg_type.FrameRange, help='range of frame to analysis')
|
|
13
|
+
def main(filename, type, group, r):
|
|
14
|
+
"""analysis msd along the given axis"""
|
|
15
|
+
u = mda.Universe(filename)
|
|
16
|
+
MSD = msd.EinsteinMSD(u, select=group, msd_type=type, fft=True)
|
|
17
|
+
if r is not None:
|
|
18
|
+
if len(r) == 2:
|
|
19
|
+
MSD.run(start=r[0], stop=r[1], verbose=True)
|
|
20
|
+
elif len(r) == 3:
|
|
21
|
+
MSD.run(start=r[0], stop=r[1], step=r[2], verbose=True)
|
|
22
|
+
else:
|
|
23
|
+
MSD.run(verbose=True)
|
|
24
|
+
|
|
25
|
+
data = np.arange(1, MSD.n_frames + 1).reshape(-1, 1)
|
|
26
|
+
s = "_"
|
|
27
|
+
name = f"{s.join(group.split(' '))}"
|
|
28
|
+
o = f"msd_{type}_{name}.dat"
|
|
29
|
+
header = ''
|
|
30
|
+
msd_cols = []
|
|
31
|
+
for i in range(MSD.n_particles):
|
|
32
|
+
msd_cols.append(MSD.results.msds_by_particle[:, i].reshape(-1, 1))
|
|
33
|
+
header += name + f"_{i}\t"
|
|
34
|
+
msd_array = np.concatenate(msd_cols, axis=1)
|
|
35
|
+
mean_col = np.mean(msd_array, axis=1, keepdims=True)
|
|
36
|
+
data = np.concatenate((data, mean_col, msd_array), axis=1)
|
|
37
|
+
header = "frame\tmean\t" + header
|
|
38
|
+
|
|
39
|
+
np.savetxt(o, data, fmt="%.5f", delimiter="\t", header=header)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == '__main__':
|
|
44
|
+
main()
|
mdkits/md_cli/rdf.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import MDAnalysis as mda
|
|
2
|
+
from MDAnalysis.analysis import rdf
|
|
3
|
+
import numpy as np
|
|
4
|
+
import click
|
|
5
|
+
from scipy import integrate
|
|
6
|
+
from mdkits.util import arg_type
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def calculate_Gab(r_values, gab_values):
|
|
10
|
+
dr = r_values[1] - r_values[0]
|
|
11
|
+
|
|
12
|
+
integrand = 4 * np.pi * r_values**2 * gab_values
|
|
13
|
+
|
|
14
|
+
G_ab = np.cumsum(integrand) * dr
|
|
15
|
+
|
|
16
|
+
return G_ab
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@click.command(name="rdf")
|
|
20
|
+
@click.argument("filename", type=click.Path(exists=True))
|
|
21
|
+
@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')
|
|
22
|
+
@click.option("--group", type=click.Tuple([str, str]), help="two group to analysis")
|
|
23
|
+
@click.option('--range', type=click.Tuple([float, float]), help="the range of rdf")
|
|
24
|
+
@click.option('-r', type=arg_type.FrameRange, help='range of frame to analysis')
|
|
25
|
+
def main(filename, cell, group, range, r):
|
|
26
|
+
"""analysis the radial distribution function"""
|
|
27
|
+
u = mda.Universe(filename)
|
|
28
|
+
u.trajectory.ts.dt = 0.0001
|
|
29
|
+
u.dimensions = cell
|
|
30
|
+
o = f"rdf_{'_'.join(group).replace(' ', '_')}.dat"
|
|
31
|
+
|
|
32
|
+
rho = 32/(9.86**3)
|
|
33
|
+
|
|
34
|
+
group1 = u.select_atoms(group[0])
|
|
35
|
+
group2 = u.select_atoms(group[1])
|
|
36
|
+
|
|
37
|
+
crdf = rdf.InterRDF(group1, group2, verbose=True, range=(range[0], range[1]), norm='rdf')
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if r is not None:
|
|
41
|
+
if len(r) == 2:
|
|
42
|
+
crdf.run(start=r[0], stop=r[1])
|
|
43
|
+
elif len(r) == 3:
|
|
44
|
+
crdf.run(start=r[0], stop=r[1], step=r[2])
|
|
45
|
+
else:
|
|
46
|
+
crdf.run()
|
|
47
|
+
|
|
48
|
+
combin = np.column_stack((crdf.results.bins, crdf.results.rdf, calculate_Gab(crdf.results.bins, crdf.results.rdf)*rho))
|
|
49
|
+
np.savetxt(o, combin, header="A\tgr\tNr", fmt="%.5f", delimiter='\t')
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
main()
|
mdkits/md_cli/setting.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from mdkits.util import arg_type, os_operation
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def common_setting(f):
|
|
6
|
+
f = click.argument('filename', type=click.Path(exists=True), default=os_operation.default_file_name('*-pos-1.xyz', last=True))(f)
|
|
7
|
+
f = click.option('-r', type=arg_type.FrameRange, help='range of frame to analysis')(f)
|
|
8
|
+
f = click.option('--angle', type=(float, float), help='update water angle judgment')(f)
|
|
9
|
+
f = click.option('--distance', type=float, help='update water distance judgment', default=1.2, show_default=True)(f)
|
|
10
|
+
f = click.option('--update_water', is_flag=True, help='update water with distance or angle judgment')(f)
|
|
11
|
+
f = click.option("--surface", type=str, help="surface group")(f)
|
|
12
|
+
f = 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")(f)
|
|
13
|
+
|
|
14
|
+
return f
|