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 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()
@@ -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
+
@@ -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......')