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,402 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from scipy.constants import epsilon_0, Planck, c
|
|
3
|
+
|
|
4
|
+
from digichem.exception.base import Digichem_exception, Result_unavailable_error
|
|
5
|
+
from digichem.result.excited_state import Excited_state
|
|
6
|
+
from digichem.result import Result_object
|
|
7
|
+
|
|
8
|
+
# Dirac constant.
|
|
9
|
+
h_bar = Planck / (math.pi *2)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Emissions(Result_object):
|
|
13
|
+
"""
|
|
14
|
+
Class that holds all emissions from a result.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, adiabatic = None, vertical = None):
|
|
18
|
+
"""
|
|
19
|
+
"""
|
|
20
|
+
# For now, we have no way of knowing which state is being optimised.
|
|
21
|
+
# As such, we assume it's the lowest of each mult (because this is most
|
|
22
|
+
# common thanks to kasha's rule). This being the case, each emission is
|
|
23
|
+
# stored in a dict, which each key is the multiplicity. Each value is not
|
|
24
|
+
# a list (because we only have one emission for each mult), but the
|
|
25
|
+
# emission object itself.
|
|
26
|
+
# TODO: Improve once we can detect which state is being optimised.
|
|
27
|
+
self.adiabatic = adiabatic if adiabatic is not None else {}
|
|
28
|
+
self.vertical = vertical if vertical is not None else {}
|
|
29
|
+
|
|
30
|
+
def dump(self, digichem_options):
|
|
31
|
+
# Several dumpers (JSON, DB backends based on JSON etc) don't support non-string keys...
|
|
32
|
+
return {
|
|
33
|
+
"adiabatic": {str(key):value.dump(digichem_options) for key,value in self.adiabatic.items()},
|
|
34
|
+
"vertical": {str(key):value.dump(digichem_options) for key,value in self.vertical.items()}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def from_dump(self, data, result_set, options):
|
|
39
|
+
"""
|
|
40
|
+
Get a list of instances of this class from its dumped representation.
|
|
41
|
+
|
|
42
|
+
:param data: The data to parse.
|
|
43
|
+
:param result_set: The partially constructed result set which is being populated.
|
|
44
|
+
"""
|
|
45
|
+
emissions = self()
|
|
46
|
+
|
|
47
|
+
for transition_type in ("adiabatic", "vertical"):
|
|
48
|
+
if transition_type not in data:
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
setattr(emissions, transition_type,
|
|
52
|
+
{mult: Relaxed_excited_state.from_dump(state_data, result_set, options, transition_type = transition_type) for mult, state_data in data[transition_type].items()}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return emissions
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Relaxed_excited_state(Excited_state):
|
|
59
|
+
"""
|
|
60
|
+
Class for representing an emission energy from an excited state to a ground state.
|
|
61
|
+
|
|
62
|
+
Note that while emission and absorption can be approximated as the reverse of each other, emission and absorption strictly have different energies.
|
|
63
|
+
Excited states, as represented by the Excited_state class, are for absorption energies.
|
|
64
|
+
This class is for emission energies, which are typically lower in energy (because the excited state has relaxed).
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def __init__(self,
|
|
68
|
+
level,
|
|
69
|
+
multiplicity,
|
|
70
|
+
multiplicity_level,
|
|
71
|
+
ground_multiplicity,
|
|
72
|
+
excited_energy,
|
|
73
|
+
ground_energy,
|
|
74
|
+
oscillator_strength,
|
|
75
|
+
transition_type,
|
|
76
|
+
# TODO: Add Support.
|
|
77
|
+
transitions = None,
|
|
78
|
+
# TODO: Add Support.
|
|
79
|
+
symmetry = None,
|
|
80
|
+
transition_dipole_moment = None,
|
|
81
|
+
):
|
|
82
|
+
"""
|
|
83
|
+
"""
|
|
84
|
+
self.ground_energy = ground_energy
|
|
85
|
+
self.excited_energy = excited_energy
|
|
86
|
+
self.ground_multiplicity = ground_multiplicity
|
|
87
|
+
# The emission type (as a string), either fluorescence or phosphorescence.
|
|
88
|
+
if ground_multiplicity == multiplicity:
|
|
89
|
+
self.emission_type = "fluorescence"
|
|
90
|
+
|
|
91
|
+
else:
|
|
92
|
+
self.emission_type = "phosphorescence"
|
|
93
|
+
|
|
94
|
+
# Either adiabatic or vertical.
|
|
95
|
+
self.transition_type = transition_type
|
|
96
|
+
|
|
97
|
+
super().__init__(level, multiplicity, multiplicity_level, symmetry, excited_energy - ground_energy, oscillator_strength, transitions if transitions is not None else [], transition_dipole_moment)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def from_results(self,
|
|
102
|
+
ground_state_result,
|
|
103
|
+
excited_state_result,
|
|
104
|
+
transition_type,
|
|
105
|
+
excited_state = None,
|
|
106
|
+
# For now we assume this is the lowest possible excited state (may change in future).
|
|
107
|
+
level = 1,
|
|
108
|
+
multiplicity_level = 1,
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
Constructor for Relaxed_excited_state objects.
|
|
112
|
+
|
|
113
|
+
:param ground_state_result: A Result_set object representing the ground state.
|
|
114
|
+
:param excited_state_result: A Result_set object representing the excited state.
|
|
115
|
+
:param transition_type: A string describing the type of transition, either 'adiabatic' (GS and ES relaxed) or 'vertical' (ES relaxed, GS @ ES geom).
|
|
116
|
+
:param excited_state: An optional Excited_state object. This is required (for example) in time dependent DFT where the total energy of excited_state_result is the ground state energy (at the excited state geometry).
|
|
117
|
+
:param level: The level (ordered index) of this excited state, this has no effect if excited_state is not None (in which case it is taken from the given excited state).
|
|
118
|
+
:param multiplicity_level: The ordered index of this excited state out of states with the same multiplicity, this has no effect if excited_state is not None (in which case it is taken from the given excited state).
|
|
119
|
+
"""
|
|
120
|
+
if excited_state is not None:
|
|
121
|
+
# If we have an excited state we can inherit certain properties from it.
|
|
122
|
+
level = excited_state.level
|
|
123
|
+
multiplicity_level = excited_state.multiplicity_level
|
|
124
|
+
oscillator_strength = excited_state.oscillator_strength
|
|
125
|
+
transition_dipole_moment = excited_state.transition_dipole_moment
|
|
126
|
+
else:
|
|
127
|
+
# We don't have a concept of oscillator strength (yet?).
|
|
128
|
+
oscillator_strength = None
|
|
129
|
+
transition_dipole_moment = None
|
|
130
|
+
|
|
131
|
+
# The total energy of the excited state in this transition.
|
|
132
|
+
# Start with our excited_state_result energy.
|
|
133
|
+
excited_energy = excited_state_result.energies.final
|
|
134
|
+
|
|
135
|
+
# Add the excited state energy (if we have it).
|
|
136
|
+
if excited_state is not None:
|
|
137
|
+
excited_energy += excited_state.energy
|
|
138
|
+
|
|
139
|
+
# The total energy of the ground state in this transition.
|
|
140
|
+
ground_energy = ground_state_result.energies.final
|
|
141
|
+
|
|
142
|
+
# The multiplicity (as a number) of the excited state in this emission transition.
|
|
143
|
+
if excited_state is not None:
|
|
144
|
+
excited_multiplicity = excited_state.multiplicity
|
|
145
|
+
else:
|
|
146
|
+
excited_multiplicity = excited_state_result.ground_state.multiplicity
|
|
147
|
+
|
|
148
|
+
# The multiplicity (as a number) of the ground state in this emission transition.
|
|
149
|
+
ground_multiplicity = ground_state_result.ground_state.multiplicity
|
|
150
|
+
|
|
151
|
+
return self(
|
|
152
|
+
level = level,
|
|
153
|
+
multiplicity = excited_multiplicity,
|
|
154
|
+
multiplicity_level = multiplicity_level,
|
|
155
|
+
ground_multiplicity = ground_multiplicity,
|
|
156
|
+
# TODO: Add Support.
|
|
157
|
+
symmetry = None,
|
|
158
|
+
excited_energy = excited_energy,
|
|
159
|
+
ground_energy = ground_energy,
|
|
160
|
+
oscillator_strength = oscillator_strength,
|
|
161
|
+
# TODO: Add Support.
|
|
162
|
+
transitions = None,
|
|
163
|
+
transition_dipole_moment = transition_dipole_moment,
|
|
164
|
+
transition_type = transition_type,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def excited_multiplicity(self):
|
|
169
|
+
"""
|
|
170
|
+
This is an alias of multiplicity
|
|
171
|
+
"""
|
|
172
|
+
return self.multiplicity
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def guess_from_results(self, *results):
|
|
176
|
+
"""
|
|
177
|
+
Try and find emission energies from a number of calculation results.
|
|
178
|
+
|
|
179
|
+
Attempts will be made to calculate both adiabatic and vertical emission energies based on the properties of the excited states in results.
|
|
180
|
+
|
|
181
|
+
:param results: A number of result sets.
|
|
182
|
+
:returns: A tuple of dictionaries of the form (vertical, adiabatic), where the key of each dict is the multiplicity of the corresponding emission.
|
|
183
|
+
"""
|
|
184
|
+
# The two types of emission we consider.
|
|
185
|
+
# Each is a dictionary where the keys are multiplicities and the items are the corresponding emission.
|
|
186
|
+
adiabatic = {}
|
|
187
|
+
vertical = {}
|
|
188
|
+
|
|
189
|
+
# We're only interested in optimisations (by definition emission needs to be from relaxed geom).
|
|
190
|
+
opt_results = [result for result in results if "Optimisation" in result.metadata.calculations]
|
|
191
|
+
|
|
192
|
+
for excited_state_result in reversed(opt_results):
|
|
193
|
+
# See if we can use this calc type as an excited state.
|
|
194
|
+
# The easiest situation is if we have excited states in the calc (and it is an opt).
|
|
195
|
+
if len(excited_state_result.excited_states) > 0:
|
|
196
|
+
# This will do fine for vertical.
|
|
197
|
+
vertical.update(self.for_each_multiplicity(excited_state_result, excited_state_result, "vertical"))
|
|
198
|
+
|
|
199
|
+
# For adiabatic, we need the earliest suitable optimisation from our list that doesn't have excited states.
|
|
200
|
+
try:
|
|
201
|
+
ground_state_result = [result for result in opt_results if len(result.excited_states) == 0][0]
|
|
202
|
+
adiabatic.update(self.for_each_multiplicity(ground_state_result, excited_state_result, "adiabatic"))
|
|
203
|
+
except IndexError:
|
|
204
|
+
# No suitable calcs.
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
else:
|
|
208
|
+
# We have no explicit excited states, but so long as we are an opt we can still find an emission if we have calcs of different mult.
|
|
209
|
+
# First look for adiabatic.
|
|
210
|
+
try:
|
|
211
|
+
# Try and find a suitable ground.
|
|
212
|
+
ground_state_result = [result for result in opt_results if result.ground_state.multiplicity != excited_state_result.ground_state.multiplicity][0]
|
|
213
|
+
|
|
214
|
+
# Get 'emission' object.
|
|
215
|
+
emission = self.from_results(ground_state_result, excited_state_result, "adiabatic")
|
|
216
|
+
|
|
217
|
+
# If the energy is negative we will ignore.
|
|
218
|
+
if emission.energy >= 0:
|
|
219
|
+
adiabatic[excited_state_result.ground_state.multiplicity] = emission
|
|
220
|
+
except IndexError:
|
|
221
|
+
# No good.
|
|
222
|
+
pass
|
|
223
|
+
|
|
224
|
+
# And now vertical (we need a single point at different geom.
|
|
225
|
+
try:
|
|
226
|
+
# Try and find a suitable ground.
|
|
227
|
+
ground_state_result = [result for result in results if "Single Point" in result.metadata.calculations and result.ground_state.multiplicity != excited_state_result.ground_state.multiplicity][0]
|
|
228
|
+
|
|
229
|
+
# Get 'emission' object.
|
|
230
|
+
emission = self.from_results(ground_state_result, excited_state_result, "vertical")
|
|
231
|
+
|
|
232
|
+
# If the energy is negative we will ignore.
|
|
233
|
+
if emission.energy >= 0:
|
|
234
|
+
vertical[excited_state_result.ground_state.multiplicity] = emission
|
|
235
|
+
except IndexError:
|
|
236
|
+
# No good.
|
|
237
|
+
pass
|
|
238
|
+
|
|
239
|
+
return (vertical, adiabatic)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
@classmethod
|
|
243
|
+
def for_each_multiplicity(self, ground_state_result, excited_state_result, transition_type):
|
|
244
|
+
"""
|
|
245
|
+
Return one emission object for each multiplicity in an excited state result.
|
|
246
|
+
|
|
247
|
+
This method is useful because frequently only the lowest excited state of each mult is considered for emission, so there is one emission type per multiplicity.
|
|
248
|
+
"""
|
|
249
|
+
return {multiplicity: self.from_results(ground_state_result, excited_state_result, transition_type, states[0]) for multiplicity, states in excited_state_result.excited_states.group().items()}
|
|
250
|
+
|
|
251
|
+
# TODO: This might not be used anywhere?
|
|
252
|
+
@classmethod
|
|
253
|
+
def determine_from_results(self, main_result, *, ground_state_result = None, excited_state_result, transition_type = None, excited_state = None):
|
|
254
|
+
"""
|
|
255
|
+
Try and determine some emission energies from a number of result sets.
|
|
256
|
+
|
|
257
|
+
:param main_result: A Result_set object containing main calculation results.
|
|
258
|
+
:param ground_state_result: A Result_set object representing the ground state.
|
|
259
|
+
:param excited_state_result: A Result_set object representing the excited state.
|
|
260
|
+
:param transition_type: A string describing the type of transition, either 'adiabatic' (GS and ES relaxed) or 'vertical' (ES relaxed, GS @ ES geom).
|
|
261
|
+
:param excited_state: An optional Excited_state object. This is required (for example) in time dependent DFT where the total energy of excited_state_result is the ground state energy (at the excited state geometry). If excited_state is not an Excited_state object (and isn't None), it is passed as criteria to Excited_state_list.get_state().
|
|
262
|
+
"""
|
|
263
|
+
# Decide on what to use for our ground state if not given explicitly.
|
|
264
|
+
if ground_state_result is None:
|
|
265
|
+
# If a transition type wasn't given, we can try and guess.
|
|
266
|
+
if transition_type is None:
|
|
267
|
+
# We don't know what type of emission we've been asked for.
|
|
268
|
+
# If the main_result is an opt, we'll assume we're adiabatic and use that as the ground state.
|
|
269
|
+
# Otherwise, we'll assume vertical and use the excited state.
|
|
270
|
+
if "Optimisation" in main_result.metadata.calculations:
|
|
271
|
+
transition_type = "adiabatic"
|
|
272
|
+
else:
|
|
273
|
+
transition_type = "vertical"
|
|
274
|
+
|
|
275
|
+
# Distinguish between the two types of excited states
|
|
276
|
+
if len(excited_state_result.excited_states) > 0:
|
|
277
|
+
# Emission from TD style excited states.
|
|
278
|
+
|
|
279
|
+
if transition_type == "vertical":
|
|
280
|
+
# For vertical emission, the excited state result is also the ground state result.
|
|
281
|
+
ground_state_result = excited_state_result
|
|
282
|
+
|
|
283
|
+
elif transition_type == "adiabatic":
|
|
284
|
+
# For adiabatic we need an optimised ground state geometry.
|
|
285
|
+
if "Optimisation" in main_result.metadata.calculations:
|
|
286
|
+
ground_state_result = main_result
|
|
287
|
+
|
|
288
|
+
else:
|
|
289
|
+
# No explicit ground given and out main result is not an Opt, so it probably isn't suitable.
|
|
290
|
+
raise Digichem_exception("Unable to determine ground state in adiabatic emission; no explicit ground state given and this calculation is not an optimisation")
|
|
291
|
+
|
|
292
|
+
else:
|
|
293
|
+
# Emission from unrestricted triplet calc.
|
|
294
|
+
# This method requires another calc type to compare to.
|
|
295
|
+
if transition_type == "vertical":
|
|
296
|
+
# For vertical, we want a singlet calc at the same geometry as the triplet calc.
|
|
297
|
+
if 'Single Point' in main_result.metadata.calculations:
|
|
298
|
+
ground_state_result = main_result
|
|
299
|
+
else:
|
|
300
|
+
raise Digichem_exception("Unable to determine ground state in vertical emission; no explicit ground state given and this calculation is not a single point")
|
|
301
|
+
|
|
302
|
+
elif transition_type == "adiabatic":
|
|
303
|
+
# For adiabatic, we need an opt.
|
|
304
|
+
if "Optimisation" in main_result.metadata.calculations:
|
|
305
|
+
ground_state_result = main_result
|
|
306
|
+
else:
|
|
307
|
+
# No explicit ground given and out main result is not an Opt, so it probably isn't suitable.
|
|
308
|
+
raise Digichem_exception("Unable to determine ground state in adiabatic emission; no explicit ground state given and this calculation is not an optimisation")
|
|
309
|
+
|
|
310
|
+
# Now decide which excited state to use.
|
|
311
|
+
excited_state = excited_state if excited_state is None or isinstance(excited_state, Excited_state) else excited_state_result.excited_states.get_state(excited_state)
|
|
312
|
+
|
|
313
|
+
# No excited state given and generating emission from TD style excited states, get all possible.
|
|
314
|
+
if len(excited_state_result.excited_states) > 0 and excited_state is None:
|
|
315
|
+
return self.for_each_multiplicity(ground_state_result, excited_state_result, transition_type)
|
|
316
|
+
|
|
317
|
+
else:
|
|
318
|
+
# Get emission.
|
|
319
|
+
emission = self.from_results(
|
|
320
|
+
ground_state_result,
|
|
321
|
+
excited_state_result,
|
|
322
|
+
transition_type,
|
|
323
|
+
excited_state)
|
|
324
|
+
|
|
325
|
+
# Return as single dict.
|
|
326
|
+
return {emission.multiplicity: emission}
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@property
|
|
331
|
+
def emission_rate(self):
|
|
332
|
+
"""
|
|
333
|
+
The rate of emission (k(F) or k(Phos) etc) from this excited state.
|
|
334
|
+
|
|
335
|
+
Calculated according to Shizu, K., Kaji, H. Commun Chem 5, 53 (2022).
|
|
336
|
+
"""
|
|
337
|
+
try:
|
|
338
|
+
return ((4 * self.joules **3) / (3 * epsilon_0 * h_bar **4 * c **3) ) * self.transition_dipole_moment.coulomb_meters **2
|
|
339
|
+
except Exception:
|
|
340
|
+
if self.transition_dipole_moment is None:
|
|
341
|
+
raise Result_unavailable_error("emission_rate", "there is no transition dipole moment associated with this emission") from None
|
|
342
|
+
|
|
343
|
+
else:
|
|
344
|
+
raise
|
|
345
|
+
|
|
346
|
+
def dump(self, digichem_options):
|
|
347
|
+
"""
|
|
348
|
+
Get a representation of this result object in primitive format.
|
|
349
|
+
"""
|
|
350
|
+
|
|
351
|
+
dump_dict = super().dump(digichem_options)
|
|
352
|
+
dump_dict['emission_type'] = self.emission_type
|
|
353
|
+
dump_dict['ground_multiplicity'] = self.ground_multiplicity
|
|
354
|
+
dump_dict['excited_energy'] = {
|
|
355
|
+
"value": float(self.excited_energy),
|
|
356
|
+
"units": "eV"
|
|
357
|
+
}
|
|
358
|
+
dump_dict['ground_energy'] = {
|
|
359
|
+
"value": float(self.ground_energy),
|
|
360
|
+
"units": "eV"
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
try:
|
|
365
|
+
dump_dict["emission_rate"] = {
|
|
366
|
+
"value": float(self.emission_rate),
|
|
367
|
+
"units": "s^-1"
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
except Result_unavailable_error:
|
|
371
|
+
pass
|
|
372
|
+
|
|
373
|
+
return dump_dict
|
|
374
|
+
|
|
375
|
+
@classmethod
|
|
376
|
+
def from_dump(self, data, result_set, options, transition_type):
|
|
377
|
+
"""
|
|
378
|
+
Get an instance of this class from its dumped representation.
|
|
379
|
+
|
|
380
|
+
:param data: The data to parse.
|
|
381
|
+
:param result_set: The partially constructed result set which is being populated.
|
|
382
|
+
"""
|
|
383
|
+
# Get our tdm (if available).
|
|
384
|
+
if 'tdm' in data and data['tdm'] is not None:
|
|
385
|
+
tdm = result_set.transition_dipole_moments[data['index']-1]
|
|
386
|
+
|
|
387
|
+
else:
|
|
388
|
+
tdm = None
|
|
389
|
+
|
|
390
|
+
return self(
|
|
391
|
+
level = data['index'],
|
|
392
|
+
multiplicity = data['multiplicity'],
|
|
393
|
+
multiplicity_level = data['multiplicity_index'],
|
|
394
|
+
ground_multiplicity = data['ground_multiplicity'],
|
|
395
|
+
excited_energy = data['excited_energy']['value'],
|
|
396
|
+
ground_energy = data['ground_energy']['value'],
|
|
397
|
+
oscillator_strength = data['oscillator_strength'],
|
|
398
|
+
transition_type = transition_type,
|
|
399
|
+
transition_dipole_moment = tdm,
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
|