orto 1.11.3__py3-none-any.whl → 1.13.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/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:
@@ -537,9 +669,99 @@ def extract_gmatrix_func(uargs, save=True):
537
669
  return
538
670
 
539
671
 
672
+ def gen_orbs_func(uargs):
673
+ '''
674
+ Wrapper for CLI gen orbs call
675
+
676
+ Parameters
677
+ ----------
678
+ uargs: argparser object
679
+ User arguments
680
+
681
+ Returns
682
+ -------
683
+ None
684
+ '''
685
+ from subto.job import SlurmJob
686
+
687
+ # Check orca module
688
+ if len(uargs.orca_load):
689
+ orca_load_val = copy.copy(uargs.orca_load)
690
+ elif os.getenv('orto_orca_load'):
691
+ try:
692
+ if len(os.getenv('orto_orca_load')):
693
+ orca_load_val = os.getenv('orto_orca_load')
694
+ except ValueError:
695
+ ut.red_exit(
696
+ (
697
+ 'Error in orto_orca_load environment variable'
698
+ )
699
+ )
700
+ else:
701
+ ut.red_exit(
702
+ (
703
+ 'Missing orto_orca_load environment variable or '
704
+ '--orca_load argument'
705
+ )
706
+ )
707
+
708
+ # Create string of command numbers for orca plot to follow
709
+ command_nums = '1\\n1\\n4'
710
+ command_nums += f'\\n{uargs.n_pts:d}'
711
+ command_nums += '\\n5\\n7'
712
+
713
+ if uargs.beta:
714
+ command_nums += '\\n3\\n1'
715
+
716
+ for orbital_number in uargs.orb_numbers:
717
+ command_nums += '\\n2'
718
+ command_nums += f'\\n{orbital_number:d}'
719
+ command_nums += '\\n11'
720
+ command_nums += '\\n12\\n'
721
+
722
+ # Generate job file for orca_plot
723
+ orb_job = SlurmJob(
724
+ pathlib.Path(f'{uargs.gbw_file.stem}_orbital_job.sh')
725
+ )
726
+
727
+ # Create content of job
728
+ orb_job.content_block = ''
729
+
730
+ orb_job.content_block += '# Load orca module\n'
731
+ orb_job.content_block += f'module load {orca_load_val}\n'
732
+ orb_job.content_block += '# Run orca_plot to generate orbital cube file(s)\n' # noqa
733
+ orb_job.content_block += f'time mpirun -np {uargs.n_procs:d} $(which orca_plot_mpi) {uargs.gbw_file.name} -i aa <<< $\'{command_nums}\'\n\n' # noqa
734
+
735
+ # Set job name
736
+ orb_job.job_name = f'{uargs.gbw_file.stem}_orbitals'
737
+
738
+ orb_job.ntasks_per_node = str(uargs.n_procs)
739
+ orb_job.mem_per_cpu = str(uargs.memory)
740
+
741
+ orb_job.error = f'{uargs.gbw_file.stem}_orbitals.%j.e'
742
+ orb_job.output = f'{uargs.gbw_file.stem}_orbitals.%j.o'
743
+
744
+ # Write job script
745
+ # with submitter configuration options specified
746
+ orb_job.write_script(True)
747
+
748
+ # Submit to queue
749
+ if not uargs.no_sub:
750
+ subprocess.call(
751
+ 'cd {}; {} "{}"; cd ../'.format(
752
+ uargs.gbw_file.parents[0],
753
+ orb_job.SUBMIT_COMMAND,
754
+ orb_job.file_path
755
+ ),
756
+ shell=True
757
+ )
758
+
759
+ return
760
+
761
+
540
762
  def gen_spden_func(uargs):
541
763
  '''
542
- Wrapper for CLI gen spin density call
764
+ Wrapper for CLI gen spin_density call
543
765
 
544
766
  Parameters
545
767
  ----------
@@ -868,7 +1090,6 @@ def plot_xes_func(uargs):
868
1090
  None
869
1091
  '''
870
1092
  import matplotlib.pyplot as plt
871
- import matplotlib as mpl
872
1093
  from . import plotter
873
1094
  from . import extractor as oe
874
1095
 
@@ -876,7 +1097,8 @@ def plot_xes_func(uargs):
876
1097
  ut.check_font_envvar()
877
1098
 
878
1099
  # Change matplotlib font size to be larger
879
- mpl.rcParams.update({'font.size': 12})
1100
+ plt.rcParams['font.size'] = 10
1101
+ plt.rcParams['legend.fontsize'] = 9
880
1102
 
881
1103
  version = oe.OrcaVersionExtractor.extract(uargs.output_file)
882
1104
 
@@ -956,8 +1178,8 @@ def plot_xes_func(uargs):
956
1178
  show=_SHOW_CONV[uargs.plot],
957
1179
  save=_SAVE_CONV[uargs.plot],
958
1180
  save_name=save_name,
959
- x_lim=uargs.x_lim,
960
- y_lim=uargs.y_lim,
1181
+ xlim=uargs.xlim,
1182
+ ylim=uargs.ylim,
961
1183
  x_shift=uargs.shift,
962
1184
  linewidth=uargs.linewidth,
963
1185
  lineshape=uargs.lineshape,
@@ -972,112 +1194,6 @@ def plot_xes_func(uargs):
972
1194
  plt.show()
973
1195
 
974
1196
 
975
- def plot_xas_func(uargs):
976
- '''
977
- Wrapper for CLI plot xas call
978
-
979
- Parameters
980
- ----------
981
- uargs: argparser object
982
- User arguments
983
-
984
- Returns
985
- -------
986
- None
987
- '''
988
- import matplotlib.pyplot as plt
989
- import matplotlib as mpl
990
- from . import plotter
991
- from . import extractor as oe
992
-
993
- # Set user specified font name
994
- ut.check_font_envvar()
995
-
996
- # Change matplotlib font size to be larger
997
- mpl.rcParams.update({'font.size': 12})
998
-
999
- version = oe.OrcaVersionExtractor.extract(uargs.output_file)
1000
-
1001
- if not len(version):
1002
- ut.cprint(
1003
- 'Warning: Cannot find version number in Orca output file',
1004
- 'black_yellowbg'
1005
- )
1006
- version = [6, 0, 0]
1007
-
1008
- if version[0] >= 6:
1009
- if uargs.intensities == 'electric':
1010
- all_data = oe.XASElectricDipoleExtractor.extract(
1011
- uargs.output_file
1012
- )
1013
- elif uargs.intensities == 'velocity':
1014
- all_data = oe.XASVelocityDipoleExtractor.extract(
1015
- uargs.output_file
1016
- )
1017
- elif uargs.intensities == 'semi-classical':
1018
- all_data = oe.XASSemiClassicalDipoleExtractor.extract(
1019
- uargs.output_file
1020
- )
1021
- elif version[0] < 6:
1022
- ut.red_exit('Unsupported version of Orca for XAS extraction', 'red')
1023
-
1024
- ut.cprint('Using intensities: {}'.format(uargs.intensities), 'cyan')
1025
-
1026
- # Plot each section
1027
- for it, data in enumerate(all_data):
1028
-
1029
- if len(all_data) > 1:
1030
- save_name = f'absorption_spectrum_section_{it:d}.png'
1031
- else:
1032
- save_name = 'absorption_spectrum.png'
1033
-
1034
- if uargs.x_unit == 'wavenumber':
1035
- x_values = np.asarray(data['energy (cm^-1)'])
1036
- elif uargs.x_unit == 'wavelength':
1037
- x_values = 1E7 / np.asarray(data['energy (cm^-1)'])
1038
- elif uargs.x_unit == 'energy':
1039
- x_values = np.asarray(data['energy (ev)'])
1040
-
1041
- data['fosc'] = np.asarray(data['fosc'])
1042
-
1043
- # Remove transitions with zero oscillator strength from
1044
- # beginning and end of spectrum
1045
- print(data['fosc'], x_values)
1046
- if not uargs.no_trim:
1047
- # Find first non-zero oscillator strength
1048
- first_nonzero = np.where(data['fosc'] > 1E-6)[0][0]
1049
- # Find last non-zero oscillator strength
1050
- last_nonzero = np.where(data['fosc'] > 1E-6)[0][-1]
1051
-
1052
- # Trim data
1053
- x_values = x_values[first_nonzero:last_nonzero + 1]
1054
- data['fosc'] = data['fosc'][first_nonzero:last_nonzero + 1]
1055
-
1056
- # Plot absorption spectrum
1057
- fig, ax = plotter.plot_abs(
1058
- x_values,
1059
- uargs.x_unit,
1060
- data['fosc'],
1061
- show=_SHOW_CONV[uargs.plot],
1062
- save=_SAVE_CONV[uargs.plot],
1063
- save_name=save_name,
1064
- x_lim=uargs.x_lim,
1065
- y_lim=uargs.y_lim,
1066
- x_shift=uargs.shift,
1067
- linewidth=uargs.linewidth,
1068
- lineshape=uargs.lineshape,
1069
- window_title=f'Absorption Spectrum from {uargs.output_file}',
1070
- osc_style=uargs.osc_style,
1071
- normalise=uargs.normalise
1072
- )
1073
-
1074
- if uargs.x_unit == 'wavenumber':
1075
- ax[0].set_xlim([0, 50000])
1076
- plt.show()
1077
-
1078
- return
1079
-
1080
-
1081
1197
  def plot_abs_func(uargs, save_data_only=False):
1082
1198
  '''
1083
1199
  Wrapper for CLI plot abs call\n\n
@@ -1102,7 +1218,6 @@ def plot_abs_func(uargs, save_data_only=False):
1102
1218
  from . import extractor as oe
1103
1219
  from . import data as d
1104
1220
 
1105
-
1106
1221
  # Process x_shift argument
1107
1222
  if uargs.x_shift is None:
1108
1223
  uargs.x_shift = [0.0 for _ in uargs.output_file]
@@ -1174,9 +1289,9 @@ def plot_abs_func(uargs, save_data_only=False):
1174
1289
  # report if multiple absorption sections found
1175
1290
  elif len(all_abs_data) > 1:
1176
1291
  ut.cprint(
1177
- f'Found {len(all_abs_data)} ABSORPTION sections in '
1292
+ f'\nFound {len(all_abs_data)} ABSORPTION sections in '
1178
1293
  f'file {output_file}\n'
1179
- f'Plotting final section ONLY',
1294
+ f'Plotting final section ONLY\n',
1180
1295
  'cyan'
1181
1296
  )
1182
1297
  # and only use final one
@@ -1208,25 +1323,25 @@ def plot_abs_func(uargs, save_data_only=False):
1208
1323
 
1209
1324
  # Set x_min
1210
1325
  # based on user arguments
1211
- if isinstance(uargs.x_lim[0], str):
1212
- if uargs.x_lim[0] == 'auto':
1326
+ if isinstance(uargs.xlim[0], str):
1327
+ if uargs.xlim[0] == 'auto':
1213
1328
  x_min = min(x_vals) * min_factor
1214
- elif ut.is_floatable(uargs.x_lim[0]):
1215
- x_min = float(uargs.x_lim[0])
1329
+ elif ut.is_floatable(uargs.xlim[0]):
1330
+ x_min = float(uargs.xlim[0])
1216
1331
  else:
1217
- raise ValueError(f'Invalid x_min value: {uargs.x_lim[0]}')
1332
+ raise ValueError(f'Invalid x_min value: {uargs.xlim[0]}')
1218
1333
  else:
1219
- x_min = uargs.x_lim[0]
1334
+ x_min = uargs.xlim[0]
1220
1335
 
1221
1336
  # Set x_max
1222
1337
  # based on user arguments
1223
- if isinstance(uargs.x_lim[1], str):
1224
- if uargs.x_lim[1] == 'auto':
1338
+ if isinstance(uargs.xlim[1], str):
1339
+ if uargs.xlim[1] == 'auto':
1225
1340
  x_max = max(x_vals) * max_factor
1226
- elif ut.is_floatable(uargs.x_lim[1]):
1227
- x_max = float(uargs.x_lim[1])
1341
+ elif ut.is_floatable(uargs.xlim[1]):
1342
+ x_max = float(uargs.xlim[1])
1228
1343
  else:
1229
- raise ValueError(f'Invalid x_max value: {uargs.x_lim[1]}')
1344
+ raise ValueError(f'Invalid x_max value: {uargs.xlim[1]}')
1230
1345
  else:
1231
1346
  x_max = uargs.xlim[1]
1232
1347
 
@@ -1265,27 +1380,27 @@ def plot_abs_func(uargs, save_data_only=False):
1265
1380
  )
1266
1381
  )
1267
1382
  ut.cprint(
1268
- 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
1269
1384
  'cyan'
1270
1385
  )
1271
1386
  ut.cprint(
1272
- 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
1273
1388
  'cyan'
1274
1389
  )
1275
1390
  else:
1276
- # Add to dictionary of spectra for plotting later
1391
+ # Add to dictionary of absorption data for plotting later
1277
1392
  spectra_dict[output_file] = abs_data
1278
1393
 
1279
1394
  # Exit if only saving data
1280
1395
  if save_data_only:
1281
1396
  return
1282
1397
 
1283
- ## Plot all spectra
1398
+ # Plot all spectra
1284
1399
  import matplotlib.pyplot as plt
1285
1400
  import matplotlib.colors as mcolors
1286
1401
 
1287
1402
  # Set font name and size
1288
- plt.rcParams['font.family'] = 'Arial'
1403
+ ut.check_font_envvar()
1289
1404
  plt.rcParams['font.size'] = 10
1290
1405
  plt.rcParams['legend.fontsize'] = 9
1291
1406
  plt.rcParams['legend.loc'] = 'center right'
@@ -1302,7 +1417,7 @@ def plot_abs_func(uargs, save_data_only=False):
1302
1417
  if len(spectra_dict) > 1:
1303
1418
  width = 6.
1304
1419
  else:
1305
- width = 4
1420
+ width = 3.425
1306
1421
  # width in cm
1307
1422
  width_cm = 2.54 * width
1308
1423
 
@@ -1324,7 +1439,7 @@ def plot_abs_func(uargs, save_data_only=False):
1324
1439
  plotter.plot_absorption_spectrum(
1325
1440
  abs_data,
1326
1441
  linecolor=colours[it],
1327
- stickcolour=colours[it],
1442
+ stickcolor=colours[it],
1328
1443
  osc_style=uargs.osc_style,
1329
1444
  normalise=uargs.normalise,
1330
1445
  window_title='',
@@ -1333,14 +1448,14 @@ def plot_abs_func(uargs, save_data_only=False):
1333
1448
  oax=oax,
1334
1449
  show=False,
1335
1450
  save=False,
1336
- x_lim=[x_min, x_max],
1337
- y_lim=uargs.y_lim,
1451
+ xlim=[x_min, x_max],
1452
+ ylim=uargs.ylim,
1338
1453
  x_shift=uargs.x_shift[it],
1339
1454
  legend=False
1340
1455
  )
1341
1456
 
1342
- if uargs.x_lim != ['auto', 'auto']:
1343
- 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]))
1344
1459
 
1345
1460
  fig.tight_layout()
1346
1461
 
@@ -1355,7 +1470,7 @@ def plot_abs_func(uargs, save_data_only=False):
1355
1470
  fig.legend(uargs.legend, loc=7)
1356
1471
 
1357
1472
  if _SAVE_CONV[uargs.plot]:
1358
- savename = f'absorption_spectrum_{output_file.stem}.png'
1473
+ savename = 'absorption_spectrum.png'
1359
1474
  plt.savefig(savename, dpi=500)
1360
1475
  ut.cprint(f'Saved image to {savename}', 'cyan')
1361
1476
  ut.cprint(
@@ -1382,7 +1497,7 @@ def plot_ir_func(uargs):
1382
1497
  -------
1383
1498
  None
1384
1499
  '''
1385
- import matplotlib as mpl
1500
+ import matplotlib.pyplot as plt
1386
1501
  from . import plotter
1387
1502
  from . import extractor as oe
1388
1503
 
@@ -1390,7 +1505,8 @@ def plot_ir_func(uargs):
1390
1505
  ut.check_font_envvar()
1391
1506
 
1392
1507
  # Change matplotlib font size to be larger
1393
- mpl.rcParams.update({'font.size': 12})
1508
+ plt.rcParams['font.size'] = 10
1509
+ plt.rcParams['legend.fontsize'] = 9
1394
1510
 
1395
1511
  # Extract frequency information
1396
1512
  data = oe.FrequencyExtractor.extract(uargs.output_file)
@@ -1776,37 +1892,107 @@ def plot_susc_func(uargs) -> None:
1776
1892
  None
1777
1893
 
1778
1894
  '''
1779
- import matplotlib.pyplot as plt
1780
- import matplotlib as mpl
1781
- from . import plotter
1782
1895
  from . import extractor as oe
1896
+ from . import data as d
1783
1897
 
1784
- # Change matplotlib font size to be larger
1785
- mpl.rcParams.update({'font.size': 12})
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 = []
1786
1906
 
1787
- # Extract data from file
1788
- data = oe.SusceptibilityExtractor.extract(uargs.output_file)
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 = []
1789
1914
 
1790
- if not len(data):
1915
+ if not len(data + data_nev):
1791
1916
  ut.red_exit(
1792
- f'Cannot find susceptibility output in {uargs.output_file}'
1917
+ f'Cannot find susceptibility data in {uargs.output_file}'
1793
1918
  )
1794
1919
 
1795
- if not uargs.quiet:
1796
- ut.cprint(
1797
- f'Found {len(data)} susceptibility blocks in file...',
1798
- 'green'
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
1928
+ import matplotlib.pyplot as plt
1929
+ import matplotlib.colors as mcolors
1930
+ from . import plotter
1931
+
1932
+ # Set font name and size
1933
+ ut.check_font_envvar()
1934
+ plt.rcParams['font.size'] = 10
1935
+ plt.rcParams['legend.fontsize'] = 9
1936
+
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())
1942
+
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
1952
+
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
1799
1975
  )
1800
- ut.cprint(
1801
- '... plotting each separately',
1802
- '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
1803
1987
  )
1804
1988
 
1805
1989
  if uargs.exp_file is not None:
1990
+
1806
1991
  exp_data = {'Temperature (K)': [], 'chi*T (cm3*K/mol)': []}
1807
1992
  with open(uargs.exp_file, newline='') as csvfile:
1808
1993
  reader = csv.DictReader(
1809
- row for row in csvfile if not row.startswith('#')
1994
+ [row for row in csvfile if not row.startswith('#')],
1995
+ skipinitialspace=True
1810
1996
  )
1811
1997
  for row in reader:
1812
1998
  exp_data['Temperature (K)'].append(
@@ -1816,60 +2002,54 @@ def plot_susc_func(uargs) -> None:
1816
2002
  float(row['chi*T (cm3*K/mol)'])
1817
2003
  )
1818
2004
 
1819
- # Conversion factors from cm3 K mol^-1 to ...
1820
- convs = {
1821
- 'A3 K': 1E24 / cst.AVOGADRO,
1822
- 'A3 mol-1 K': 1E24,
1823
- 'cm3 K': 1 / cst.AVOGADRO,
1824
- 'cm3 mol-1 K': 1,
1825
- 'emu K': 1 / (4 * np.pi * cst.AVOGADRO),
1826
- 'emu mol-1 K': 1 / (4 * np.pi)
1827
- }
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
+ }
1828
2014
 
1829
- unit_labels = {
1830
- 'A3 K': r'\AA^3\,K',
1831
- 'A3 mol-1 K': r'\AA^3\,mol^{-1}\,K',
1832
- 'cm3 K': r'cm^3\,K',
1833
- 'cm3 mol-1 K': r'cm^3\,mol^{-1}\,K',
1834
- 'emu K': r'emu\,K',
1835
- 'emu mol-1 K': r'emu\,mol^{-1} \ K',
1836
- }
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
+ )
1837
2028
 
1838
- for dataframe in data:
1839
-
1840
- fig, ax = plotter.plot_chit(
1841
- dataframe['chi*T (cm3*K/mol)'] * convs[uargs.susc_units],
1842
- dataframe['Temperature (K)'],
1843
- fields=dataframe['Static Field (Gauss)'],
1844
- window_title=f'Susceptibility from {uargs.output_file}',
1845
- y_unit=unit_labels[uargs.susc_units],
1846
- show=_SHOW_CONV[uargs.plot] if uargs.exp_file is None else False,
1847
- save=_SAVE_CONV[uargs.plot] if uargs.exp_file is None else False,
1848
- )
1849
- if uargs.exp_file is not None:
1850
- ax.plot(
1851
- exp_data['Temperature (K)'],
1852
- [
1853
- val * convs[uargs.esusc_units]
1854
- for val in exp_data['chi*T (cm3*K/mol)']
1855
- ],
1856
- lw=0,
1857
- marker='o',
1858
- fillstyle='none',
1859
- color='k',
1860
- label='Experiment'
1861
- )
1862
- fig.tight_layout()
1863
- 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()
1864
2034
 
1865
- _ylim = ax.get_ylim()
1866
- 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')
1867
2041
 
1868
- if _SAVE_CONV[uargs.plot]:
1869
- 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
+ )
1870
2050
 
1871
- if _SHOW_CONV[uargs.plot]:
1872
- plt.show()
2051
+ if _SHOW_CONV[uargs.plot]:
2052
+ plt.show()
1873
2053
 
1874
2054
  return
1875
2055
 
@@ -1888,12 +2068,14 @@ def plot_ailft_func(uargs) -> None:
1888
2068
  None
1889
2069
  '''
1890
2070
  import matplotlib.pyplot as plt
1891
- import matplotlib as mpl
1892
2071
  from . import plotter
1893
2072
  from . import extractor as oe
1894
2073
 
2074
+ # Set user specified font name
2075
+ ut.check_font_envvar()
1895
2076
  # Change matplotlib font size to be larger
1896
- mpl.rcParams.update({'font.size': 12})
2077
+ plt.rcParams['font.size'] = 10
2078
+ plt.rcParams['legend.fontsize'] = 9
1897
2079
 
1898
2080
  # Create extractor
1899
2081
  data = oe.AILFTOrbEnergyExtractor.extract(uargs.output_file)
@@ -2081,6 +2263,7 @@ def read_args(arg_list=None):
2081
2263
 
2082
2264
  extract_hyperfine.add_argument(
2083
2265
  '--output_format',
2266
+ '-of',
2084
2267
  type=str,
2085
2268
  help='Format of outputted data file',
2086
2269
  choices=['txt', 'docx'],
@@ -2112,6 +2295,7 @@ def read_args(arg_list=None):
2112
2295
 
2113
2296
  extract_gmatrix.add_argument(
2114
2297
  '--output_format',
2298
+ '-of',
2115
2299
  type=str,
2116
2300
  help='Format of outputted data file',
2117
2301
  choices=['txt', 'docx'],
@@ -2135,6 +2319,7 @@ def read_args(arg_list=None):
2135
2319
 
2136
2320
  extract_sfenergies.add_argument(
2137
2321
  '--output_format',
2322
+ '-of',
2138
2323
  type=str,
2139
2324
  help='Format of outputted data file',
2140
2325
  choices=['txt', 'docx'],
@@ -2203,6 +2388,89 @@ def read_args(arg_list=None):
2203
2388
  )
2204
2389
  )
2205
2390
 
2391
+ gen_orbs = gen_parser.add_parser(
2392
+ 'orbs',
2393
+ aliases=['orbitals', 'mos', 'mo'],
2394
+ description='Generate molecular orbital cube file(s) from gbw file', # noqa
2395
+ usage=ut.cstring(
2396
+ 'orto gen orbs <gbw_file> <orbs> <n_procs> [options]',
2397
+ 'cyan'
2398
+ ),
2399
+ formatter_class=argparse.RawTextHelpFormatter
2400
+ )
2401
+ gen_orbs._positionals.title = 'Mandatory Arguments'
2402
+ gen_orbs.set_defaults(func=gen_orbs_func)
2403
+
2404
+ gen_orbs.add_argument(
2405
+ 'gbw_file',
2406
+ type=pathlib.Path,
2407
+ help='Orca gbw file name'
2408
+ )
2409
+
2410
+ gen_orbs.add_argument(
2411
+ 'orb_numbers',
2412
+ type=int,
2413
+ nargs='+',
2414
+ help=(
2415
+ 'Orbital number(s) to generate cube file for'
2416
+ '(these are alpha spin by default)'
2417
+ )
2418
+ )
2419
+
2420
+ gen_orbs.add_argument(
2421
+ 'n_procs',
2422
+ type=int,
2423
+ help='Number of processors/cores used in calculation',
2424
+ default=1
2425
+ )
2426
+
2427
+ gen_orbs.add_argument(
2428
+ '--n_pts',
2429
+ '-n',
2430
+ type=int,
2431
+ default=100,
2432
+ help=(
2433
+ 'Number of points in each dimension of cube file\n'
2434
+ 'Default: %(default)s'
2435
+ )
2436
+ )
2437
+
2438
+ gen_orbs.add_argument(
2439
+ '--memory',
2440
+ '-mem',
2441
+ type=int,
2442
+ default=500,
2443
+ help=(
2444
+ 'Per-core Memory to use in MB\n'
2445
+ 'Default: %(default)s'
2446
+ )
2447
+ )
2448
+
2449
+ gen_orbs.add_argument(
2450
+ '-om',
2451
+ '--orca_load',
2452
+ type=str,
2453
+ default='',
2454
+ help='Orca environment module (overrides ORTO_ORCA_LOAD envvar)'
2455
+ )
2456
+
2457
+ gen_orbs.add_argument(
2458
+ '--beta',
2459
+ action='store_true',
2460
+ help=(
2461
+ 'Plot beta orbitals instead of alpha (for open shell calculations)'
2462
+ )
2463
+ )
2464
+
2465
+ gen_orbs.add_argument(
2466
+ '--no_sub',
2467
+ '-ns',
2468
+ action='store_true',
2469
+ help=(
2470
+ 'Disables submission of job to queue'
2471
+ )
2472
+ )
2473
+
2206
2474
  gen_spden = gen_parser.add_parser(
2207
2475
  'spdens',
2208
2476
  aliases=['spin_density', 'spden'],
@@ -2435,6 +2703,7 @@ def read_args(arg_list=None):
2435
2703
 
2436
2704
  gen_abs.add_argument(
2437
2705
  '--x_unit',
2706
+ '-xu',
2438
2707
  type=str,
2439
2708
  choices=['energy', 'wavelength', 'wavenumber'],
2440
2709
  default='energy',
@@ -2463,7 +2732,7 @@ def read_args(arg_list=None):
2463
2732
  )
2464
2733
 
2465
2734
  gen_abs.add_argument(
2466
- '--x_lim',
2735
+ '--xlim',
2467
2736
  nargs=2,
2468
2737
  default=['auto', 'auto'],
2469
2738
  help='x limits of spectrum'
@@ -2603,6 +2872,7 @@ def read_args(arg_list=None):
2603
2872
 
2604
2873
  plot_abs.add_argument(
2605
2874
  '--x_unit',
2875
+ '-xu',
2606
2876
  type=str,
2607
2877
  choices=['energy', 'wavelength', 'wavelength_rev', 'wavenumber'],
2608
2878
  default='energy',
@@ -2621,14 +2891,14 @@ def read_args(arg_list=None):
2621
2891
  )
2622
2892
 
2623
2893
  plot_abs.add_argument(
2624
- '--x_lim',
2894
+ '--xlim',
2625
2895
  nargs=2,
2626
2896
  default=['auto', 'auto'],
2627
2897
  help='x limits of spectrum'
2628
2898
  )
2629
2899
 
2630
2900
  plot_abs.add_argument(
2631
- '--y_lim',
2901
+ '--ylim',
2632
2902
  nargs=2,
2633
2903
  default=[0., 'auto'],
2634
2904
  help='Epsilon limits of spectrum in cm^-1 mol^-1 L'
@@ -2799,14 +3069,14 @@ def read_args(arg_list=None):
2799
3069
  )
2800
3070
 
2801
3071
  plot_xes.add_argument(
2802
- '--x_lim',
3072
+ '--xlim',
2803
3073
  nargs=2,
2804
3074
  default=['auto', 'auto'],
2805
3075
  help='x limits of spectrum'
2806
3076
  )
2807
3077
 
2808
3078
  plot_xes.add_argument(
2809
- '--y_lim',
3079
+ '--ylim',
2810
3080
  nargs=2,
2811
3081
  default=[0., 'auto'],
2812
3082
  help='Epsilon limits of spectrum in cm^-1 mol^-1 L'
@@ -2918,6 +3188,29 @@ def read_args(arg_list=None):
2918
3188
  help='Orca output file name'
2919
3189
  )
2920
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
+
2921
3214
  plot_susc.add_argument(
2922
3215
  '--susc_units',
2923
3216
  '-su',
@@ -2987,6 +3280,20 @@ def read_args(arg_list=None):
2987
3280
  )
2988
3281
  )
2989
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
+
2990
3297
  plot_susc.add_argument(
2991
3298
  '--quiet',
2992
3299
  action='store_true',