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/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 AbsorptionElectricDipoleExtractor(extto.BetweenExtractor):
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]{408}\s)' # noqa
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(extto.BetweenExtractor):
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