mdkits 0.1.28__py3-none-any.whl → 0.1.30__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/md_cli/angle.py +122 -0
- mdkits/md_cli/density.py +11 -13
- mdkits/md_cli/dipole.py +120 -0
- mdkits/md_cli/hb_distribution.py +14 -15
- mdkits/md_cli/md_cli.py +16 -5
- mdkits/md_cli/monitor.py +104 -0
- mdkits/md_cli/msd.py +30 -0
- mdkits/md_cli/rdf.py +39 -0
- mdkits/md_cli/setting.py +14 -0
- mdkits/{cli → md_cli}/wrap.py +1 -1
- mdkits/mdkits.py +2 -4
- mdkits/util/arg_type.py +2 -2
- mdkits/util/encapsulated_mda.py +4 -1
- mdkits/util/numpy_geo.py +10 -5
- mdkits/util/out_err.py +1 -1
- {mdkits-0.1.28.dist-info → mdkits-0.1.30.dist-info}/METADATA +122 -26
- {mdkits-0.1.28.dist-info → mdkits-0.1.30.dist-info}/RECORD +22 -16
- {mdkits-0.1.28.dist-info → mdkits-0.1.30.dist-info}/LICENSE +0 -0
- {mdkits-0.1.28.dist-info → mdkits-0.1.30.dist-info}/WHEEL +0 -0
- {mdkits-0.1.28.dist-info → mdkits-0.1.30.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/md_cli/angle.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
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
|
+
from .setting import common_setting
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Angle_distribution(AnalysisBase):
|
|
12
|
+
def __init__(self, filename, cell, water_height, update_water, surface, distance_judg=None, angle_judg=(None, None), dt=0.001, bin_size=5):
|
|
13
|
+
u = Universe(filename)
|
|
14
|
+
u.trajectory.ts.dt = dt
|
|
15
|
+
u.dimensions = cell
|
|
16
|
+
|
|
17
|
+
self.u = u
|
|
18
|
+
self.atomgroup = u.select_atoms("all")
|
|
19
|
+
self.bin_size = bin_size
|
|
20
|
+
self.frame_count = 0
|
|
21
|
+
self.surface = surface
|
|
22
|
+
self.update_water = update_water
|
|
23
|
+
self.mid_z = u.dimensions[2]/2
|
|
24
|
+
|
|
25
|
+
self.normal_up = np.array([0, 0, 1])
|
|
26
|
+
self.normal_down = np.array([0, 0, -1])
|
|
27
|
+
self.total_angle = 180
|
|
28
|
+
|
|
29
|
+
if water_height is None:
|
|
30
|
+
sys.exit("Please specify the water height")
|
|
31
|
+
else:
|
|
32
|
+
self.water_height = water_height
|
|
33
|
+
|
|
34
|
+
if self.update_water:
|
|
35
|
+
self.distance_judg = distance_judg
|
|
36
|
+
self.angle_judg = angle_judg
|
|
37
|
+
|
|
38
|
+
if surface is not None:
|
|
39
|
+
self.surface_group = self.atomgroup.select_atoms(f"{surface}")
|
|
40
|
+
if self.surface_group.n_atoms == 0:
|
|
41
|
+
sys.exit("Please specify the correct surface group")
|
|
42
|
+
else:
|
|
43
|
+
sys.exit("Please specify a surface group")
|
|
44
|
+
|
|
45
|
+
super(Angle_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
|
|
46
|
+
|
|
47
|
+
def _prepare(self):
|
|
48
|
+
self.bin_num = int(self.total_angle / self.bin_size) + 2
|
|
49
|
+
self.angle_w_distribution = np.zeros(self.bin_num, dtype=np.float64)
|
|
50
|
+
self.angle_oh_distribution = np.zeros(self.bin_num, dtype=np.float64)
|
|
51
|
+
|
|
52
|
+
def _append(self, angle, anglew=True):
|
|
53
|
+
bins = np.floor(angle / self.bin_size).astype(int) + 1
|
|
54
|
+
|
|
55
|
+
if anglew:
|
|
56
|
+
bins = bins[bins < len(self.angle_w_distribution)]
|
|
57
|
+
np.add.at(self.angle_w_distribution, bins, 1)
|
|
58
|
+
else:
|
|
59
|
+
bins = bins[bins < len(self.angle_oh_distribution)]
|
|
60
|
+
np.add.at(self.angle_oh_distribution, bins, 1)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _single_frame(self):
|
|
64
|
+
surface = numpy_geo.find_surface(self.surface_group.positions[:, 2])
|
|
65
|
+
|
|
66
|
+
if len(surface) == 1:
|
|
67
|
+
o_group = self.atomgroup.select_atoms(f"name O and prop z < {surface[0]+self.water_height}", updating=True)
|
|
68
|
+
else:
|
|
69
|
+
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)
|
|
70
|
+
|
|
71
|
+
h_group = self.atomgroup.select_atoms("name H")
|
|
72
|
+
|
|
73
|
+
if self.update_water:
|
|
74
|
+
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)
|
|
75
|
+
else:
|
|
76
|
+
o = o_group
|
|
77
|
+
oh1 = self.atomgroup[o_group.indices + 1]
|
|
78
|
+
oh2 = self.atomgroup[o_group.indices + 2]
|
|
79
|
+
|
|
80
|
+
vec1 = MDAnalysis.lib.distances.minimize_vectors(oh1.positions - o.positions, self.u.dimensions)
|
|
81
|
+
vec2 = MDAnalysis.lib.distances.minimize_vectors(oh2.positions - o.positions, self.u.dimensions)
|
|
82
|
+
|
|
83
|
+
bisector = numpy_geo.vector_between_two_vector(vec1, vec2)
|
|
84
|
+
|
|
85
|
+
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)))
|
|
86
|
+
|
|
87
|
+
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)))
|
|
88
|
+
|
|
89
|
+
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)))
|
|
90
|
+
|
|
91
|
+
self._append(angle_vec1, anglew=False)
|
|
92
|
+
self._append(angle_vec2, anglew=False)
|
|
93
|
+
self._append(angle_bisector)
|
|
94
|
+
|
|
95
|
+
self.frame_count += 1
|
|
96
|
+
|
|
97
|
+
def _conclude(self):
|
|
98
|
+
if self.frame_count > 0:
|
|
99
|
+
average_angle_w = self.angle_w_distribution / self.frame_count
|
|
100
|
+
average_angle_oh = self.angle_oh_distribution / (self.frame_count*2)
|
|
101
|
+
bins_z = np.arange(len(average_angle_w)) * self.bin_size
|
|
102
|
+
conbined_data = np.column_stack((bins_z, average_angle_w, average_angle_oh))
|
|
103
|
+
np.savetxt("angle_distribution.dat", conbined_data, header="angle\tw_suf_dist\toh_suf_dist", fmt='%.5f', delimiter='\t')
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@click.command(name="angle", help="analysis angle between normal vectors and OH vector or bisector")
|
|
107
|
+
@common_setting
|
|
108
|
+
@click.option("--water_height", type=float, help="water height from surface")
|
|
109
|
+
def main(filename, cell, water_height, update_water, distance, angle, surface, r):
|
|
110
|
+
"""analysis angle between normal vectors and OH vector or bisector"""
|
|
111
|
+
a = Angle_distribution(filename, cell, water_height, update_water, distance_judg=distance, angle_judg=angle, surface=surface)
|
|
112
|
+
if r is not None:
|
|
113
|
+
if len(r) == 2:
|
|
114
|
+
a.run(start=r[0], stop=r[1])
|
|
115
|
+
elif len(r) == 3:
|
|
116
|
+
a.run(start=r[0], stop=r[1], step=r[2])
|
|
117
|
+
else:
|
|
118
|
+
a.run()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if __name__ == "__main__":
|
|
122
|
+
main()
|
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
|
|
|
@@ -75,13 +76,14 @@ 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
|
-
|
|
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
|
@@ -7,6 +7,7 @@ from MDAnalysis import Universe
|
|
|
7
7
|
from MDAnalysis.analysis.base import AnalysisBase
|
|
8
8
|
from mdkits.util import arg_type, os_operation, 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,18 +163,12 @@ 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"""
|
|
173
172
|
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
173
|
|
|
175
174
|
if r is not None:
|
mdkits/md_cli/md_cli.py
CHANGED
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import click
|
|
2
2
|
from mdkits.md_cli import (
|
|
3
|
+
wrap,
|
|
4
|
+
dipole,
|
|
5
|
+
angle,
|
|
3
6
|
density,
|
|
4
7
|
hb_distribution,
|
|
8
|
+
rdf,
|
|
9
|
+
msd,
|
|
10
|
+
monitor,
|
|
5
11
|
)
|
|
6
12
|
|
|
7
13
|
|
|
8
14
|
@click.group(name='md')
|
|
9
15
|
@click.pass_context
|
|
10
|
-
def
|
|
16
|
+
def cli(ctx):
|
|
11
17
|
"""kits for MD analysis"""
|
|
12
|
-
pass
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
cli.add_command(wrap.main)
|
|
20
|
+
cli.add_command(density.main)
|
|
21
|
+
cli.add_command(dipole.main)
|
|
22
|
+
cli.add_command(angle.main)
|
|
23
|
+
cli.add_command(hb_distribution.main)
|
|
24
|
+
cli.add_command(rdf.main)
|
|
25
|
+
cli.add_command(msd.main)
|
|
26
|
+
cli.add_command(monitor.main)
|
|
16
27
|
|
|
17
28
|
|
|
18
29
|
if __name__ == '__main__':
|
|
19
|
-
|
|
30
|
+
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,39 @@
|
|
|
1
|
+
import MDAnalysis as mda
|
|
2
|
+
from MDAnalysis.analysis import rdf
|
|
3
|
+
import numpy as np
|
|
4
|
+
import click
|
|
5
|
+
from mdkits.util import arg_type
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.command(name="rdf")
|
|
9
|
+
@click.argument("filename", type=click.Path(exists=True))
|
|
10
|
+
@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')
|
|
11
|
+
@click.option("--group", type=click.Tuple([str, str]), help="two group to analysis")
|
|
12
|
+
@click.option('--range', type=click.Tuple([float, float]), help="the range of rdf")
|
|
13
|
+
@click.option('-r', type=arg_type.FrameRange, help='range of frame to analysis')
|
|
14
|
+
def main(filename, cell, group, range, r):
|
|
15
|
+
"""analysis the radial distribution function"""
|
|
16
|
+
u = mda.Universe(filename)
|
|
17
|
+
u.trajectory.ts.dt = 0.0001
|
|
18
|
+
u.dimensions = cell
|
|
19
|
+
o = f"rdf_{'_'.join(group).replace(' ', '_')}.dat"
|
|
20
|
+
|
|
21
|
+
group1 = u.select_atoms(group[0])
|
|
22
|
+
group2 = u.select_atoms(group[1])
|
|
23
|
+
|
|
24
|
+
crdf = rdf.InterRDF(group1, group2, verbose=True, range=(range[0], range[1]), norm='density')
|
|
25
|
+
|
|
26
|
+
if r is not None:
|
|
27
|
+
if len(r) == 2:
|
|
28
|
+
crdf.run(start=r[0], stop=r[1])
|
|
29
|
+
elif len(r) == 3:
|
|
30
|
+
crdf.run(start=r[0], stop=r[1], step=r[2])
|
|
31
|
+
else:
|
|
32
|
+
crdf.run()
|
|
33
|
+
|
|
34
|
+
combin = np.column_stack((crdf.results.bins, crdf.results.rdf))
|
|
35
|
+
np.savetxt(o, combin, header="A\tgr", fmt="%.5f", delimiter='\t')
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
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
|
mdkits/{cli → md_cli}/wrap.py
RENAMED
mdkits/mdkits.py
CHANGED
|
@@ -4,7 +4,6 @@ from mdkits.dft_cli import dft_cli
|
|
|
4
4
|
from mdkits.md_cli import md_cli
|
|
5
5
|
from mdkits.cli import (
|
|
6
6
|
convert,
|
|
7
|
-
wrap,
|
|
8
7
|
extract,
|
|
9
8
|
data,
|
|
10
9
|
plot,
|
|
@@ -19,11 +18,10 @@ def cli(ctx):
|
|
|
19
18
|
pass
|
|
20
19
|
|
|
21
20
|
|
|
22
|
-
cli.add_command(md_cli.
|
|
23
|
-
cli.add_command(dft_cli.main)
|
|
21
|
+
cli.add_command(md_cli.cli)
|
|
24
22
|
cli.add_command(build_cli.cli_build)
|
|
23
|
+
cli.add_command(dft_cli.main)
|
|
25
24
|
cli.add_command(convert.main)
|
|
26
|
-
cli.add_command(wrap.main)
|
|
27
25
|
cli.add_command(extract.main)
|
|
28
26
|
cli.add_command(data.main)
|
|
29
27
|
cli.add_command(plot.main)
|
mdkits/util/arg_type.py
CHANGED
|
@@ -6,7 +6,7 @@ from mdkits.util import os_operation, cp2k_input_parsing, out_err
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class CellType(click.ParamType):
|
|
9
|
-
name = "
|
|
9
|
+
name = "cell type"
|
|
10
10
|
|
|
11
11
|
def convert(self, value, param, ctx):
|
|
12
12
|
if isinstance(value, str):
|
|
@@ -36,7 +36,7 @@ class FrameRangeType(click.ParamType):
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
class StructureType(click.ParamType):
|
|
39
|
-
name = "structure
|
|
39
|
+
name = "structure type"
|
|
40
40
|
def convert(self, value, param, ctx):
|
|
41
41
|
no_cell=np.array([0., 0., 0., 90., 90., 90.])
|
|
42
42
|
if isinstance(value, str):
|
mdkits/util/encapsulated_mda.py
CHANGED
|
@@ -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]
|
mdkits/util/numpy_geo.py
CHANGED
|
@@ -45,7 +45,10 @@ def vector_between_two_vector(vector1, vector2):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def vector_vector_angle(vector, surface_vector):
|
|
48
|
-
|
|
48
|
+
if len(vector.shape) == 1:
|
|
49
|
+
cos = np.dot(vector, surface_vector) / (np.linalg.norm(vector) * np.linalg.norm(surface_vector))
|
|
50
|
+
else:
|
|
51
|
+
cos = np.dot(vector, surface_vector) / (np.linalg.norm(vector, axis=1) * np.linalg.norm(surface_vector))
|
|
49
52
|
vector_vector_angle = np.arccos(np.clip(cos, -1.0, 1.0))
|
|
50
53
|
vector_vector_angle = np.degrees(vector_vector_angle)
|
|
51
54
|
return vector_vector_angle
|
|
@@ -96,7 +99,7 @@ def unwrap(atom1, atom2, coefficients, max=0, total=False):
|
|
|
96
99
|
return min_dist, closest_point
|
|
97
100
|
|
|
98
101
|
|
|
99
|
-
def find_surface(surface_group:np.ndarray, layer_tolerance=
|
|
102
|
+
def find_surface(surface_group:np.ndarray, layer_tolerance=0.05, surface_tolerance=5):
|
|
100
103
|
sort_group = np.sort(surface_group)
|
|
101
104
|
layer_mean = []
|
|
102
105
|
current_layer = [sort_group[0]]
|
|
@@ -108,12 +111,14 @@ def find_surface(surface_group:np.ndarray, layer_tolerance=1, surface_tolerance=
|
|
|
108
111
|
current_layer = [sort_group[i]]
|
|
109
112
|
layer_mean.append(np.mean(current_layer))
|
|
110
113
|
|
|
111
|
-
if len(
|
|
112
|
-
return layer_mean[0]
|
|
114
|
+
if len(layer_mean) == 1:
|
|
115
|
+
return [layer_mean[0]]
|
|
113
116
|
|
|
114
117
|
diff = np.diff(layer_mean)
|
|
115
118
|
if np.any(diff > surface_tolerance):
|
|
116
|
-
index = np.argmax(diff >
|
|
119
|
+
index = np.argmax(diff > surface_tolerance)
|
|
117
120
|
return (layer_mean[index], layer_mean[index + 1])
|
|
118
121
|
else:
|
|
122
|
+
if layer_mean[-1] > layer_mean[0]:
|
|
123
|
+
return [layer_mean[-1]]
|
|
119
124
|
return (layer_mean[-1], layer_mean[0])
|
mdkits/util/out_err.py
CHANGED
|
@@ -9,7 +9,7 @@ import sys, os
|
|
|
9
9
|
def cell_output(atoms):
|
|
10
10
|
cell = atoms.cell.cellpar()
|
|
11
11
|
if not hasattr(atoms, "name"):
|
|
12
|
-
atoms.name = ""
|
|
12
|
+
atoms.name = "present"
|
|
13
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
14
|
|
|
15
15
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: mdkits
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.30
|
|
4
4
|
Summary: kits for md or dft
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: molecular dynamics,density functional theory
|
|
@@ -21,102 +21,144 @@ Requires-Dist: julia (>=0.6.2,<0.7.0)
|
|
|
21
21
|
Requires-Dist: matplotlib (>=3.9.0,<4.0.0)
|
|
22
22
|
Requires-Dist: numpy (>=1.26.4,<2.0.0)
|
|
23
23
|
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
24
|
+
Requires-Dist: tidynamics (>=1.1.2,<2.0.0)
|
|
24
25
|
Project-URL: Repository, https://github.com/jxxcr/mdkits
|
|
25
26
|
Description-Content-Type: text/markdown
|
|
26
27
|
|
|
27
|
-
#
|
|
28
|
+
# mdkits
|
|
28
29
|
`mdkits` 提供了多种工具, 安装脚本:
|
|
29
30
|
```bash
|
|
30
31
|
pip install mdkits --upgrade
|
|
31
32
|
```
|
|
33
|
+
## 通用的选项参数类型
|
|
34
|
+
1. `CELL TYPE`: 指定晶胞参数, 如`10,10,10`, `10,10,10,90,90,90`等
|
|
35
|
+
2. `FRAME RANGE`: 指定帧范围, 如`1`, `1:10:2`等
|
|
36
|
+
3. `--group`和`--surface`: 按[选择语言](https://userguide.mdanalysis.org/stable/selections.html)选取分析对象
|
|
37
|
+
4. `--update_water`, `--distance` 和 `--angle`: 在分析轨迹的过程中开启动态更新水分子的功能
|
|
32
38
|
|
|
39
|
+
## 轨迹文件处理脚本
|
|
40
|
+
`md`为轨迹文件处理工具, 其中包含多个处理工具
|
|
33
41
|
### 密度分布
|
|
34
|
-
`density`用于分析体系中的某种元素沿z轴的密度分布, 如分析体系中的`O`元素沿z
|
|
42
|
+
`density`用于分析体系中的某种元素沿z轴的密度分布, 如分析体系中的`O`元素沿z轴的密度分布:
|
|
35
43
|
```bash
|
|
36
|
-
mdkits density [FILENAME] --
|
|
44
|
+
mdkits md density [FILENAME] --group="name H" --cell [FILENAME]
|
|
37
45
|
```
|
|
38
46
|
这样会输出一个文件名为`density_name_H.dat`的文件, 第一列为z轴坐标, 第二列为浓度分布, 单位为 mol/L. 如果想输出为单位为 $g/cm^3$ 的密度分布, 可以指定`--atomic_mass` 选项, 如:
|
|
39
47
|
```bash
|
|
40
|
-
mdkits density [FILENAME] --
|
|
48
|
+
mdkits md density [FILENAME] --group="name H" --cell [FILENAME] --atomic_mass=1.00784
|
|
41
49
|
```
|
|
42
50
|
则输出单位为 $g/cm^3$ 的密度分布. 可以指定表面原子来将密度分布归一化到表面, 如:
|
|
43
51
|
```bash
|
|
44
|
-
mdkits density [FILENAME] --
|
|
52
|
+
mdkits md density [FILENAME] --group="name O" --cell 10,10,10 --atomic_mass=18.01528 --surface="name Pt and name Ru"
|
|
45
53
|
```
|
|
46
54
|
这样会将密度分布归一化到表面, 同时以O原子的位置作为水分子的位置分析处理水分子的密度分布. 对于体系中存在 $OH^-$ 离子的体系可以使用`--update_water`的选项在每一帧更新水分子的位置, 不需要额外指定元素, 如:
|
|
47
55
|
```bash
|
|
48
|
-
mdkits density [FILENAME] --update_water --cell 10,10,10 --atomic_mass=18.01528 --surface="name Pt and name Ru"
|
|
56
|
+
mdkits md density [FILENAME] --update_water --cell 10,10,10 --atomic_mass=18.01528 --surface="name Pt and name Ru"
|
|
49
57
|
```
|
|
50
58
|
输出的文件名为`density_water.dat`.
|
|
51
59
|
|
|
52
60
|
### 氢键
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
`hb`用于分析体系中的氢键, 如分析体系中的氢键在z轴上的分布:
|
|
62
|
+
```bash
|
|
63
|
+
mdkits md hb [FILENAME] --cell 10,10,40 --surface "prop z < 10" --update_water
|
|
64
|
+
```
|
|
65
|
+
或分析单个水分子的氢键:
|
|
66
|
+
```bash
|
|
67
|
+
mdkits md hb [FILENAME] --cell 10,10,40 --index 15
|
|
68
|
+
```
|
|
57
69
|
|
|
58
70
|
### 角度
|
|
71
|
+
`angel`用于分析水分子中的二分向量和OH向量与表面法向量的夹角的丰度分布, 如分析距离表面 5 Å 的水分子的角度丰度分布:
|
|
72
|
+
```bash
|
|
73
|
+
mdkits md angle [FILENAME] --cell 10,10,40 --surface "name Pt" --water_height 5
|
|
74
|
+
```
|
|
59
75
|
|
|
60
|
-
|
|
76
|
+
### 偶极分布
|
|
77
|
+
`diople`用于分析体系中的偶极($\cos \phi \rho_{H_2 O}$)分布, 如分析体系中的 $\cos \phi \rho_{H_2 O}$ 分布:
|
|
78
|
+
```bash
|
|
79
|
+
mdkits md diople [FILENAME] --cell 10,10,40 --surface "name Pt"
|
|
80
|
+
```
|
|
61
81
|
|
|
62
|
-
|
|
82
|
+
### 径向分布函数(RDF)
|
|
83
|
+
`rdf`用于分析两个`group`之间的径向分布函数, 如分析体系中的`O`元素与`H`元素之间的径向分布函数:
|
|
84
|
+
```bash
|
|
85
|
+
mdkits md rdf [FILENAME] --group "name O" "name H" --cell 10,10,40 --range 0.1 5
|
|
86
|
+
```
|
|
63
87
|
|
|
64
|
-
|
|
88
|
+
### 均方位移(MSD)
|
|
89
|
+
`msd`用于分析体系中某些原子的均方位移, 如分析体系中`Li`原子在z轴上的均方位移:
|
|
90
|
+
```bash
|
|
91
|
+
mdkits md msd [FILENAME] z "name Li"
|
|
92
|
+
```
|
|
65
93
|
|
|
66
|
-
###
|
|
94
|
+
### 监控
|
|
95
|
+
`monitor`用于监控体系中原子高度, 键长和键角的变化, 如监控`index`为0的原子的高度:
|
|
96
|
+
```bash
|
|
97
|
+
mdkits md monitor [FILENAME] --cell 10,10,40 --surface "name Pt" -i 0
|
|
98
|
+
```
|
|
99
|
+
会输出0距离表面的高度随每一帧的变化, 如监控0-1的键长:
|
|
100
|
+
```bash
|
|
101
|
+
mdkits md monitor [FILENAME] --cell 10,10,40 --surface "name Pt" -i 0 -i 1
|
|
102
|
+
```
|
|
103
|
+
会输出0和1距离表面的高度和0-1之间的键长随每一帧的变化, 如监控1-0-2的键角:
|
|
104
|
+
```bash
|
|
105
|
+
mdkits md monitor [FILENAME] --cell 10,10,40 --surface "name Pt" -i 1 -i 0 -i 2
|
|
106
|
+
```
|
|
107
|
+
会输出1, 0, 2距离表面的高度, 1-0和0-2的键长和1-0-2的键角随每一帧的变化, 注意位于角上的原子应该放在中间
|
|
67
108
|
|
|
68
109
|
### 位置归一化
|
|
69
110
|
`wrap`用于将轨迹文件中的原子位置进行归一化处理, 如将`[FILENAME]`中的原子位置归一化到晶胞中, 并输出为`wrapped.xyz`, 默认从`cp2k`的输出文件`input_inp`中读取`ABC`和`ALPHA_BETA_GAMMA`信息作为晶胞参数:
|
|
70
111
|
```bash
|
|
71
|
-
mdkits wrap [FILENAME]
|
|
112
|
+
mdkits md wrap [FILENAME]
|
|
72
113
|
```
|
|
73
114
|
或指定`cp2k`的输入文件:
|
|
74
115
|
```bash
|
|
75
|
-
mdkits wrap [FILENAME] --cp2k_input_file setting.inp
|
|
116
|
+
mdkits md wrap [FILENAME] --cp2k_input_file setting.inp
|
|
76
117
|
```
|
|
77
118
|
或指定晶胞参数:
|
|
78
119
|
```bash
|
|
79
|
-
mdkits wrap [FILENAME] --cell 10,10,10
|
|
120
|
+
mdkits md wrap [FILENAME] --cell 10,10,10
|
|
80
121
|
```
|
|
81
122
|
默认的`[FILENAME]`为`*-pos-1.xyz`
|
|
82
123
|
|
|
83
124
|
## DFT 性质分析脚本
|
|
125
|
+
`dft`为DFT性质分析工具, 其中包含多个分析工具
|
|
84
126
|
### PDOS
|
|
85
127
|
`pdos`用于分析体系中的pdos, 分析[FILENAME]的d轨道的dos:
|
|
86
128
|
```bash
|
|
87
|
-
mdkits pdos [FILENAME] -t d
|
|
129
|
+
mdkits dft pdos [FILENAME] -t d
|
|
88
130
|
```
|
|
89
131
|
|
|
90
132
|
### CUBE 文件
|
|
91
133
|
`cube`用于处理[`cube`格式](https://paulbourke.net/dataformats/cube/)的文件, 将其在z轴上进行平均:
|
|
92
134
|
```bash
|
|
93
|
-
mdkits cube [FILENAME]
|
|
135
|
+
mdkits dft cube [FILENAME]
|
|
94
136
|
```
|
|
95
137
|
分析好的数据会输出为`cube.out`, 可以同时计算一个区域内的平均值:
|
|
96
138
|
```bash
|
|
97
|
-
mdkits cube [FILENAME] -b 1 2
|
|
139
|
+
mdkits dft cube [FILENAME] -b 1 2
|
|
98
140
|
```
|
|
99
141
|
会将平均值打印在屏幕上, 同时记录在`cube.out`中的注释行.
|
|
100
142
|
|
|
101
143
|
## 建模
|
|
102
|
-
`build
|
|
144
|
+
`build`为建模的工具, 其中包含多个建模工具
|
|
103
145
|
|
|
104
146
|
### 构建体相模型
|
|
105
147
|
`bulk`用于构建体相模型, 如构建`Pt`的`fcc`体相模型:
|
|
106
148
|
```bash
|
|
107
|
-
mdkits
|
|
149
|
+
mdkits build bulk Pt fcc
|
|
108
150
|
```
|
|
109
151
|
构建为常胞模型:
|
|
110
152
|
```bash
|
|
111
|
-
mdkits
|
|
153
|
+
mdkits build bulk Pt fcc --cubic
|
|
112
154
|
```
|
|
113
155
|
构建一个`Caesium chloride`结构的模型:
|
|
114
156
|
```bash
|
|
115
|
-
mdkits
|
|
157
|
+
mdkits build bulk CsCl cesiumchloride -a 4.123
|
|
116
158
|
```
|
|
117
159
|
构建一个`fluorite `结构的模型:
|
|
118
160
|
```bash
|
|
119
|
-
mdkits
|
|
161
|
+
mdkits build bulk BaF2 fluorite -a 6.196
|
|
120
162
|
```
|
|
121
163
|
|
|
122
164
|
### 构建表面模型
|
|
@@ -133,6 +175,60 @@ mdkits build surface Pt fcc111 2 2 3 --vacuum 15
|
|
|
133
175
|
mdkits build surface C2 graphene 3 3 1 --vacuum 15
|
|
134
176
|
```
|
|
135
177
|
|
|
178
|
+
### 从现有结构中构建表面模型
|
|
179
|
+
`cut`用于从现有的结构中构建表面模型(模型必须为常胞模型), 如从`Pt_fcc.cif`中构建`fcc331`表面模型:
|
|
180
|
+
```bash
|
|
181
|
+
mdkits build cut Pt_fcc.cif --face 3 3 1 --size 3 3 5 --vacuum 15
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 在表面结构上添加吸附物
|
|
185
|
+
`adsorbate`用于在表面结构上添加吸附物, 如在`surface.cif`上添加`H`原子:
|
|
186
|
+
```bash
|
|
187
|
+
mdkits build adsorbate surface.cif H --select "index 0" --height 1
|
|
188
|
+
```
|
|
189
|
+
或在`Pt_fcc111_335.cif`上添加覆盖度为5的`H`原子:
|
|
190
|
+
```bash
|
|
191
|
+
mdkits build adsorbate Pt_fcc111_335.cif H --select "prop z > 16" --height 2 --cover 5
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 构建溶液相模型
|
|
195
|
+
`solution`用于构建溶液相模型, 初次使用时应先安装`juliaup`:
|
|
196
|
+
```bash
|
|
197
|
+
mdkits build solution --install_julia
|
|
198
|
+
```
|
|
199
|
+
然后安装`Packmol`:
|
|
200
|
+
```bash
|
|
201
|
+
mdkits build solution --install_packmol
|
|
202
|
+
```
|
|
203
|
+
成功安装后就可以使用`solution`功能了, 如构建一个32个水分子的水盒子:
|
|
204
|
+
```bash
|
|
205
|
+
mdkits build solution --water_number 32 --cell 9.86,9.86,9.86
|
|
206
|
+
```
|
|
207
|
+
或构建一个含有离子的溶液:
|
|
208
|
+
```bash
|
|
209
|
+
mdkits build solution li.xyz k.xyz --water_number 64 --tolerance 2.5 -n 25 -n 45 --cell 15,15,15
|
|
210
|
+
```
|
|
211
|
+
其中`-n`的个数必须与指定的溶剂分子种类数量一致, 用于分别指定添加的溶剂的数量. 或者从`packmol`的输入文件中构建溶液相模型:
|
|
212
|
+
```bash
|
|
213
|
+
mdkits build solution input.pm input2.pm --infile
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 构建界面模型
|
|
217
|
+
`interface`用于构建界面模型, 如构建一个没有真空的界面模型:
|
|
218
|
+
```bash
|
|
219
|
+
mdkits build interface --slab Pt_fcc100_555.cif --sol water_160.cif
|
|
220
|
+
```
|
|
221
|
+
或构建一个带有气相模型的界面:
|
|
222
|
+
```bash
|
|
223
|
+
mdkits build interface --slab Pt_fcc100_555.cif --sol water_160.cif --cap ne --vacuum 20
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 构建超胞模型
|
|
227
|
+
`supercell`用于构建超胞模型:
|
|
228
|
+
```bash
|
|
229
|
+
mdkits build supercell Li3PO4.cif 2 2 2
|
|
230
|
+
```
|
|
231
|
+
|
|
136
232
|
## 其他
|
|
137
233
|
### 轨迹提取
|
|
138
234
|
`extract`用于提取轨迹文件中的特定的帧, 如从`frames.xyz`中提取第 1000 帧到第 2000 帧的轨迹文件, 并输出为`1000-2000.xyz`, `-r`选项的参数与`Python`的切片语法一致:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
mdkits/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
mdkits/build_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
mdkits/build_cli/adsorbate.py,sha256=
|
|
3
|
+
mdkits/build_cli/adsorbate.py,sha256=9D_IYpnXd30pALC6JIvVPPxuxDfpsoArgMhE2hSeOSw,1947
|
|
4
4
|
mdkits/build_cli/build_bulk.py,sha256=o3SFov5Ggk-qKcy6-NBoIYKvZV24OhcH3-du1d0U6H4,1593
|
|
5
5
|
mdkits/build_cli/build_cli.py,sha256=sqjnq5aHWLYLbNzN5SORkEYeYaewLagFuSvspJxyh7E,725
|
|
6
6
|
mdkits/build_cli/build_interface.py,sha256=3EDxUb-vGHFuat1Ex_wojVsN8PtzHiGrnDQIEa9WZ60,2448
|
|
7
7
|
mdkits/build_cli/build_solution.py,sha256=7bwaDH-vLBNRzGoYXT72bzLVXdQAZ4HXNuUDuR7AI78,5377
|
|
8
|
-
mdkits/build_cli/build_surface.py,sha256=
|
|
8
|
+
mdkits/build_cli/build_surface.py,sha256=9GGpmQlCG6vxNevMyWcfI2EL_JiAAKIhxNokZyEzVLU,2739
|
|
9
9
|
mdkits/build_cli/cut_surface.py,sha256=_f0t2OyBKb8ZV04b3GezfSDUN4XFd5kQM-yWbSmOofs,2742
|
|
10
10
|
mdkits/build_cli/supercell.py,sha256=3iTTt3DHaERWDFonhBRS0oqWhjFh6pbS5SpIR-O1gYg,1034
|
|
11
11
|
mdkits/build_cli/water.xyz,sha256=ByLDz-rYhw_wLPBU78lIQHe4s4Xf5Ckjft-Dus3czIc,171
|
|
@@ -18,29 +18,35 @@ mdkits/cli/hartree_potential_ave.py,sha256=25oy3QsgIdxrTFpTqpnGvLAheb-d6poeLMN7i
|
|
|
18
18
|
mdkits/cli/hb.py,sha256=lADr4tlctbtQ3_f_UpznkLnSI0MJlAT-pknEf_dwrnU,5330
|
|
19
19
|
mdkits/cli/packmol_input.py,sha256=76MjjMMRDaW2q459B5mEpXDYSSn14W-JXudOOsx-8E4,2849
|
|
20
20
|
mdkits/cli/plot.py,sha256=1yh5dq5jnQDuyWlxV_9g5ztsnuFHVu4ouYQ9VJYSrUU,8938
|
|
21
|
-
mdkits/cli/wrap.py,sha256=AUxGISuiCfEjdMYl-TKc2VMCPHSybWKrMIOTn_6kSp0,1043
|
|
22
21
|
mdkits/config/__init__.py,sha256=ZSwmnPK02LxJLMgcYmNb-tIOk8fEuHf5jpqD3SDHWLg,1039
|
|
23
22
|
mdkits/config/settings.yml,sha256=PY7u0PbFLuxSnd54H5tI9oMjUf-mzyADqSZtm99BwG0,71
|
|
24
23
|
mdkits/dft_cli/cube.py,sha256=G-QNup8W6J1-LCcEl1EHsV3nstd23byePDOcE_95t18,1176
|
|
25
24
|
mdkits/dft_cli/dft_cli.py,sha256=Ou9-e4uGhDJJk2Gdg7tcj6iKApkAJZFSbN1hr7SlCMc,281
|
|
26
25
|
mdkits/dft_cli/pdos.py,sha256=ALAZ5uOaoT0UpCyKYleWxwmk569HMzKTTK-lMJeicM8,1411
|
|
27
|
-
mdkits/md_cli/
|
|
28
|
-
mdkits/md_cli/
|
|
29
|
-
mdkits/md_cli/
|
|
30
|
-
mdkits/
|
|
26
|
+
mdkits/md_cli/angle.py,sha256=cfhI6dsn_hIy-YXSTXemu1m1O_l2HuL_x6zx_3uL-Uw,5450
|
|
27
|
+
mdkits/md_cli/density.py,sha256=_w6UunY6alTp0jLa8cyqR8sSYubN0XbM-PDF4SkzsJU,5058
|
|
28
|
+
mdkits/md_cli/dipole.py,sha256=tXTO8CZAQTVY55GwuXWJNGo7EQ4Tb2611g5IHucdlec,4836
|
|
29
|
+
mdkits/md_cli/hb_distribution.py,sha256=x5QC6X0TBkN_9jRazDuxjzOzLDiZKIyBxTroueYbG5g,7921
|
|
30
|
+
mdkits/md_cli/md_cli.py,sha256=YOz4qJuYIfJAv-vt0xkw2gopkxGGN7JPp86_dXgPVz8,534
|
|
31
|
+
mdkits/md_cli/monitor.py,sha256=JNEgz5RGbFn4x_E85pAiPUY1NVIyZ3b2vjpBk_d1dR8,4536
|
|
32
|
+
mdkits/md_cli/msd.py,sha256=v-9TPKBGHz6ce2PUwexrekVq_9eiutIOQYaw582yN30,965
|
|
33
|
+
mdkits/md_cli/rdf.py,sha256=u-euWDKpWC4VkZJFBFPqBFJLkLC3nzpfcf1dmf_aBiw,1402
|
|
34
|
+
mdkits/md_cli/setting.py,sha256=mxMTYpm6DUjMt9hOKsJbBSKwCqzMilOR0bo1azSdJP0,846
|
|
35
|
+
mdkits/md_cli/wrap.py,sha256=YdUpvhRyKn7bYnIAVgP39qItPdrEoTeJl55TmbS7Qqk,1044
|
|
36
|
+
mdkits/mdkits.py,sha256=EiAt7dxGTaHuuj7bCNxgAqZbX0i3sldO0mBxOG-aMnY,595
|
|
31
37
|
mdkits/util/.fig_operation.py.swp,sha256=iZYqdYMj4UKS1rmbXv8Ve2FcVBcNljX7Y43-neMdPSk,12288
|
|
32
38
|
mdkits/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
mdkits/util/arg_type.py,sha256=
|
|
39
|
+
mdkits/util/arg_type.py,sha256=_WmcFKUeOvG5LmQwzcL8-xBQgdwIxUP3gMqEqU7FYNU,2428
|
|
34
40
|
mdkits/util/cp2k_input_parsing.py,sha256=7NMVOYEGycarokLJlhLoWWilciM7sd8MWp5FVTF7hqI,1223
|
|
35
41
|
mdkits/util/encapsulated_ase.py,sha256=uhqIhsALxzwJYuFrfOYGGC6U0QLm_dcZNridvfl_XGc,4339
|
|
36
|
-
mdkits/util/encapsulated_mda.py,sha256=
|
|
42
|
+
mdkits/util/encapsulated_mda.py,sha256=m3i-XrcscMcM5V7JzLnor3JtAOfuDx3LLMl0tZt0n-w,2325
|
|
37
43
|
mdkits/util/fig_operation.py,sha256=FwffNUtXorMl6qE04FipgzcVljEQii7wrNJUCJMyY3E,1045
|
|
38
|
-
mdkits/util/numpy_geo.py,sha256=
|
|
44
|
+
mdkits/util/numpy_geo.py,sha256=zkh3uNC3HGHIwtHOmiDXborab5_40PmaJF54jSQ-njU,3874
|
|
39
45
|
mdkits/util/os_operation.py,sha256=ErN2ExjX9vZRfPe3ypsj4eyoQTEePqzlEX0Xm1N4lL4,980
|
|
40
|
-
mdkits/util/out_err.py,sha256=
|
|
46
|
+
mdkits/util/out_err.py,sha256=7vGDI7wVoJWe1S0BDbcq-UC2KAhblCzg-NAYZKBZ4lo,900
|
|
41
47
|
mdkits/util/structure_parsing.py,sha256=mRPMJeih3O-ST7HeETDvBEkfV-1psT-XgxyYgDadV0U,4152
|
|
42
|
-
mdkits-0.1.
|
|
43
|
-
mdkits-0.1.
|
|
44
|
-
mdkits-0.1.
|
|
45
|
-
mdkits-0.1.
|
|
46
|
-
mdkits-0.1.
|
|
48
|
+
mdkits-0.1.30.dist-info/entry_points.txt,sha256=xoWWZ_yL87S501AzCO2ZjpnVuYkElC6z-8J3tmuIGXQ,44
|
|
49
|
+
mdkits-0.1.30.dist-info/LICENSE,sha256=VLaqyB0r_H7y3hUntfpPWcE3OATTedHWI983htLftcQ,1081
|
|
50
|
+
mdkits-0.1.30.dist-info/METADATA,sha256=4JvkdEnBa0Pcpluc1jgOWDwkw3RIjgU5Lmvk5JQP5RY,10964
|
|
51
|
+
mdkits-0.1.30.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
|
52
|
+
mdkits-0.1.30.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|