digichem-core 6.0.0rc1__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.
- digichem/__init__.py +75 -0
- digichem/basis.py +116 -0
- digichem/config/README +3 -0
- digichem/config/__init__.py +5 -0
- digichem/config/base.py +321 -0
- digichem/config/locations.py +14 -0
- digichem/config/parse.py +90 -0
- digichem/config/util.py +117 -0
- digichem/data/README +4 -0
- digichem/data/batoms/COPYING +18 -0
- digichem/data/batoms/LICENSE +674 -0
- digichem/data/batoms/README +2 -0
- digichem/data/batoms/__init__.py +0 -0
- digichem/data/batoms/batoms-renderer.py +351 -0
- digichem/data/config/digichem.yaml +714 -0
- digichem/data/functionals.csv +15 -0
- digichem/data/solvents.csv +185 -0
- digichem/data/tachyon/COPYING.md +5 -0
- digichem/data/tachyon/LICENSE +30 -0
- digichem/data/tachyon/tachyon_LINUXAMD64 +0 -0
- digichem/data/vmd/common.tcl +468 -0
- digichem/data/vmd/generate_combined_orbital_images.tcl +70 -0
- digichem/data/vmd/generate_density_images.tcl +45 -0
- digichem/data/vmd/generate_dipole_images.tcl +68 -0
- digichem/data/vmd/generate_orbital_images.tcl +57 -0
- digichem/data/vmd/generate_spin_images.tcl +66 -0
- digichem/data/vmd/generate_structure_images.tcl +40 -0
- digichem/datas.py +14 -0
- digichem/exception/__init__.py +7 -0
- digichem/exception/base.py +133 -0
- digichem/exception/uncatchable.py +63 -0
- digichem/file/__init__.py +1 -0
- digichem/file/base.py +364 -0
- digichem/file/cube.py +284 -0
- digichem/file/fchk.py +94 -0
- digichem/file/prattle.py +277 -0
- digichem/file/types.py +97 -0
- digichem/image/__init__.py +6 -0
- digichem/image/base.py +113 -0
- digichem/image/excited_states.py +335 -0
- digichem/image/graph.py +293 -0
- digichem/image/orbitals.py +239 -0
- digichem/image/render.py +617 -0
- digichem/image/spectroscopy.py +797 -0
- digichem/image/structure.py +115 -0
- digichem/image/vmd.py +826 -0
- digichem/input/__init__.py +3 -0
- digichem/input/base.py +78 -0
- digichem/input/digichem_input.py +500 -0
- digichem/input/gaussian.py +140 -0
- digichem/log.py +179 -0
- digichem/memory.py +166 -0
- digichem/misc/__init__.py +4 -0
- digichem/misc/argparse.py +44 -0
- digichem/misc/base.py +61 -0
- digichem/misc/io.py +239 -0
- digichem/misc/layered_dict.py +285 -0
- digichem/misc/text.py +139 -0
- digichem/misc/time.py +73 -0
- digichem/parse/__init__.py +13 -0
- digichem/parse/base.py +220 -0
- digichem/parse/cclib.py +138 -0
- digichem/parse/dump.py +253 -0
- digichem/parse/gaussian.py +130 -0
- digichem/parse/orca.py +96 -0
- digichem/parse/turbomole.py +201 -0
- digichem/parse/util.py +523 -0
- digichem/result/__init__.py +6 -0
- digichem/result/alignment/AA.py +114 -0
- digichem/result/alignment/AAA.py +61 -0
- digichem/result/alignment/FAP.py +148 -0
- digichem/result/alignment/__init__.py +3 -0
- digichem/result/alignment/base.py +310 -0
- digichem/result/angle.py +153 -0
- digichem/result/atom.py +742 -0
- digichem/result/base.py +258 -0
- digichem/result/dipole_moment.py +332 -0
- digichem/result/emission.py +402 -0
- digichem/result/energy.py +323 -0
- digichem/result/excited_state.py +821 -0
- digichem/result/ground_state.py +94 -0
- digichem/result/metadata.py +644 -0
- digichem/result/multi.py +98 -0
- digichem/result/nmr.py +1086 -0
- digichem/result/orbital.py +647 -0
- digichem/result/result.py +244 -0
- digichem/result/soc.py +272 -0
- digichem/result/spectroscopy.py +514 -0
- digichem/result/tdm.py +267 -0
- digichem/result/vibration.py +167 -0
- digichem/test/__init__.py +6 -0
- digichem/test/conftest.py +4 -0
- digichem/test/test_basis.py +71 -0
- digichem/test/test_calculate.py +30 -0
- digichem/test/test_config.py +78 -0
- digichem/test/test_cube.py +369 -0
- digichem/test/test_exception.py +16 -0
- digichem/test/test_file.py +104 -0
- digichem/test/test_image.py +337 -0
- digichem/test/test_input.py +64 -0
- digichem/test/test_parsing.py +79 -0
- digichem/test/test_prattle.py +36 -0
- digichem/test/test_result.py +489 -0
- digichem/test/test_translate.py +112 -0
- digichem/test/util.py +207 -0
- digichem/translate.py +591 -0
- digichem_core-6.0.0rc1.dist-info/METADATA +96 -0
- digichem_core-6.0.0rc1.dist-info/RECORD +111 -0
- digichem_core-6.0.0rc1.dist-info/WHEEL +4 -0
- digichem_core-6.0.0rc1.dist-info/licenses/COPYING.md +10 -0
- digichem_core-6.0.0rc1.dist-info/licenses/LICENSE +11 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Code for processing results from calculations and generating reports.
|
|
2
|
+
|
|
3
|
+
# General imports.
|
|
4
|
+
import itertools
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
from digichem.exception import Result_unavailable_error
|
|
8
|
+
|
|
9
|
+
from digichem.result import Result_object
|
|
10
|
+
import digichem.result.excited_state
|
|
11
|
+
from digichem.result.emission import Emissions
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Result_set(Result_object):
|
|
15
|
+
"""
|
|
16
|
+
Class that represents a collection of results from a calculation.
|
|
17
|
+
|
|
18
|
+
This class is a bit heavy and might not be around for long...
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, **attributes):
|
|
22
|
+
"""Constructor for Result_set objects."""
|
|
23
|
+
super().__init__()
|
|
24
|
+
|
|
25
|
+
# The ID uniquely identifies this calculation result.
|
|
26
|
+
# In most cases, it is generated from the combined chekcsum of the log files from which the results was parsed.
|
|
27
|
+
# If this result was not read from log files (but was read from a database or from a .si calc result or similar),
|
|
28
|
+
# then the id will simply be the same as was written previously.
|
|
29
|
+
#
|
|
30
|
+
# Note that the underscore here does not imply that this attribute is 'hidden'. Instead, this is used for
|
|
31
|
+
# consistency with mongo-like DBs, where the ID field is also typically named _id.
|
|
32
|
+
#self._id = attributes.pop('database_id', None)
|
|
33
|
+
self._id = attributes.pop('_id', None)
|
|
34
|
+
|
|
35
|
+
self.results = (self,)
|
|
36
|
+
self.emission = attributes.pop('emission', Emissions())
|
|
37
|
+
|
|
38
|
+
for attr_name, attribute in attributes.items():
|
|
39
|
+
setattr(self, attr_name, attribute)
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def alignment(self):
|
|
43
|
+
warnings.warn("alignment is deprecated, use atoms instead", DeprecationWarning)
|
|
44
|
+
return self.atoms
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def CC_energies(self):
|
|
48
|
+
warnings.warn("CC_energies is deprecated, use energies.cc instead", DeprecationWarning)
|
|
49
|
+
return self.energies.cc
|
|
50
|
+
|
|
51
|
+
@CC_energies.setter
|
|
52
|
+
def CC_energies(self, value):
|
|
53
|
+
warnings.warn("CC_energies is deprecated, use energies.cc instead", DeprecationWarning)
|
|
54
|
+
self.energies.cc = value
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def MP_energies(self):
|
|
58
|
+
warnings.warn("MP_energies is deprecated, use energies.mp instead", DeprecationWarning)
|
|
59
|
+
return self.energies.mp
|
|
60
|
+
|
|
61
|
+
@MP_energies.setter
|
|
62
|
+
def MP_energies(self, value):
|
|
63
|
+
warnings.warn("MP_energies is deprecated, use energies.mp instead", DeprecationWarning)
|
|
64
|
+
self.energies.mp = value
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def SCF_energies(self):
|
|
68
|
+
warnings.warn("SCF_energies is deprecated, use energies.scf instead", DeprecationWarning)
|
|
69
|
+
return self.energies.scf
|
|
70
|
+
|
|
71
|
+
@SCF_energies.setter
|
|
72
|
+
def SCF_energies(self, value):
|
|
73
|
+
warnings.warn("SCF_energies is deprecated, use energies.scf instead", DeprecationWarning)
|
|
74
|
+
self.energies.scf = value
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def molecular_orbitals(self):
|
|
78
|
+
warnings.warn("molecular_orbitals is deprecated, use orbitals instead", DeprecationWarning)
|
|
79
|
+
return self.orbitals
|
|
80
|
+
|
|
81
|
+
@molecular_orbitals.setter
|
|
82
|
+
def molecular_orbitals(self, value):
|
|
83
|
+
warnings.warn("molecular_orbitals is deprecated, use orbitals instead", DeprecationWarning)
|
|
84
|
+
self.orbitals = value
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def spin_orbit_coupling(self):
|
|
88
|
+
warnings.warn("spin_orbit_coupling is deprecated, use soc instead", DeprecationWarning)
|
|
89
|
+
return self.soc
|
|
90
|
+
|
|
91
|
+
@spin_orbit_coupling.setter
|
|
92
|
+
def spin_orbit_coupling(self, value):
|
|
93
|
+
warnings.warn("spin_orbit_coupling is deprecated, use soc instead", DeprecationWarning)
|
|
94
|
+
self.soc = value
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def dipole_moment(self):
|
|
98
|
+
warnings.warn("dipole_moment is deprecated, use pdm instead", DeprecationWarning)
|
|
99
|
+
return self.pdm
|
|
100
|
+
|
|
101
|
+
@dipole_moment.setter
|
|
102
|
+
def dipole_moment(self, value):
|
|
103
|
+
warnings.warn("dipole_moment is deprecated, use pdm instead", DeprecationWarning)
|
|
104
|
+
self.pdm = value
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def vertical_emission(self):
|
|
108
|
+
warnings.warn("vertical_emission is deprecated, use emission.vertical instead", DeprecationWarning)
|
|
109
|
+
return self.emission.vertical
|
|
110
|
+
|
|
111
|
+
@vertical_emission.setter
|
|
112
|
+
def vertical_emission(self, value):
|
|
113
|
+
warnings.warn("vertical_emission is deprecated, use emission.vertical instead", DeprecationWarning)
|
|
114
|
+
self.emission.vertical = value
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def adiabatic_emission(self):
|
|
118
|
+
warnings.warn("adiabatic_emission is deprecated, use emission.adiabatic instead", DeprecationWarning)
|
|
119
|
+
return self.emission.adiabatic
|
|
120
|
+
|
|
121
|
+
@adiabatic_emission.setter
|
|
122
|
+
def adiabatic_emission(self, value):
|
|
123
|
+
warnings.warn("adiabatic_emission is deprecated, use emission.adiabatic instead", DeprecationWarning)
|
|
124
|
+
self.emission.adiabatic = value
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def metadatas(self):
|
|
128
|
+
"""
|
|
129
|
+
Property providing access to the list of metadatas of the calculations that were merged together.
|
|
130
|
+
"""
|
|
131
|
+
return [result.metadata for result in self.results]
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def level_of_theory(self):
|
|
135
|
+
"""
|
|
136
|
+
A short-hand summary of the methods and basis sets used.
|
|
137
|
+
"""
|
|
138
|
+
methods = []
|
|
139
|
+
basis_sets = []
|
|
140
|
+
for metadata in self.metadatas:
|
|
141
|
+
if len(metadata.converted_methods) > 0:
|
|
142
|
+
method = metadata.converted_methods[-1]
|
|
143
|
+
# for method in metadata.converted_methods:
|
|
144
|
+
if method not in methods:
|
|
145
|
+
methods.append(method)
|
|
146
|
+
|
|
147
|
+
if metadata.basis_set is not None and metadata.basis_set not in basis_sets:
|
|
148
|
+
basis_sets.append(metadata.basis_set)
|
|
149
|
+
|
|
150
|
+
return "/".join(itertools.chain(methods, basis_sets))
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def title(self):
|
|
154
|
+
"""
|
|
155
|
+
A string Title describing this result.
|
|
156
|
+
"""
|
|
157
|
+
title = ", ".join(self.metadata.calculations)
|
|
158
|
+
if "Excited States" in self.metadata.calculations:
|
|
159
|
+
# Add multiplicity based on ES.
|
|
160
|
+
mult = self.excited_states.group()
|
|
161
|
+
mult_strings = [digichem.result.excited_state.Energy_state.multiplicity_number_to_string(multiplicity).capitalize() for multiplicity in mult]
|
|
162
|
+
if len(mult_strings) <= 2:
|
|
163
|
+
# Add the strings.
|
|
164
|
+
title += " ({})".format(", ".join(mult_strings))
|
|
165
|
+
else:
|
|
166
|
+
# Add something non-specific.
|
|
167
|
+
title += " (Various Multiplicities)"
|
|
168
|
+
else:
|
|
169
|
+
title += " ({})".format(digichem.result.excited_state.Energy_state.multiplicity_number_to_string(self.metadata.multiplicity).capitalize())
|
|
170
|
+
return title
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def energy(self):
|
|
174
|
+
"""
|
|
175
|
+
The total energy of this calculation.
|
|
176
|
+
|
|
177
|
+
This convenience property is the energy at the highest level of theory available (CC > MP > SCF).
|
|
178
|
+
|
|
179
|
+
:raises Result_unavailable_error: If no total energy is available.
|
|
180
|
+
"""
|
|
181
|
+
warnings.warn("energy is deprecated, use energies.final instead", DeprecationWarning)
|
|
182
|
+
return self.energies.final
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def electric_transition_dipole_moment(self):
|
|
187
|
+
"""
|
|
188
|
+
The S1 electric dipole moment, commonly referred to as THE electric transition dipole moment (although this name is ambiguous).
|
|
189
|
+
|
|
190
|
+
None is returned if the S1 dipole moment is not available.
|
|
191
|
+
"""
|
|
192
|
+
tdm = self.transition_dipole_moment
|
|
193
|
+
if tdm is not None:
|
|
194
|
+
return tdm.electric
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def magnetic_transition_dipole_moment(self):
|
|
198
|
+
"""
|
|
199
|
+
The S1 magnetic dipole moment, commonly referred to as THE magnetic transition dipole moment (although this name is ambiguous).
|
|
200
|
+
|
|
201
|
+
None is returned if the S1 dipole moment is not available.
|
|
202
|
+
"""
|
|
203
|
+
tdm = self.transition_dipole_moment
|
|
204
|
+
if tdm is not None:
|
|
205
|
+
return tdm.magnetic
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def transition_dipole_moment(self):
|
|
209
|
+
"""
|
|
210
|
+
The S1 dipole moment (both electric and magnetic), commonly referred to as THE transition dipole moment (although this name is ambiguous).
|
|
211
|
+
|
|
212
|
+
None is returned if the S1 dipole moment is not available.
|
|
213
|
+
"""
|
|
214
|
+
try:
|
|
215
|
+
S1 = self.excited_states.get_state("S(1)")
|
|
216
|
+
return S1.transition_dipole_moment
|
|
217
|
+
except Result_unavailable_error:
|
|
218
|
+
# No S1 available.
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
def dump(self, digichem_options):
|
|
222
|
+
"Dump the data contained in this result set, serialising it to a hierarchy of dicts that can be saved in various formats."
|
|
223
|
+
# Start with our DB ID if we have one.
|
|
224
|
+
dump_dic = {}
|
|
225
|
+
if self._id is not None:
|
|
226
|
+
dump_dic['_id'] = self._id
|
|
227
|
+
|
|
228
|
+
dump_dic.update({
|
|
229
|
+
"metadata": self.metadata.dump(digichem_options),
|
|
230
|
+
"ground_state": self.ground_state.dump(digichem_options) if self.ground_state is not None else None,
|
|
231
|
+
"energies": self.energies.dump(digichem_options),
|
|
232
|
+
"atoms": self.atoms.dump(digichem_options),
|
|
233
|
+
"raw_atoms": self.raw_atoms.dump(digichem_options),
|
|
234
|
+
"orbitals": self.orbitals.dump(digichem_options),
|
|
235
|
+
"beta_orbitals": self.beta_orbitals.dump(digichem_options),
|
|
236
|
+
"pdm": self.pdm.dump(digichem_options) if self.pdm is not None else None,
|
|
237
|
+
"excited_states": self.excited_states.dump(digichem_options),
|
|
238
|
+
"soc": self.soc.dump(digichem_options),
|
|
239
|
+
"vibrations": self.vibrations.dump(digichem_options),
|
|
240
|
+
"nmr": self.nmr.dump(digichem_options),
|
|
241
|
+
"emission": self.emission.dump(digichem_options)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
return dump_dic
|
digichem/result/soc.py
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# General imports.
|
|
2
|
+
import math
|
|
3
|
+
|
|
4
|
+
from digichem.exception import Result_unavailable_error
|
|
5
|
+
from digichem.result import Result_container
|
|
6
|
+
from digichem.result import Result_object
|
|
7
|
+
from digichem.result.base import Floatable_mixin
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SOC_list(Result_container):
|
|
11
|
+
"""
|
|
12
|
+
An augmented list containing spin orbit coupling.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def find(self, criteria):
|
|
16
|
+
"""
|
|
17
|
+
"""
|
|
18
|
+
states = criteria.split(",")
|
|
19
|
+
|
|
20
|
+
# Check we have two states.
|
|
21
|
+
if len(states) != 2:
|
|
22
|
+
raise ValueError("SOC can only be found between exactly 2 states, not {} states.".format(len(states)))
|
|
23
|
+
|
|
24
|
+
return self.between(*states)
|
|
25
|
+
|
|
26
|
+
def between(self, state1, state2, **kwargs):
|
|
27
|
+
"""
|
|
28
|
+
Return the spin-orbit coupling object between the two states with given symbols.
|
|
29
|
+
|
|
30
|
+
:param states: Symbols identifying the two states to get SOC between (eg, "S(1)" "T(1)").
|
|
31
|
+
:param default: A default argument that will be returned if the given states cannot be found.
|
|
32
|
+
"""
|
|
33
|
+
states = set((state1, state2))
|
|
34
|
+
|
|
35
|
+
# Iterate through all our SOC.
|
|
36
|
+
for soc in self:
|
|
37
|
+
# Check if the two states match the two we've been asked to find.
|
|
38
|
+
if len(states.intersection((soc.singlet_state.state_symbol, soc.triplet_state.state_symbol))) == 2:
|
|
39
|
+
# A match!
|
|
40
|
+
return soc
|
|
41
|
+
|
|
42
|
+
# No match.
|
|
43
|
+
# Return the default if given, otherwise panic.
|
|
44
|
+
if "default" in kwargs:
|
|
45
|
+
return kwargs['default']
|
|
46
|
+
else:
|
|
47
|
+
raise Result_unavailable_error("Spin-orbit coupling", "could not find SOC between states with symbols '{}' and '{}'".format(state1, state2))
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def from_parser(self, parser):
|
|
51
|
+
"""
|
|
52
|
+
Get a SOC_list object from an output file parser.
|
|
53
|
+
|
|
54
|
+
:param parser: An output file parser.
|
|
55
|
+
:return: A SOC_list object. The list will be empty if no SOC is available.
|
|
56
|
+
"""
|
|
57
|
+
# Decide which SOC class to use.
|
|
58
|
+
if hasattr(parser.data, "socelements"):
|
|
59
|
+
soc_cls = Spin_orbit_coupling
|
|
60
|
+
else:
|
|
61
|
+
soc_cls = Total_spin_orbit_coupling
|
|
62
|
+
|
|
63
|
+
return self(soc_cls.list_from_parser(parser))
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def from_dump(self, data, result_set, options):
|
|
67
|
+
"""
|
|
68
|
+
Get an instance of this class from its dumped representation.
|
|
69
|
+
|
|
70
|
+
:param data: The data to parse.
|
|
71
|
+
:param result_set: The partially constructed result set which is being populated.
|
|
72
|
+
"""
|
|
73
|
+
return self([(Spin_orbit_coupling if 'soc' in soc_dict else Total_spin_orbit_coupling).from_dump(soc_dict, result_set, options) for soc_dict in data])
|
|
74
|
+
|
|
75
|
+
def sort(self, *, key = None, **kwargs):
|
|
76
|
+
"""
|
|
77
|
+
Sort this list in place.
|
|
78
|
+
"""
|
|
79
|
+
# If no key is given, we use a custom default key.
|
|
80
|
+
if key is None:
|
|
81
|
+
key = lambda SOC: (SOC.singlet_state.level, SOC.triplet_state.level)
|
|
82
|
+
|
|
83
|
+
return super().sort(key = key, **kwargs)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class Spin_orbit_coupling(Result_object, Floatable_mixin):
|
|
87
|
+
"""
|
|
88
|
+
Class that represents spin-orbit coupling between two states.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, singlet_state, triplet_state, positive_one, zero, negative_one):
|
|
92
|
+
"""
|
|
93
|
+
Constructor for SOC objects.
|
|
94
|
+
|
|
95
|
+
:param singlet_state: The singlet excited state this coupling is between.
|
|
96
|
+
:param triplet_state: The triplet excited state this coupling is between.
|
|
97
|
+
:param positive_one: SOC between the singlet state and triplet sub-state with quantum number +1 in cm-1.
|
|
98
|
+
:param zero: SOC between the singlet state and triplet sub-state with quantum number 0 in cm-1.
|
|
99
|
+
:param negative_one: SOC between the singlet state and triplet sub-state with quantum number -1 in cm-1.
|
|
100
|
+
"""
|
|
101
|
+
self.singlet_state = singlet_state
|
|
102
|
+
self.triplet_state = triplet_state
|
|
103
|
+
self.positive_one = positive_one
|
|
104
|
+
self.zero = zero
|
|
105
|
+
self.negative_one = negative_one
|
|
106
|
+
|
|
107
|
+
def dump(self, digichem_options):
|
|
108
|
+
"""
|
|
109
|
+
Get a representation of this result object in primitive format.
|
|
110
|
+
"""
|
|
111
|
+
return {
|
|
112
|
+
"singlet": self.singlet_state.state_symbol,
|
|
113
|
+
"triplet": self.triplet_state.state_symbol,
|
|
114
|
+
"soc": {
|
|
115
|
+
"+1": {
|
|
116
|
+
"value": self.positive_one,
|
|
117
|
+
"units": "c m^-1",
|
|
118
|
+
},
|
|
119
|
+
"0": {
|
|
120
|
+
"value": self.zero,
|
|
121
|
+
"units": "c m^-1",
|
|
122
|
+
},
|
|
123
|
+
"-1": {
|
|
124
|
+
"value": self.negative_one,
|
|
125
|
+
"units": "c m^-1",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
"rss": {
|
|
129
|
+
"units": "c m^-1",
|
|
130
|
+
"value": self.root_sum_square,
|
|
131
|
+
},
|
|
132
|
+
"mixing_coefficient": self.mixing_coefficient
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@classmethod
|
|
136
|
+
def from_dump(self, data, result_set, options):
|
|
137
|
+
"""
|
|
138
|
+
Get an instance of this class from its dumped representation.
|
|
139
|
+
|
|
140
|
+
:param data: The data to parse.
|
|
141
|
+
:param result_set: The partially constructed result set which is being populated.
|
|
142
|
+
"""
|
|
143
|
+
return self(result_set.energy_states.find(data['singlet']), result_set.energy_states.find(data['triplet']), data['soc']['+1']['value'], data['soc']['0']['value'], data['soc']['-1']['value'])
|
|
144
|
+
|
|
145
|
+
@classmethod
|
|
146
|
+
def list_from_parser(self, parser):
|
|
147
|
+
"""
|
|
148
|
+
Create a SOC object from an output file parser.
|
|
149
|
+
"""
|
|
150
|
+
# Go through our data.
|
|
151
|
+
try:
|
|
152
|
+
return [self(
|
|
153
|
+
singlet_state = parser.results.energy_states.get_state(state_symbol = singlet_symbol),
|
|
154
|
+
triplet_state = parser.results.energy_states.get_state(state_symbol = triplet_symbol),
|
|
155
|
+
positive_one = positive_soc,
|
|
156
|
+
zero = zero_soc,
|
|
157
|
+
negative_one = negative_soc
|
|
158
|
+
) for (singlet_symbol, triplet_symbol), (positive_soc, zero_soc, negative_soc) in zip(parser.data.socstates, parser.data.socelements)]
|
|
159
|
+
except AttributeError:
|
|
160
|
+
# No data.
|
|
161
|
+
return []
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def splitting_energy(self):
|
|
165
|
+
"""
|
|
166
|
+
The difference in energy between these two states.
|
|
167
|
+
"""
|
|
168
|
+
return max(float(self.singlet_state), float(self.triplet_state)) - min(float(self.singlet_state), float(self.triplet_state))
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def mixing_coefficient(self):
|
|
172
|
+
"""
|
|
173
|
+
The first order mixing coefficient (λ), given by Hso / dEst.
|
|
174
|
+
Be aware that λ will == math.inf if dEst == 0.
|
|
175
|
+
"""
|
|
176
|
+
try:
|
|
177
|
+
return self.energy / self.splitting_energy
|
|
178
|
+
except (FloatingPointError, ZeroDivisionError):
|
|
179
|
+
return math.inf
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def root_sum_square(self):
|
|
183
|
+
"""
|
|
184
|
+
The root sum square of this SOC.
|
|
185
|
+
"""
|
|
186
|
+
return math.sqrt(self.positive_one **2 + self.zero **2 + self.negative_one **2)
|
|
187
|
+
|
|
188
|
+
def __float__(self):
|
|
189
|
+
"""
|
|
190
|
+
Floatify this SOC class.
|
|
191
|
+
"""
|
|
192
|
+
return float(self.root_sum_square)
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def wavenumbers(self):
|
|
196
|
+
"""
|
|
197
|
+
SOC in wavenumbers.
|
|
198
|
+
"""
|
|
199
|
+
return self.root_sum_square
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def energy(self):
|
|
203
|
+
"""
|
|
204
|
+
SOC in eV.
|
|
205
|
+
"""
|
|
206
|
+
try:
|
|
207
|
+
return self.wavenumbers_to_energy(self.root_sum_square)
|
|
208
|
+
except (FloatingPointError, ZeroDivisionError):
|
|
209
|
+
return 0.0
|
|
210
|
+
|
|
211
|
+
def __str__(self):
|
|
212
|
+
"""
|
|
213
|
+
Stringify this SOC class.
|
|
214
|
+
"""
|
|
215
|
+
return "<{}|Hso|{}> (RSS, +1, 0, -1) (cm-1): {:10.5f} {:10.5f} {:10.5f} {:10.5f}".format(self.singlet_state.state_symbol, self.triplet_state.state_symbol, self.root_sum_square, self.positive_one, self.zero, self.negative_one)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class Total_spin_orbit_coupling(Spin_orbit_coupling):
|
|
219
|
+
"""
|
|
220
|
+
A class for representing SOC when only the total is known (and not the individual elements).
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
def __init__(self, singlet_state, triplet_state, total):
|
|
224
|
+
super().__init__(singlet_state, triplet_state, None, None, None)
|
|
225
|
+
|
|
226
|
+
self._root_sum_square = total
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def root_sum_square(self):
|
|
230
|
+
return self._root_sum_square
|
|
231
|
+
|
|
232
|
+
def __str__(self):
|
|
233
|
+
"""
|
|
234
|
+
Stringify this SOC class.
|
|
235
|
+
"""
|
|
236
|
+
return "<{}|Hso|{}> (cm-1): {:10.5f}".format(self.singlet_state.state_symbol, self.triplet_state.state_symbol, self.root_sum_square)
|
|
237
|
+
|
|
238
|
+
def dump(self, digichem_options):
|
|
239
|
+
"""
|
|
240
|
+
Get a representation of this result object in primitive format.
|
|
241
|
+
"""
|
|
242
|
+
dump_dic = super().dump(digichem_options)
|
|
243
|
+
# Remove elements.
|
|
244
|
+
del(dump_dic['soc'])
|
|
245
|
+
return dump_dic
|
|
246
|
+
|
|
247
|
+
@classmethod
|
|
248
|
+
def from_dump(self, data, result_set, options):
|
|
249
|
+
"""
|
|
250
|
+
Get an instance of this class from its dumped representation.
|
|
251
|
+
|
|
252
|
+
:param data: The data to parse.
|
|
253
|
+
:param result_set: The partially constructed result set which is being populated.
|
|
254
|
+
"""
|
|
255
|
+
return self(result_set.energy_states.find(data['singlet']), result_set.energy_states.find(data['triplet']), data['rss']['value'])
|
|
256
|
+
|
|
257
|
+
@classmethod
|
|
258
|
+
def list_from_parser(self, parser):
|
|
259
|
+
"""
|
|
260
|
+
Create a SOC object from an output file parser.
|
|
261
|
+
"""
|
|
262
|
+
# Go through our data.
|
|
263
|
+
try:
|
|
264
|
+
return [self(
|
|
265
|
+
singlet_state = parser.results.energy_states.get_state(state_symbol = singlet_symbol),
|
|
266
|
+
triplet_state = parser.results.energy_states.get_state(state_symbol = triplet_symbol),
|
|
267
|
+
total = total
|
|
268
|
+
) for (singlet_symbol, triplet_symbol), total in zip(parser.data.socstates, parser.data.socenergies)]
|
|
269
|
+
except (AttributeError, Result_unavailable_error):
|
|
270
|
+
# No data.
|
|
271
|
+
return []
|
|
272
|
+
|