orto 1.12.0__py3-none-any.whl → 1.13.1__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/cli.py CHANGED
@@ -79,16 +79,31 @@ def extract_sf_energies_func(uargs):
79
79
  from docx.enum.table import WD_ALIGN_VERTICAL
80
80
  from docx.shared import Pt
81
81
 
82
- all_data = oe.SpinFreeEnergyExtractor().extract(
83
- uargs.output_file
82
+ cas_energies = oe.SpinFreeEnergyExtractor().extract(
83
+ uargs.output_file,
84
+ before='NEVPT2 TRANSITION ENERGIES'
84
85
  )
85
86
 
87
+ # Extract NEVPT2 data
88
+ try:
89
+ nev_energies = oe.SpinFreeEnergyExtractor().extract(
90
+ uargs.output_file,
91
+ after='NEVPT2 TRANSITION ENERGIES'
92
+ )
93
+ except DataNotFoundError:
94
+ nev_energies = []
95
+ except (DataFormattingError, ValueError) as e:
96
+ ut.red_exit(str(e))
97
+
98
+ # Section names
99
+ names = ['CASSCF Results'] * len(cas_energies)
100
+ names += ['NEVPT2 Results'] * len(nev_energies)
101
+
86
102
  if uargs.output_format == 'txt':
87
103
  out_name = f'{uargs.output_file.stem}_sfenergies.txt'
88
104
  with open(out_name, 'w') as f:
89
- for it, data in enumerate(all_data):
90
- if len(all_data) > 1:
91
- f.write(f'# Section {it + 1:d}\n')
105
+ for it, data in enumerate(cas_energies + nev_energies):
106
+ f.write(f'{names[it]}\n')
92
107
 
93
108
  f.write('State, Root, Multiplicity, Relative Energy (cm⁻¹)\n')
94
109
 
@@ -99,18 +114,23 @@ def extract_sf_energies_func(uargs):
99
114
  f.write(
100
115
  f'{rit + 1:d}, {data['root'][rit]:d}, {data['multiplicity'][rit]:d}, {data['delta energy (cm^-1)'][rit - 1]:.2f}\n' # noqa
101
116
  )
102
- if len(all_data) > 1:
117
+ if len(names) > 1:
103
118
  f.write('-------------------\n')
104
119
 
105
120
  if uargs.output_format == 'docx':
106
121
  out_name = f'{uargs.output_file.stem}_sfenergies.docx'
107
122
 
108
- title = 'Spin-Free energies'
109
-
110
123
  # Create document
111
124
  doc = Document()
112
125
 
113
- doc.add_heading(title, 0)
126
+ # Add style
127
+ style = doc.styles['Normal']
128
+ font = style.font
129
+ font.name = 'Arial'
130
+ font.size = Pt(12)
131
+
132
+ title = 'Spin-Free energies'
133
+ doc.add_paragraph(title, style='Normal')
114
134
 
115
135
  # Add style
116
136
  style = doc.styles['Normal']
@@ -119,9 +139,8 @@ def extract_sf_energies_func(uargs):
119
139
  font.size = Pt(12)
120
140
 
121
141
  # For each extracted section, print matrix, vectors, and values
122
- for it, data in enumerate(all_data):
123
- if len(all_data) > 1:
124
- doc.add_paragraph(f'\nSection {it + 1:d}\n')
142
+ for it, data in enumerate(cas_energies + nev_energies):
143
+ doc.add_paragraph(f'\n {names[it]}\n')
125
144
 
126
145
  # Table of data
127
146
  table = doc.add_table(rows=len(data['root']) + 1, cols=4)
@@ -134,6 +153,14 @@ def extract_sf_energies_func(uargs):
134
153
  ss.font.superscript = True
135
154
  table.cell(0, 3).paragraphs[0].add_run(')')
136
155
 
156
+ single = {"sz": 12, "color": "#000000", "val": "single"}
157
+ double = {"sz": 12, "color": "#000000", "val": "double"}
158
+
159
+ ut.set_cell_border(table.cell(0, 0), bottom=double, top=single)
160
+ ut.set_cell_border(table.cell(0, 1), bottom=double, top=single)
161
+ ut.set_cell_border(table.cell(0, 2), bottom=double, top=single)
162
+ ut.set_cell_border(table.cell(0, 3), bottom=double, top=single)
163
+
137
164
  # Add data
138
165
  for rit in range(len(data['root'])):
139
166
  table.cell(rit + 1, 0).text = f'{rit + 1:d}'
@@ -144,6 +171,12 @@ def extract_sf_energies_func(uargs):
144
171
  else:
145
172
  table.cell(rit + 1, 3).text = f'{data['delta energy (cm^-1)'][rit - 1]:.2f}' # noqa
146
173
 
174
+ for cit in range(4):
175
+ ut.set_cell_border(
176
+ table.cell(len(data['root']), cit),
177
+ bottom=single
178
+ )
179
+
147
180
  for row in table.rows:
148
181
  for cell in row.cells:
149
182
  cell.paragraphs[0].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # noqa
@@ -169,15 +202,30 @@ def extract_so_energies_func(uargs):
169
202
  '''
170
203
  from . import extractor as oe
171
204
 
172
- all_energies = oe.SpinOrbitEnergyExtractor().extract(
173
- uargs.output_file
205
+ cas_energies = oe.SpinOrbitEnergyExtractor().extract(
206
+ uargs.output_file,
207
+ before='QDPT WITH NEVPT2 DIAGONAL ENERGIES'
174
208
  )
175
209
 
210
+ # Extract NEVPT2 data
211
+ try:
212
+ nev_energies = oe.SpinOrbitEnergyExtractor().extract(
213
+ uargs.output_file,
214
+ after='QDPT WITH NEVPT2 DIAGONAL ENERGIES'
215
+ )
216
+ except DataNotFoundError:
217
+ nev_energies = []
218
+ except (DataFormattingError, ValueError) as e:
219
+ ut.red_exit(str(e))
220
+
221
+ # Section names
222
+ names = ['CASSCF Results'] * len(cas_energies)
223
+ names += ['NEVPT2 Results'] * len(nev_energies)
224
+
176
225
  out_name = f'{uargs.output_file.stem}_soenergies.txt'
177
226
  with open(out_name, 'w') as f:
178
- for it, energies in enumerate(all_energies):
179
- if len(all_energies) > 1:
180
- f.write(f'# Section {it + 1:d}\n')
227
+ for it, energies in enumerate(cas_energies + nev_energies):
228
+ f.write(f'{names[it]}\n')
181
229
 
182
230
  f.write('State, Relative Energy (cm⁻¹)\n')
183
231
 
@@ -185,7 +233,7 @@ def extract_so_energies_func(uargs):
185
233
  f.write(
186
234
  f'{eit + 1:d}, {energy:.4f}\n'
187
235
  )
188
- if len(all_energies) > 1:
236
+ if len(names) > 1:
189
237
  f.write('-------------------\n')
190
238
 
191
239
  ut.cprint(f'Data written to {out_name}', 'cyan')
@@ -227,7 +275,7 @@ def extract_hyperfine_func(uargs, save=True):
227
275
  out_name = f'{uargs.output_file.stem}_hyperfine.txt'
228
276
  with open(out_name, 'w') as f:
229
277
  f.write(f'Data from {uargs.output_file}\n')
230
- f.write('All values are in MHz')
278
+ f.write('All values are in MHz\n')
231
279
  for data in all_data:
232
280
  if len(all_data) > 1:
233
281
  f.write('=================\n')
@@ -402,7 +450,7 @@ def extract_gmatrix_func(uargs, save=True):
402
450
  from docx import Document
403
451
  from docx.enum.text import WD_ALIGN_PARAGRAPH
404
452
  from docx.enum.table import WD_ALIGN_VERTICAL
405
- from docx.shared import Pt
453
+ from docx.shared import Pt, RGBColor
406
454
 
407
455
  choices = {
408
456
  'total': oe.GMatrixExtractor,
@@ -416,63 +464,134 @@ def extract_gmatrix_func(uargs, save=True):
416
464
  if oe.EPRNMRDetector(uargs.output_file):
417
465
  uargs.type = 'dft'
418
466
 
419
- try:
420
- all_data = choices[uargs.type]().extract(uargs.output_file)
421
- except (DataFormattingError, ValueError) as e:
422
- ut.red_exit(str(e))
467
+ if uargs.type == 'dft':
468
+ cas_data, nev_data = [], []
469
+
470
+ # Extract DFT data
471
+ try:
472
+ dft_data = choices[uargs.type]().extract(
473
+ uargs.output_file
474
+ )
475
+ except DataNotFoundError:
476
+ dft_data = []
477
+ except (DataFormattingError, ValueError) as e:
478
+ ut.red_exit(str(e))
479
+ else:
480
+ dft_data = []
481
+
482
+ # Extract CASSCF data
483
+ try:
484
+ cas_data = choices[uargs.type]().extract(
485
+ uargs.output_file,
486
+ before='QDPT WITH NEVPT2 DIAGONAL ENERGIES',
487
+ after='QDPT WITH CASSCF DIAGONAL ENERGIES'
488
+ )
489
+ except (DataFormattingError, ValueError) as e:
490
+ ut.red_exit(str(e))
491
+
492
+ # Extract NEVPT2 data
493
+ try:
494
+ nev_data = choices[uargs.type]().extract(
495
+ uargs.output_file,
496
+ after='QDPT WITH NEVPT2 DIAGONAL ENERGIES'
497
+ )
498
+ except DataNotFoundError:
499
+ nev_data = []
500
+ except (DataFormattingError, ValueError) as e:
501
+ ut.red_exit(str(e))
423
502
 
424
503
  if not save:
425
- for it, data in enumerate(all_data):
426
- print(f'Section {it + 1:d}')
504
+ for it, data in enumerate(dft_data):
505
+ print('\nDFT Results')
427
506
  for key, val in data.items():
428
507
  print(f'{key}:')
429
508
  print(val)
509
+
510
+ for it, data in enumerate(cas_data):
511
+ print('\nCASSCF Results')
512
+ for key, val in data.items():
513
+ print(f'{key}:')
514
+ print(val)
515
+
516
+ for it, data in enumerate(nev_data):
517
+ print('\nNEVPT2 Results')
518
+ for key, val in data.items():
519
+ print(f'{key}:')
520
+ print(val)
521
+
430
522
  sys.exit(0)
431
523
 
524
+ titles = {
525
+ 'total': 'ELECTRONIC G-MATRIX',
526
+ 'L': 'ELECTRONIC G-MATRIX: L contribution',
527
+ 'S': 'ELECTRONIC G-MATRIX: S contribution',
528
+ 'eff': 'ELECTRONIC G-MATRIX FROM EFFECTIVE HAMILTONIAN',
529
+ 'dft': 'ELECTRONIC G-MATRIX FROM DFT LINEAR RESPONSE'
530
+ }
531
+
432
532
  if uargs.output_format == 'txt':
433
533
  out_name = f'{uargs.output_file.stem}_gmatrix.txt'
434
534
  with open(out_name, 'w') as f:
435
- for it, data in enumerate(all_data):
436
- if len(all_data) > 1:
437
- f.write(f'Section {it + 1:d}\n')
438
- for key, val in data.items():
439
- f.write(f'{key}:\n')
440
- f.write(str(val).replace('[', '').replace(']', ''))
441
- f.write('\n')
535
+ f.write(f'G Matrix data from {uargs.output_file}\n')
536
+ f.write(f'{titles[uargs.type]}\n')
537
+ f.write('=======================================\n')
538
+
539
+ if len(dft_data):
540
+ f.write('\nDFT Results\n')
541
+ for it, data in enumerate(dft_data):
542
+ for key, val in data.items():
543
+ f.write(f'{key}:\n')
544
+ f.write(str(val).replace('[', '').replace(']', ''))
545
+ f.write('\n')
546
+
547
+ if len(cas_data):
548
+ f.write('\nCASSCF Results\n')
549
+ for it, data in enumerate(cas_data):
550
+ for key, val in data.items():
551
+ f.write(f'{key}:\n')
552
+ f.write(str(val).replace('[', '').replace(']', ''))
553
+ f.write('\n')
554
+
555
+ if len(nev_data):
556
+ f.write('\nNEVPT2 Results\n')
557
+ for it, data in enumerate(nev_data):
558
+ for key, val in data.items():
559
+ f.write(f'{key}:\n')
560
+ f.write(str(val).replace('[', '').replace(']', ''))
561
+ f.write('\n')
442
562
 
443
563
  if uargs.output_format == 'docx':
444
564
  out_name = f'{uargs.output_file.stem}_gmatrix.docx'
445
565
 
446
- titles = {
447
- 'total': 'ELECTRONIC G-MATRIX',
448
- 'L': 'ELECTRONIC G-MATRIX: L contribution',
449
- 'S': 'ELECTRONIC G-MATRIX: S contribution',
450
- 'eff': 'ELECTRONIC G-MATRIX FROM EFFECTIVE HAMILTONIAN',
451
- 'dft': 'ELECTRONIC G-MATRIX FROM DFT LINEAR RESPONSE'
452
- }
453
-
454
- title = titles[uargs.type]
455
-
456
566
  # Create document
457
567
  doc = Document()
458
568
 
459
- doc.add_heading(title, 0)
460
-
461
569
  # Add style
462
570
  style = doc.styles['Normal']
463
571
  font = style.font
464
572
  font.name = 'Arial'
465
573
  font.size = Pt(12)
574
+ font.color.rgb = RGBColor(0, 0, 0)
575
+
576
+ title = titles[uargs.type]
577
+ doc.add_paragraph(title, style='Normal')
578
+ doc.add_paragraph(f'Data from {uargs.output_file}', style='Normal')
579
+
580
+ # Section names
581
+ names = ['CASSCF Results'] * len(cas_data)
582
+ names += ['NEVPT2 Results'] * len(nev_data)
583
+ names += ['DFT Results'] * len(dft_data)
466
584
 
467
585
  # For each extracted section, print matrix, vectors, and values
468
- for it, data in enumerate(all_data):
469
- if len(all_data) > 1:
470
- doc.add_paragraph(f'Section {it + 1:d}')
586
+ for it, data in enumerate(cas_data + nev_data + dft_data):
587
+ doc.add_paragraph(f'{names[it]}', style='Normal')
471
588
 
472
589
  if uargs.type == 'eff':
473
590
  doc.add_paragraph(f'Effective S={data['spin_mult']:2d}')
474
591
 
475
592
  # Full matrix
593
+ doc.add_paragraph('Full Matrix', style='Normal')
594
+
476
595
  matrix = doc.add_table(rows=3, cols=3)
477
596
 
478
597
  matrix.cell(0, 0).text = '{:.4f}'.format(data['matrix'][0, 0])
@@ -496,11 +615,17 @@ def extract_gmatrix_func(uargs, save=True):
496
615
  cell.paragraphs[0].style = 'Normal'
497
616
 
498
617
  # g values and g vectors
618
+ doc.add_paragraph('Eigenpairs', style='Normal')
619
+
499
620
  table = doc.add_table(rows=4, cols=4)
500
621
  table.cell(0, 1).merge(table.cell(0, 1)).merge(table.cell(0, 2)).merge(table.cell(0, 3)) # noqa
501
622
 
623
+ single = {"sz": 12, "color": "#000000", "val": "single"}
624
+ double = {"sz": 12, "color": "#000000", "val": "double"}
502
625
  table.cell(0, 0).text = 'Values'
626
+ ut.set_cell_border(table.cell(0, 0), bottom=double, top=single)
503
627
  table.cell(0, 1).text = 'Vectors'
628
+ ut.set_cell_border(table.cell(0, 1), bottom=double, top=single)
504
629
 
505
630
  table.cell(1, 0).text = '{:.4f}'.format(data['values'][0])
506
631
  table.cell(2, 0).text = '{:.4f}'.format(data['values'][1])
@@ -518,12 +643,19 @@ def extract_gmatrix_func(uargs, save=True):
518
643
  table.cell(2, 3).text = '{:.4f}'.format(data['vectors'][2, 1])
519
644
  table.cell(3, 3).text = '{:.4f}'.format(data['vectors'][2, 2])
520
645
 
646
+ ut.set_cell_border(table.cell(3, 0), bottom=single)
647
+ ut.set_cell_border(table.cell(3, 1), bottom=single)
648
+ ut.set_cell_border(table.cell(3, 2), bottom=single)
649
+ ut.set_cell_border(table.cell(3, 3), bottom=single)
650
+
521
651
  for row in table.rows:
522
652
  for cell in row.cells:
523
653
  cell.paragraphs[0].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # noqa
524
654
  cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
525
655
  cell.paragraphs[0].style = 'Normal'
526
656
 
657
+ if it != len(names) - 1:
658
+ doc.add_page_break()
527
659
  try:
528
660
  doc.save(out_name)
529
661
  except PermissionError:
@@ -1046,8 +1178,8 @@ def plot_xes_func(uargs):
1046
1178
  show=_SHOW_CONV[uargs.plot],
1047
1179
  save=_SAVE_CONV[uargs.plot],
1048
1180
  save_name=save_name,
1049
- x_lim=uargs.x_lim,
1050
- y_lim=uargs.y_lim,
1181
+ xlim=uargs.xlim,
1182
+ ylim=uargs.ylim,
1051
1183
  x_shift=uargs.shift,
1052
1184
  linewidth=uargs.linewidth,
1053
1185
  lineshape=uargs.lineshape,
@@ -1062,112 +1194,6 @@ def plot_xes_func(uargs):
1062
1194
  plt.show()
1063
1195
 
1064
1196
 
1065
- def plot_xas_func(uargs):
1066
- '''
1067
- Wrapper for CLI plot xas call
1068
-
1069
- Parameters
1070
- ----------
1071
- uargs: argparser object
1072
- User arguments
1073
-
1074
- Returns
1075
- -------
1076
- None
1077
- '''
1078
- import matplotlib.pyplot as plt
1079
- from . import plotter
1080
- from . import extractor as oe
1081
-
1082
- # Set user specified font name
1083
- ut.check_font_envvar()
1084
-
1085
- # Change matplotlib font size to be larger
1086
- plt.rcParams['font.size'] = 10
1087
- plt.rcParams['legend.fontsize'] = 9
1088
-
1089
- version = oe.OrcaVersionExtractor.extract(uargs.output_file)
1090
-
1091
- if not len(version):
1092
- ut.cprint(
1093
- 'Warning: Cannot find version number in Orca output file',
1094
- 'black_yellowbg'
1095
- )
1096
- version = [6, 0, 0]
1097
-
1098
- if version[0] >= 6:
1099
- if uargs.intensities == 'electric':
1100
- all_data = oe.XASElectricDipoleExtractor.extract(
1101
- uargs.output_file
1102
- )
1103
- elif uargs.intensities == 'velocity':
1104
- all_data = oe.XASVelocityDipoleExtractor.extract(
1105
- uargs.output_file
1106
- )
1107
- elif uargs.intensities == 'semi-classical':
1108
- all_data = oe.XASSemiClassicalDipoleExtractor.extract(
1109
- uargs.output_file
1110
- )
1111
- elif version[0] < 6:
1112
- ut.red_exit('Unsupported version of Orca for XAS extraction', 'red')
1113
-
1114
- ut.cprint('Using intensities: {}'.format(uargs.intensities), 'cyan')
1115
-
1116
- # Plot each section
1117
- for it, data in enumerate(all_data):
1118
-
1119
- if len(all_data) > 1:
1120
- save_name = f'absorption_spectrum_section_{it:d}.png'
1121
- else:
1122
- save_name = 'absorption_spectrum.png'
1123
-
1124
- if uargs.x_unit == 'wavenumber':
1125
- x_values = np.asarray(data['energy (cm^-1)'])
1126
- elif uargs.x_unit == 'wavelength':
1127
- x_values = 1E7 / np.asarray(data['energy (cm^-1)'])
1128
- elif uargs.x_unit == 'energy':
1129
- x_values = np.asarray(data['energy (ev)'])
1130
-
1131
- data['fosc'] = np.asarray(data['fosc'])
1132
-
1133
- # Remove transitions with zero oscillator strength from
1134
- # beginning and end of spectrum
1135
- print(data['fosc'], x_values)
1136
- if not uargs.no_trim:
1137
- # Find first non-zero oscillator strength
1138
- first_nonzero = np.where(data['fosc'] > 1E-6)[0][0]
1139
- # Find last non-zero oscillator strength
1140
- last_nonzero = np.where(data['fosc'] > 1E-6)[0][-1]
1141
-
1142
- # Trim data
1143
- x_values = x_values[first_nonzero:last_nonzero + 1]
1144
- data['fosc'] = data['fosc'][first_nonzero:last_nonzero + 1]
1145
-
1146
- # Plot absorption spectrum
1147
- fig, ax = plotter.plot_abs(
1148
- x_values,
1149
- uargs.x_unit,
1150
- data['fosc'],
1151
- show=_SHOW_CONV[uargs.plot],
1152
- save=_SAVE_CONV[uargs.plot],
1153
- save_name=save_name,
1154
- x_lim=uargs.x_lim,
1155
- y_lim=uargs.y_lim,
1156
- x_shift=uargs.shift,
1157
- linewidth=uargs.linewidth,
1158
- lineshape=uargs.lineshape,
1159
- window_title=f'Absorption Spectrum from {uargs.output_file}',
1160
- osc_style=uargs.osc_style,
1161
- normalise=uargs.normalise
1162
- )
1163
-
1164
- if uargs.x_unit == 'wavenumber':
1165
- ax[0].set_xlim([0, 50000])
1166
- plt.show()
1167
-
1168
- return
1169
-
1170
-
1171
1197
  def plot_abs_func(uargs, save_data_only=False):
1172
1198
  '''
1173
1199
  Wrapper for CLI plot abs call\n\n
@@ -1263,9 +1289,9 @@ def plot_abs_func(uargs, save_data_only=False):
1263
1289
  # report if multiple absorption sections found
1264
1290
  elif len(all_abs_data) > 1:
1265
1291
  ut.cprint(
1266
- f'Found {len(all_abs_data)} ABSORPTION sections in '
1292
+ f'\nFound {len(all_abs_data)} ABSORPTION sections in '
1267
1293
  f'file {output_file}\n'
1268
- f'Plotting final section ONLY',
1294
+ f'Plotting final section ONLY\n',
1269
1295
  'cyan'
1270
1296
  )
1271
1297
  # and only use final one
@@ -1297,25 +1323,25 @@ def plot_abs_func(uargs, save_data_only=False):
1297
1323
 
1298
1324
  # Set x_min
1299
1325
  # based on user arguments
1300
- if isinstance(uargs.x_lim[0], str):
1301
- if uargs.x_lim[0] == 'auto':
1326
+ if isinstance(uargs.xlim[0], str):
1327
+ if uargs.xlim[0] == 'auto':
1302
1328
  x_min = min(x_vals) * min_factor
1303
- elif ut.is_floatable(uargs.x_lim[0]):
1304
- x_min = float(uargs.x_lim[0])
1329
+ elif ut.is_floatable(uargs.xlim[0]):
1330
+ x_min = float(uargs.xlim[0])
1305
1331
  else:
1306
- raise ValueError(f'Invalid x_min value: {uargs.x_lim[0]}')
1332
+ raise ValueError(f'Invalid x_min value: {uargs.xlim[0]}')
1307
1333
  else:
1308
- x_min = uargs.x_lim[0]
1334
+ x_min = uargs.xlim[0]
1309
1335
 
1310
1336
  # Set x_max
1311
1337
  # based on user arguments
1312
- if isinstance(uargs.x_lim[1], str):
1313
- if uargs.x_lim[1] == 'auto':
1338
+ if isinstance(uargs.xlim[1], str):
1339
+ if uargs.xlim[1] == 'auto':
1314
1340
  x_max = max(x_vals) * max_factor
1315
- elif ut.is_floatable(uargs.x_lim[1]):
1316
- x_max = float(uargs.x_lim[1])
1341
+ elif ut.is_floatable(uargs.xlim[1]):
1342
+ x_max = float(uargs.xlim[1])
1317
1343
  else:
1318
- raise ValueError(f'Invalid x_max value: {uargs.x_lim[1]}')
1344
+ raise ValueError(f'Invalid x_max value: {uargs.xlim[1]}')
1319
1345
  else:
1320
1346
  x_max = uargs.xlim[1]
1321
1347
 
@@ -1354,15 +1380,15 @@ def plot_abs_func(uargs, save_data_only=False):
1354
1380
  )
1355
1381
  )
1356
1382
  ut.cprint(
1357
- f'Saved absorption data to absorption_spectrum_{output_file.stem}.csv', # noqa
1383
+ f'Saved absorption spectrum to absorption_spectrum_{output_file.stem}.csv', # noqa
1358
1384
  'cyan'
1359
1385
  )
1360
1386
  ut.cprint(
1361
- f'Saved absorption spectrum data to transition_data_{output_file.stem}.csv', # noqa
1387
+ f'Saved absorption data to transition_data_{output_file.stem}.csv', # noqa
1362
1388
  'cyan'
1363
1389
  )
1364
1390
  else:
1365
- # Add to dictionary of spectra for plotting later
1391
+ # Add to dictionary of absorption data for plotting later
1366
1392
  spectra_dict[output_file] = abs_data
1367
1393
 
1368
1394
  # Exit if only saving data
@@ -1391,7 +1417,7 @@ def plot_abs_func(uargs, save_data_only=False):
1391
1417
  if len(spectra_dict) > 1:
1392
1418
  width = 6.
1393
1419
  else:
1394
- width = 4
1420
+ width = 4.
1395
1421
  # width in cm
1396
1422
  width_cm = 2.54 * width
1397
1423
 
@@ -1413,7 +1439,7 @@ def plot_abs_func(uargs, save_data_only=False):
1413
1439
  plotter.plot_absorption_spectrum(
1414
1440
  abs_data,
1415
1441
  linecolor=colours[it],
1416
- stickcolour=colours[it],
1442
+ stickcolor=colours[it],
1417
1443
  osc_style=uargs.osc_style,
1418
1444
  normalise=uargs.normalise,
1419
1445
  window_title='',
@@ -1422,14 +1448,14 @@ def plot_abs_func(uargs, save_data_only=False):
1422
1448
  oax=oax,
1423
1449
  show=False,
1424
1450
  save=False,
1425
- x_lim=[x_min, x_max],
1426
- y_lim=uargs.y_lim,
1451
+ xlim=[x_min, x_max],
1452
+ ylim=uargs.ylim,
1427
1453
  x_shift=uargs.x_shift[it],
1428
1454
  legend=False
1429
1455
  )
1430
1456
 
1431
- if uargs.x_lim != ['auto', 'auto']:
1432
- ax.set_xlim(float(uargs.x_lim[0]), float(uargs.x_lim[1]))
1457
+ if uargs.xlim != ['auto', 'auto']:
1458
+ ax.set_xlim(float(uargs.xlim[0]), float(uargs.xlim[1]))
1433
1459
 
1434
1460
  fig.tight_layout()
1435
1461
 
@@ -1444,7 +1470,7 @@ def plot_abs_func(uargs, save_data_only=False):
1444
1470
  fig.legend(uargs.legend, loc=7)
1445
1471
 
1446
1472
  if _SAVE_CONV[uargs.plot]:
1447
- savename = f'absorption_spectrum_{output_file.stem}.png'
1473
+ savename = 'absorption_spectrum.png'
1448
1474
  plt.savefig(savename, dpi=500)
1449
1475
  ut.cprint(f'Saved image to {savename}', 'cyan')
1450
1476
  ut.cprint(
@@ -1866,35 +1892,102 @@ def plot_susc_func(uargs) -> None:
1866
1892
  None
1867
1893
 
1868
1894
  '''
1895
+ from . import extractor as oe
1896
+ from . import data as d
1897
+
1898
+ # Extract data from file before NEV section
1899
+ try:
1900
+ data = oe.SusceptibilityExtractor.extract(
1901
+ uargs.output_file,
1902
+ before='QDPT WITH NEVPT2 DIAGONAL ENERGIES'
1903
+ )
1904
+ except DataNotFoundError:
1905
+ data = []
1906
+
1907
+ try:
1908
+ data_nev = oe.SusceptibilityExtractor.extract(
1909
+ uargs.output_file,
1910
+ after='QDPT WITH NEVPT2 DIAGONAL ENERGIES'
1911
+ )
1912
+ except DataNotFoundError:
1913
+ data_nev = []
1914
+
1915
+ if not len(data + data_nev):
1916
+ ut.red_exit(
1917
+ f'Cannot find susceptibility data in {uargs.output_file}'
1918
+ )
1919
+
1920
+ # Create susceptibilitydata objects, one per data section
1921
+ susc_data = d.SusceptibilityData.from_extractor_data(data)
1922
+ nev_susc_data = d.SusceptibilityData.from_extractor_data(data_nev)
1923
+
1924
+ if uargs.nev_only:
1925
+ susc_data = []
1926
+
1927
+ # Plot all data
1869
1928
  import matplotlib.pyplot as plt
1929
+ import matplotlib.colors as mcolors
1870
1930
  from . import plotter
1871
- from . import extractor as oe
1872
1931
 
1873
- # Set user specified font name
1932
+ # Set font name and size
1874
1933
  ut.check_font_envvar()
1875
- # Change matplotlib font size to be larger
1876
1934
  plt.rcParams['font.size'] = 10
1877
1935
  plt.rcParams['legend.fontsize'] = 9
1878
1936
 
1879
- # Extract data from file
1880
- data = oe.SusceptibilityExtractor.extract(uargs.output_file)
1937
+ # Create list of colours for plotting
1938
+ if len(susc_data + nev_susc_data) == 1:
1939
+ colours = ['black']
1940
+ else:
1941
+ colours = list(mcolors.TABLEAU_COLORS.values())
1881
1942
 
1882
- if not len(data):
1883
- ut.red_exit(
1884
- f'Cannot find susceptibility output in {uargs.output_file}'
1885
- )
1943
+ # Width of figure in inches
1944
+ # Make wider if multiple spectra to plot
1945
+ # to include legend
1946
+ if len(susc_data + nev_susc_data) > 1 and uargs.legend_separate:
1947
+ width = 6.
1948
+ else:
1949
+ width = 3.425
1950
+ # width in cm
1951
+ width_cm = 2.54 * width
1886
1952
 
1887
- if not uargs.quiet:
1888
- ut.cprint(
1889
- f'Found {len(data)} susceptibility blocks in file...',
1890
- 'green'
1953
+ # Create figure and axis with
1954
+ # height based on golden ratio for 4 inch wide figure
1955
+ golden = (1 + np.sqrt(5))/2
1956
+ height = 4. / golden
1957
+ fig, ax = plt.subplots(
1958
+ 1,
1959
+ 1,
1960
+ num='Magnetic Susceptibility',
1961
+ figsize=(width, height)
1962
+ )
1963
+
1964
+ for it, sd in enumerate(susc_data):
1965
+ plotter.plot_susceptibility(
1966
+ sd,
1967
+ uargs.y_style,
1968
+ linecolor=colours[it],
1969
+ xlim=uargs.xlim,
1970
+ ylim=uargs.ylim,
1971
+ save=False,
1972
+ show=False,
1973
+ fig=fig,
1974
+ ax=ax
1891
1975
  )
1892
- ut.cprint(
1893
- '... plotting each separately',
1894
- 'green'
1976
+
1977
+ for it, sd in enumerate(nev_susc_data):
1978
+ plotter.plot_susceptibility(
1979
+ sd,
1980
+ uargs.y_style,
1981
+ linecolor=colours[it + len(susc_data)],
1982
+ label=f'Calculated NEVPT2 ($H$ = {sd.field:.1f} Oe)',
1983
+ save=False,
1984
+ show=False,
1985
+ fig=fig,
1986
+ ax=ax
1895
1987
  )
1896
1988
 
1897
1989
  if uargs.exp_file is not None:
1990
+
1898
1991
  exp_data = {'Temperature (K)': [], 'chi*T (cm3*K/mol)': []}
1899
1992
  with open(uargs.exp_file, newline='') as csvfile:
1900
1993
  reader = csv.DictReader(
@@ -1909,60 +2002,54 @@ def plot_susc_func(uargs) -> None:
1909
2002
  float(row['chi*T (cm3*K/mol)'])
1910
2003
  )
1911
2004
 
1912
- # Conversion factors from cm3 K mol^-1 to ...
1913
- convs = {
1914
- 'A3 K': 1E24 / cst.AVOGADRO,
1915
- 'A3 mol-1 K': 1E24,
1916
- 'cm3 K': 1 / cst.AVOGADRO,
1917
- 'cm3 mol-1 K': 1,
1918
- 'emu K': 1 / (4 * np.pi * cst.AVOGADRO),
1919
- 'emu mol-1 K': 1 / (4 * np.pi)
1920
- }
2005
+ # Conversion factors to cm3 K mol^-1 from ...
2006
+ convs = {
2007
+ 'A3 K': 1E24 / cst.AVOGADRO,
2008
+ 'A3 mol-1 K': 1E24,
2009
+ 'cm3 K': 1 / cst.AVOGADRO,
2010
+ 'cm3 mol-1 K': 1,
2011
+ 'emu K': 1 / (4 * np.pi * cst.AVOGADRO),
2012
+ 'emu mol-1 K': 1 / (4 * np.pi)
2013
+ }
1921
2014
 
1922
- unit_labels = {
1923
- 'A3 K': r'\AA^3\,K',
1924
- 'A3 mol-1 K': r'\AA^3\,mol^{-1}\,K',
1925
- 'cm3 K': r'cm^3\,K',
1926
- 'cm3 mol-1 K': r'cm^3\,mol^{-1}\,K',
1927
- 'emu K': r'emu\,K',
1928
- 'emu mol-1 K': r'emu\,mol^{-1} \ K',
1929
- }
2015
+ ax.plot(
2016
+ exp_data['Temperature (K)'],
2017
+ [
2018
+ val * convs[uargs.esusc_units]
2019
+ for val in exp_data['chi*T (cm3*K/mol)']
2020
+ ],
2021
+ lw=0,
2022
+ marker='o',
2023
+ fillstyle='none',
2024
+ mew=.3,
2025
+ color='k',
2026
+ label='Experiment'
2027
+ )
1930
2028
 
1931
- for dataframe in data:
1932
-
1933
- fig, ax = plotter.plot_chit(
1934
- dataframe['chi*T (cm3*K/mol)'] * convs[uargs.susc_units],
1935
- dataframe['Temperature (K)'],
1936
- fields=dataframe['Static Field (Gauss)'],
1937
- window_title=f'Susceptibility from {uargs.output_file}',
1938
- y_unit=unit_labels[uargs.susc_units],
1939
- show=_SHOW_CONV[uargs.plot] if uargs.exp_file is None else False,
1940
- save=_SAVE_CONV[uargs.plot] if uargs.exp_file is None else False,
1941
- )
1942
- if uargs.exp_file is not None:
1943
- ax.plot(
1944
- exp_data['Temperature (K)'],
1945
- [
1946
- val * convs[uargs.esusc_units]
1947
- for val in exp_data['chi*T (cm3*K/mol)']
1948
- ],
1949
- lw=0,
1950
- marker='o',
1951
- fillstyle='none',
1952
- color='k',
1953
- label='Experiment'
1954
- )
1955
- fig.tight_layout()
1956
- ax.legend(frameon=False)
2029
+ # Set x and y limits
2030
+ plotter.set_axlims(ax, 'x', uargs.xlim)
2031
+ plotter.set_axlims(ax, 'y', uargs.ylim)
2032
+
2033
+ fig.tight_layout()
1957
2034
 
1958
- _ylim = ax.get_ylim()
1959
- ax.set_ylim(0, _ylim[1])
2035
+ if len(susc_data + nev_susc_data) > 1 or uargs.exp_file is not None:
2036
+ if uargs.legend_separate:
2037
+ fig.subplots_adjust(right=3.3/6.)
2038
+ fig.legend(loc='center right')
2039
+ else:
2040
+ ax.legend(loc='best')
1960
2041
 
1961
- if _SAVE_CONV[uargs.plot]:
1962
- plt.savefig('chit_vs_t.png', dpi=500)
2042
+ if _SAVE_CONV[uargs.plot]:
2043
+ savename = 'susceptibility.png'
2044
+ plt.savefig(savename, dpi=500)
2045
+ ut.cprint(f'Saved image to {savename}', 'cyan')
2046
+ ut.cprint(
2047
+ f'Use width={width:.1f} in. or {width_cm:.1f} cm',
2048
+ 'cyan'
2049
+ )
1963
2050
 
1964
- if _SHOW_CONV[uargs.plot]:
1965
- plt.show()
2051
+ if _SHOW_CONV[uargs.plot]:
2052
+ plt.show()
1966
2053
 
1967
2054
  return
1968
2055
 
@@ -2176,6 +2263,7 @@ def read_args(arg_list=None):
2176
2263
 
2177
2264
  extract_hyperfine.add_argument(
2178
2265
  '--output_format',
2266
+ '-of',
2179
2267
  type=str,
2180
2268
  help='Format of outputted data file',
2181
2269
  choices=['txt', 'docx'],
@@ -2207,6 +2295,7 @@ def read_args(arg_list=None):
2207
2295
 
2208
2296
  extract_gmatrix.add_argument(
2209
2297
  '--output_format',
2298
+ '-of',
2210
2299
  type=str,
2211
2300
  help='Format of outputted data file',
2212
2301
  choices=['txt', 'docx'],
@@ -2230,6 +2319,7 @@ def read_args(arg_list=None):
2230
2319
 
2231
2320
  extract_sfenergies.add_argument(
2232
2321
  '--output_format',
2322
+ '-of',
2233
2323
  type=str,
2234
2324
  help='Format of outputted data file',
2235
2325
  choices=['txt', 'docx'],
@@ -2613,6 +2703,7 @@ def read_args(arg_list=None):
2613
2703
 
2614
2704
  gen_abs.add_argument(
2615
2705
  '--x_unit',
2706
+ '-xu',
2616
2707
  type=str,
2617
2708
  choices=['energy', 'wavelength', 'wavenumber'],
2618
2709
  default='energy',
@@ -2641,7 +2732,7 @@ def read_args(arg_list=None):
2641
2732
  )
2642
2733
 
2643
2734
  gen_abs.add_argument(
2644
- '--x_lim',
2735
+ '--xlim',
2645
2736
  nargs=2,
2646
2737
  default=['auto', 'auto'],
2647
2738
  help='x limits of spectrum'
@@ -2781,6 +2872,7 @@ def read_args(arg_list=None):
2781
2872
 
2782
2873
  plot_abs.add_argument(
2783
2874
  '--x_unit',
2875
+ '-xu',
2784
2876
  type=str,
2785
2877
  choices=['energy', 'wavelength', 'wavelength_rev', 'wavenumber'],
2786
2878
  default='energy',
@@ -2799,14 +2891,14 @@ def read_args(arg_list=None):
2799
2891
  )
2800
2892
 
2801
2893
  plot_abs.add_argument(
2802
- '--x_lim',
2894
+ '--xlim',
2803
2895
  nargs=2,
2804
2896
  default=['auto', 'auto'],
2805
2897
  help='x limits of spectrum'
2806
2898
  )
2807
2899
 
2808
2900
  plot_abs.add_argument(
2809
- '--y_lim',
2901
+ '--ylim',
2810
2902
  nargs=2,
2811
2903
  default=[0., 'auto'],
2812
2904
  help='Epsilon limits of spectrum in cm^-1 mol^-1 L'
@@ -2977,14 +3069,14 @@ def read_args(arg_list=None):
2977
3069
  )
2978
3070
 
2979
3071
  plot_xes.add_argument(
2980
- '--x_lim',
3072
+ '--xlim',
2981
3073
  nargs=2,
2982
3074
  default=['auto', 'auto'],
2983
3075
  help='x limits of spectrum'
2984
3076
  )
2985
3077
 
2986
3078
  plot_xes.add_argument(
2987
- '--y_lim',
3079
+ '--ylim',
2988
3080
  nargs=2,
2989
3081
  default=[0., 'auto'],
2990
3082
  help='Epsilon limits of spectrum in cm^-1 mol^-1 L'
@@ -3096,6 +3188,29 @@ def read_args(arg_list=None):
3096
3188
  help='Orca output file name'
3097
3189
  )
3098
3190
 
3191
+ plot_susc.add_argument(
3192
+ '--y_style',
3193
+ '-ys',
3194
+ type=str,
3195
+ metavar='<str>',
3196
+ choices=['X', 'XT', '1/X'],
3197
+ default='XT'
3198
+ )
3199
+
3200
+ plot_susc.add_argument(
3201
+ '--xlim',
3202
+ nargs=2,
3203
+ default=['auto', 'auto'],
3204
+ help='x limits of plot'
3205
+ )
3206
+
3207
+ plot_susc.add_argument(
3208
+ '--ylim',
3209
+ nargs=2,
3210
+ default=[0., 'auto'],
3211
+ help='y limits of plot'
3212
+ )
3213
+
3099
3214
  plot_susc.add_argument(
3100
3215
  '--susc_units',
3101
3216
  '-su',
@@ -3165,6 +3280,20 @@ def read_args(arg_list=None):
3165
3280
  )
3166
3281
  )
3167
3282
 
3283
+ plot_susc.add_argument(
3284
+ '--nev_only',
3285
+ '-no',
3286
+ action='store_true',
3287
+ help='Only plot NEVPT2 data'
3288
+ )
3289
+
3290
+ plot_susc.add_argument(
3291
+ '--legend_separate',
3292
+ '-ls',
3293
+ action='store_true',
3294
+ help='Plot legend next to plot'
3295
+ )
3296
+
3168
3297
  plot_susc.add_argument(
3169
3298
  '--quiet',
3170
3299
  action='store_true',