orto 1.4.0__py3-none-any.whl → 1.6.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 +1 -1
- orto/cli.py +486 -37
- orto/constants.py +2 -0
- orto/data.py +351 -0
- orto/extractor.py +210 -3
- orto/plotter.py +128 -194
- orto/utils.py +123 -0
- {orto-1.4.0.dist-info → orto-1.6.0.dist-info}/METADATA +3 -1
- orto-1.6.0.dist-info/RECORD +17 -0
- orto-1.6.0.dist-info/licenses/LICENSE +165 -0
- orto-1.4.0.dist-info/RECORD +0 -15
- {orto-1.4.0.dist-info → orto-1.6.0.dist-info}/WHEEL +0 -0
- {orto-1.4.0.dist-info → orto-1.6.0.dist-info}/entry_points.txt +0 -0
- {orto-1.4.0.dist-info → orto-1.6.0.dist-info}/top_level.txt +0 -0
orto/data.py
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from numpy.typing import NDArray, ArrayLike
|
|
3
|
+
|
|
4
|
+
from .exceptions import DataFormattingError
|
|
5
|
+
from . import constants as const
|
|
6
|
+
from . import extractor as oe
|
|
7
|
+
from . import utils as ut
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AbsorptionSpectrum():
|
|
11
|
+
'''
|
|
12
|
+
Stores absorption spectrum data
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
x_grid: NDArray
|
|
17
|
+
Grid of x values (energies, wavelengths, or wavenumbers)
|
|
18
|
+
x_unit: str
|
|
19
|
+
Unit of x values: 'eV', 'nm', or 'cm^-1'
|
|
20
|
+
x_label: str
|
|
21
|
+
Label for x axis using LaTeX formatting
|
|
22
|
+
y_unit: str
|
|
23
|
+
Unit of y values, e.g. 'cm^-1 mol^-1 L'
|
|
24
|
+
y_label: str
|
|
25
|
+
Label for y axis using LaTeX formatting
|
|
26
|
+
spectrum: NDArray
|
|
27
|
+
Absorption spectrum values at each point in x_grid
|
|
28
|
+
fwhm: float
|
|
29
|
+
Full width at half maximum used in spectrum generation
|
|
30
|
+
comment: str, default=''
|
|
31
|
+
Comment or metadata for the spectrum
|
|
32
|
+
|
|
33
|
+
Attributes
|
|
34
|
+
----------
|
|
35
|
+
x_grid: NDArray
|
|
36
|
+
Grid of x values (energies, wavelengths, or wavenumbers)
|
|
37
|
+
x_unit: str
|
|
38
|
+
Unit of x values: 'eV', 'nm', or 'cm^-1'
|
|
39
|
+
x_label: str
|
|
40
|
+
Label for x axis using LaTeX formatting
|
|
41
|
+
y_unit: str
|
|
42
|
+
Unit of y values, e.g. 'cm^-1 mol^-1 L'
|
|
43
|
+
y_label: str
|
|
44
|
+
Label for y axis using LaTeX formatting
|
|
45
|
+
y_values: NDArray
|
|
46
|
+
Absorption spectrum values at each point in x_grid
|
|
47
|
+
fwhm: float
|
|
48
|
+
Full width at half maximum used in spectrum generation
|
|
49
|
+
comment: str
|
|
50
|
+
Comment or metadata for the spectrum
|
|
51
|
+
'''
|
|
52
|
+
|
|
53
|
+
def __init__(self, x_grid: NDArray, x_unit: str, x_label: str, y_unit: str,
|
|
54
|
+
y_label: str, y_values: NDArray, fwhm: float,
|
|
55
|
+
comment: str = '') -> None:
|
|
56
|
+
self.x_grid = x_grid
|
|
57
|
+
self.x_unit = x_unit
|
|
58
|
+
self.x_label = x_label
|
|
59
|
+
self.y_unit = y_unit
|
|
60
|
+
self.y_label = y_label
|
|
61
|
+
self.fwhm = fwhm
|
|
62
|
+
self.y_values = y_values
|
|
63
|
+
self.comment = comment
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def from_data(cls, x_grid: NDArray, y_values: NDArray,
|
|
68
|
+
fwhm: float) -> 'AbsorptionSpectrum':
|
|
69
|
+
'''
|
|
70
|
+
Creates AbsorptionSpectrum object from data
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
x_grid: NDArray
|
|
75
|
+
Grid of x values (energies, wavelengths, or wavenumbers)
|
|
76
|
+
y_values: NDArray
|
|
77
|
+
Absorption spectrum values at each point in x_grid
|
|
78
|
+
fwhm: float
|
|
79
|
+
Full width at half maximum used in spectrum generation
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
AbsorptionSpectrum
|
|
84
|
+
Created AbsorptionSpectrum object
|
|
85
|
+
'''
|
|
86
|
+
return cls(x_grid, y_values, fwhm)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class AbsorptionData():
|
|
90
|
+
'''
|
|
91
|
+
Stores absorption data for a given set of transitions
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
energies: array_like
|
|
96
|
+
Transition energies in eV
|
|
97
|
+
osc_strengths: array_like
|
|
98
|
+
Oscillator strengths for each transition
|
|
99
|
+
operator: str
|
|
100
|
+
Type of operator used to calculate transitions
|
|
101
|
+
|
|
102
|
+
Attributes
|
|
103
|
+
----------
|
|
104
|
+
energies: list
|
|
105
|
+
Transition energies in eV
|
|
106
|
+
osc_strengths: list
|
|
107
|
+
Oscillator strengths for each transition
|
|
108
|
+
operator: str
|
|
109
|
+
Type of operator used to calculate transitions
|
|
110
|
+
spectrum: AbsorptionSpectrum
|
|
111
|
+
Spectrum object containing spectrum curve
|
|
112
|
+
wavelengths: list
|
|
113
|
+
Transition wavelengths in nm
|
|
114
|
+
wavenumbers: list
|
|
115
|
+
Transition wavenumbers in cm^-1
|
|
116
|
+
'''
|
|
117
|
+
|
|
118
|
+
def __init__(self, energies: ArrayLike, osc_strengths: ArrayLike,
|
|
119
|
+
operator: str) -> None:
|
|
120
|
+
self.energies = energies
|
|
121
|
+
self.osc_strengths = osc_strengths
|
|
122
|
+
self.operator = operator
|
|
123
|
+
self.spectrum: None | AbsorptionSpectrum = None
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def osc_strengths(self) -> list:
|
|
128
|
+
'''Oscillator strengths for each transition'''
|
|
129
|
+
return self._osc_strengths
|
|
130
|
+
|
|
131
|
+
@osc_strengths.setter
|
|
132
|
+
def osc_strengths(self, osc_strengths: ArrayLike) -> None:
|
|
133
|
+
self._osc_strengths = list(osc_strengths)
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def energies(self) -> list:
|
|
138
|
+
'''Transition energies in eV'''
|
|
139
|
+
return self._energies
|
|
140
|
+
|
|
141
|
+
@energies.setter
|
|
142
|
+
def energies(self, energies: ArrayLike) -> None:
|
|
143
|
+
self._energies = list(energies)
|
|
144
|
+
return
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def wavelengths(self) -> list:
|
|
148
|
+
'''Transition wavelengths in nm'''
|
|
149
|
+
return [const.EV_TO_NM / energy for energy in self.energies]
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def wavenumbers(self) -> list:
|
|
153
|
+
'''Transition wavenumbers in cm^-1'''
|
|
154
|
+
return [energy * const.EV_TO_WAVENUMBER for energy in self.energies]
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def spectrum(self) -> AbsorptionSpectrum:
|
|
158
|
+
'''Absorption spectrum object'''
|
|
159
|
+
if self._spectrum is None:
|
|
160
|
+
raise ValueError(
|
|
161
|
+
'Spectrum has not been generated yet\n'
|
|
162
|
+
'Call generate_spectrum() first.'
|
|
163
|
+
)
|
|
164
|
+
return self._spectrum
|
|
165
|
+
|
|
166
|
+
@spectrum.setter
|
|
167
|
+
def spectrum(self, spectrum: AbsorptionSpectrum) -> None:
|
|
168
|
+
if not isinstance(spectrum, AbsorptionSpectrum | None):
|
|
169
|
+
raise TypeError('spectrum must be an AbsorptionSpectrum object')
|
|
170
|
+
self._spectrum = spectrum
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
def from_extractor(cls, extractor: oe.AbsorptionExtractor,
|
|
175
|
+
remove_zero_osc: bool = True) -> list['AbsorptionData']: # noqa
|
|
176
|
+
'''
|
|
177
|
+
Creates AbsorptionData object from data extractor
|
|
178
|
+
|
|
179
|
+
Parameters
|
|
180
|
+
----------
|
|
181
|
+
extractor: Extractor
|
|
182
|
+
Data extractor object containing transition data
|
|
183
|
+
remove_zero_osc: bool
|
|
184
|
+
If True, removes transitions with zero oscillator strength
|
|
185
|
+
|
|
186
|
+
Returns
|
|
187
|
+
-------
|
|
188
|
+
list['AbsorptionData']
|
|
189
|
+
AbsorptionData objects, one for each section in extractor
|
|
190
|
+
'''
|
|
191
|
+
|
|
192
|
+
all_abs_data = [
|
|
193
|
+
cls.from_extractor_dataset(
|
|
194
|
+
dataset,
|
|
195
|
+
extractor.operator_type,
|
|
196
|
+
remove_zero_osc=remove_zero_osc
|
|
197
|
+
)
|
|
198
|
+
for dataset in extractor.data
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
return all_abs_data
|
|
202
|
+
|
|
203
|
+
@classmethod
|
|
204
|
+
def from_extractor_dataset(cls,
|
|
205
|
+
dataset: dict[str, list[int | float]],
|
|
206
|
+
operator: str,
|
|
207
|
+
remove_zero_osc: bool = False) -> 'AbsorptionData': # noqa
|
|
208
|
+
'''
|
|
209
|
+
Creates AbsorptionData object from data extractor
|
|
210
|
+
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
dataset: dict[str, list[int | float]]
|
|
214
|
+
Dataset from orto AbsorptionExtractor.data
|
|
215
|
+
operator: str
|
|
216
|
+
Type of operator used to calculate transitions
|
|
217
|
+
remove_zero_osc: bool
|
|
218
|
+
If True, removes transitions with zero oscillator strength
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
AbsorptionData
|
|
223
|
+
AbsorptionData object for dataset
|
|
224
|
+
'''
|
|
225
|
+
|
|
226
|
+
energies = dataset['energy (ev)']
|
|
227
|
+
osc_strengths = dataset['fosc']
|
|
228
|
+
|
|
229
|
+
# Remove transitions with zero oscillator strength from
|
|
230
|
+
# beginning and end of spectrum
|
|
231
|
+
if remove_zero_osc:
|
|
232
|
+
osc_strengths = np.array(osc_strengths)
|
|
233
|
+
# Find first non-zero oscillator strength
|
|
234
|
+
first_nonzero = np.where(osc_strengths > 1E-4)[0][0]
|
|
235
|
+
# Find last non-zero oscillator strength
|
|
236
|
+
last_nonzero = np.where(osc_strengths > 1E-4)[0][-1]
|
|
237
|
+
|
|
238
|
+
# Trim data
|
|
239
|
+
energies = energies[first_nonzero:last_nonzero + 1]
|
|
240
|
+
osc_strengths = osc_strengths[first_nonzero:last_nonzero + 1]
|
|
241
|
+
|
|
242
|
+
return cls(energies, osc_strengths, operator)
|
|
243
|
+
|
|
244
|
+
def generate_spectrum(self, fwhm: float, lineshape: str, x_min: float,
|
|
245
|
+
x_max: float, num_points: int,
|
|
246
|
+
x_type: str = 'energy',
|
|
247
|
+
comment: str = '') -> AbsorptionSpectrum:
|
|
248
|
+
'''
|
|
249
|
+
Generates absorption spectrum using Gaussian broadening
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
fwhm: float
|
|
254
|
+
Full width at half maximum for Gaussian broadening\n
|
|
255
|
+
in same units as x_type. Applied to each transition.
|
|
256
|
+
lineshape: str
|
|
257
|
+
Lineshape function to use: 'gaussian' or 'lorentzian'
|
|
258
|
+
x_min: float | str
|
|
259
|
+
Minimum x value for spectrum (eV, nm, or cm^-1)
|
|
260
|
+
x_max: float | str
|
|
261
|
+
Maximum x value for spectrum (eV, nm, or cm^-1)
|
|
262
|
+
num_points: int
|
|
263
|
+
Number of points in the spectrum grid
|
|
264
|
+
x_type: str
|
|
265
|
+
Type of x values: \n
|
|
266
|
+
'energy' (eV)\n
|
|
267
|
+
'wavelength' (nm)\n
|
|
268
|
+
'wavenumber' (cm^-1)
|
|
269
|
+
comment: str
|
|
270
|
+
Comment to add to spectrum metadata
|
|
271
|
+
|
|
272
|
+
Returns
|
|
273
|
+
-------
|
|
274
|
+
None
|
|
275
|
+
'''
|
|
276
|
+
|
|
277
|
+
if len(self.energies) == 0 or len(self.osc_strengths) == 0:
|
|
278
|
+
raise DataFormattingError(
|
|
279
|
+
'No transition data available to generate spectrum.'
|
|
280
|
+
)
|
|
281
|
+
elif len(self.energies) != len(self.osc_strengths):
|
|
282
|
+
raise DataFormattingError(
|
|
283
|
+
'Energies and oscillator strengths must have the same length.'
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Set labels and x values based on x_type
|
|
287
|
+
if x_type == 'energy':
|
|
288
|
+
x_unit = 'eV'
|
|
289
|
+
x_label = 'Energy (eV)'
|
|
290
|
+
x_vals = self.energies
|
|
291
|
+
elif x_type == 'wavelength':
|
|
292
|
+
x_unit = 'nm'
|
|
293
|
+
x_label = 'Wavelength (nm)'
|
|
294
|
+
x_vals = self.wavelengths
|
|
295
|
+
elif x_type == 'wavenumber':
|
|
296
|
+
x_unit = 'cm^-1'
|
|
297
|
+
x_label = r'Wavenumber (cm$\mathregular{^{-1}}$)'
|
|
298
|
+
x_vals = self.wavenumbers
|
|
299
|
+
else:
|
|
300
|
+
raise DataFormattingError(f'Invalid x_type: {x_type}')
|
|
301
|
+
|
|
302
|
+
y_unit = 'cm mol^-1 eV^-1'
|
|
303
|
+
y_label = r'$\epsilon$ (cm$^\mathregular{-1}$ mol$^\mathregular{-1}$ L)' # noqa
|
|
304
|
+
|
|
305
|
+
# Create grid for spectrum
|
|
306
|
+
x_grid = np.linspace(x_min, x_max, num_points)
|
|
307
|
+
spectrum = np.zeros_like(x_grid)
|
|
308
|
+
|
|
309
|
+
# Conversion from oscillator strength to napierian integrated
|
|
310
|
+
# absorption coefficient
|
|
311
|
+
# This is the value of A for a harmonically oscillating electron
|
|
312
|
+
A_elec = 2.31E8
|
|
313
|
+
#
|
|
314
|
+
A_logs = [fosc * A_elec for fosc in self.osc_strengths]
|
|
315
|
+
|
|
316
|
+
ls_func = {
|
|
317
|
+
'gaussian': ut.gaussian,
|
|
318
|
+
'lorentzian': ut.lorentzian
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
# Spectrum as sum of signals in given unit
|
|
322
|
+
y_vals = np.sum([
|
|
323
|
+
ls_func[lineshape](x_grid, fwhm, x_value, A_log)
|
|
324
|
+
for x_value, A_log in zip(x_vals, A_logs)
|
|
325
|
+
], axis=0)
|
|
326
|
+
|
|
327
|
+
# Transform y values into epsilon in cm^-1 mol^-1 L
|
|
328
|
+
if x_type == 'energy':
|
|
329
|
+
y_vals /= const.EV_TO_WAVENUMBER
|
|
330
|
+
elif x_type == 'wavelength':
|
|
331
|
+
# calc x grid in wavenumbers
|
|
332
|
+
xgwn = 1E7 / x_grid
|
|
333
|
+
# Calculate jacobian for non linear transformation
|
|
334
|
+
jacobian = (1E7 / xgwn**2) # d(nm)/d(cm^-1)
|
|
335
|
+
# obtain y values in wavenumbers
|
|
336
|
+
y_vals = y_vals * jacobian
|
|
337
|
+
|
|
338
|
+
spectrum = AbsorptionSpectrum(
|
|
339
|
+
x_grid=x_grid,
|
|
340
|
+
x_unit=x_unit,
|
|
341
|
+
x_label=x_label,
|
|
342
|
+
y_unit=y_unit,
|
|
343
|
+
y_label=y_label,
|
|
344
|
+
y_values=y_vals,
|
|
345
|
+
fwhm=fwhm,
|
|
346
|
+
comment=comment
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
self.spectrum = spectrum
|
|
350
|
+
|
|
351
|
+
return
|
orto/extractor.py
CHANGED
|
@@ -8,6 +8,7 @@ import pandas as pd
|
|
|
8
8
|
from io import StringIO
|
|
9
9
|
import pathlib
|
|
10
10
|
import copy
|
|
11
|
+
from abc import abstractmethod
|
|
11
12
|
|
|
12
13
|
from .exceptions import DataFormattingError
|
|
13
14
|
from . import constants as const
|
|
@@ -1313,12 +1314,26 @@ class HessianExtractor(extto.BetweenExtractor):
|
|
|
1313
1314
|
return _ext.data
|
|
1314
1315
|
|
|
1315
1316
|
|
|
1316
|
-
class
|
|
1317
|
+
class AbsorptionExtractor(extto.BetweenExtractor):
|
|
1318
|
+
|
|
1319
|
+
@property
|
|
1320
|
+
@abstractmethod
|
|
1321
|
+
def OPERATOR_TYPE() -> bytes:
|
|
1322
|
+
'''
|
|
1323
|
+
Name of operator type being extracted, e.g. 'Electric Dipole'
|
|
1324
|
+
'''
|
|
1325
|
+
raise NotImplementedError
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
class AbsorptionElectricDipoleExtractor(AbsorptionExtractor):
|
|
1317
1329
|
'''
|
|
1318
1330
|
Extracts ABSORPTION SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS table\n
|
|
1319
1331
|
from ORCA output file for versions newer than 6.
|
|
1320
1332
|
'''
|
|
1321
1333
|
|
|
1334
|
+
#: Operator Type
|
|
1335
|
+
OPERATOR_TYPE = 'Electric Dipole'
|
|
1336
|
+
|
|
1322
1337
|
# Regex Start Pattern
|
|
1323
1338
|
START_PATTERN = rb'(?<=ABSORPTION SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS\s[\S\s]{408}\s)' # noqa
|
|
1324
1339
|
|
|
@@ -1408,6 +1423,9 @@ class AbsorptionVelocityDipoleExtractor(AbsorptionElectricDipoleExtractor):
|
|
|
1408
1423
|
from ORCA output file for versions newer than 6.
|
|
1409
1424
|
'''
|
|
1410
1425
|
|
|
1426
|
+
#: Operator Type
|
|
1427
|
+
OPERATOR_TYPE = 'Electric Dipole (Velocity)'
|
|
1428
|
+
|
|
1411
1429
|
# Regex Start Pattern
|
|
1412
1430
|
START_PATTERN = rb'(?<=ABSORPTION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS\s[\S\s]{408}\s)' # noqa
|
|
1413
1431
|
|
|
@@ -1421,8 +1439,11 @@ class AbsorptionSemiClassicalDipoleExtractor(AbsorptionElectricDipoleExtractor):
|
|
|
1421
1439
|
from ORCA output file for versions newer than 6.
|
|
1422
1440
|
'''
|
|
1423
1441
|
|
|
1442
|
+
#: Operator Type
|
|
1443
|
+
OPERATOR_TYPE = 'Semi-Classical'
|
|
1444
|
+
|
|
1424
1445
|
# Regex Start Pattern
|
|
1425
|
-
START_PATTERN = rb'(?<=ABSORPTION SPECTRUM VIA FULL SEMI-CLASSICAL FORMULATION\s[\S\s]{
|
|
1446
|
+
START_PATTERN = rb'(?<=ABSORPTION SPECTRUM VIA FULL SEMI-CLASSICAL FORMULATION\s[\S\s]{4}-{77}[\S\s]{206}\s)' # noqa
|
|
1426
1447
|
|
|
1427
1448
|
# Regex End Pattern
|
|
1428
1449
|
END_PATTERN = rb'(?=-{77})'
|
|
@@ -1464,6 +1485,10 @@ class AbsorptionSemiClassicalDipoleExtractor(AbsorptionElectricDipoleExtractor):
|
|
|
1464
1485
|
result = np.asarray(result, dtype=str).T
|
|
1465
1486
|
|
|
1466
1487
|
fresult = result[1:].astype(float)
|
|
1488
|
+
if not len(result):
|
|
1489
|
+
raise ValueError(
|
|
1490
|
+
'No data found in the block. Please check the output file.'
|
|
1491
|
+
)
|
|
1467
1492
|
|
|
1468
1493
|
data = {
|
|
1469
1494
|
'state': result[0].tolist(),
|
|
@@ -1476,12 +1501,15 @@ class AbsorptionSemiClassicalDipoleExtractor(AbsorptionElectricDipoleExtractor):
|
|
|
1476
1501
|
return data
|
|
1477
1502
|
|
|
1478
1503
|
|
|
1479
|
-
class OldAbsorptionElectricDipoleExtractor(
|
|
1504
|
+
class OldAbsorptionElectricDipoleExtractor(AbsorptionExtractor):
|
|
1480
1505
|
'''
|
|
1481
1506
|
Extracts ABSORPTION SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS table
|
|
1482
1507
|
from ORCA output file for versions older than 6.
|
|
1483
1508
|
'''
|
|
1484
1509
|
|
|
1510
|
+
#: Operator Type
|
|
1511
|
+
OPERATOR_TYPE = 'Electric Dipole (Old)'
|
|
1512
|
+
|
|
1485
1513
|
# Regex Start Pattern
|
|
1486
1514
|
START_PATTERN = rb'(?<=ABSORPTION SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS\s[\S\s]{311}\s)' # noqa
|
|
1487
1515
|
|
|
@@ -1495,6 +1523,7 @@ class OldAbsorptionElectricDipoleExtractor(extto.BetweenExtractor):
|
|
|
1495
1523
|
A dictionary with keys:\n
|
|
1496
1524
|
state\n
|
|
1497
1525
|
energy (cm^-1)\n
|
|
1526
|
+
energy (ev)\n
|
|
1498
1527
|
wavelength (nm)\n
|
|
1499
1528
|
fosc\n
|
|
1500
1529
|
t2 (a.u.^2)\n
|
|
@@ -1529,6 +1558,7 @@ class OldAbsorptionElectricDipoleExtractor(extto.BetweenExtractor):
|
|
|
1529
1558
|
|
|
1530
1559
|
data = {
|
|
1531
1560
|
'state': result[0].tolist(),
|
|
1561
|
+
'energy (ev)': list(result[1] / const.EV_TO_WAVENUMBER),
|
|
1532
1562
|
'energy (cm^-1)': result[1].tolist(),
|
|
1533
1563
|
'wavelength (nm)': result[2].tolist(),
|
|
1534
1564
|
'fosc': result[3].tolist(),
|
|
@@ -1562,11 +1592,105 @@ class OldAbsorptionElectricDipoleExtractor(extto.BetweenExtractor):
|
|
|
1562
1592
|
return _ext.data
|
|
1563
1593
|
|
|
1564
1594
|
|
|
1595
|
+
class XASElectricDipoleExtractor(AbsorptionExtractor):
|
|
1596
|
+
'''
|
|
1597
|
+
Extracts XAS SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS table\n
|
|
1598
|
+
from ORCA output file for versions newer than 6.
|
|
1599
|
+
'''
|
|
1600
|
+
|
|
1601
|
+
#: Operator Type
|
|
1602
|
+
OPERATOR_TYPE = 'Electric Dipole'
|
|
1603
|
+
|
|
1604
|
+
# Regex Start Pattern
|
|
1605
|
+
START_PATTERN = rb'(?<=ABSORPTION SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS\s[\S\s]{408}\s)' # noqa
|
|
1606
|
+
|
|
1607
|
+
# Regex End Pattern
|
|
1608
|
+
END_PATTERN = rb'(?=-{77})'
|
|
1609
|
+
|
|
1610
|
+
@property
|
|
1611
|
+
def data(self) -> dict[str, list[str | float]]:
|
|
1612
|
+
'''
|
|
1613
|
+
Absorption spectrum data:\n
|
|
1614
|
+
A dictionary with keys:\n
|
|
1615
|
+
transition\n
|
|
1616
|
+
energy (cm^-1)\n
|
|
1617
|
+
energy (ev)\n
|
|
1618
|
+
wavelength (nm)\n
|
|
1619
|
+
fosc\n
|
|
1620
|
+
d2 (a.u.^2)\n
|
|
1621
|
+
dx (a.u.)\n
|
|
1622
|
+
dy (a.u.)\n
|
|
1623
|
+
dz (a.u.)\n
|
|
1624
|
+
All values are list[float], but 'transition' entries are list[str]
|
|
1625
|
+
'''
|
|
1626
|
+
return self._data
|
|
1627
|
+
|
|
1628
|
+
@staticmethod
|
|
1629
|
+
def _process_block(block: str) -> dict[str, list[int | float]]: # noqa
|
|
1630
|
+
'''
|
|
1631
|
+
Converts single block into data entries described in self.data
|
|
1632
|
+
|
|
1633
|
+
Parameters
|
|
1634
|
+
----------
|
|
1635
|
+
block: str
|
|
1636
|
+
String block extracted from file
|
|
1637
|
+
|
|
1638
|
+
Returns
|
|
1639
|
+
-------
|
|
1640
|
+
dict[str, list[float]]
|
|
1641
|
+
'''
|
|
1642
|
+
|
|
1643
|
+
result = re.findall(
|
|
1644
|
+
r'\s+(\d+[A-Za-z]*-\d*[A-Za-z]\s+->\s+\d+[A-Za-z]*-\d*[A-Za-z])\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d\.\d{5})\s+(-*\d\.\d{5})\s+(-*\d\.\d{5})\s+(-*\d\.\d{5})', # noqa
|
|
1645
|
+
block
|
|
1646
|
+
)
|
|
1647
|
+
|
|
1648
|
+
result = np.asarray(result, dtype=str).T
|
|
1649
|
+
|
|
1650
|
+
fresult = result[1:].astype(float)
|
|
1651
|
+
|
|
1652
|
+
data = {
|
|
1653
|
+
'state': result[0].tolist(),
|
|
1654
|
+
'energy (ev)': fresult[0].tolist(),
|
|
1655
|
+
'energy (cm^-1)': fresult[1].tolist(),
|
|
1656
|
+
'wavelength (nm)': fresult[2].tolist(),
|
|
1657
|
+
'fosc': fresult[3].tolist(),
|
|
1658
|
+
't2 (a.u.^2)': fresult[4].tolist(),
|
|
1659
|
+
'tx (a.u).': fresult[5].tolist(),
|
|
1660
|
+
'ty (a.u).': fresult[6].tolist(),
|
|
1661
|
+
'tz (a.u).': fresult[7].tolist()
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
return data
|
|
1665
|
+
|
|
1666
|
+
@classmethod
|
|
1667
|
+
def extract(cls, file_name: str | pathlib.Path) -> dict[str, list[int | float]]: # noqa
|
|
1668
|
+
'''
|
|
1669
|
+
Convenience method which instantiates class, extracts blocks, and
|
|
1670
|
+
returns processed datasets
|
|
1671
|
+
|
|
1672
|
+
Parameters
|
|
1673
|
+
----------
|
|
1674
|
+
file_name: str | pathlib.Path
|
|
1675
|
+
File to parse
|
|
1676
|
+
|
|
1677
|
+
Returns
|
|
1678
|
+
-------
|
|
1679
|
+
dict[str, list[int | float]]
|
|
1680
|
+
Each entry contains processed data, as defined in cls.data
|
|
1681
|
+
'''
|
|
1682
|
+
_ext = cls()
|
|
1683
|
+
_ext(file_name, process=True)
|
|
1684
|
+
return _ext.data
|
|
1685
|
+
|
|
1686
|
+
|
|
1565
1687
|
class OldAbsorptionVelocityDipoleExtractor(OldAbsorptionElectricDipoleExtractor): # noqa
|
|
1566
1688
|
'''
|
|
1567
1689
|
Extracts ABSORPTION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS table
|
|
1568
1690
|
from ORCA output file for versions older than 6.
|
|
1569
1691
|
'''
|
|
1692
|
+
#: Operator Type
|
|
1693
|
+
OPERATOR_TYPE = 'Electric Dipole (Velocity, Old)'
|
|
1570
1694
|
|
|
1571
1695
|
# Regex Start Pattern
|
|
1572
1696
|
START_PATTERN = rb'(?<=ABSORPTION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS\s[\S\s]{311}\s)' # noqa
|
|
@@ -1575,6 +1699,89 @@ class OldAbsorptionVelocityDipoleExtractor(OldAbsorptionElectricDipoleExtractor)
|
|
|
1575
1699
|
END_PATTERN = rb'(?=-{77})'
|
|
1576
1700
|
|
|
1577
1701
|
|
|
1702
|
+
class XESElectricDipoleExtractor(AbsorptionElectricDipoleExtractor):
|
|
1703
|
+
'''
|
|
1704
|
+
Extracts X-RAY EMISSION SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS table\n # noqa
|
|
1705
|
+
from ORCA output file for versions newer than 6.
|
|
1706
|
+
'''
|
|
1707
|
+
|
|
1708
|
+
#: Operator Type
|
|
1709
|
+
OPERATOR_TYPE = 'Electric Dipole'
|
|
1710
|
+
|
|
1711
|
+
# Regex Start Pattern
|
|
1712
|
+
START_PATTERN = rb'(?<= X-RAY EMISSION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS\s[\S\s]{408}\s)' # noqa
|
|
1713
|
+
|
|
1714
|
+
# Regex End Pattern
|
|
1715
|
+
END_PATTERN = rb'(?=-{77})'
|
|
1716
|
+
|
|
1717
|
+
|
|
1718
|
+
class XESVelocityDipoleExtractor(AbsorptionElectricDipoleExtractor):
|
|
1719
|
+
'''
|
|
1720
|
+
Extracts X-RAY EMISSION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS table\n # noqa
|
|
1721
|
+
from ORCA output file for versions newer than 6.
|
|
1722
|
+
'''
|
|
1723
|
+
#: Operator Type
|
|
1724
|
+
OPERATOR_TYPE = 'Electric Dipole (Velocity)'
|
|
1725
|
+
|
|
1726
|
+
# Regex Start Pattern
|
|
1727
|
+
START_PATTERN = rb'(?<= X-RAY EMISSION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS\s[\S\s]{415}\s)' # noqa
|
|
1728
|
+
|
|
1729
|
+
|
|
1730
|
+
class SOXESElectricDipoleExtractor(XESElectricDipoleExtractor):
|
|
1731
|
+
'''
|
|
1732
|
+
Extracts SPIN-ORBIT X-RAY EMISSION SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS table\n # noqa
|
|
1733
|
+
from ORCA output file for versions newer than 6.
|
|
1734
|
+
'''
|
|
1735
|
+
|
|
1736
|
+
#: Operator Type
|
|
1737
|
+
OPERATOR_TYPE = 'Electric Dipole'
|
|
1738
|
+
|
|
1739
|
+
# Regex Start Pattern
|
|
1740
|
+
START_PATTERN = rb'(?<=SPIN-ORBIT X-RAY EMISSION SPECTRUM VIA TRANSITION ELECTRIC DIPOLE MOMENTS\s[\S\s\(\)]{415}\s)' # noqa
|
|
1741
|
+
|
|
1742
|
+
|
|
1743
|
+
class SOXESVelocityDipoleExtractor(XESVelocityDipoleExtractor):
|
|
1744
|
+
'''
|
|
1745
|
+
Extracts SPIN-ORBIT X-RAY EMISSION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS table\n # noqa
|
|
1746
|
+
from ORCA output file for versions newer than 6.
|
|
1747
|
+
'''
|
|
1748
|
+
|
|
1749
|
+
#: Operator Type
|
|
1750
|
+
OPERATOR_TYPE = 'Electric Dipole (Velocity)'
|
|
1751
|
+
|
|
1752
|
+
# Regex Start Pattern
|
|
1753
|
+
START_PATTERN = rb'(?<= SPIN-ORBIT X-RAY EMISSION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS\s[\S\s]{415}\s)' # noqa
|
|
1754
|
+
|
|
1755
|
+
# Regex End Pattern
|
|
1756
|
+
END_PATTERN = rb'(?=-{104})'
|
|
1757
|
+
|
|
1758
|
+
|
|
1759
|
+
class XESSemiClassicalDipoleExtractor(AbsorptionSemiClassicalDipoleExtractor):
|
|
1760
|
+
'''
|
|
1761
|
+
Extracts X-RAY EMISSION SPECTRUM VIA FULL SEMI-CLASSICAL FORMULATION table\n # noqa
|
|
1762
|
+
from ORCA output file for versions newer than 6.
|
|
1763
|
+
'''
|
|
1764
|
+
|
|
1765
|
+
#: Operator Type
|
|
1766
|
+
OPERATOR_TYPE = 'Semi-Classical'
|
|
1767
|
+
|
|
1768
|
+
# Regex Start Pattern
|
|
1769
|
+
START_PATTERN = rb'(?<= X-RAY EMISSION SPECTRUM VIA FULL SEMI-CLASSICAL FORMULATION\s[\S\s]{408}\s)' # noqa
|
|
1770
|
+
|
|
1771
|
+
|
|
1772
|
+
class SOXESSemiClassicalDipoleExtractor(AbsorptionSemiClassicalDipoleExtractor): # noqa
|
|
1773
|
+
'''
|
|
1774
|
+
Extracts SPIN-ORBIT X-RAY EMISSION SPECTRUM VIA TRANSITION VELOCITY DIPOLE MOMENTS table\n # noqa
|
|
1775
|
+
from ORCA output file for versions newer than 6.
|
|
1776
|
+
'''
|
|
1777
|
+
|
|
1778
|
+
#: Operator Type
|
|
1779
|
+
OPERATOR_TYPE = 'Semi-Classical'
|
|
1780
|
+
|
|
1781
|
+
# Regex Start Pattern
|
|
1782
|
+
START_PATTERN = rb'(?<= SPIN-ORBIT X-RAY EMISSION SPECTRUM VIA FULL SEMI-CLASSICAL FORMULATION\s[\S\s]{408}\s)' # noqa
|
|
1783
|
+
|
|
1784
|
+
|
|
1578
1785
|
class HessNameInputExtractor(extto.LineExtractor):
|
|
1579
1786
|
'''
|
|
1580
1787
|
Extracts Hessian file name from %mtr block of input file
|