mdkits 0.1.29__py3-none-any.whl → 0.2.0__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.
Potentially problematic release.
This version of mdkits might be problematic. Click here for more details.
- mdkits/build_cli/adsorbate.py +1 -0
- mdkits/build_cli/build_surface.py +1 -4
- mdkits/cli/extract.py +27 -16
- mdkits/md_cli/angle.py +3 -8
- mdkits/md_cli/density.py +10 -12
- mdkits/md_cli/dipole.py +120 -0
- mdkits/md_cli/hb_distribution.py +14 -15
- mdkits/md_cli/md_cli.py +18 -7
- mdkits/md_cli/monitor.py +104 -0
- mdkits/md_cli/msd.py +30 -0
- mdkits/md_cli/rdf.py +53 -0
- mdkits/md_cli/setting.py +14 -0
- mdkits/md_cli/vac.py +68 -0
- mdkits/{cli → md_cli}/wrap.py +1 -1
- mdkits/mdkits.py +2 -4
- mdkits/util/arg_type.py +2 -2
- mdkits/util/numpy_geo.py +4 -1
- {mdkits-0.1.29.dist-info → mdkits-0.2.0.dist-info}/METADATA +122 -26
- {mdkits-0.1.29.dist-info → mdkits-0.2.0.dist-info}/RECORD +22 -21
- 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/packmol_input.py +0 -76
- {mdkits-0.1.29.dist-info → mdkits-0.2.0.dist-info}/LICENSE +0 -0
- {mdkits-0.1.29.dist-info → mdkits-0.2.0.dist-info}/WHEEL +0 -0
- {mdkits-0.1.29.dist-info → mdkits-0.2.0.dist-info}/entry_points.txt +0 -0
mdkits/build_cli/adsorbate.py
CHANGED
|
@@ -18,6 +18,7 @@ from mdkits.util import arg_type, encapsulated_ase, out_err
|
|
|
18
18
|
@click.option('--offset', type=click.Tuple([float, float]), help='adjust site', default=(0, 0), show_default=True)
|
|
19
19
|
@click.option("--cover", type=int, help='cover the surface with adsorbate randomly')
|
|
20
20
|
def main(atoms, adsorbate, cell, select, height, rotate, offset, cover):
|
|
21
|
+
"""add adsorbate molcule to the surface"""
|
|
21
22
|
if height is None:
|
|
22
23
|
raise ValueError("height is required")
|
|
23
24
|
|
|
@@ -22,10 +22,7 @@ def surface_check(obj, surface_type):
|
|
|
22
22
|
@click.option('--orth', is_flag=True, help='if specified and true, forces the creation of a unit cell with orthogonal basis vectors. if the default is such a unit cell, this argument is not supported')
|
|
23
23
|
@click.option('--vacuum', type=float, help='designate vacuum of surface, default is None', default=0.1, show_default=True)
|
|
24
24
|
def main(symbol, surface, size, kind, a, c, thickness, orth, vacuum):
|
|
25
|
-
|
|
26
|
-
# a = args.a * 0.7071 * 2
|
|
27
|
-
#else:
|
|
28
|
-
# a = args.a
|
|
25
|
+
"""build a common surface"""
|
|
29
26
|
|
|
30
27
|
vacuum = vacuum / 2
|
|
31
28
|
build_surface = surface_check(build, surface)
|
mdkits/cli/extract.py
CHANGED
|
@@ -9,11 +9,12 @@ import MDAnalysis
|
|
|
9
9
|
from MDAnalysis import Universe
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def write_to_xyz(u, frames, o, cut=None):
|
|
13
|
-
|
|
12
|
+
def write_to_xyz(u, frames, o, select, cut=None):
|
|
13
|
+
ag = u.select_atoms(select)
|
|
14
|
+
with MDAnalysis.Writer(o, ag.atoms.n_atoms, format='XYZ') as w:
|
|
14
15
|
for ts in u.trajectory:
|
|
15
16
|
if ts.frame in frames:
|
|
16
|
-
w.write(
|
|
17
|
+
w.write(ag)
|
|
17
18
|
if cut:
|
|
18
19
|
with open(o, 'r') as fi, open(o+'t', 'w') as fo:
|
|
19
20
|
for i, line in enumerate(fi):
|
|
@@ -22,13 +23,18 @@ def write_to_xyz(u, frames, o, cut=None):
|
|
|
22
23
|
os.replace(o+'t', o)
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
def write_to_xyz_s(u, frames, cut=None):
|
|
26
|
+
def write_to_xyz_s(u, frames, select, cut=None):
|
|
26
27
|
index = 0
|
|
28
|
+
ag = u.select_atoms(select)
|
|
29
|
+
if select:
|
|
30
|
+
dir = f'./coord/{"_".join(select.split())}'
|
|
31
|
+
else:
|
|
32
|
+
dir = './coord/all'
|
|
27
33
|
for ts in u.trajectory:
|
|
28
34
|
if ts.frame in frames:
|
|
29
|
-
o = f'
|
|
30
|
-
with MDAnalysis.Writer(o,
|
|
31
|
-
w.write(
|
|
35
|
+
o = f'{dir}/coord_{index:03d}'
|
|
36
|
+
with MDAnalysis.Writer(o, ag.atoms.n_atoms, format='XYZ') as w:
|
|
37
|
+
w.write(ag)
|
|
32
38
|
index += 1
|
|
33
39
|
if cut:
|
|
34
40
|
with open(o, 'r') as fi, open(o+'t', 'w') as fo:
|
|
@@ -39,10 +45,10 @@ def write_to_xyz_s(u, frames, cut=None):
|
|
|
39
45
|
|
|
40
46
|
@click.command(name='extract')
|
|
41
47
|
@click.argument('input_file_name', type=click.Path(exists=True), default=os_operation.default_file_name('*-pos-1.xyz', last=True))
|
|
42
|
-
@click.option('-o', type=str, help='output file name', default='extracted.xyz', show_default=True)
|
|
43
48
|
@click.option('-r', type=arg_type.FrameRange, help='frame range to slice', default='-1', show_default=True)
|
|
44
49
|
@click.option('-c', help='output a coord.xyz', is_flag=True)
|
|
45
|
-
|
|
50
|
+
@click.option("--select", type=str, help="select atoms to extract")
|
|
51
|
+
def main(input_file_name, r, c, select):
|
|
46
52
|
"""
|
|
47
53
|
extract frames in trajectory file
|
|
48
54
|
"""
|
|
@@ -63,16 +69,21 @@ def main(input_file_name, o, r, c):
|
|
|
63
69
|
cut = None
|
|
64
70
|
|
|
65
71
|
if len(r) == 3 and r[-1] is not None:
|
|
66
|
-
if
|
|
67
|
-
|
|
72
|
+
if select:
|
|
73
|
+
dir = f'./coord/{"_".join(select.split())}'
|
|
74
|
+
else:
|
|
75
|
+
dir = './coord/all'
|
|
76
|
+
if not os.path.exists(dir):
|
|
77
|
+
os.makedirs(dir)
|
|
68
78
|
else:
|
|
69
79
|
import shutil
|
|
70
|
-
shutil.rmtree(
|
|
71
|
-
os.makedirs(
|
|
72
|
-
write_to_xyz_s(u, frames, cut=cut)
|
|
73
|
-
click.echo(os.path.abspath(
|
|
80
|
+
shutil.rmtree(dir)
|
|
81
|
+
os.makedirs(dir)
|
|
82
|
+
write_to_xyz_s(u, frames, select, cut=cut)
|
|
83
|
+
click.echo(os.path.abspath(dir))
|
|
74
84
|
else:
|
|
75
|
-
|
|
85
|
+
o = f"{os.path.basename(u.filename).split('.')[0]}_{'_'.join([str(i) for i in r])}_{'_'.join(select.split()) if select else 'all'}.xyz"
|
|
86
|
+
write_to_xyz(u, frames, o, select, cut=cut)
|
|
76
87
|
click.echo(os.path.abspath(o))
|
|
77
88
|
|
|
78
89
|
|
mdkits/md_cli/angle.py
CHANGED
|
@@ -5,6 +5,7 @@ import MDAnalysis
|
|
|
5
5
|
import sys
|
|
6
6
|
from mdkits.util import numpy_geo, encapsulated_mda, arg_type
|
|
7
7
|
import numpy as np
|
|
8
|
+
from .setting import common_setting
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class Angle_distribution(AnalysisBase):
|
|
@@ -102,15 +103,9 @@ class Angle_distribution(AnalysisBase):
|
|
|
102
103
|
np.savetxt("angle_distribution.dat", conbined_data, header="angle\tw_suf_dist\toh_suf_dist", fmt='%.5f', delimiter='\t')
|
|
103
104
|
|
|
104
105
|
|
|
105
|
-
@click.command(name="angle")
|
|
106
|
-
@
|
|
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")
|
|
106
|
+
@click.command(name="angle", help="analysis angle between normal vectors and OH vector or bisector")
|
|
107
|
+
@common_setting
|
|
108
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
109
|
def main(filename, cell, water_height, update_water, distance, angle, surface, r):
|
|
115
110
|
"""analysis angle between normal vectors and OH vector or bisector"""
|
|
116
111
|
a = Angle_distribution(filename, cell, water_height, update_water, distance_judg=distance, angle_judg=angle, surface=surface)
|
mdkits/md_cli/density.py
CHANGED
|
@@ -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
|
|
|
@@ -79,9 +80,10 @@ class Density_distribution(AnalysisBase):
|
|
|
79
80
|
self._append(group.positions[:, 2])
|
|
80
81
|
|
|
81
82
|
if self.surface_group:
|
|
82
|
-
|
|
83
|
-
self.surface_pos[0] +=
|
|
84
|
-
|
|
83
|
+
surface = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
84
|
+
self.surface_pos[0] += surface[0]
|
|
85
|
+
if len(surface) > 1:
|
|
86
|
+
self.surface_pos[1] += surface[1]
|
|
85
87
|
|
|
86
88
|
self.frame_count += 1
|
|
87
89
|
|
|
@@ -98,7 +100,8 @@ class Density_distribution(AnalysisBase):
|
|
|
98
100
|
|
|
99
101
|
if self.surface:
|
|
100
102
|
lower_z = self.surface_pos[0] / self.frame_count
|
|
101
|
-
|
|
103
|
+
if self.surface_pos[1] == 0:
|
|
104
|
+
upper_z = np.inf
|
|
102
105
|
|
|
103
106
|
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
104
107
|
filtered_bins_z = bins_z[mask] - lower_z
|
|
@@ -110,16 +113,11 @@ class Density_distribution(AnalysisBase):
|
|
|
110
113
|
|
|
111
114
|
np.savetxt(self.o, conbined_data, header="Z\tdensity", fmt='%.5f', delimiter='\t')
|
|
112
115
|
|
|
113
|
-
@click.command(name='density')
|
|
114
|
-
@
|
|
115
|
-
@click.option('--
|
|
116
|
-
@click.option('--element', type=str, help='element to analysis')
|
|
116
|
+
@click.command(name='density', help="analysis density or concentration of element in a trajectory file")
|
|
117
|
+
@common_setting
|
|
118
|
+
@click.option('--group', type=str, help='group to analysis')
|
|
117
119
|
@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
120
|
@click.option('-o', type=str, help='output file name', default='density_{element}.dat', show_default=True)
|
|
119
|
-
@click.option('--update_water', is_flag=True, help='update water with distance or angle judgment')
|
|
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
121
|
def main(filename, cell, o, element, atomic_mass, update_water, distance, angle, surface):
|
|
124
122
|
"""
|
|
125
123
|
analysis density or concentration of element in a trajectory file
|
mdkits/md_cli/dipole.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
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
|
|
90
|
+
|
|
91
|
+
if self.surface:
|
|
92
|
+
lower_z, upper_z = self.surface_pos / self.frame_count
|
|
93
|
+
|
|
94
|
+
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
95
|
+
filtered_bins_z = bins_z[mask] - lower_z
|
|
96
|
+
filtered_dipole_distribution = average_dipole[mask]
|
|
97
|
+
|
|
98
|
+
conbined_data = np.column_stack((filtered_bins_z, filtered_dipole_distribution))
|
|
99
|
+
else:
|
|
100
|
+
conbined_data = np.column_stack((bins_z, average_dipole))
|
|
101
|
+
|
|
102
|
+
np.savetxt("dipole_distribution.dat", conbined_data, header="z\tDipole Z Positions\tWater Density", fmt='%.5f', delimiter='\t')
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@click.command(name="dipole")
|
|
106
|
+
@common_setting
|
|
107
|
+
def main(filename, cell, update_water, distance, angle, surface, r):
|
|
108
|
+
"""analysis dipole along z-axis"""
|
|
109
|
+
a = Dipole_distribution(filename, cell, update_water, distance_judg=distance, angle_judg=angle, surface=surface)
|
|
110
|
+
if r is not None:
|
|
111
|
+
if len(r) == 2:
|
|
112
|
+
a.run(start=r[0], stop=r[1])
|
|
113
|
+
elif len(r) == 3:
|
|
114
|
+
a.run(start=r[0], stop=r[1], step=r[2])
|
|
115
|
+
else:
|
|
116
|
+
a.run()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
if __name__ == "__main__":
|
|
120
|
+
main()
|
mdkits/md_cli/hb_distribution.py
CHANGED
|
@@ -5,8 +5,9 @@ import click
|
|
|
5
5
|
import MDAnalysis
|
|
6
6
|
from MDAnalysis import Universe
|
|
7
7
|
from MDAnalysis.analysis.base import AnalysisBase
|
|
8
|
-
from mdkits.util import
|
|
8
|
+
from mdkits.util import numpy_geo, encapsulated_mda
|
|
9
9
|
import warnings, sys
|
|
10
|
+
from .setting import common_setting
|
|
10
11
|
warnings.filterwarnings("ignore")
|
|
11
12
|
|
|
12
13
|
|
|
@@ -120,23 +121,27 @@ class Hb_distribution(AnalysisBase):
|
|
|
120
121
|
self._append(hb_d, hb_a, o_group.positions[:, 2])
|
|
121
122
|
|
|
122
123
|
if self.surface_group:
|
|
123
|
-
|
|
124
|
-
self.surface_pos[0] +=
|
|
125
|
-
|
|
124
|
+
surface = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
125
|
+
self.surface_pos[0] += surface[0]
|
|
126
|
+
if len(surface) > 1:
|
|
127
|
+
self.surface_pos[1] += surface[1]
|
|
126
128
|
|
|
127
129
|
self.frame_count += 1
|
|
128
130
|
|
|
129
131
|
def _conclude(self):
|
|
130
132
|
if self.frame_count > 0 and self.index is None:
|
|
131
133
|
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_donor = np.nan_to_num((self.donor / self.frame_count) / average_od, nan=0)
|
|
135
|
+
average_accepter = np.nan_to_num((self.accepter / self.frame_count) / average_od, nan=0)
|
|
134
136
|
average_sum = average_donor + average_accepter
|
|
135
137
|
|
|
136
138
|
bins_z = np.arange(len(self.donor)) * self.bin_size
|
|
137
139
|
|
|
138
140
|
if self.surface:
|
|
139
|
-
|
|
141
|
+
surface = self.surface_pos/self.frame_count
|
|
142
|
+
lower_z = surface[0]
|
|
143
|
+
if surface[1] ==0:
|
|
144
|
+
upper_z = np.inf
|
|
140
145
|
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
141
146
|
filtered_bins_z = bins_z[mask] - lower_z
|
|
142
147
|
filtered_average_accepter = average_accepter[mask]
|
|
@@ -158,15 +163,9 @@ class Hb_distribution(AnalysisBase):
|
|
|
158
163
|
print(output)
|
|
159
164
|
|
|
160
165
|
|
|
161
|
-
@click.command(name="hb")
|
|
162
|
-
@
|
|
166
|
+
@click.command(name="hb", help="analysis hydrogen bond distribution along z-axis")
|
|
167
|
+
@common_setting
|
|
163
168
|
@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
169
|
@click.option('--index', type=int, help='index of an atom')
|
|
171
170
|
def main(filename, hb_param, cell, surface, r, update_water, distance, angle, index):
|
|
172
171
|
"""analysis hydrogen bond distribution along z-axis"""
|
mdkits/md_cli/md_cli.py
CHANGED
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
import click
|
|
2
2
|
from mdkits.md_cli import (
|
|
3
|
+
wrap,
|
|
4
|
+
dipole,
|
|
5
|
+
angle,
|
|
3
6
|
density,
|
|
4
7
|
hb_distribution,
|
|
5
|
-
|
|
8
|
+
vac,
|
|
9
|
+
rdf,
|
|
10
|
+
msd,
|
|
11
|
+
monitor,
|
|
6
12
|
)
|
|
7
13
|
|
|
8
14
|
|
|
9
15
|
@click.group(name='md')
|
|
10
16
|
@click.pass_context
|
|
11
|
-
def
|
|
17
|
+
def cli(ctx):
|
|
12
18
|
"""kits for MD analysis"""
|
|
13
|
-
pass
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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)
|
|
18
29
|
|
|
19
30
|
|
|
20
31
|
if __name__ == '__main__':
|
|
21
|
-
|
|
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,30 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import MDAnalysis as mda
|
|
3
|
+
import MDAnalysis.analysis.msd as msd
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@click.command(name="msd")
|
|
8
|
+
@click.argument("filename", type=click.Path(exists=True))
|
|
9
|
+
@click.argument('type', type=click.Choice(['xyz', 'xy', 'yz', 'xz', 'x', 'y', 'z']))
|
|
10
|
+
@click.argument("group", type=str)
|
|
11
|
+
def main(filename, type, group):
|
|
12
|
+
"""analysis msd along the given axis"""
|
|
13
|
+
u = mda.Universe(filename)
|
|
14
|
+
MSD = msd.EinsteinMSD(u, select=group, msd_type=type, fft=True)
|
|
15
|
+
MSD.run(verbose=True)
|
|
16
|
+
|
|
17
|
+
data = np.arange(1, MSD.n_frames + 1).reshape(-1, 1)
|
|
18
|
+
s = "_"
|
|
19
|
+
name = f"{s.join(group.split(' '))}"
|
|
20
|
+
header = ''
|
|
21
|
+
for i in range(MSD.n_particles):
|
|
22
|
+
data = np.concatenate((data, MSD.results.msds_by_particle[:, i].reshape(-1, 1)), axis=1)
|
|
23
|
+
header += name + f"_{i}\t"
|
|
24
|
+
|
|
25
|
+
np.savetxt(f"msd_{type}.dat", data, fmt="%.5f", delimiter="\t", header=f"frame\t{header}")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == '__main__':
|
|
30
|
+
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
|