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/cli/matplot.py ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ import argparse
6
+ import os
7
+ from matplotlib import use as muse
8
+ muse('Agg')
9
+
10
+
11
+ def parse_slice(s):
12
+ if s == None:
13
+ return None
14
+ return [int(x) for x in s.replace(':', ' ').split()]
15
+
16
+
17
+ def parse_argument():
18
+ parser = argparse.ArgumentParser(description='extract pos file from output file')
19
+
20
+ parser.add_argument('input_file_name', type=str, help='input file name')
21
+ parser.add_argument('-o', type=str, help='output file name, default is "out.xyz"', default='out.png')
22
+ parser.add_argument('-u', type=parse_slice, help='which clume to use, look like gnuplot u 1:2', default=[0, 1])
23
+ parser.add_argument('--label', type=str, help='line name')
24
+ parser.add_argument('--dpi', type=int, help='image dpi, default is 300', default=300)
25
+ parser.add_argument('--err', help='plot err line', action='store_true')
26
+
27
+ return parser.parse_args()
28
+
29
+
30
+ def plot_data(x, y, dpi, label, name):
31
+ fig, ax = plt.subplots(dpi=dpi)
32
+ ax.plot(x, y, label=label)
33
+ ax.legend()
34
+ fig.savefig(name)
35
+
36
+
37
+ def plot_err(x, y, dpi, label, name):
38
+ fig, ax = plt.subplots(dpi=dpi)
39
+ ax.scatter(x, y, label=label)
40
+ line = np.linspace(np.amax(x), np.amin(x), 1000)
41
+ ax.plot(line, line)
42
+ ax.legend()
43
+ fig.savefig(name)
44
+
45
+
46
+ def main():
47
+ args = parse_argument()
48
+ if args.label == None:
49
+ args.label = args.input_file_name
50
+ data = np.loadtxt(args.input_file_name)
51
+ if args.err:
52
+ plot_err(data[:, 0], data[:, 1], dpi=args.dpi, label=args.label, name=args.o)
53
+ else:
54
+ plot_data(data[:, 0], data[:, 1], dpi=args.dpi, label=args.label, name=args.o)
55
+
56
+ print(os.path.abspath(args.o))
57
+
58
+
59
+ if __name__ == '__main__':
60
+ main()
@@ -0,0 +1,76 @@
1
+ import argparse
2
+
3
+
4
+ def parse_cell(s):
5
+ return [float(x) for x in s.replace(',', ' ').split()]
6
+
7
+
8
+ def parse_argument():
9
+ parser = argparse.ArgumentParser(description='generate packmol input file with give parameter')
10
+ parser.add_argument('--size', type=int, help='water size default is 30', default=30)
11
+ parser.add_argument('--cell', type=parse_cell, help='input box size(a,b,c)')
12
+ parser.add_argument('--addwat', type=int, help='add some additional water, default is 0', default=0)
13
+ parser.add_argument('--ioncon', type=float, help='concentration of sol box, default is 0.0', default=0.0)
14
+ parser.add_argument('--tolerance', type=float, help='tolerance of packmol, default is 2.5', default=2.5)
15
+ parser.add_argument('--watpath', type=str, help='water xyz file path', default='C:\\home\\.can\\temp\\packmol\\default\\water.xyz')
16
+ parser.add_argument('--ionpath', type=str, help='ion xyz file path')
17
+ parser.add_argument('-o', type=str, help='output file name, default is "input.pm"', default='input.pm')
18
+ parser.add_argument('--output', type=str, help='output file name of packmol, default is "solbox.xyz"', default='solbox.xyz')
19
+
20
+ return parser.parse_args()
21
+
22
+
23
+ def get_water_number():
24
+ water_number = water_volume / water_size
25
+
26
+ return int(round(water_number, 0))
27
+
28
+
29
+ def get_ion_number(concentration):
30
+ ion_number = ( (concentration * avogadro) / 1e+27 ) * water_volume
31
+
32
+ return int(round(ion_number, 0))
33
+
34
+
35
+ def main():
36
+ global water_volume, water_size, avogadro
37
+ args = parse_argument()
38
+ water_volume = args.cell[0] * args.cell[1] * args.cell[2]
39
+ water_size = args.size
40
+ avogadro = 6.02214179e+23
41
+ water_number = get_water_number() + args.addwat
42
+ ion_number = get_ion_number(args.ioncon)
43
+
44
+ if ion_number == 0:
45
+ packmol_input_str = f"""
46
+ tolerance {args.tolerance}
47
+ filetype xyz
48
+ output {args.output}
49
+ pbc {args.cell[3]} {args.cell[4]} {args.cell[5]}
50
+ structure {args.watpath}
51
+ number {water_number}
52
+ inside box 2. 2. 2. {args.cell[0]-2} {args.cell[1]-2} {args.cell[2]-2}
53
+ end structure
54
+ """
55
+ else:
56
+ packmol_input_str = f"""
57
+ tolerance {args.tolerance}
58
+ filetype xyz
59
+ output {args.output}
60
+ pbc {args.cell[3]} {args.cell[4]} {args.cell[5]}
61
+ structure {args.watpath}
62
+ number {water_number}
63
+ inside box 2. 2. 2. {args.cell[0]-2} {args.cell[1]-2} {args.cell[2]-2}
64
+ end structure
65
+ structure {args.ionpath}
66
+ number {ion_number}
67
+ inside box 2. 2. 2. {args.cell[0]-2} {args.cell[1]-2} {args.cell[2]-2}
68
+ end structure
69
+ """
70
+
71
+ with open(args.o, 'w') as f:
72
+ f.write(packmol_input_str)
73
+
74
+
75
+ if __name__ == '__main__':
76
+ main()
mdkits/cli/pdos.py ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env python3.9
2
+
3
+ # caculate pdos
4
+
5
+ from cp2kdata import Cp2kPdos
6
+ import argparse
7
+ import numpy as np
8
+ from util import os_operation
9
+
10
+
11
+ def to_file(filename, ener, dos):
12
+ to_file = np.column_stack((ener, dos))
13
+ np.savetxt(filename, to_file, delimiter=" ")
14
+
15
+
16
+ # set argument
17
+ parser = argparse.ArgumentParser(description='calculate pdos')
18
+ parser.add_argument('filename', type=str, nargs='?', default=os_operation.default_file_name('*-k*.pdos'))
19
+ parser.add_argument('--type', type=str, default='total')
20
+ args = parser.parse_args()
21
+
22
+
23
+ # pdos
24
+ #dos_types = ['0']
25
+ #for dos_type in dos_types:
26
+ # for atom_type in range(1, args.type_number+1):
27
+ # dos_obj = Cp2kPdos(f'{args.project_name}-k{atom_type}-1_{args.run_step}.pdos')
28
+ # dos, ener = dos_obj.get_raw_dos()
29
+ # to_file(f"{dos_obj.read_dos_element()}_{dos_type}.pdos", ener, dos)
30
+
31
+ # total dos
32
+ print(args.filename)
33
+ for file in args.filename:
34
+ dos_obj = Cp2kPdos(file)
35
+ dos, ener = dos_obj.get_raw_dos(dos_type=args.type)
36
+ to_file(f'{dos_obj.read_dos_element()}_{args.type}.pdos', ener, dos)
mdkits/cli/plot.py ADDED
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import numpy as np
5
+ from matplotlib import pyplot as plt
6
+ from matplotlib import rcParams
7
+ import matplotlib.ticker as ticker
8
+ import yaml, click
9
+ from mdtool.util import fig_operation
10
+
11
+ DEFAULT_CONFIG = {
12
+ 'data': {},
13
+ 'x': {},
14
+ 'y': {},
15
+ 'figsize': None,
16
+ 'x_range': None,
17
+ 'y_range': None,
18
+ 'legend_fontsize': None,
19
+ 'ticks_fontsize': None,
20
+ 'line': {},
21
+ 'fold': None
22
+ }
23
+
24
+
25
+ def load_config(file_path):
26
+ try:
27
+ with open(file_path, 'r') as file:
28
+ data = yaml.safe_load(file)
29
+ except FileNotFoundError:
30
+ print(f"no file {file_path}")
31
+ exit(1)
32
+ except yaml.YAMLError as exc:
33
+ print(f"yaml parse error: {exc}")
34
+ exit(1)
35
+ config = data.copy()
36
+ #for key, default in DEFAULT_CONFIG.items():
37
+ # config[key] = data.get(key, default)
38
+ for key, value in config.items():
39
+ for dkey, dvalue in DEFAULT_CONFIG.items():
40
+ value[dkey] = data[key].get(dkey, dvalue)
41
+
42
+ return config
43
+
44
+
45
+ def check_figsize(figsize):
46
+ match figsize:
47
+ case list() if len(figsize) == 2:
48
+ rcParams['figure.figsize'] = figsize
49
+ case None:
50
+ pass
51
+ case _:
52
+ print("wrong yaml structure")
53
+ exit(1)
54
+
55
+
56
+ def check_int_ticks(ax, int_ticks):
57
+ match int_ticks:
58
+ case 'x':
59
+ ax.xaxis.set_major_locator(ticker.MaxNLocator(integer=True))
60
+ case 'y':
61
+ ax.yaxis.set_major_locator(ticker.MaxNLocator(integer=True))
62
+ case 'a':
63
+ ax.xaxis.set_major_locator(ticker.MaxNLocator(integer=True))
64
+ ax.yaxis.set_major_locator(ticker.MaxNLocator(integer=True))
65
+ case _:
66
+ pass
67
+
68
+
69
+ def check_axis_range(ax, x_range=None, y_range=None):
70
+ if x_range:
71
+ match x_range:
72
+ case list() if len(x_range) == 2:
73
+ ax.set_xlim(x_range[0], x_range[1])
74
+ case None:
75
+ pass
76
+ case _:
77
+ print("wrong yaml structure")
78
+ exit(1)
79
+ if y_range:
80
+ match y_range:
81
+ case list() if len(y_range) == 2:
82
+ ax.set_ylim(y_range[0], y_range[1])
83
+ case None:
84
+ pass
85
+ case _:
86
+ print("wrong yaml structure")
87
+ exit(1)
88
+
89
+
90
+ def check_lenend_fontsize(ax, legend_fontsize, rmse=None):
91
+ if rmse is not None:
92
+ match legend_fontsize:
93
+ case int():
94
+ l = ax.legend(fontsize=legend_fontsize, markerscale=0, handlelength=0)
95
+ case None:
96
+ l = ax.legend(markerscale=0, handlelength=0)
97
+ case _:
98
+ pass
99
+
100
+ #p = l.get_window_extent()
101
+ #ax.annotate(f"RMSE:{rmse:.4f}", (p.p0[0], p.p1[1]), (p.p0[0], p.p1[1]-300), xycoords='figure pixels', fontsize=legend_fontsize)
102
+ else:
103
+ match legend_fontsize:
104
+ case int():
105
+ ax.legend(fontsize=legend_fontsize)
106
+ case None:
107
+ ax.legend()
108
+ case _:
109
+ pass
110
+
111
+
112
+ def check_output_mode(fig, plt, m, figure, fold=None):
113
+ match m:
114
+ case 'show':
115
+ plt.show()
116
+ case 'save':
117
+ fig_operation.savefig(fig, f"{figure}", fold)
118
+ plt.close()
119
+ case 'all':
120
+ fig_operation.savefig(fig, f"{figure}", fold)
121
+ plt.show()
122
+ plt.close()
123
+ case _:
124
+ pass
125
+
126
+
127
+ def check_ticks_fontsize(ax, ticks_fontsize):
128
+ match ticks_fontsize:
129
+ case int():
130
+ ax.tick_params(axis='both', labelsize=ticks_fontsize)
131
+ case None:
132
+ pass
133
+ case _:
134
+ pass
135
+
136
+
137
+ def mode_1(data_dict, figure, **kwargs):
138
+ # init config
139
+ check_figsize(data_dict['figsize'])
140
+
141
+ fig, ax = plt.subplots()
142
+
143
+ # ticks config
144
+ check_int_ticks(ax, kwargs['int_ticks'])
145
+
146
+ # plot part
147
+ for label, data in data_dict['data'].items():
148
+ label = r"$\mathrm{ "+ label +" }$"
149
+ data = np.loadtxt(data)
150
+ x_slice, xlabel = next(iter(data_dict['x'].items()))
151
+ for y_slice, ylabel in data_dict['y'].items():
152
+ ax.plot(data[:, x_slice], data[:, y_slice], label=label)
153
+
154
+ # range config
155
+ check_axis_range(ax, x_range=data_dict['x_range'], y_range=data_dict['y_range'])
156
+
157
+ # axis label part
158
+ ax.set_xlabel(r"$\mathrm{ "+ xlabel +" }$")
159
+ ax.set_ylabel(r"$\mathrm{ "+ ylabel +" }$")
160
+
161
+ # h or v line
162
+ match data_dict['line']:
163
+ case _:
164
+ pass
165
+
166
+ # legend config
167
+ check_lenend_fontsize(ax, data_dict['legend_fontsize'])
168
+
169
+ # output part
170
+ check_output_mode(fig, plt, kwargs['m'], figure, data_dict['fold'])
171
+
172
+
173
+ def mode_2(data_dict, figure, **kwargs):
174
+ # init config
175
+ check_figsize(data_dict['figsize'])
176
+
177
+ fig, ax = plt.subplots()
178
+
179
+ # ticks config
180
+ check_int_ticks(ax, kwargs['int_ticks'])
181
+
182
+ # plot part
183
+ ylabel, data = next(iter(data_dict['data'].items()))
184
+ data = np.loadtxt(data)
185
+ x_slice, xlabel = next(iter(data_dict['x'].items()))
186
+ for y_slice, label in data_dict['y'].items():
187
+ label = r"$\mathrm{ "+ label +" }$"
188
+ ax.plot(data[:, x_slice], data[:, y_slice], label=label)
189
+
190
+ # range config
191
+ check_axis_range(ax, x_range=data_dict['x_range'], y_range=data_dict['y_range'])
192
+
193
+ # axis label part
194
+ ax.set_xlabel(r"$\mathrm{ "+ xlabel +" }$")
195
+ ax.set_ylabel(r"$\mathrm{ "+ ylabel +" }$")
196
+
197
+ # legend config
198
+ check_lenend_fontsize(ax, data_dict['legend_fontsize'])
199
+
200
+ # output part
201
+ check_output_mode(fig, plt, kwargs['m'], figure, data_dict['fold'])
202
+
203
+
204
+ def mode_error(data_dict, figure, **kwargs):
205
+ # init config
206
+ check_figsize(data_dict['figsize'])
207
+
208
+ fig, ax = plt.subplots(figsize=(4.8, 4.8))
209
+
210
+ # ticks config
211
+ check_int_ticks(ax, kwargs['int_ticks'])
212
+
213
+ # plot part
214
+ label, data = next(iter(data_dict['data'].items()))
215
+ data = np.loadtxt(data)
216
+ x_slice, xlabel = next(iter(data_dict['x'].items()))
217
+ for y_slice, ylabel in data_dict['y'].items():
218
+ label = r"$\mathrm{ "+ label +" }$"
219
+ ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f'))
220
+ ax.yaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f'))
221
+ ax.scatter(data[:, x_slice], data[:, y_slice], label=label)
222
+ data_diff = data[:, x_slice] - data[:, y_slice]
223
+ data_rmse = np.sqrt(np.average(data_diff*data_diff))
224
+ ax.axline((data[0, x_slice], data[0, x_slice]), slope=1, ls='--', c='black')
225
+ ax.set_xticks([])
226
+ ax.set_yticks([])
227
+ check_lenend_fontsize(ax, data_dict['ticks_fontsize'])
228
+
229
+ # range config
230
+ check_axis_range(ax, x_range=data_dict['x_range'], y_range=data_dict['y_range'])
231
+
232
+ # axis label part
233
+ ax.set_xlabel(r"$\mathrm{ "+ xlabel +" }$")
234
+ ax.set_ylabel(r"$\mathrm{ "+ ylabel +" }$")
235
+
236
+ lims = [np.min([ax.get_xlim(), ax.get_ylim()]), np.max([ax.get_xlim(), ax.get_ylim()])]
237
+ ax.text(lims[0]+(lims[1]-lims[0])*.6, lims[0]+(lims[1]-lims[0])*.1, f"RMSE: {data_rmse:.4f}", fontsize=data_dict['legend_fontsize'])
238
+ ax.set_xlim(lims)
239
+ ax.set_ylim(lims)
240
+ #ax.set_aspect('equal')
241
+ #plt.axis('equal')
242
+ # legend config
243
+ check_lenend_fontsize(ax, data_dict['legend_fontsize'], rmse=data_rmse)
244
+
245
+ # output part
246
+ check_output_mode(fig, plt, kwargs['m'], figure, data_dict['fold'])
247
+
248
+
249
+ @click.command(name='plot')
250
+ @click.argument('yaml_file', type=click.Path(exists=True), nargs=-1)
251
+ @click.option('--int_ticks', help='set x ticks or y ticks with int, choices: x, y, a(all)', type=click.Choice(['x', 'y', 'a']))
252
+ @click.option('--error', help='set error mode', is_flag=True)
253
+ @click.option('-m', help='output mode: show, save, all, default is save', type=click.Choice(['show', 'save', 'all']), default='save')
254
+ def main(yaml_file, int_ticks, error, m):
255
+ kwargs = locals()
256
+ figure_dict = {}
257
+ for yaml_file in yaml_file:
258
+ yaml_dict = load_config(yaml_file)
259
+ figure_dict.update(yaml_dict)
260
+
261
+ for figure, data_dict in figure_dict.items():
262
+ check_data = len(data_dict['data'])
263
+
264
+ # mode error
265
+ if error:
266
+ mode = 'error'
267
+ mode_error(data_dict, figure, **kwargs)
268
+
269
+ # mode 1
270
+ elif check_data > 1:
271
+ if len(data_dict['y']) > 1:
272
+ print("wrong yaml structure")
273
+ exit(1)
274
+ mode = 1
275
+ mode_1(data_dict, figure, **kwargs)
276
+
277
+ # mode 2
278
+ elif check_data == 1:
279
+ mode = 2
280
+ mode_2(data_dict, figure, **kwargs)
281
+
282
+ else:
283
+ print("wrong yaml structure")
284
+ exit(1)
285
+ print(f"{figure} is done with mode {mode}")
286
+
287
+
288
+ if __name__ == '__main__':
289
+ main()
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from ase.io import read
4
+ import argparse, os
5
+ import numpy as np
6
+ from ase.build import make_supercell
7
+ from util import (
8
+ structure_parsing,
9
+ encapsulated_ase,
10
+ cp2k_input_parsing
11
+ )
12
+
13
+
14
+ def supercell(atom, x, y, z):
15
+ P = [ [x, 0, 0], [0, y, 0], [0, 0, z] ]
16
+ super_atom = make_supercell(atom, P)
17
+ return super_atom
18
+
19
+
20
+ def parse_cell(s):
21
+ return [float(x) for x in s.replace(',', ' ').split()]
22
+
23
+
24
+ def super_cell(s):
25
+ super_cell = [int(x) for x in s.replace(',', ' ').split()]
26
+ leng = len(super_cell)
27
+ if leng == 2:
28
+ super_cell.append(1)
29
+ elif leng == 3:
30
+ pass
31
+ else:
32
+ print('wrong super cell size')
33
+ exit(1)
34
+
35
+ return super_cell
36
+
37
+
38
+ def parse_argument():
39
+ parser = argparse.ArgumentParser(description='make a supercell')
40
+
41
+ parser.add_argument('input_file_name', type=str, help='input file name')
42
+ parser.add_argument('super', type=super_cell, help='super cell size, a,b,c')
43
+ parser.add_argument('-o', type=str, help='output file name, default is "super.cif"', default='super.cif')
44
+ parser.add_argument('--cp2k_input_file', type=str, help='input file name of cp2k, default is "input.inp"', default='input.inp')
45
+ parser.add_argument('--coord', help='coord format', action='store_true')
46
+ parser.add_argument('--cell', type=parse_cell, help='set cell, a list of lattice, --cell x,y,z or x,y,z,a,b,c')
47
+
48
+ return parser.parse_args()
49
+
50
+
51
+ def main():
52
+ args = parse_argument()
53
+ if args.input_file_name == None:
54
+ print('give a xyz file')
55
+ sys.exit()
56
+
57
+ atom = encapsulated_ase.atoms_read_with_cell(args.input_file_name, cell=args.cell, coord_mode=args.coord)
58
+ atom.set_pbc(True)
59
+ atom.wrap()
60
+ super_atom = supercell(atom, args.super[0], args.super[1], args.super[2])
61
+
62
+ suffix = args.o.split('.')[-1]
63
+ if suffix == 'data':
64
+ super_atom.write(f'{args.o}', format='lammps-data', atom_style='atomic')
65
+ else:
66
+ super_atom.write(f'{args.o}')
67
+
68
+ print(os.path.abspath(args.o))
69
+
70
+
71
+ if __name__ == '__main__':
72
+ main()
mdkits/cli/wrap.py ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ from MDAnalysis import Universe
5
+ import MDAnalysis, click
6
+ from mdtool.util import (
7
+ arg_type,
8
+ os_operation,
9
+ cp2k_input_parsing
10
+ )
11
+
12
+
13
+ @click.command(name='wrap')
14
+ @click.argument('filename', type=click.Path(exists=True), default=os_operation.default_file_name('*-pos-1.xyz', last=True))
15
+ @click.option('-o', type=str, help='output file name', default='wraped.xyz', show_default=True)
16
+ @click.option('--cell', type=arg_type.Cell, help='set cell from cp2k input file or a list of lattice: --cell x,y,z or x,y,z,a,b,c', default='input.inp', show_default=True)
17
+ def main(filename, o, cell):
18
+ """
19
+ wrap the coordinates in a cell from a trajectory file
20
+ """
21
+
22
+ u = Universe(filename)
23
+ u.dimensions = cell
24
+ ag = u.select_atoms("all")
25
+
26
+ with MDAnalysis.Writer(o, ag.n_atoms) as W:
27
+ for ts in u.trajectory:
28
+ ag.wrap()
29
+ W.write(ag)
30
+
31
+ click.echo("\nwrap is done, output file {o} is:")
32
+ click.echo(os.path.abspath(o))
33
+
34
+
35
+ if __name__ == '__main__':
36
+ main()
@@ -0,0 +1,35 @@
1
+ """
2
+ Configuration center.
3
+ Use https://www.dynaconf.com/
4
+ """""
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ from dynaconf import Dynaconf
10
+
11
+
12
+ _base_dir = Path(__file__).parent.parent
13
+
14
+ _settings_files = [
15
+ # All config file will merge.
16
+ Path(__file__).parent / 'settings.yml', # Load default config.
17
+ ]
18
+
19
+ # User configuration. It will be created automatically by the pip installer .
20
+ _external_files = [
21
+ Path(sys.prefix, 'etc', 'mdtool', 'settings.yml')
22
+ ]
23
+
24
+
25
+ settings = Dynaconf(
26
+ # Set env `MDTOOL_FOO='bar'`,use `settings.FOO` .
27
+ envvar_prefix='MDTOOL',
28
+ settings_files=_settings_files, # load user configuration.
29
+ # environments=True, # Enable multi-level configuration,eg: default, development, production
30
+ load_dotenv=True, # Enable load .env
31
+ # env_switcher='MDTOOL_ENV',
32
+ lowercase_read=False, # If true, can't use `settings.foo`, but can only use `settings.FOO`
33
+ includes=_external_files, # Customs settings.
34
+ base_dir=_base_dir, # `settings.BASE_DIR`
35
+ )
@@ -0,0 +1,4 @@
1
+ verbose: false
2
+ debug: false
3
+ loglevel: warning
4
+ logpath: /tmp/mdtool
mdkits/mdtool.py ADDED
@@ -0,0 +1,28 @@
1
+ import click
2
+ from mdtool.cli import (
3
+ convert,
4
+ wrap,
5
+ extract,
6
+ data,
7
+ plot,
8
+ )
9
+
10
+
11
+ @click.group(name='cli')
12
+ @click.pass_context
13
+ @click.version_option()
14
+ def cli(ctx):
15
+ print(ctx)
16
+ """tools for md or dft"""
17
+ pass
18
+
19
+
20
+ cli.add_command(convert.main)
21
+ cli.add_command(wrap.main)
22
+ cli.add_command(extract.main)
23
+ cli.add_command(data.main)
24
+ cli.add_command(plot.main)
25
+
26
+
27
+ if __name__ == '__main__':
28
+ cli()
File without changes
@@ -0,0 +1,41 @@
1
+ import click, os
2
+ from . import cp2k_input_parsing
3
+
4
+
5
+ class CellType(click.ParamType):
6
+ name = "pbc cell type"
7
+
8
+ def convert(self, value, param, ctx):
9
+ if isinstance(value, str):
10
+ if ',' not in value:
11
+ cell = cp2k_input_parsing.parse_cell(value)
12
+ return cell
13
+ else:
14
+ cell = [float(x) for x in value.split(',')]
15
+
16
+ if len(cell) == 3:
17
+ click.echo(f"system cell: x = {cell[0]}, y = {cell[1]}, z = {cell[2]}, a = {90}\u00B0, b = {90}\u00B0, c = {90}\u00B0")
18
+ return cell + [90, 90, 90]
19
+ elif len(cell) == 6:
20
+ click.echo(f"system cell: x = {cell[0]}, y = {cell[1]}, z = {cell[2]}, a = {cell[3]}\u00B0, b = {cell[4]}\u00B0, c = {cell[5]}\u00B0")
21
+ return cell
22
+ else:
23
+ self.fail(f"{value} is not a valid cell parameter", param, ctx)
24
+
25
+
26
+ class FrameRangeType(click.ParamType):
27
+ name = "frame range"
28
+ def convert(self, value, param, ctx):
29
+ if isinstance(value, str):
30
+ parts = value.split(':')
31
+
32
+ range_list = [int(x) if x else None for x in parts]
33
+
34
+ if len(range_list) > 0 and len(range_list) <= 3:
35
+ return range_list
36
+ else:
37
+ self.fail(f"{value} is not a valid frame range", param, ctx)
38
+
39
+
40
+ Cell = CellType()
41
+ FrameRange = FrameRangeType()