orto 0.0.1__tar.gz

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.
orto-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.1
2
+ Name: orto
3
+ Version: 0.0.1
4
+ Summary: A package to make life easier when performing Orca calculations.
5
+ Home-page: https://gitlab.com/kragskow-group/orto
6
+ Author: Jon Kragskow
7
+ Author-email: jgck20@bath.ac.uk
8
+ Project-URL: Bug Tracker, https://gitlab.com/kragskow-group/orto/issues
9
+ Project-URL: Documentation, https://www.kragskow.dev/orto/index.html
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: numpy
16
+ Requires-Dist: xyz_py>=5.11.0
17
+
18
+
19
+ `orto` is a package to make life easier when performing Orca calculations.
20
+
21
+
22
+
23
+ Please see the `orto` documentation for more details.
orto-0.0.1/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # orto
2
+ OrcaTools
@@ -0,0 +1,4 @@
1
+ from orto.cli import *
2
+ """
3
+ orto is a package for using Orca
4
+ """
@@ -0,0 +1 @@
1
+ __version__ = '1.2.1'
@@ -0,0 +1,3 @@
1
+ import numpy as np
2
+
3
+
orto-0.0.1/orto/cli.py ADDED
@@ -0,0 +1,467 @@
1
+ import argparse
2
+ import xyz_py as xyzp
3
+ import matplotlib.pyplot as plt
4
+ import os
5
+ import copy
6
+
7
+ from . import reader
8
+ from . import plotter
9
+ from . import extractor
10
+ from . import job
11
+ from . import utils as ut
12
+ from . import input
13
+
14
+
15
+ def extract_coords_func(uargs):
16
+ '''
17
+ Wrapper for extract_coords function
18
+ '''
19
+
20
+ # Open file and extract coordinates
21
+ labels, coords = extractor.get_coords(
22
+ uargs.file_name,
23
+ coord_type=uargs.type,
24
+ index_style=uargs.index_style
25
+ )
26
+
27
+ # Save to new .xyz file
28
+ head = os.path.splitext(uargs.file_name)[0]
29
+ xyzp.save_xyz(
30
+ f'{head}_coords.xyz',
31
+ labels,
32
+ coords,
33
+ comment=f'Coordinates extracted from {uargs.file_name}'
34
+ )
35
+
36
+ return
37
+
38
+
39
+ def gen_job_func(uargs):
40
+ '''
41
+ Wrapper for CLI gen_job call
42
+
43
+ Parameters
44
+ ----------
45
+ uargs : argparser object
46
+ User arguments
47
+
48
+ Returns
49
+ -------
50
+ None
51
+ '''
52
+
53
+ oj = job.OrcaJob(
54
+ uargs.file_name
55
+ )
56
+
57
+ # Get orca module and pre- and post- commands
58
+ orca_args = [
59
+ 'orca_load',
60
+ 'pre_orca',
61
+ 'post_orca'
62
+ ]
63
+
64
+ required = [
65
+ 'orca_load'
66
+ ]
67
+
68
+ for oarg in orca_args:
69
+ uarg_val = getattr(uargs, oarg)
70
+ if len(uarg_val):
71
+ oarg_val = copy.copy(uarg_val)
72
+ elif os.getenv(f'orto_{oarg}'):
73
+ try:
74
+ if len(os.getenv(f'orto_{oarg}')):
75
+ oarg_val = os.getenv(f'orto_{oarg}')
76
+ except ValueError:
77
+ ut.red_exit(
78
+ (
79
+ f'Error in orto_{oarg} environment variable'
80
+ )
81
+ )
82
+ elif oarg in required:
83
+ ut.red_exit(
84
+ (
85
+ f'Missing orto_{oarg} environment variable or '
86
+ f'--{oarg} argument'
87
+ )
88
+ )
89
+ else:
90
+ oarg_val = ''
91
+
92
+ if oarg == 'orca_load':
93
+ oarg = 'load'
94
+ oarg_val = f'{oarg_val}'
95
+ setattr(oj, oarg, oarg_val)
96
+
97
+ # Load submission system config from template file, either from cli
98
+ # or environment variable
99
+ if len(uargs.sub_template):
100
+ config = oj.scheduler_job_class.read_template_file(
101
+ uargs.sub_template
102
+ )
103
+ elif os.getenv('orto_sub_template'):
104
+ config = oj.scheduler_job_class.read_template_file(
105
+ os.getenv('orto_sub_template')
106
+ )
107
+ else:
108
+ config = {}
109
+
110
+ # Load number of procs and amount of memory from orca input file
111
+ n_procs = input.get_nprocs(uargs.file_name)
112
+ maxcore = input.get_maxcore(uargs.file_name)
113
+
114
+ # If memory and procs specified as arguments, give warning when
115
+ # these dont match numbers in orca input file
116
+ if n_procs > uargs.n_procs:
117
+ ut.red_exit('Too few processors requested for input file')
118
+ elif n_procs < uargs.n_procs:
119
+ ut.cprint(
120
+ (
121
+ 'Warning: Requesting more cores than in input file\n'
122
+ ' ... this may be fine!'
123
+ ),
124
+ 'yellow'
125
+ )
126
+ config['ntasks_per_node'] = n_procs
127
+
128
+ if uargs.memory > 0:
129
+ if uargs.memory * uargs.n_procs < n_procs * maxcore:
130
+ ut.red_exit('Requested too little memory for orca input')
131
+ config['mem_per_cpu'] = uargs.memory
132
+ elif 'mem_per_cpu' not in config.keys():
133
+ ut.red_exit(
134
+ 'Missing mem_per_cpu in both command line and template file'
135
+ )
136
+
137
+ # Write job script
138
+ oj.write_script(True, **config)
139
+
140
+ return
141
+
142
+
143
+ def plot_uvvis_func(uargs):
144
+ '''
145
+ Wrapper for CLI plot_uvvis call
146
+
147
+ Parameters
148
+ ----------
149
+ uargs : argparser object
150
+ User arguments
151
+
152
+ Returns
153
+ -------
154
+ None
155
+ '''
156
+
157
+ # Read output file
158
+ wavenumbers, fosc, p2 = reader.read_uvvis(
159
+ uargs.file_name,
160
+ uargs.intensity_type
161
+ )
162
+
163
+ if uargs.x_lim is None:
164
+ if uargs.x_unit == 'wavenumber':
165
+ uargs.x_lim = [0, 50000]
166
+ if uargs.x_unit == 'wavelength':
167
+ # 1 to 2000 nm
168
+ uargs.x_lim = [5000., 10000000.]
169
+
170
+ # Plot uvvis spectrum
171
+ fig, ax = plotter.plot_uvvis(
172
+ wavenumbers,
173
+ fosc,
174
+ show=False,
175
+ x_lim=uargs.x_lim,
176
+ y_lim=uargs.y_lim,
177
+ x_unit=uargs.x_unit,
178
+ linewidth=uargs.linewidth,
179
+ lineshape=uargs.lineshape,
180
+ window_title=f'UV-Visible Spectrum from {uargs.file_name}',
181
+ show_osc=not uargs.no_osc
182
+ )
183
+
184
+ if uargs.x_unit == 'wavenumber':
185
+ ax[0].set_xlim([0, 50000])
186
+ if uargs.x_unit == 'wavelength':
187
+ ax[0].set_xlim([0, 2000])
188
+ plt.show()
189
+
190
+ return
191
+
192
+
193
+ def plot_ir_func(uargs):
194
+ '''
195
+ Wrapper for CLI plot_ir call
196
+
197
+ Parameters
198
+ ----------
199
+ uargs : argparser object
200
+ User arguments
201
+
202
+ Returns
203
+ -------
204
+ None
205
+ '''
206
+
207
+ # Read output file
208
+ wavenumbers, intensities, _ = reader.read_infrared(
209
+ uargs.file_name
210
+ )
211
+ # Plot uvvis spectrum
212
+ fig, ax = plotter.plot_ir(
213
+ wavenumbers,
214
+ intensities,
215
+ linewidth=uargs.linewidth,
216
+ lineshape=uargs.lineshape,
217
+ window_title=f'Infrared Spectrum from {uargs.file_name}'
218
+ )
219
+
220
+ return
221
+
222
+
223
+ def read_args(arg_list=None):
224
+ '''
225
+ Reader for command line arguments. Uses subReaders for individual programs
226
+
227
+ Parameters
228
+ ----------
229
+ args : argparser object
230
+ command line arguments
231
+
232
+ Returns
233
+ -------
234
+ None
235
+
236
+ '''
237
+
238
+ description = '''
239
+ A package for working with Orca
240
+ '''
241
+
242
+ epilog = '''
243
+ To display options for a specific program, use splash \
244
+ PROGRAMFILETYPE -h
245
+ '''
246
+ parser = argparse.ArgumentParser(
247
+ description=description,
248
+ epilog=epilog,
249
+ formatter_class=argparse.RawDescriptionHelpFormatter
250
+ )
251
+
252
+ subparsers = parser.add_subparsers(dest='prog')
253
+
254
+ extract_coords = subparsers.add_parser(
255
+ 'extract_coords',
256
+ description='Extracts coordinates from Orca output file'
257
+ )
258
+ extract_coords.set_defaults(func=extract_coords_func)
259
+
260
+ extract_coords.add_argument(
261
+ 'file_name',
262
+ type=str,
263
+ help='Orca output file name(s)'
264
+ )
265
+
266
+ extract_coords.add_argument(
267
+ '--type',
268
+ type=str,
269
+ help='Which coordinates to extract',
270
+ choices=['opt', 'init'],
271
+ default='init'
272
+ )
273
+
274
+ extract_coords.add_argument(
275
+ '--index_style',
276
+ type=str,
277
+ help='Style of indexing used for output atom labels',
278
+ choices=['per_element', 'sequential', 'sequential_orca', 'none'],
279
+ default='per_element'
280
+ )
281
+
282
+ gen_job = subparsers.add_parser(
283
+ 'gen_job',
284
+ description='Generate submission script for orca calculation'
285
+ )
286
+ gen_job.set_defaults(func=gen_job_func)
287
+
288
+ gen_job.add_argument(
289
+ 'file_name',
290
+ type=str,
291
+ help='Orca output file name(s)'
292
+ )
293
+
294
+ gen_job.add_argument(
295
+ 'n_procs',
296
+ type=int,
297
+ help=(
298
+ 'Number of cores requested in submission system\n'
299
+ ' This does not need to match the orca input, but must not be less'
300
+ )
301
+ )
302
+
303
+ gen_job.add_argument(
304
+ '--memory',
305
+ '-mem',
306
+ type=int,
307
+ default=0,
308
+ help=(
309
+ 'Per core memory requested in submission system\n'
310
+ ' This does not need to match the orca input, but must not be less'
311
+ )
312
+ )
313
+
314
+ gen_job.add_argument(
315
+ '-st',
316
+ '--sub_template',
317
+ type=str,
318
+ default='',
319
+ help='Template file for submission system'
320
+ )
321
+
322
+ gen_job.add_argument(
323
+ '-om',
324
+ '--orca_load',
325
+ type=str,
326
+ default='',
327
+ help='Orca environment module (overrides environment variable)'
328
+ )
329
+
330
+ gen_job.add_argument(
331
+ '-pre',
332
+ '--pre_orca',
333
+ type=str,
334
+ default='',
335
+ help='Commands to include before Orca call'
336
+ )
337
+
338
+ gen_job.add_argument(
339
+ '-post',
340
+ '--post_orca',
341
+ type=str,
342
+ default='',
343
+ help='Commands to include after Orca call'
344
+ )
345
+
346
+ plot_uvvis = subparsers.add_parser(
347
+ 'plot_uvvis',
348
+ description='Plots uvvis spectrum from CI calculation output'
349
+ )
350
+ plot_uvvis.set_defaults(func=plot_uvvis_func)
351
+
352
+ plot_uvvis.add_argument(
353
+ 'file_name',
354
+ type=str,
355
+ help='Orca output file name(s)'
356
+ )
357
+
358
+ plot_uvvis.add_argument(
359
+ '--intensity_type',
360
+ type=str,
361
+ choices=['velocity', 'electric'],
362
+ default='electric',
363
+ help='Type of intensity to plot (orca_mapspc uses electric)'
364
+ )
365
+
366
+ plot_uvvis.add_argument(
367
+ '--linewidth',
368
+ '-lw',
369
+ type=float,
370
+ default=2000,
371
+ help=(
372
+ 'Width of signal (FWHM for Gaussian, Width for Lorentzian),'
373
+ ' in Wavenumbers'
374
+ )
375
+ )
376
+
377
+ plot_uvvis.add_argument(
378
+ '--no_osc',
379
+ action='store_true',
380
+ help=(
381
+ 'Disables oscillator strength stem plots'
382
+ )
383
+ )
384
+
385
+ plot_uvvis.add_argument(
386
+ '--lineshape',
387
+ '-ls',
388
+ type=str,
389
+ choices=['gaussian', 'lorentzian'],
390
+ default='lorentzian',
391
+ help='Lineshape to use for each signal'
392
+ )
393
+
394
+ plot_uvvis.add_argument(
395
+ '--x_unit',
396
+ type=str,
397
+ choices=['wavenumber', 'wavelength'],
398
+ default='wavelength',
399
+ help='x units to use for spectrum'
400
+ )
401
+
402
+ plot_uvvis.add_argument(
403
+ '--x_lim',
404
+ type=float,
405
+ nargs=2,
406
+ help='Wavenumber or Wavelength limits of spectrum'
407
+ )
408
+
409
+ plot_uvvis.add_argument(
410
+ '--y_lim',
411
+ nargs=2,
412
+ default=['auto', 'auto'],
413
+ help='Epsilon limits of spectrum in cm^-1 mol^-1 L'
414
+ )
415
+
416
+ plot_ir = subparsers.add_parser(
417
+ 'plot_ir',
418
+ description='Plots IR spectrum from frequency calculation output'
419
+ )
420
+ plot_ir.set_defaults(func=plot_ir_func)
421
+
422
+ plot_ir.add_argument(
423
+ 'file_name',
424
+ type=str,
425
+ help='Orca output file name(s)'
426
+ )
427
+
428
+ plot_ir.add_argument(
429
+ '--linewidth',
430
+ '-lw',
431
+ type=float,
432
+ default=2000,
433
+ help=(
434
+ 'Width of signal (FWHM for Gaussian, Width for Lorentzian),'
435
+ ' in Wavenumbers'
436
+ )
437
+ )
438
+
439
+ plot_ir.add_argument(
440
+ '--lineshape',
441
+ '-ls',
442
+ type=str,
443
+ choices=['gaussian', 'lorentzian'],
444
+ default='lorentzian',
445
+ help='Lineshape to use for each signal'
446
+ )
447
+
448
+ # If argument list is none, then call function func
449
+ # which is assigned to help function
450
+ parser.set_defaults(func=lambda _: parser.print_help())
451
+
452
+ # read sub-parser
453
+ _args, _ = parser.parse_known_args(arg_list)
454
+
455
+ # select parsing option based on sub-parser
456
+ if _args.prog in ['rst_opt']:
457
+ args, job_args = parser.parse_known_args(arg_list)
458
+ args.func(args, job_args)
459
+ else:
460
+ args = parser.parse_args(arg_list)
461
+ args.func(args)
462
+ return args
463
+
464
+
465
+ def interface():
466
+ read_args()
467
+ return
@@ -0,0 +1,63 @@
1
+ import numpy as np
2
+ from numpy.typing import NDArray
3
+ import xyz_py as xyzp
4
+
5
+
6
+ def get_coords(file_name: str, coord_type: str = 'init',
7
+ index_style: str = 'per_element') -> tuple[list, NDArray]:
8
+ '''
9
+ Extracts cartesian coordinates and atom labels from Orca output file
10
+
11
+ Parameters
12
+ ----------
13
+ file_name: str
14
+ Name of Orca output file to parse
15
+ coord_type: str, {'init', 'opt'}
16
+ Specifies which set of coordinates to extract\n
17
+ Options are:\n
18
+ "init" = Initial coordinates\n
19
+ "opt" = Final optimised coordinates
20
+ index_style: str {'per_element', 'sequential', 'sequential_orca', 'none'}
21
+ Specifies what type of atom label indexing used for final atom labels\n
22
+ Options are:\n
23
+ 'per_element' = Index by element e.g. Dy1, Dy2, N1, N2, etc.\n
24
+ 'sequential' = Index the atoms 1->N regardless of element\n
25
+ 'sequential_orca' = Index the atoms 0->N-1 regardless of element\n
26
+ 'none' = No label indexing
27
+
28
+ Returns
29
+ -------
30
+ list
31
+ Atomic labels
32
+ ndarray of floats
33
+ (n_atoms,3) array containing xyz coordinates of each atom
34
+ '''
35
+
36
+ labels, coords = [], []
37
+
38
+ with open(file_name, 'r') as f:
39
+ for line in f:
40
+ if 'CARTESIAN COORDINATES (ANGSTROEM)' in line:
41
+ labels, coords = [], []
42
+ line = next(f)
43
+ line = next(f)
44
+ while len(line.lstrip().rstrip()):
45
+ labels.append(line.split()[0])
46
+ coords.append([float(val) for val in line.split()[1:4]])
47
+ line = next(f)
48
+ if coord_type.lower() == 'init':
49
+ break
50
+
51
+ if not len(labels):
52
+ raise ValueError(f'Cannot find coordinates in {file_name}')
53
+
54
+ if index_style in ['per_element', 'sequential']:
55
+ labels = xyzp.add_label_indices(labels, style=index_style)
56
+ elif index_style == 'sequential_orca':
57
+ labels = xyzp.add_label_indices(
58
+ labels, style='sequential', start_index=0
59
+ )
60
+ else:
61
+ labels = xyzp.remove_label_indices(labels)
62
+
63
+ return labels, np.asarray(coords)
@@ -0,0 +1,54 @@
1
+ import re
2
+ import mmap
3
+
4
+
5
+ def get_nprocs(file_name: str) -> int:
6
+ '''
7
+ Extracts nprocs number from orca input file
8
+
9
+ Parameters
10
+ ----------
11
+ file_name: str
12
+ Orca input file
13
+
14
+ Returns
15
+ -------
16
+ int
17
+ nprocs value
18
+ '''
19
+ pattern = re.compile(
20
+ r' ?%PAL NPROCS (\d+) END'.encode(),
21
+ re.DOTALL | re.IGNORECASE | re.MULTILINE
22
+ )
23
+
24
+ with open(file_name, 'rb') as f:
25
+ content = mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ)
26
+ it = pattern.findall(content)
27
+
28
+ return int(it[0].decode())
29
+
30
+
31
+ def get_maxcore(file_name: str) -> int:
32
+ '''
33
+ Extracts maxcore number from orca input file
34
+
35
+ Parameters
36
+ ----------
37
+ file_name: str
38
+ Orca input file
39
+
40
+ Returns
41
+ -------
42
+ int
43
+ maxcore value
44
+ '''
45
+ pattern = re.compile(
46
+ r' ?%maxcore (\d+)'.encode(),
47
+ re.DOTALL | re.IGNORECASE | re.MULTILINE
48
+ )
49
+
50
+ with open(file_name, 'rb') as f:
51
+ content = mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ)
52
+ it = pattern.findall(content)
53
+
54
+ return int(it[0].decode())