orto 1.10.1__py3-none-any.whl → 1.11.0__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.
orto/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '1.10.1'
1
+ __version__ = '1.11.0'
orto/cli.py CHANGED
@@ -1,6 +1,4 @@
1
1
  import argparse
2
- import xyz_py as xyzp
3
- from xyz_py.atomic import elements as atomic_elements
4
2
  import sys
5
3
  import pathlib
6
4
  import os
@@ -9,14 +7,11 @@ import subprocess
9
7
  import csv
10
8
  import numpy as np
11
9
  import re
12
- from mmap import mmap, ACCESS_READ
13
- from shutil import move as shutilmove
14
- from subto.job import SlurmJob
10
+ from xyz_py.atomic import elements as atomic_elements
15
11
 
16
12
  from . import job
17
13
  from . import utils as ut
18
14
  from . import constants as cst
19
- from . import data as d
20
15
  from .exceptions import DataNotFoundError, DataFormattingError
21
16
 
22
17
  _SHOW_CONV = {
@@ -40,9 +35,9 @@ def extract_coords_func(uargs, save=True):
40
35
 
41
36
  Parameters
42
37
  ----------
43
- args : argparser object
38
+ uargs: argparser object
44
39
  command line arguments
45
- save : bool, default=True
40
+ save: bool, default=True
46
41
  If True, saves data to file. If False, prints to stdout.
47
42
 
48
43
  Returns
@@ -50,6 +45,7 @@ def extract_coords_func(uargs, save=True):
50
45
  None
51
46
  '''
52
47
  from . import extractor as oe
48
+ import xyz_py as xyzp
53
49
 
54
50
  # Open file and extract coordinates
55
51
  labels, coords = oe.get_coords(
@@ -120,7 +116,7 @@ def extract_sf_energies_func(uargs):
120
116
  style = doc.styles['Normal']
121
117
  font = style.font
122
118
  font.name = 'Arial'
123
- font.size = Pt(9)
119
+ font.size = Pt(12)
124
120
 
125
121
  # For each extracted section, print matrix, vectors, and values
126
122
  for it, data in enumerate(all_data):
@@ -154,7 +150,13 @@ def extract_sf_energies_func(uargs):
154
150
  cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
155
151
  cell.paragraphs[0].style = 'Normal'
156
152
 
157
- doc.save(out_name)
153
+ try:
154
+ doc.save(out_name)
155
+ except PermissionError:
156
+ ut.red_exit(
157
+ f'Cannot write to {out_name}\n'
158
+ 'is the file open somewhere else?'
159
+ )
158
160
 
159
161
  ut.cprint(f'Data written to {out_name}', 'cyan')
160
162
 
@@ -191,15 +193,205 @@ def extract_so_energies_func(uargs):
191
193
  return
192
194
 
193
195
 
196
+ def extract_hyperfine_func(uargs, save=True):
197
+ '''
198
+ Wrapper for cli call to extract hyperfine
199
+
200
+ Parameters
201
+ ----------
202
+ uargs: argparser object
203
+ command line arguments
204
+ save: bool, default=True
205
+ If True, saves data to file, else prints to stdout.
206
+ '''
207
+
208
+ from . import extractor as oe
209
+ from docx import Document
210
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
211
+ from docx.enum.table import WD_ALIGN_VERTICAL
212
+ from docx.shared import Pt
213
+
214
+ try:
215
+ all_data = oe.HyperfineExtractor.extract(uargs.output_file)
216
+ except (DataFormattingError, ValueError) as e:
217
+ ut.red_exit(str(e))
218
+
219
+ if not save:
220
+ for data in all_data:
221
+ for key, val in data.items():
222
+ print(f'{key}:')
223
+ print(val)
224
+ sys.exit(0)
225
+
226
+ if uargs.output_format == 'txt':
227
+ out_name = f'{uargs.output_file.stem}_hyperfine.txt'
228
+ with open(out_name, 'w') as f:
229
+ f.write(f'Data from {uargs.output_file}\n')
230
+ f.write('All values are in MHz')
231
+ for data in all_data:
232
+ if len(all_data) > 1:
233
+ f.write('=================\n')
234
+ for key, val in data.items():
235
+ f.write(f'{key}:\n')
236
+ f.write(str(val).replace('[', '').replace(']', ''))
237
+ f.write('\n')
238
+
239
+ if uargs.output_format == 'docx':
240
+ out_name = f'{uargs.output_file.stem}_hyperfine.docx'
241
+
242
+ title = 'Hyperfine coupling data from DFT'
243
+ title += (f'Data from {uargs.output_file}\n')
244
+
245
+ # Create document
246
+ doc = Document()
247
+
248
+ doc.add_heading(title, 0)
249
+
250
+ # Add style
251
+ style = doc.styles['Normal']
252
+ font = style.font
253
+ font.name = 'Arial'
254
+ font.size = Pt(12)
255
+
256
+ # For each extracted section, print all data
257
+ for data in all_data:
258
+ if len(all_data) > 1:
259
+ doc.add_paragraph(
260
+ f'Nucleus: {data['nucleus']}, Isotope: {data['isotope']}'
261
+ )
262
+
263
+ # Full matrix
264
+ matrix = doc.add_table(rows=5, cols=3)
265
+
266
+ matrix.cell(0, 0).merge(
267
+ matrix.cell(0, 1)
268
+ ).merge(
269
+ matrix.cell(0, 2)
270
+ )
271
+
272
+ matrix.cell(0, 0).text = 'Full Hyperfine Tensor / MHz'
273
+
274
+ matrix.cell(1, 0).text = '{:.4f}'.format(data['matrix'][0, 0])
275
+ matrix.cell(2, 0).text = '{:.4f}'.format(data['matrix'][0, 1])
276
+ matrix.cell(3, 0).text = '{:.4f}'.format(data['matrix'][0, 2])
277
+
278
+ matrix.cell(1, 1).text = '{:.4f}'.format(data['matrix'][1, 0])
279
+ matrix.cell(2, 1).text = '{:.4f}'.format(data['matrix'][1, 1])
280
+ matrix.cell(3, 1).text = '{:.4f}'.format(data['matrix'][1, 2])
281
+
282
+ matrix.cell(1, 2).text = '{:.4f}'.format(data['matrix'][2, 0])
283
+ matrix.cell(2, 2).text = '{:.4f}'.format(data['matrix'][2, 1])
284
+ matrix.cell(3, 2).text = '{:.4f}'.format(data['matrix'][2, 2])
285
+
286
+ matrix.cell(4, 0).text = 'Isotropic / MHz'
287
+
288
+ # Merge three cells for isotropic value
289
+ matrix.cell(4, 1).merge(
290
+ matrix.cell(4, 2)
291
+ )
292
+ matrix.cell(4, 1).text = f'{data['iso']:.4f}'
293
+
294
+ doc.add_paragraph('\n')
295
+
296
+ for row in matrix.rows:
297
+ for cell in row.cells:
298
+ cell.paragraphs[0].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # noqa
299
+ cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
300
+ cell.paragraphs[0].style = 'Normal'
301
+
302
+ # g values and g vectors
303
+ eigs = doc.add_table(rows=4, cols=4)
304
+ eigs.cell(0, 1).merge(eigs.cell(0, 1)).merge(eigs.cell(0, 2)).merge(eigs.cell(0, 3)) # noqa
305
+
306
+ eigs.cell(0, 0).text = 'Values / MHz'
307
+ eigs.cell(0, 1).text = 'Vectors'
308
+
309
+ eigs.cell(1, 0).text = '{:.4f}'.format(data['values'][0])
310
+ eigs.cell(2, 0).text = '{:.4f}'.format(data['values'][1])
311
+ eigs.cell(3, 0).text = '{:.4f}'.format(data['values'][2])
312
+
313
+ eigs.cell(1, 1).text = '{:.4f}'.format(data['vectors'][0, 0])
314
+ eigs.cell(2, 1).text = '{:.4f}'.format(data['vectors'][0, 1])
315
+ eigs.cell(3, 1).text = '{:.4f}'.format(data['vectors'][0, 2])
316
+
317
+ eigs.cell(1, 2).text = '{:.4f}'.format(data['vectors'][1, 0])
318
+ eigs.cell(2, 2).text = '{:.4f}'.format(data['vectors'][1, 1])
319
+ eigs.cell(3, 2).text = '{:.4f}'.format(data['vectors'][1, 2])
320
+
321
+ eigs.cell(1, 3).text = '{:.4f}'.format(data['vectors'][2, 0])
322
+ eigs.cell(2, 3).text = '{:.4f}'.format(data['vectors'][2, 1])
323
+ eigs.cell(3, 3).text = '{:.4f}'.format(data['vectors'][2, 2])
324
+
325
+ for row in eigs.rows:
326
+ for cell in row.cells:
327
+ cell.paragraphs[0].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # noqa
328
+ cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
329
+ cell.paragraphs[0].style = 'Normal'
330
+ doc.add_paragraph('\n')
331
+
332
+ components = doc.add_table(rows=5, cols=5)
333
+ components.cell(1, 0).text = 'Fermi Contact'
334
+ components.cell(2, 0).text = 'Spin Dipole'
335
+ components.cell(3, 0).text = 'Diamagnetic (Gauge Corr.)'
336
+ components.cell(4, 0).text = 'Spin-Orbit'
337
+
338
+ components.cell(0, 1).text = 'x / MHz'
339
+ components.cell(0, 2).text = 'y / MHz'
340
+ components.cell(0, 3).text = 'z / MHz'
341
+ components.cell(0, 4).text = 'Average / MHz'
342
+
343
+ if len(data['fc']):
344
+ components.cell(1, 1).text = f'{data['fc'][0]:.4f}'
345
+ components.cell(1, 2).text = f'{data['fc'][1]:.4f}'
346
+ components.cell(1, 3).text = f'{data['fc'][2]:.4f}'
347
+ components.cell(1, 4).text = f'{np.mean(data['fc']):.4f}'
348
+ if len(data['sd']):
349
+ components.cell(2, 1).text = f'{data['sd'][0]:.4f}'
350
+ components.cell(2, 2).text = f'{data['sd'][1]:.4f}'
351
+ components.cell(2, 3).text = f'{data['sd'][2]:.4f}'
352
+ components.cell(2, 4).text = f'{np.mean(data['sd']):.4f}'
353
+ if len(data['dia']):
354
+ components.cell(3, 1).text = f'{data['dia'][0]:.4f}'
355
+ components.cell(3, 2).text = f'{data['dia'][1]:.4f}'
356
+ components.cell(3, 3).text = f'{data['dia'][2]:.4f}'
357
+ components.cell(3, 4).text = f'{np.mean(data['dia']):.4f}'
358
+ if len(data['orb']):
359
+ components.cell(4, 1).text = f'{data['orb'][0]:.4f}'
360
+ components.cell(4, 2).text = f'{data['orb'][1]:.4f}'
361
+ components.cell(4, 3).text = f'{data['orb'][2]:.4f}'
362
+ components.cell(4, 4).text = f'{np.mean(data['orb']):.4f}'
363
+
364
+ for tab in [matrix, eigs, components]:
365
+ for row in tab.rows:
366
+ for cell in row.cells:
367
+ cell.paragraphs[0].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # noqa
368
+ cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
369
+ cell.paragraphs[0].style = 'Normal'
370
+
371
+ doc.add_page_break()
372
+
373
+ try:
374
+ doc.save(out_name)
375
+ except PermissionError:
376
+ ut.red_exit(
377
+ f'Cannot write to {out_name}\n'
378
+ 'is the file open somewhere else?'
379
+ )
380
+
381
+ ut.cprint(f'Data written to {out_name}', 'cyan')
382
+
383
+ return
384
+
385
+
194
386
  def extract_gmatrix_func(uargs, save=True):
195
387
  '''
196
388
  Wrapper for cli call to extract gmatrix
197
389
 
198
390
  Parameters
199
391
  ----------
200
- args : argparser object
392
+ uargs: argparser object
201
393
  command line arguments
202
- save : bool, default=True
394
+ save: bool, default=True
203
395
  If True, saves data to file. If False, prints to stdout.
204
396
 
205
397
  Returns
@@ -220,6 +412,7 @@ def extract_gmatrix_func(uargs, save=True):
220
412
  'dft': oe.GMatrixDFTExtractor
221
413
  }
222
414
 
415
+ # Check for linear response hyperfines
223
416
  if oe.EPRNMRDetector(uargs.output_file):
224
417
  uargs.type = 'dft'
225
418
 
@@ -269,7 +462,7 @@ def extract_gmatrix_func(uargs, save=True):
269
462
  style = doc.styles['Normal']
270
463
  font = style.font
271
464
  font.name = 'Arial'
272
- font.size = Pt(9)
465
+ font.size = Pt(12)
273
466
 
274
467
  # For each extracted section, print matrix, vectors, and values
275
468
  for it, data in enumerate(all_data):
@@ -331,7 +524,13 @@ def extract_gmatrix_func(uargs, save=True):
331
524
  cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
332
525
  cell.paragraphs[0].style = 'Normal'
333
526
 
334
- doc.save(out_name)
527
+ try:
528
+ doc.save(out_name)
529
+ except PermissionError:
530
+ ut.red_exit(
531
+ f'Cannot write to {out_name}\n'
532
+ 'is the file open somewhere else?'
533
+ )
335
534
 
336
535
  ut.cprint(f'Data written to {out_name}', 'cyan')
337
536
 
@@ -344,13 +543,14 @@ def gen_spden_func(uargs):
344
543
 
345
544
  Parameters
346
545
  ----------
347
- uargs : argparser object
546
+ uargs: argparser object
348
547
  User arguments
349
548
 
350
549
  Returns
351
550
  -------
352
551
  None
353
552
  '''
553
+ from subto.job import SlurmJob
354
554
 
355
555
  # Check orca module
356
556
  if len(uargs.orca_load):
@@ -424,13 +624,15 @@ def gen_trunc_molden_func(uargs):
424
624
 
425
625
  Parameters
426
626
  ----------
427
- uargs : argparser object
627
+ uargs: argparser object
428
628
  User arguments
429
629
 
430
630
  Returns
431
631
  -------
432
632
  None
433
633
  '''
634
+ from mmap import mmap, ACCESS_READ
635
+ from shutil import move as shutilmove
434
636
 
435
637
  # Read molden file in as binary string
436
638
  # and find number of MOs by counting number of
@@ -493,7 +695,7 @@ def gen_job_func(uargs):
493
695
 
494
696
  Parameters
495
697
  ----------
496
- uargs : argparser object
698
+ uargs: argparser object
497
699
  User arguments
498
700
 
499
701
  Returns
@@ -658,7 +860,7 @@ def plot_xes_func(uargs):
658
860
 
659
861
  Parameters
660
862
  ----------
661
- uargs : argparser object
863
+ uargs: argparser object
662
864
  User arguments
663
865
 
664
866
  Returns
@@ -774,7 +976,7 @@ def plot_xas_func(uargs):
774
976
 
775
977
  Parameters
776
978
  ----------
777
- uargs : argparser object
979
+ uargs: argparser object
778
980
  User arguments
779
981
 
780
982
  Returns
@@ -883,10 +1085,10 @@ def plot_abs_func(uargs, save_data_only=False):
883
1085
 
884
1086
  Parameters
885
1087
  ----------
886
- uargs : argparser object
1088
+ uargs: argparser object
887
1089
  User arguments
888
1090
 
889
- save_data_only : bool, default=False
1091
+ save_data_only: bool, default=False
890
1092
  If True, saves generated spectrum data to file only.
891
1093
 
892
1094
  Returns
@@ -898,6 +1100,7 @@ def plot_abs_func(uargs, save_data_only=False):
898
1100
  import matplotlib.colors as mcolors
899
1101
  from . import plotter
900
1102
  from . import extractor as oe
1103
+ from . import data as d
901
1104
 
902
1105
  # Change matplotlib font size to be larger
903
1106
  mpl.rcParams.update({'font.size': 12})
@@ -1107,14 +1310,13 @@ def plot_ir_func(uargs):
1107
1310
 
1108
1311
  Parameters
1109
1312
  ----------
1110
- uargs : argparser object
1313
+ uargs: argparser object
1111
1314
  User arguments
1112
1315
 
1113
1316
  Returns
1114
1317
  -------
1115
1318
  None
1116
1319
  '''
1117
- import matplotlib.pyplot as plt
1118
1320
  import matplotlib as mpl
1119
1321
  from . import plotter
1120
1322
  from . import extractor as oe
@@ -1152,7 +1354,7 @@ def distort_func(uargs):
1152
1354
 
1153
1355
  Parameters
1154
1356
  ----------
1155
- args : argparser object
1357
+ uargs: argparser object
1156
1358
  command line arguments
1157
1359
 
1158
1360
  Returns
@@ -1160,6 +1362,7 @@ def distort_func(uargs):
1160
1362
  None
1161
1363
 
1162
1364
  '''
1365
+ import xyz_py as xyzp
1163
1366
  from . import extractor as oe
1164
1367
 
1165
1368
  # Open file and extract coordinates
@@ -1198,9 +1401,9 @@ def extract_orbs_func(uargs, save=True) -> None:
1198
1401
 
1199
1402
  Parameters
1200
1403
  ----------
1201
- args : argparser object
1404
+ uargs: argparser object
1202
1405
  command line arguments
1203
- save : bool, default=True
1406
+ save: bool, default=True
1204
1407
  If True, saves data to file. If False, prints to stdout.
1205
1408
 
1206
1409
  Returns
@@ -1337,7 +1540,7 @@ def extract_orbs_func(uargs, save=True) -> None:
1337
1540
  total = 0.
1338
1541
  for row, val in mo.items():
1339
1542
  if val > uargs.threshold and row[1] in uargs.elements:
1340
- _output += f' {row[1]+str(row[0]):5} {row[2]:5} : {val:>5.1f} %\n' # noqa
1543
+ _output += f' {row[1]+str(row[0]):5} {row[2]:5}: {val:>5.1f} %\n' # noqa
1341
1544
  total += val
1342
1545
  if len(_output):
1343
1546
  print(f'MO #{mo_num} (Occ={occupancies[mo_num]}, E={energies[mo_num]: .5f}):') # noqa
@@ -1374,9 +1577,9 @@ def extract_freq_func(uargs, save=True):
1374
1577
 
1375
1578
  Parameters
1376
1579
  ----------
1377
- args : argparser object
1580
+ uargs: argparser object
1378
1581
  command line arguments
1379
- save : bool, default=True
1582
+ save: bool, default=True
1380
1583
  If True, saves data to file. If False, prints to stdout.
1381
1584
 
1382
1585
  Returns
@@ -1425,14 +1628,15 @@ def extract_pop_func(uargs, save=True) -> None:
1425
1628
 
1426
1629
  Parameters
1427
1630
  ----------
1428
- uargs : argparser object
1631
+ uargs: argparser object
1429
1632
  User arguments
1430
- save : bool, default=False
1633
+ save: bool, default=False
1431
1634
  If True, saves data to file. If False, prints to stdout.
1432
1635
  Returns
1433
1636
  -------
1434
1637
  None
1435
1638
  '''
1639
+ import xyz_py as xyzp
1436
1640
  from . import extractor as oe
1437
1641
 
1438
1642
  if uargs.flavour in ['loewdin', 'lowdin']:
@@ -1486,7 +1690,7 @@ def extract_pop_func(uargs, save=True) -> None:
1486
1690
  _chg = sum([datum[0][labels[ind]] for ind in entity])
1487
1691
  _spin = sum([datum[1][labels[ind]] for ind in entity])
1488
1692
  ut.cprint(
1489
- f'{entity_name} : {_chg:.4f} {_spin:.4f}',
1693
+ f'{entity_name}: {_chg:.4f} {_spin:.4f}',
1490
1694
  'cyan'
1491
1695
  )
1492
1696
 
@@ -1499,7 +1703,7 @@ def plot_susc_func(uargs) -> None:
1499
1703
 
1500
1704
  Parameters
1501
1705
  ----------
1502
- args : argparser object
1706
+ uargs: argparser object
1503
1707
  command line arguments
1504
1708
 
1505
1709
  Returns
@@ -1611,7 +1815,7 @@ def plot_ailft_func(uargs) -> None:
1611
1815
 
1612
1816
  Parameters
1613
1817
  ----------
1614
- args : argparser object
1818
+ uargs: argparser object
1615
1819
  command line arguments
1616
1820
 
1617
1821
  Returns
@@ -1697,7 +1901,7 @@ def read_args(arg_list=None):
1697
1901
 
1698
1902
  Parameters
1699
1903
  ----------
1700
- args : argparser object
1904
+ uargs: argparser object
1701
1905
  command line arguments
1702
1906
 
1703
1907
  Returns
@@ -1792,6 +1996,32 @@ def read_args(arg_list=None):
1792
1996
  help='Number of frequencies to print, default is all'
1793
1997
  )
1794
1998
 
1999
+ extract_hyperfine = extract_parser.add_parser(
2000
+ 'hyperfine',
2001
+ description='Extracts hyperfine couplings from Orca output file',
2002
+ usage=ut.cstring(
2003
+ 'orto extract hyperfine <output_file> [options]',
2004
+ 'cyan'
2005
+ ),
2006
+ formatter_class=argparse.RawTextHelpFormatter
2007
+ )
2008
+ extract_hyperfine._positionals.title = 'Mandatory Arguments'
2009
+ extract_hyperfine.set_defaults(func=extract_hyperfine_func)
2010
+
2011
+ extract_hyperfine.add_argument(
2012
+ 'output_file',
2013
+ type=pathlib.Path,
2014
+ help='Path to/Name of Orca output file containing HYPERFINE section'
2015
+ )
2016
+
2017
+ extract_hyperfine.add_argument(
2018
+ '--output_format',
2019
+ type=str,
2020
+ help='Format of outputted data file',
2021
+ choices=['txt', 'docx'],
2022
+ default='txt'
2023
+ )
2024
+
1795
2025
  extract_gmatrix = extract_parser.add_parser(
1796
2026
  'gmatrix',
1797
2027
  description='Extracts coordinates from Orca output file',
@@ -1804,14 +2034,14 @@ def read_args(arg_list=None):
1804
2034
  extract_gmatrix.add_argument(
1805
2035
  'output_file',
1806
2036
  type=pathlib.Path,
1807
- help='Orca output file name containing G-MATRIX block'
2037
+ help='Path to/Name of Orca output file containing G-MATRIX block'
1808
2038
  )
1809
2039
 
1810
2040
  extract_gmatrix.add_argument(
1811
2041
  '--type',
1812
2042
  type=str,
1813
- help='Which G-MATRIX block to extract.',
1814
- choices=['total', 'S', 'L', 'eff'],
2043
+ help='Which G-MATRIX block to extract - if DFT then this option is redundant', # noqa
2044
+ choices=['total', 'S', 'L', 'eff', 'dft'],
1815
2045
  default='total'
1816
2046
  )
1817
2047
 
@@ -2753,9 +2983,30 @@ def read_args(arg_list=None):
2753
2983
  # If argument list is empty then call help function
2754
2984
  print_subprog.set_defaults(func=lambda _: print_subprog.print_help())
2755
2985
 
2986
+ print_hyperfine = print_parser.add_parser(
2987
+ 'hyperfine',
2988
+ description='Prints hyperfine couplings from Orca output file',
2989
+ usage=ut.cstring(
2990
+ 'orto print hyperfine <output_file> [options]',
2991
+ 'cyan'
2992
+ ),
2993
+ formatter_class=argparse.RawTextHelpFormatter
2994
+ )
2995
+ print_hyperfine._positionals.title = 'Mandatory Arguments'
2996
+
2997
+ print_hyperfine.set_defaults(
2998
+ func=lambda x: extract_hyperfine_func(x, save=False)
2999
+ )
3000
+
3001
+ print_hyperfine.add_argument(
3002
+ 'output_file',
3003
+ type=pathlib.Path,
3004
+ help='Path to/Name of Orca output file containing HYPERFINE section'
3005
+ )
3006
+
2756
3007
  print_gmatrix = print_parser.add_parser(
2757
3008
  'gmatrix',
2758
- description='Extracts g matrix from Orca output file',
3009
+ description='Prints g matrix from Orca output file',
2759
3010
  usage=ut.cstring('orto print gmatrix <output_file> [options]', 'cyan'),
2760
3011
  formatter_class=argparse.RawTextHelpFormatter
2761
3012
  )
@@ -2768,7 +3019,7 @@ def read_args(arg_list=None):
2768
3019
  print_gmatrix.add_argument(
2769
3020
  'output_file',
2770
3021
  type=pathlib.Path,
2771
- help='Orca output file name containing G-MATRIX block'
3022
+ help='Path to/Name of Orca output file containing G-MATRIX block'
2772
3023
  )
2773
3024
 
2774
3025
  print_gmatrix.add_argument(
@@ -2781,7 +3032,7 @@ def read_args(arg_list=None):
2781
3032
 
2782
3033
  print_freq = print_parser.add_parser(
2783
3034
  'freq',
2784
- description='Prints frequencies',
3035
+ description='Prints frequencies from Orca output file',
2785
3036
  usage=ut.cstring('orto print freq <output_file> [options]', 'cyan'),
2786
3037
  formatter_class=argparse.RawTextHelpFormatter
2787
3038
  )
@@ -2792,7 +3043,7 @@ def read_args(arg_list=None):
2792
3043
  print_freq.add_argument(
2793
3044
  'output_file',
2794
3045
  type=pathlib.Path,
2795
- help='Orca output file name - must contain Frequencies section'
3046
+ help='Path to/Name of Orca output file containing FREQUENCIES section'
2796
3047
  )
2797
3048
 
2798
3049
  print_freq.add_argument(
@@ -2819,8 +3070,8 @@ def read_args(arg_list=None):
2819
3070
  'output_file',
2820
3071
  type=pathlib.Path,
2821
3072
  help=(
2822
- 'Orca output file name\n'
2823
- 'File must contain one of the following sections\n'
3073
+ 'Path to/Name of Orca output file containing\n'
3074
+ 'one of the following sections\n'
2824
3075
  ' LOEWDIN ORBITAL-COMPOSITIONS\n'
2825
3076
  ' LOEWDIN REDUCED ORBITAL POPULATIONS PER MO\n'
2826
3077
  ' LOEWDIN ORBITAL POPULATIONS PER MO\n'
orto/extractor.py CHANGED
@@ -16,7 +16,7 @@ from . import constants as const
16
16
 
17
17
  def EPRNMRDetector(file_name: str | pathlib.Path) -> bool:
18
18
  '''
19
- Detects if Orca output file is from EPR/NMR calculation
19
+ Detects if Orca output file contains an EPRNMR section
20
20
  '''
21
21
  with open(file_name, 'rb') as f:
22
22
  file_content = f.read()
@@ -29,7 +29,7 @@ def EPRNMRDetector(file_name: str | pathlib.Path) -> bool:
29
29
 
30
30
  class OrcaVersionExtractor(extto.LineExtractor):
31
31
  '''
32
- Extracts Orca version from output file
32
+ Extracts Orca version from Orca output file
33
33
  '''
34
34
 
35
35
  # Regex Start Pattern
@@ -235,7 +235,8 @@ class SusceptibilityExtractor(extto.BetweenExtractor):
235
235
 
236
236
  class ExchangeCouplingExtractor(extto.BetweenExtractor):
237
237
  '''
238
- Extracts Exchange Coupling Constants and information (J) from output file
238
+ Extracts Exchange Coupling Constants and information (J) from Orca \n
239
+ output file
239
240
  '''
240
241
 
241
242
  # Regex Start Pattern
@@ -342,7 +343,7 @@ class ExchangeCouplingExtractor(extto.BetweenExtractor):
342
343
 
343
344
  class AILFTOrbEnergyExtractor(extto.BetweenExtractor):
344
345
  '''
345
- Extracts AI-LFT orbital energies from output file
346
+ Extracts AI-LFT orbital energies from Orca output file
346
347
  '''
347
348
  # Regex Start Pattern
348
349
  START_PATTERN = rb'(?<=The ligand field one electron eigenfunctions:\s-{41})' # noqa
@@ -437,7 +438,7 @@ class AILFTOrbEnergyExtractor(extto.BetweenExtractor):
437
438
  class FrequencyExtractor(extto.BetweenExtractor):
438
439
  '''
439
440
  Extracts Vibrational mode energies, eigenvectors, intensities, \n
440
- and irreps from output file
441
+ and irreps from Orca output file
441
442
  '''
442
443
 
443
444
  # Regex Start Pattern
@@ -665,7 +666,7 @@ class FrequencyExtractor(extto.BetweenExtractor):
665
666
 
666
667
  class LoewdinPopulationExtractor(extto.BetweenExtractor):
667
668
  '''
668
- Extracts Loewdin Population Analysis Section from output file
669
+ Extracts Loewdin Population Analysis Section from Orca output file
669
670
  '''
670
671
 
671
672
  # Regex Start Pattern
@@ -746,7 +747,7 @@ class MullikenPopulationExtractorDensities(LoewdinPopulationExtractor):
746
747
  '''
747
748
  Extracts Mulliken Population Analysis Section with \n
748
749
  MULLIKEN ATOMIC CHARGES AND SPIN DENSITIES header\n
749
- from output file
750
+ from Orca output file`
750
751
  '''
751
752
 
752
753
  # Regex Start Pattern
@@ -759,8 +760,8 @@ class MullikenPopulationExtractorDensities(LoewdinPopulationExtractor):
759
760
  class MullikenPopulationExtractorPopulations(LoewdinPopulationExtractor):
760
761
  '''
761
762
  Extracts Mulliken Population Analysis Section with \n
762
- MULLIKEN ATOMIC CHARGES AND SPIN POPULATIONS header
763
- from output file
763
+ MULLIKEN ATOMIC CHARGES AND SPIN POPULATIONS header\n
764
+ from Orca output file
764
765
  '''
765
766
 
766
767
  # Regex Start Pattern
@@ -772,13 +773,13 @@ class MullikenPopulationExtractorPopulations(LoewdinPopulationExtractor):
772
773
 
773
774
  class MullikenPopulationExtractor(MullikenPopulationExtractorDensities):
774
775
  '''
775
- Extracts Mulliken Population Analysis Section from output file
776
+ Extracts Mulliken Population Analysis Section from Orca output file
776
777
  '''
777
778
 
778
779
 
779
780
  class LoewdinCompositionExtractor(extto.BetweenExtractor):
780
781
  '''
781
- Extracts Loewdin Orbital-Compositions Section from output file\n
782
+ Extracts Loewdin Orbital-Compositions Section from Orca output file
782
783
  '''
783
784
 
784
785
  # Regex Start Pattern
@@ -2434,9 +2435,176 @@ class SimpleInputExtractor(extto.LineExtractor):
2434
2435
  return _ext.data
2435
2436
 
2436
2437
 
2438
+ class HyperfineExtractor(extto.BetweenExtractor):
2439
+ '''
2440
+ Extracts Hyperfine coupling tensor and associated information from Orca\n
2441
+ output file
2442
+ '''
2443
+
2444
+ # Regex Start Pattern
2445
+ START_PATTERN = rb'(?<=-{59}\s Nucleus)'
2446
+
2447
+ # Regex End Pattern
2448
+ END_PATTERN = rb'(?=The A matrix conforms to the)'
2449
+
2450
+ @property
2451
+ def data(self) -> dict[str, NDArray]:
2452
+ '''
2453
+ Hyperfine data:\n
2454
+ A dictionary with keys:\n
2455
+ nucleus\n
2456
+ element\n
2457
+ isotope\n
2458
+ matrix\n
2459
+ values\n
2460
+ vectors\n
2461
+ iso\n
2462
+ fc\n
2463
+ sd\n
2464
+ orb\n
2465
+ dia\n
2466
+ All values are ndarray of floats and have units of MHz
2467
+ '''
2468
+ return self._data
2469
+
2470
+ @staticmethod
2471
+ def _process_block(block: str) -> dict[str, NDArray]:
2472
+ '''
2473
+ Converts single block into data entries described in self.data
2474
+
2475
+ Parameters
2476
+ ----------
2477
+ block: str
2478
+ String block extracted from file
2479
+
2480
+ Returns
2481
+ -------
2482
+ dict[str, NDArray]
2483
+ '''
2484
+
2485
+ def float_triple(list_str: str) -> list[float]:
2486
+ '''
2487
+ Converts string form of three element list to list of floats
2488
+
2489
+ list_str: str
2490
+ String of three float values separated by spaces
2491
+
2492
+ Returns
2493
+ -------
2494
+ list[float]
2495
+ floats in list
2496
+ '''
2497
+
2498
+ if list_str is None:
2499
+ list_float = []
2500
+ else:
2501
+ list_float = [
2502
+ float(val)
2503
+ for val in list_str.split()
2504
+ ]
2505
+
2506
+ return list_float
2507
+
2508
+ # Get Nucleus
2509
+ nucleus = block.split(':')[0].lstrip().rstrip()
2510
+ element = ''.join(
2511
+ [
2512
+ letter
2513
+ for letter in nucleus
2514
+ if letter not in '0123456789'
2515
+ ]
2516
+ )
2517
+
2518
+ isotope = int(re.findall(r'Isotope\=\s+(\d+)', block)[0])
2519
+
2520
+ # Get Matrix
2521
+ _matrix = re.findall(
2522
+ r'(\s-?\d+\.\d{4}\s+-?\d+\.\d{4}\s+-?\d+\.\d{4})',
2523
+ block
2524
+ )[:3]
2525
+
2526
+ _fc = re.findall(
2527
+ r'A\(FC\)\s+(-?\d+.\d{4}\s+-?\d+.\d{4}\s+-?\d+.\d{4})',
2528
+ block
2529
+ )
2530
+ fc = float_triple(_fc[0])
2531
+
2532
+ _sd = re.findall(
2533
+ r'A\(SD\)\s+(-?\d+.\d{4}\s+-?\d+.\d{4}\s+-?\d+.\d{4})',
2534
+ block
2535
+ )
2536
+ sd = float_triple(_sd[0])
2537
+
2538
+ _orb = re.findall(
2539
+ r'A\(ORB\)\s+(-?\d+.\d{4}\s+-?\d+.\d{4}\s+-?\d+.\d{4})',
2540
+ block
2541
+ )
2542
+ orb = float_triple(_orb[0])
2543
+
2544
+ _dia = re.findall(
2545
+ r'A\(DIA\)\s+(-?\d+.\d{4}\s+-?\d+.\d{4}\s+-?\d+.\d{4})',
2546
+ block
2547
+ )
2548
+ dia = float_triple(_dia[0])
2549
+
2550
+ # Convert to matrix of floats
2551
+ matrix = np.asarray([
2552
+ [float(v) for v in val.split()]
2553
+ for val in _matrix
2554
+ ])
2555
+
2556
+ if matrix.shape != (3, 3):
2557
+ raise DataFormattingError(
2558
+ 'Hyperfine tensor is not the correct shape (3x3)'
2559
+ )
2560
+
2561
+ # Calculate isotropic hyperfine coupling
2562
+ iso = np.trace(matrix) / 3.
2563
+
2564
+ # Diagonalise tensor
2565
+ vals, vecs = la.eigh(matrix)
2566
+
2567
+ # Future - pseudocontact/dipolar?
2568
+ data = {
2569
+ 'nucleus': nucleus,
2570
+ 'element': element,
2571
+ 'isotope': isotope,
2572
+ 'matrix': matrix,
2573
+ 'values': vals,
2574
+ 'vectors': vecs,
2575
+ 'iso': iso,
2576
+ 'fc': fc,
2577
+ 'sd': sd,
2578
+ 'dia': dia,
2579
+ 'orb': orb,
2580
+ }
2581
+
2582
+ return data
2583
+
2584
+ @classmethod
2585
+ def extract(cls, file_name: str | pathlib.Path) -> list[dict[str, NDArray]]: # noqa
2586
+ '''
2587
+ Convenience method which instantiates class, extracts blocks, and
2588
+ returns processed datasets
2589
+
2590
+ Parameters
2591
+ ----------
2592
+ file_name: str | pathlib.Path
2593
+ File to parse
2594
+
2595
+ Returns
2596
+ -------
2597
+ list[dict[str, NDArray]]
2598
+ Each entry contains processed data, as defined in cls.data
2599
+ '''
2600
+ _ext = cls()
2601
+ _ext(file_name, process=True)
2602
+ return _ext.data
2603
+
2604
+
2437
2605
  class GMatrixDFTExtractor(extto.BetweenExtractor):
2438
2606
  '''
2439
- Extracts DFT ELECTRONIC G-MATRIX block from output file
2607
+ Extracts DFT ELECTRONIC G-MATRIX block from Orca output file
2440
2608
  '''
2441
2609
 
2442
2610
  # Regex Start Pattern
@@ -2530,7 +2698,7 @@ class GMatrixDFTExtractor(extto.BetweenExtractor):
2530
2698
 
2531
2699
  class GMatrixExtractor(extto.BetweenExtractor):
2532
2700
  '''
2533
- Extracts ELECTRONIC G-MATRIX block from output file
2701
+ Extracts ELECTRONIC G-MATRIX block from Orca output file
2534
2702
  '''
2535
2703
 
2536
2704
  # Regex Start Pattern
@@ -2620,8 +2788,8 @@ class GMatrixExtractor(extto.BetweenExtractor):
2620
2788
 
2621
2789
  class GMatrixEffectiveExtractor(GMatrixExtractor):
2622
2790
  '''
2623
- Extracts ELECTRONIC G-MATRIX FROM EFFECTIVE HAMILTONIAN block from output\n
2624
- file
2791
+ Extracts ELECTRONIC G-MATRIX FROM EFFECTIVE HAMILTONIAN block from Orca\n
2792
+ output file
2625
2793
  '''
2626
2794
  # Regex Start Pattern
2627
2795
  START_PATTERN = rb'(?<=ELECTRONIC G-MATRIX FROM EFFECTIVE HAMILTONIAN\s[\S\s]{46}\s)' # noqa
@@ -2707,7 +2875,8 @@ class GMatrixEffectiveExtractor(GMatrixExtractor):
2707
2875
 
2708
2876
  class GMatrixLExtractor(GMatrixExtractor):
2709
2877
  '''
2710
- Extracts ELECTRONIC G-MATRIX: L contribution block from output file
2878
+ Extracts ELECTRONIC G-MATRIX: L contribution block from Orca\n
2879
+ output file
2711
2880
  '''
2712
2881
  # Regex Start Pattern
2713
2882
  START_PATTERN = rb'(?<=ELECTRONIC G-MATRIX: L contribution\s[\S\s]{47}\s)'
@@ -2715,7 +2884,8 @@ class GMatrixLExtractor(GMatrixExtractor):
2715
2884
 
2716
2885
  class GMatrixSExtractor(GMatrixExtractor):
2717
2886
  '''
2718
- Extracts ELECTRONIC G-MATRIX: S contribution block from output file
2887
+ Extracts ELECTRONIC G-MATRIX: S contribution block from Orca\n
2888
+ output file
2719
2889
  '''
2720
2890
  # Regex Start Pattern
2721
2891
  START_PATTERN = rb'(?<=ELECTRONIC G-MATRIX: S contribution\s[\S\s]{47}\s)'
@@ -2723,7 +2893,7 @@ class GMatrixSExtractor(GMatrixExtractor):
2723
2893
 
2724
2894
  class SpinFreeEnergyExtractor(extto.BetweenExtractor):
2725
2895
  '''
2726
- Extracts Spin-Free TRANSITION ENERGIES block from output file
2896
+ Extracts Spin-Free TRANSITION ENERGIES block from Orca output file
2727
2897
  '''
2728
2898
 
2729
2899
  # Regex Start Pattern
@@ -2814,7 +2984,7 @@ class SpinFreeEnergyExtractor(extto.BetweenExtractor):
2814
2984
 
2815
2985
  class SpinOrbitEnergyExtractor(extto.BetweenExtractor):
2816
2986
  '''
2817
- Extracts Spin-Orbit Energies block from output file
2987
+ Extracts Spin-Orbit Energies block from Orca output file
2818
2988
  '''
2819
2989
 
2820
2990
  # Regex Start Pattern
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orto
3
- Version: 1.10.1
3
+ Version: 1.11.0
4
4
  Summary: A package to make life easier when performing Orca calculations.
5
5
  Home-page: https://orto.kragskow.group
6
6
  Author: Jon Kragskow
@@ -14,7 +14,7 @@ Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
  Requires-Dist: numpy>=2.1.2
17
- Requires-Dist: xyz_py>=5.13.1
17
+ Requires-Dist: xyz_py>=5.19.2
18
18
  Requires-Dist: matplotlib>=3.9.2
19
19
  Requires-Dist: extto>=1.0.1
20
20
  Requires-Dist: pandas>=2.2.3
@@ -1,17 +1,17 @@
1
1
  orto/__init__.py,sha256=IedlltYr3qYZxChNUdz62qogXA9Pos_MUvXdGXqAa0E,41
2
- orto/__version__.py,sha256=kyV3BXDGSm-dqv8S24R6icRK9FHceg_fI3l9YdKi3-8,23
3
- orto/cli.py,sha256=VkpBU8C85twXF7pjZREURUyiWFoLUdqEBoftAzy-QZg,86376
2
+ orto/__version__.py,sha256=glAkwZsi0Hbv-R1Jbe-2qECv-6AWHNGvlRS_cgbvCTU,23
3
+ orto/cli.py,sha256=l470BgtTLUD2vtWNdMuoY7A1zcW7lzCGBJO-n1YI9_Q,95935
4
4
  orto/constants.py,sha256=anxaiTykO8Q_CXliR7zuOAdnXZrQ2-C4ndaviyl7kGc,419
5
5
  orto/data.py,sha256=960LHFeG7l626X_WA-8YxvG2toNAsgNvLo86OoYAmBY,14910
6
6
  orto/exceptions.py,sha256=D7oNeAEGeJNt5thzt6PaCn5FY6JcbJOWUE1N1LVhhuE,159
7
- orto/extractor.py,sha256=oqRdDWLaVPIwB4aZ5nrITWexx60hKn0zghACmymwVfM,80618
7
+ orto/extractor.py,sha256=GKCFU7oSawYCYjOizER8e6HSp4bOsyqOxYcTPQHwdjM,84923
8
8
  orto/input.py,sha256=uUQV6A-8D0GZpRoY1rKK_aUPmk9kVVTnMzTHuisP5t4,11888
9
9
  orto/job.py,sha256=tDiz9omFwinoYJamgz66MZez0Ee9HMhuCIAeHMhXRF8,5916
10
10
  orto/plotter.py,sha256=_t9bow6sUMoRAvD6gVFGJTc-_ifW7RmeR0JAPWK_lm4,17799
11
11
  orto/utils.py,sha256=GcMZ9uebOSnkPQT_U5O0X49LUtTu8YpXZxEsNKgXNTY,9838
12
- orto-1.10.1.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
13
- orto-1.10.1.dist-info/METADATA,sha256=cT2SJvM85V5vClhAMf5g-trlg1NyOWxcOeONyzRDZ0s,1185
14
- orto-1.10.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- orto-1.10.1.dist-info/entry_points.txt,sha256=HXenCglMp_03JkN34pK2phkjXK9CFcXTGHKv5QaVY8I,39
16
- orto-1.10.1.dist-info/top_level.txt,sha256=hQ-z28gTN_FZ2B5Kiwxr_9cUTcCoib9W5HjbkceDXw4,5
17
- orto-1.10.1.dist-info/RECORD,,
12
+ orto-1.11.0.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
13
+ orto-1.11.0.dist-info/METADATA,sha256=CrxR7SnLc7EfAUvA26nct7SyVxCtFbwiJVw2oy4jNg0,1185
14
+ orto-1.11.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ orto-1.11.0.dist-info/entry_points.txt,sha256=HXenCglMp_03JkN34pK2phkjXK9CFcXTGHKv5QaVY8I,39
16
+ orto-1.11.0.dist-info/top_level.txt,sha256=hQ-z28gTN_FZ2B5Kiwxr_9cUTcCoib9W5HjbkceDXw4,5
17
+ orto-1.11.0.dist-info/RECORD,,
File without changes