mdkits 0.1a1__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/__init__.py +0 -0
- mdkits/cli/,hb_distribution.py +126 -0
- mdkits/cli/,hb_distribution_down.py +114 -0
- mdkits/cli/adsorbate.py +84 -0
- mdkits/cli/build_bulk.py +55 -0
- mdkits/cli/build_interface.py +86 -0
- mdkits/cli/build_surface.py +134 -0
- mdkits/cli/cmdline.py +41 -0
- mdkits/cli/convert.py +63 -0
- mdkits/cli/cp2k_input.py +479 -0
- mdkits/cli/cube.py +59 -0
- mdkits/cli/cut_surface.py +38 -0
- mdkits/cli/data.py +80 -0
- mdkits/cli/density.py +89 -0
- mdkits/cli/density2.py +91 -0
- mdkits/cli/extract.py +80 -0
- mdkits/cli/hartree_potential.py +59 -0
- mdkits/cli/hartree_potential_ave.py +84 -0
- mdkits/cli/hb.py +101 -0
- mdkits/cli/log.py +64 -0
- mdkits/cli/matplot.py +60 -0
- mdkits/cli/packmol_input.py +76 -0
- mdkits/cli/pdos.py +36 -0
- mdkits/cli/plot.py +289 -0
- mdkits/cli/supercell.py +72 -0
- mdkits/cli/wrap.py +36 -0
- mdkits/config/__init__.py +35 -0
- mdkits/config/settings.yml +4 -0
- mdkits/mdtool.py +28 -0
- mdkits/util/__init__.py +0 -0
- mdkits/util/arg_type.py +41 -0
- mdkits/util/cp2k_input_parsing.py +46 -0
- mdkits/util/encapsulated_ase.py +134 -0
- mdkits/util/encapsulated_mda.py +59 -0
- mdkits/util/fig_operation.py +28 -0
- mdkits/util/numpy_geo.py +118 -0
- mdkits/util/os_operation.py +35 -0
- mdkits/util/structure_parsing.py +147 -0
- mdkits-0.1a1.dist-info/LICENSE +21 -0
- mdkits-0.1a1.dist-info/METADATA +161 -0
- mdkits-0.1a1.dist-info/RECORD +43 -0
- mdkits-0.1a1.dist-info/WHEEL +4 -0
- mdkits-0.1a1.dist-info/entry_points.txt +3 -0
mdkits/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import argparse
|
|
5
|
+
import MDAnalysis
|
|
6
|
+
from MDAnalysis import Universe
|
|
7
|
+
from MDAnalysis.analysis.base import AnalysisBase
|
|
8
|
+
from util import cp2k_input_parsing
|
|
9
|
+
import warnings
|
|
10
|
+
warnings.filterwarnings("ignore")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Hb_distribution(AnalysisBase):
|
|
14
|
+
def __init__(self, filename, cell, surface, dt=0.001, hb_distance=3.5, hb_angle=35, bin_size=0.2):
|
|
15
|
+
u = Universe(filename)
|
|
16
|
+
u.trajectory.ts.dt = dt
|
|
17
|
+
u.dimensions = cell
|
|
18
|
+
self.u = u
|
|
19
|
+
self.atomgroup = u.select_atoms("all")
|
|
20
|
+
self.hb_distance = hb_distance
|
|
21
|
+
self.hb_angle = hb_angle
|
|
22
|
+
self.bin_size = bin_size
|
|
23
|
+
self.surface = surface
|
|
24
|
+
self.frame_count = 0
|
|
25
|
+
super(Hb_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
|
|
26
|
+
|
|
27
|
+
def _prepare(self):
|
|
28
|
+
bin_num = int(self.u.dimensions[2] / self.bin_size) + 2
|
|
29
|
+
self.accepter = np.zeros(bin_num, dtype=np.float64)
|
|
30
|
+
self.donor = np.zeros(bin_num, dtype=np.float64)
|
|
31
|
+
|
|
32
|
+
def _append(self, hb_d, hb_a):
|
|
33
|
+
bins_d = np.floor(hb_d / self.bin_size).astype(int) + 1
|
|
34
|
+
bins_a = np.floor(hb_a / self.bin_size).astype(int) + 1
|
|
35
|
+
|
|
36
|
+
bins_d = bins_d[bins_d < len(self.donor)]
|
|
37
|
+
bins_a = bins_a[bins_a < len(self.accepter)]
|
|
38
|
+
|
|
39
|
+
np.add.at(self.donor, bins_d, 1)
|
|
40
|
+
np.add.at(self.accepter, bins_a, 1)
|
|
41
|
+
|
|
42
|
+
self.frame_count += 1
|
|
43
|
+
|
|
44
|
+
def _single_frame(self):
|
|
45
|
+
o_group = self.atomgroup.select_atoms("name O")
|
|
46
|
+
o_pair = MDAnalysis.lib.distances.capped_distance(o_group.positions, o_group.positions, min_cutoff=0, max_cutoff=self.hb_distance, box=self.u.dimensions, return_distances=False)
|
|
47
|
+
|
|
48
|
+
o0 = o_group[o_pair[:, 0]]
|
|
49
|
+
o1 = o_group[o_pair[:, 1]]
|
|
50
|
+
|
|
51
|
+
o0h1 = self.atomgroup[o0.indices + 1]
|
|
52
|
+
o0h2 = self.atomgroup[o0.indices + 2]
|
|
53
|
+
o1h1 = self.atomgroup[o1.indices + 1]
|
|
54
|
+
o1h2 = self.atomgroup[o1.indices + 2]
|
|
55
|
+
|
|
56
|
+
angle_o0h1_o0_o1 = np.degrees(
|
|
57
|
+
MDAnalysis.lib.distances.calc_angles(o0h1.positions, o0.positions, o1.positions, box=self.u.dimensions)
|
|
58
|
+
)
|
|
59
|
+
angle_o0h2_o0_o1 = np.degrees(
|
|
60
|
+
MDAnalysis.lib.distances.calc_angles(o0h2.positions, o0.positions, o1.positions, box=self.u.dimensions)
|
|
61
|
+
)
|
|
62
|
+
angle_o1h1_o1_o0 = np.degrees(
|
|
63
|
+
MDAnalysis.lib.distances.calc_angles(o1h1.positions, o1.positions, o0.positions, box=self.u.dimensions)
|
|
64
|
+
)
|
|
65
|
+
angle_o1h2_o1_o0 = np.degrees(
|
|
66
|
+
MDAnalysis.lib.distances.calc_angles(o1h2.positions, o1.positions, o0.positions, box=self.u.dimensions)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
condition_d = (angle_o0h1_o0_o1 < self.hb_angle) | (angle_o0h2_o0_o1 < self.hb_angle)
|
|
70
|
+
condition_a = (angle_o1h1_o1_o0 < self.hb_angle) | (angle_o1h2_o1_o0 < self.hb_angle)
|
|
71
|
+
|
|
72
|
+
hb_d = (o0.positions[:, 2][condition_d] + o1.positions[:, 2][condition_d]) / 2
|
|
73
|
+
hb_a = (o0.positions[:, 2][condition_a] + o1.positions[:, 2][condition_a]) / 2
|
|
74
|
+
|
|
75
|
+
self._append(hb_d, hb_a)
|
|
76
|
+
|
|
77
|
+
def _conclude(self):
|
|
78
|
+
if self.frame_count > 0:
|
|
79
|
+
average_donor = self.donor / self.frame_count
|
|
80
|
+
average_accepter = self.accepter / self.frame_count
|
|
81
|
+
average_sum = average_donor + average_accepter
|
|
82
|
+
|
|
83
|
+
bins_z = np.arange(len(self.donor)) * self.bin_size
|
|
84
|
+
|
|
85
|
+
lower_z, upper_z = self.surface
|
|
86
|
+
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
87
|
+
filtered_bins_z = bins_z[mask] - lower_z
|
|
88
|
+
filtered_average_accepter = average_accepter[mask]
|
|
89
|
+
filtered_average_donor = average_donor[mask]
|
|
90
|
+
filtered_average_sum = average_sum[mask]
|
|
91
|
+
|
|
92
|
+
combined_data = np.column_stack((filtered_bins_z, filtered_average_accepter, filtered_average_donor, filtered_average_sum))
|
|
93
|
+
|
|
94
|
+
np.savetxt("hb_distribution.dat", combined_data, header="Z\tAccepter\tDonor\tAccepter+Donor", fmt='%.5f', delimiter='\t')
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def parse_data(s):
|
|
98
|
+
return [float(x) for x in s.replace(',', ' ').split()]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def parse_r(s):
|
|
102
|
+
return [int(x) for x in s.replace(':', ' ').split()]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def parse_argument():
|
|
106
|
+
parser = argparse.ArgumentParser(description="analysis hb distribution")
|
|
107
|
+
parser.add_argument('filename', type=str, help='filename to analysis')
|
|
108
|
+
parser.add_argument('--cp2k_input_file', type=str, help='input file name of cp2k, default is "input.inp"', default='input.inp')
|
|
109
|
+
parser.add_argument('-r', type=parse_r, help='range of analysis', default=[0, -1, 1])
|
|
110
|
+
parser.add_argument('--cell', type=parse_data, help='set cell, a list of lattice, --cell x,y,z or x,y,z,a,b,c')
|
|
111
|
+
parser.add_argument('--surface', type=parse_data, help='[down_surface_z, up_surface_z]')
|
|
112
|
+
parser.add_argument('--hb_param', type=parse_data, help='[hb_distance, hb_angle], default is [3.5, 35]', default=[3.5, 35])
|
|
113
|
+
|
|
114
|
+
return parser.parse_args()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def main():
|
|
118
|
+
args = parse_argument()
|
|
119
|
+
cell = cp2k_input_parsing.get_cell(args.cp2k_input_file, args.cell)
|
|
120
|
+
|
|
121
|
+
hb_dist = Hb_distribution(args.filename, cell, args.surface, hb_distance=args.hb_param[0], hb_angle=args.hb_param[1])
|
|
122
|
+
hb_dist.run(start=args.r[0], stop=args.r[1], step=args.r[2])
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == '__main__':
|
|
126
|
+
main()
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import argparse
|
|
5
|
+
import MDAnalysis
|
|
6
|
+
from MDAnalysis import Universe
|
|
7
|
+
from MDAnalysis.analysis.base import AnalysisBase
|
|
8
|
+
from util import cp2k_input_parsing
|
|
9
|
+
import warnings
|
|
10
|
+
warnings.filterwarnings("ignore")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Hb_distribution(AnalysisBase):
|
|
14
|
+
def __init__(self, filename, cell, surface, dt=0.001, hb_distance=3.5, hb_angle=35, bin_size=0.2):
|
|
15
|
+
u = Universe(filename)
|
|
16
|
+
u.trajectory.ts.dt = dt
|
|
17
|
+
u.dimensions = cell
|
|
18
|
+
self.u = u
|
|
19
|
+
self.atomgroup = u.select_atoms("all")
|
|
20
|
+
self.hb_distance = hb_distance
|
|
21
|
+
self.hb_angle = hb_angle
|
|
22
|
+
self.bin_size = bin_size
|
|
23
|
+
self.surface = surface
|
|
24
|
+
self.frame_count = 0
|
|
25
|
+
super(Hb_distribution, self).__init__(self.atomgroup.universe.trajectory, verbose=True)
|
|
26
|
+
|
|
27
|
+
def _prepare(self):
|
|
28
|
+
bin_num = int(self.u.dimensions[2] / self.bin_size) + 2
|
|
29
|
+
self.donor = np.zeros(bin_num, dtype=np.float64)
|
|
30
|
+
|
|
31
|
+
def _append(self, hb_d):
|
|
32
|
+
bins_d = np.floor(hb_d / self.bin_size).astype(int) + 1
|
|
33
|
+
|
|
34
|
+
bins_d = bins_d[bins_d < len(self.donor)]
|
|
35
|
+
|
|
36
|
+
np.add.at(self.donor, bins_d, 1)
|
|
37
|
+
|
|
38
|
+
self.frame_count += 1
|
|
39
|
+
|
|
40
|
+
def _single_frame(self):
|
|
41
|
+
o_group = self.atomgroup.select_atoms("name O")
|
|
42
|
+
o_pair = MDAnalysis.lib.distances.capped_distance(o_group.positions, o_group.positions, min_cutoff=0, max_cutoff=self.hb_distance, box=self.u.dimensions, return_distances=False)
|
|
43
|
+
|
|
44
|
+
o0 = o_group[o_pair[:, 0]]
|
|
45
|
+
o1 = o_group[o_pair[:, 1]]
|
|
46
|
+
|
|
47
|
+
o0h1 = self.atomgroup[o0.indices + 1]
|
|
48
|
+
o0h2 = self.atomgroup[o0.indices + 2]
|
|
49
|
+
|
|
50
|
+
angle_o0h1_o0_o1 = np.degrees(
|
|
51
|
+
MDAnalysis.lib.distances.calc_angles(o0h1.positions, o0.positions, o1.positions, box=self.u.dimensions)
|
|
52
|
+
)
|
|
53
|
+
angle_o0h2_o0_o1 = np.degrees(
|
|
54
|
+
MDAnalysis.lib.distances.calc_angles(o0h2.positions, o0.positions, o1.positions, box=self.u.dimensions)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
mid_z = (self.surface[0] + self.surface[1]) / 2
|
|
58
|
+
|
|
59
|
+
condition_d = ((angle_o0h1_o0_o1 < self.hb_angle) | (angle_o0h2_o0_o1 < self.hb_angle)) & (o0.positions[:, 2] - o1.positions[:, 2] > 0)
|
|
60
|
+
#condition_d = ((angle_o0h1_o0_o1 < self.hb_angle) | (angle_o0h2_o0_o1 < self.hb_angle)) & (((o0.positions[:, 2] < mid_z) & (o0.positions[:, 2] - o1.positions[:, 2] > 0)) | ((o0.positions[:, 2] > mid_z) & (o0.positions[:, 2] - o1.positions[:, 2] < 0)))
|
|
61
|
+
#condition_a = ((angle_o1h1_o1_o0 < self.hb_angle) | (angle_o1h2_o1_o0 < self.hb_angle)) & (((o1.positions[:, 2] < mid_z) & (o1.positions[:, 2] - o0.positions[:, 2] > 1.5)) | ((o1.positions[:, 2] > mid_z) & (o1.positions[:, 2] - o0.positions[:, 2] < -1.5)))
|
|
62
|
+
|
|
63
|
+
hb_d = (o0.positions[:, 2][condition_d] + o1.positions[:, 2][condition_d]) / 2
|
|
64
|
+
#hb_a = (o0.positions[:, 2][condition_a] + o1.positions[:, 2][condition_a]) / 2
|
|
65
|
+
|
|
66
|
+
self._append(hb_d)
|
|
67
|
+
|
|
68
|
+
def _conclude(self):
|
|
69
|
+
if self.frame_count > 0:
|
|
70
|
+
average_donor = self.donor / self.frame_count
|
|
71
|
+
|
|
72
|
+
bins_z = np.arange(len(self.donor)) * self.bin_size
|
|
73
|
+
|
|
74
|
+
lower_z, upper_z = self.surface
|
|
75
|
+
mask = (bins_z >= lower_z) & (bins_z <= upper_z)
|
|
76
|
+
filtered_bins_z = bins_z[mask] - lower_z
|
|
77
|
+
filtered_average_donor = average_donor[mask]
|
|
78
|
+
|
|
79
|
+
combined_data = np.column_stack((filtered_bins_z, filtered_average_donor))
|
|
80
|
+
|
|
81
|
+
filename = 'hb_distribution_down.dat'
|
|
82
|
+
np.savetxt(filename, combined_data, header="Z\tDonor", fmt='%.5f', delimiter='\t')
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def parse_data(s):
|
|
86
|
+
return [float(x) for x in s.replace(',', ' ').split()]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def parse_r(s):
|
|
90
|
+
return [int(x) for x in s.replace(':', ' ').split()]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def parse_argument():
|
|
94
|
+
parser = argparse.ArgumentParser(description="analysis hb distribution")
|
|
95
|
+
parser.add_argument('filename', type=str, help='filename to analysis')
|
|
96
|
+
parser.add_argument('--cp2k_input_file', type=str, help='input file name of cp2k, default is "input.inp"', default='input.inp')
|
|
97
|
+
parser.add_argument('-r', type=parse_r, help='range of analysis', default=[0, -1, 1])
|
|
98
|
+
parser.add_argument('--cell', type=parse_data, help='set cell, a list of lattice, --cell x,y,z or x,y,z,a,b,c')
|
|
99
|
+
parser.add_argument('--surface', type=parse_data, help='[down_surface_z, up_surface_z]')
|
|
100
|
+
parser.add_argument('--hb_param', type=parse_data, help='[hb_distance, hb_angle], default is [3.5, 35]', default=[3.5, 35])
|
|
101
|
+
|
|
102
|
+
return parser.parse_args()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def main():
|
|
106
|
+
args = parse_argument()
|
|
107
|
+
cell = cp2k_input_parsing.get_cell(args.cp2k_input_file, args.cell)
|
|
108
|
+
|
|
109
|
+
hb_dist = Hb_distribution(args.filename, cell, args.surface, hb_distance=args.hb_param[0], hb_angle=args.hb_param[1])
|
|
110
|
+
hb_dist.run(start=args.r[0], stop=args.r[1], step=args.r[2])
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == '__main__':
|
|
114
|
+
main()
|
mdkits/cli/adsorbate.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from ase import io, build
|
|
4
|
+
from ase.collections import g2
|
|
5
|
+
import argparse, os
|
|
6
|
+
import numpy as np
|
|
7
|
+
from util import encapsulated_ase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def parse_size(s):
|
|
11
|
+
if s == None:
|
|
12
|
+
return None
|
|
13
|
+
return [float(x) for x in s.replace(',', ' ').split()]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def parse_index(s):
|
|
17
|
+
return [int(x)-1 for x in s.replace(',', ' ').split()]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def parse_argument():
|
|
21
|
+
parser = argparse.ArgumentParser(description='add some adsorbate')
|
|
22
|
+
parser.add_argument('filename', type=str, help='init structure filename')
|
|
23
|
+
parser.add_argument('-m', type=str, help='atom or molecule to add')
|
|
24
|
+
parser.add_argument('--index', type=parse_index, help='index(list) of atom to add atom(top site)')
|
|
25
|
+
parser.add_argument('--offset', type=parse_size, help='adjust site, default is 0,0', default='0,0')
|
|
26
|
+
parser.add_argument('--height', type=float, help='designate vacuum of surface, default is None', default=0.0)
|
|
27
|
+
parser.add_argument('-x', type=float, help='rotate axis and angle')
|
|
28
|
+
parser.add_argument('-y', type=float, help='rotate axis and angle')
|
|
29
|
+
parser.add_argument('-z', type=float, help='rotate axis and angle')
|
|
30
|
+
parser.add_argument('-o', type=str, help='specify the output file name without suffix, default is "adsorbated.cif"', default='adsorbated.cif')
|
|
31
|
+
parser.add_argument('--coord', help='coord format', action='store_true')
|
|
32
|
+
parser.add_argument('--cell', type=parse_size, help='set xyz file cell, --cell x,y,z,a,b,c')
|
|
33
|
+
parser.add_argument('--cp2k', help='output cp2k format', action='store_true')
|
|
34
|
+
|
|
35
|
+
return parser.parse_args()
|
|
36
|
+
|
|
37
|
+
def main():
|
|
38
|
+
args = parse_argument()
|
|
39
|
+
atoms = encapsulated_ase.atoms_read_with_cell(args.filename, cell=args.cell, coord_mode=args.coord)
|
|
40
|
+
|
|
41
|
+
if len(args.offset) < 2:
|
|
42
|
+
args.offset.append(0)
|
|
43
|
+
offset = np.array(args.offset)
|
|
44
|
+
|
|
45
|
+
position_list = []
|
|
46
|
+
for atom in atoms:
|
|
47
|
+
if atom.index in args.index:
|
|
48
|
+
position_list.append(np.copy(atom.position[0:2])+offset)
|
|
49
|
+
|
|
50
|
+
if args.m in g2.names:
|
|
51
|
+
molecule = build.molecule(args.m)
|
|
52
|
+
if args.x:
|
|
53
|
+
molecule.rotate(args.x, 'x')
|
|
54
|
+
if args.y:
|
|
55
|
+
molecule.rotate(args.y, 'y')
|
|
56
|
+
if args.z:
|
|
57
|
+
molecule.rotate(args.z, 'z')
|
|
58
|
+
for position in position_list:
|
|
59
|
+
build.add_adsorbate(atoms, molecule, args.height, position=position)
|
|
60
|
+
else:
|
|
61
|
+
for position in position_list:
|
|
62
|
+
build.add_adsorbate(atoms, args.m, args.height, position=position)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
if args.cp2k:
|
|
66
|
+
args.o = 'coord.xyz'
|
|
67
|
+
atoms.write(args.o, format='xyz')
|
|
68
|
+
with open(args.o, 'r') as f:
|
|
69
|
+
lines = f.readlines()
|
|
70
|
+
with open(args.o, 'w') as f:
|
|
71
|
+
f.writelines(lines[2:])
|
|
72
|
+
with open('cell.inc', 'w') as f:
|
|
73
|
+
cell = atoms.get_cell().cellpar()
|
|
74
|
+
f.write('ABC [angstrom] ' + str(cell[0]) + ' ' + str(cell[1]) + ' ' + str(cell[2]) + ' ' + '\n')
|
|
75
|
+
f.write('ALPHA_BETA_GAMMA ' + str(cell[3]) + ' ' + str(cell[4]) + ' ' + str(cell[5]) + '\n')
|
|
76
|
+
else:
|
|
77
|
+
atoms.write(args.o, format='cif')
|
|
78
|
+
|
|
79
|
+
print(os.path.abspath(args.o))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == '__main__':
|
|
83
|
+
main()
|
|
84
|
+
|
mdkits/cli/build_bulk.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from ase.build import bulk
|
|
5
|
+
from ase.geometry import cell_to_cellpar
|
|
6
|
+
from ase.io import write
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def parse_size(s):
|
|
10
|
+
return [int(x) for x in s.replace(',', ' ').split()]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def parse_argument():
|
|
14
|
+
parser = argparse.ArgumentParser(description='build a surface structure of matel')
|
|
15
|
+
parser.add_argument('symbol', type=str, help='designate the symbol of matel')
|
|
16
|
+
parser.add_argument('--crystal', type=str, help='designate the crystal of structure')
|
|
17
|
+
parser.add_argument('--orth', help='outpue orthorhombic crystal', action='store_true')
|
|
18
|
+
parser.add_argument('-a', type=float, help='designate a lattice constant')
|
|
19
|
+
parser.add_argument('--primitve', help='designate a lattice constant of real', action='store_true')
|
|
20
|
+
parser.add_argument('-o', type=str, help='output structure name', default='bulk.xyz')
|
|
21
|
+
parser.add_argument('-c', help='output coord.xyz and cell.inc', action='store_true')
|
|
22
|
+
parser.add_argument('-k', help='output kpoint.inc', action='store_true')
|
|
23
|
+
|
|
24
|
+
return parser.parse_args()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main():
|
|
28
|
+
args = parse_argument()
|
|
29
|
+
if args.primitve:
|
|
30
|
+
a = args.a * 0.7071 * 2
|
|
31
|
+
else:
|
|
32
|
+
a = args.a
|
|
33
|
+
atoms = bulk(args.symbol, args.crystal, a=a, orthorhombic=args.orth)
|
|
34
|
+
if args.c:
|
|
35
|
+
atoms.write('coord.xyz', format='xyz')
|
|
36
|
+
with open('coord.xyz', 'r') as f:
|
|
37
|
+
lines = f.readlines()[2:]
|
|
38
|
+
with open('coord.xyz', 'w') as f:
|
|
39
|
+
f.writelines(lines)
|
|
40
|
+
with open('cell.inc', 'w') as f:
|
|
41
|
+
cell = list(cell_to_cellpar(atoms.cell))
|
|
42
|
+
f.write('ABC [angstrom] ' + str(cell[0]) + ' ' + str(cell[1]) + ' ' + str(cell[2]) + ' ' + '\n')
|
|
43
|
+
f.write('ALPHA_BETA_GAMMA ' + str(cell[3]) + ' ' + str(cell[4]) + ' ' + str(cell[5]) + '\n')
|
|
44
|
+
if args.k:
|
|
45
|
+
with open('kpoint.inc', 'w') as f:
|
|
46
|
+
if True:
|
|
47
|
+
if True:
|
|
48
|
+
f.write(f"SCHEME MONKHORST-PACK {int(round(30/cell[0]))} {int(round(30/cell[1]))} {int(round(30/cell[2]))}" + "\n")
|
|
49
|
+
else:
|
|
50
|
+
atoms.write(args.o)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == '__main__':
|
|
54
|
+
main()
|
|
55
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from ase.io import write, read
|
|
2
|
+
import argparse
|
|
3
|
+
from ase.geometry import cell_to_cellpar, cellpar_to_cell
|
|
4
|
+
import math
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_argument():
|
|
8
|
+
parser = argparse.ArgumentParser(description='combain solbox and surface to a interface')
|
|
9
|
+
parser.add_argument('--surface', type=str, help='surface path')
|
|
10
|
+
parser.add_argument('--sol', type=str, help='solbox path')
|
|
11
|
+
parser.add_argument('--move', type=float, help='move at z, default = 0', default=0)
|
|
12
|
+
parser.add_argument('--interval', type=float, help='interval between surface to sol, default is 2', default=2)
|
|
13
|
+
parser.add_argument('--vacuum', type=float, help='vacuum of structure, default is 0', default=0)
|
|
14
|
+
parser.add_argument('--symmetry', help='two side interface, default is false', action='store_true')
|
|
15
|
+
parser.add_argument('--ne', help='two side interface, one side is Ne atom, default is false', action='store_true')
|
|
16
|
+
parser.add_argument('-o', type=str, help='output file name', default='interface')
|
|
17
|
+
|
|
18
|
+
return parser.parse_args()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def chformat(input_filename, output_filename, format):
|
|
22
|
+
atoms = read(input_filename)
|
|
23
|
+
write(output_filename, atoms, format=format)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main():
|
|
27
|
+
args = parse_argument()
|
|
28
|
+
surface = read(args.surface)
|
|
29
|
+
surface.set_pbc(True)
|
|
30
|
+
surface.center()
|
|
31
|
+
sy_surface = surface.copy()
|
|
32
|
+
cell = surface.get_cell()
|
|
33
|
+
[lenx, leny, lenz, anga, angb, angc] = cell_to_cellpar(cell)
|
|
34
|
+
|
|
35
|
+
solbox = read(args.sol)
|
|
36
|
+
solbox_cell = solbox.cell.cellpar()
|
|
37
|
+
solbox.set_pbc(True)
|
|
38
|
+
solbox.center()
|
|
39
|
+
tmp_list = solbox.get_positions()
|
|
40
|
+
tmp_list[:, 2] += lenz + args.interval
|
|
41
|
+
solbox.set_positions(tmp_list)
|
|
42
|
+
|
|
43
|
+
surface.extend(solbox)
|
|
44
|
+
surface.cell = [lenx, leny, (lenz + args.interval + solbox_cell[2] + args.interval), anga, angb, angc]
|
|
45
|
+
surface.center()
|
|
46
|
+
|
|
47
|
+
if args.symmetry:
|
|
48
|
+
tmp_list = surface.get_positions()
|
|
49
|
+
tmp_list[:, 2] += -(lenz + args.interval + solbox_cell[2] + args.interval)
|
|
50
|
+
surface.set_positions(tmp_list)
|
|
51
|
+
surface.extend(sy_surface)
|
|
52
|
+
surface.cell = [lenx, leny, (lenz + args.interval + solbox_cell[2] + args.interval + lenz + args.vacuum), anga, angb, angc]
|
|
53
|
+
surface.center()
|
|
54
|
+
elif args.ne:
|
|
55
|
+
from ase import Atoms
|
|
56
|
+
ne_interval = 4 # adjust water density
|
|
57
|
+
ne_cell = [lenx, leny, 2, 90, 90, 90]
|
|
58
|
+
ne_position = []
|
|
59
|
+
ne_symbols = []
|
|
60
|
+
ne_site = [int(lenx//ne_interval), int(leny//ne_interval)]
|
|
61
|
+
for i in range(ne_site[0]):
|
|
62
|
+
for j in range(ne_site[1]):
|
|
63
|
+
ne_position.append((i*ne_interval, j*ne_interval, 0))
|
|
64
|
+
ne_symbols.append('Ne')
|
|
65
|
+
ne_atoms = Atoms(symbols=ne_symbols, positions=ne_position, cell=ne_cell)
|
|
66
|
+
ne_atoms.center()
|
|
67
|
+
tmp_list = surface.get_positions()
|
|
68
|
+
tmp_list[:, 2] += -(lenz + args.interval + solbox_cell[2])
|
|
69
|
+
surface.set_positions(tmp_list)
|
|
70
|
+
surface.extend(ne_atoms)
|
|
71
|
+
surface.cell = [lenx, leny, (lenz + args.interval + solbox_cell[2] + args.interval + 2 + args.vacuum), anga, angb, angc]
|
|
72
|
+
surface.center()
|
|
73
|
+
else:
|
|
74
|
+
surface.set_pbc(True)
|
|
75
|
+
tmp_list = surface.get_positions()
|
|
76
|
+
#tmp_list[:, 2] -= lenz
|
|
77
|
+
tmp_list[:, 2] -= args.move
|
|
78
|
+
surface.set_positions(tmp_list)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
write(args.o + '.xyz', surface, format='extxyz')
|
|
82
|
+
write(args.o + '.cif', surface, format='cif')
|
|
83
|
+
#chformat(args.o + '.cif', args.o + '.xyz', format='xyz')
|
|
84
|
+
|
|
85
|
+
if __name__ == '__main__':
|
|
86
|
+
main()
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import argparse, sys
|
|
4
|
+
from ase import build
|
|
5
|
+
from ase.geometry import cell_to_cellpar
|
|
6
|
+
from ase.io import write
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def parse_size(s):
|
|
12
|
+
if s == None:
|
|
13
|
+
return None
|
|
14
|
+
return [int(x) for x in s.replace(',', ' ').split()]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def surface_check(obj, surface_type):
|
|
18
|
+
if hasattr(obj, surface_type):
|
|
19
|
+
return getattr(obj, surface_type)
|
|
20
|
+
else:
|
|
21
|
+
print(f'dont have face named {surface_type}')
|
|
22
|
+
exit()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def parse_argument():
|
|
26
|
+
parser = argparse.ArgumentParser(description='build a surface structure of matel')
|
|
27
|
+
parser.add_argument('symbol', type=str, help='designate the symbol of matel')
|
|
28
|
+
parser.add_argument('--face', type=str, help='designate the face of surface')
|
|
29
|
+
parser.add_argument('-a', type=float, help='designate a lattice constant', default=None)
|
|
30
|
+
parser.add_argument('--primitive', help='designate a lattice constant of real', action='store_true')
|
|
31
|
+
parser.add_argument('--size', type=parse_size, help='designate surface size(a,b,c)')
|
|
32
|
+
parser.add_argument('--vacuum', type=float, help='designate vacuum of surface, default is None', default=0.0)
|
|
33
|
+
parser.add_argument('--adsorbate', type=str, help='add adsorbate on surface', default=None)
|
|
34
|
+
parser.add_argument('--position', type=str, help='position of adsorbate', default='ontop')
|
|
35
|
+
parser.add_argument('--offset', type=str, help='offset')
|
|
36
|
+
parser.add_argument('--height', type=float, help='position of adsorbate', default=1)
|
|
37
|
+
parser.add_argument('-o', type=str, help='output structure name', default='surface.xyz')
|
|
38
|
+
parser.add_argument('-c', help='output coord.xyz and cell.inc', action='store_true')
|
|
39
|
+
parser.add_argument('-k', type=parse_size, help='output kpoint.inc(a,b,c)', default=None)
|
|
40
|
+
parser.add_argument('--autok', help='output kpoint.inc', action='store_true')
|
|
41
|
+
parser.add_argument('--orth', help='orth cell', action='store_true')
|
|
42
|
+
parser.add_argument('--coverh', type=int, help='cover H atom', default=0)
|
|
43
|
+
|
|
44
|
+
return parser.parse_args()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def main():
|
|
48
|
+
args = parse_argument()
|
|
49
|
+
if args.primitive:
|
|
50
|
+
a = args.a * 0.7071 * 2
|
|
51
|
+
else:
|
|
52
|
+
a = args.a
|
|
53
|
+
|
|
54
|
+
vacuum = args.vacuum / 2
|
|
55
|
+
|
|
56
|
+
build_surface = surface_check(build, args.face)
|
|
57
|
+
|
|
58
|
+
if args.orth:
|
|
59
|
+
atoms = build_surface(args.symbol, args.size, a=a, vacuum=vacuum, orthogonal=args.orth)
|
|
60
|
+
else:
|
|
61
|
+
atoms = build_surface(args.symbol, args.size, a=a, vacuum=vacuum)
|
|
62
|
+
|
|
63
|
+
# add adsorbate
|
|
64
|
+
if args.adsorbate != None:
|
|
65
|
+
## add H2Oa and OH
|
|
66
|
+
if args.adsorbate in ['H2Oa', 'OH']:
|
|
67
|
+
if args.adsorbate in ['OH']:
|
|
68
|
+
h2o = build.molecule(args.adsorbate)
|
|
69
|
+
h2o.rotate(90, 'y')
|
|
70
|
+
build.add_adsorbate(atoms, h2o, args.height, position=args.position, offset=args.offset)
|
|
71
|
+
else:
|
|
72
|
+
h2o = build.molecule('H2O')
|
|
73
|
+
h2o.rotate(90, 'y')
|
|
74
|
+
build.add_adsorbate(atoms, h2o, args.height, position=args.position, offset=args.offset)
|
|
75
|
+
## add H2Ob
|
|
76
|
+
elif args.adsorbate in ['H2Ob']:
|
|
77
|
+
h2o = build.molecule('H2O')
|
|
78
|
+
h2o.rotate(90, 'z')
|
|
79
|
+
h2o.rotate(45, 'y')
|
|
80
|
+
build.add_adsorbate(atoms, h2o, args.height, position=args.position, offset=args.offset)
|
|
81
|
+
## add default something
|
|
82
|
+
else:
|
|
83
|
+
build.add_adsorbate(atoms, args.adsorbate, args.height, position=args.position, offset=args.offset)
|
|
84
|
+
|
|
85
|
+
# add h with coverage
|
|
86
|
+
if args.coverh != 0:
|
|
87
|
+
## get atom position at surface
|
|
88
|
+
surface_positions_dict = {}
|
|
89
|
+
for atom in atoms:
|
|
90
|
+
if atom.tag == 1:
|
|
91
|
+
surface_positions_dict[atom.index] = atom.position
|
|
92
|
+
## error checking
|
|
93
|
+
if site_number := len(surface_positions_dict) < args.coverh:
|
|
94
|
+
print(f"coverh is too big, please less then {site_number}")
|
|
95
|
+
sys.exit()
|
|
96
|
+
## get random site
|
|
97
|
+
random_site_list = np.random.choice(list(surface_positions_dict.keys()), args.coverh, replace=False)
|
|
98
|
+
random_site_list = np.unique(random_site_list)
|
|
99
|
+
## add H atom at hollow site
|
|
100
|
+
for site in random_site_list:
|
|
101
|
+
site_position = surface_positions_dict[site][0:2]
|
|
102
|
+
build.add_adsorbate(atoms, 'H', 2, position=site_position, offset=(0.3, 0.3))
|
|
103
|
+
|
|
104
|
+
# control output format
|
|
105
|
+
## output with coord.xyz(cp2k format)
|
|
106
|
+
if args.c:
|
|
107
|
+
atoms.write('coord.xyz', format='xyz')
|
|
108
|
+
with open('coord.xyz', 'r') as f:
|
|
109
|
+
lines = f.readlines()[2:]
|
|
110
|
+
with open('coord.xyz', 'w') as f:
|
|
111
|
+
f.writelines(lines)
|
|
112
|
+
with open('cell.inc', 'w') as f:
|
|
113
|
+
cell = list(cell_to_cellpar(atoms.cell))
|
|
114
|
+
f.write('ABC [angstrom] ' + str(cell[0]) + ' ' + str(cell[1]) + ' ' + str(cell[2]) + ' ' + '\n')
|
|
115
|
+
f.write('ALPHA_BETA_GAMMA ' + str(cell[3]) + ' ' + str(cell[4]) + ' ' + str(cell[5]) + '\n')
|
|
116
|
+
## output kpoint file with specific number
|
|
117
|
+
if args.k != None:
|
|
118
|
+
if True: #judge M or G
|
|
119
|
+
with open('kpoint.inc', 'w') as f:
|
|
120
|
+
f.write(f"SCHEME MONKHORST-PACK {args.k[0]} {args.k[1]} {args.k[2]}" + "\n")
|
|
121
|
+
## output kpoint file autoly
|
|
122
|
+
if args.autok:
|
|
123
|
+
if True: # judge matel or semi or else
|
|
124
|
+
if True: # judge M or G
|
|
125
|
+
with open('kpoint.inc', 'w') as f:
|
|
126
|
+
f.write(f"SCHEME MONKHORST-PACK {int(round(30/cell[0]))} {int(round(30/cell[1]))} {int(round(30/cell[2]))}" + "\n")
|
|
127
|
+
## output default format or specific xyz file
|
|
128
|
+
else:
|
|
129
|
+
atoms.write(args.o)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if __name__ == '__main__':
|
|
133
|
+
main()
|
|
134
|
+
|
mdkits/cli/cmdline.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Command line"""
|
|
2
|
+
import click
|
|
3
|
+
from click import Context
|
|
4
|
+
|
|
5
|
+
from mdtool import __version__
|
|
6
|
+
from mdtool.config import settings
|
|
7
|
+
from mdtool.log import init_log
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.group(invoke_without_command=True)
|
|
11
|
+
@click.pass_context
|
|
12
|
+
@click.option(
|
|
13
|
+
'-V',
|
|
14
|
+
'--version',
|
|
15
|
+
is_flag=True,
|
|
16
|
+
help='Show version and exit.'
|
|
17
|
+
) # If it's true, it will override `settings.VERBOSE`
|
|
18
|
+
@click.option('-v', '--verbose', is_flag=True, help='Show more info.')
|
|
19
|
+
@click.option(
|
|
20
|
+
'--debug',
|
|
21
|
+
is_flag=True,
|
|
22
|
+
help='Enable debug.'
|
|
23
|
+
) # If it's true, it will override `settings.DEBUG`
|
|
24
|
+
def main(ctx: Context, version: str, verbose: bool, debug: bool):
|
|
25
|
+
"""Main commands"""
|
|
26
|
+
if version:
|
|
27
|
+
click.echo(__version__)
|
|
28
|
+
elif ctx.invoked_subcommand is None:
|
|
29
|
+
click.echo(ctx.get_help())
|
|
30
|
+
else:
|
|
31
|
+
if verbose:
|
|
32
|
+
settings.set('VERBOSE', True)
|
|
33
|
+
if debug:
|
|
34
|
+
settings.set('DEBUG', True)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@main.command()
|
|
38
|
+
def run():
|
|
39
|
+
"""Run command"""
|
|
40
|
+
init_log()
|
|
41
|
+
click.echo('run......')
|