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,323 @@
|
|
|
1
|
+
"""Classes for total system energies."""
|
|
2
|
+
import itertools
|
|
3
|
+
import scipy.constants
|
|
4
|
+
|
|
5
|
+
from digichem.exception.base import Result_unavailable_error
|
|
6
|
+
from digichem.result import Result_container
|
|
7
|
+
from digichem.result import Unmergeable_container_mixin
|
|
8
|
+
from digichem.result import Result_object
|
|
9
|
+
|
|
10
|
+
class Energies(Result_object):
|
|
11
|
+
"""
|
|
12
|
+
Class that holds all the energies calculated from a computation.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, scf = None, mp = None, cc = None):
|
|
16
|
+
"""
|
|
17
|
+
:param scf: List of self-consistent field energies.
|
|
18
|
+
:param mp: List of lists of Moller-Plesset energies.
|
|
19
|
+
:param cc: List of coupled cluster energies.
|
|
20
|
+
"""
|
|
21
|
+
self.scf = SCF_energy_list(scf if scf is not None else [])
|
|
22
|
+
self.mp_energies = mp
|
|
23
|
+
self.cc = CC_energy_list(cc if cc is not None else [])
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def mp(self):
|
|
27
|
+
try:
|
|
28
|
+
return self.mp_energies[-1]
|
|
29
|
+
|
|
30
|
+
except IndexError:
|
|
31
|
+
return MP_energy_list([], 0)
|
|
32
|
+
|
|
33
|
+
def __iter__(self):
|
|
34
|
+
for energy in (self.scf, self.mp, self.cc):
|
|
35
|
+
yield energy
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def final(self):
|
|
39
|
+
"""
|
|
40
|
+
The total energy of this calculation.
|
|
41
|
+
|
|
42
|
+
This convenience property is the energy at the highest level of theory available (CC > MP > SCF).
|
|
43
|
+
|
|
44
|
+
:raises Result_unavailable_error: If no total energy is available.
|
|
45
|
+
"""
|
|
46
|
+
# Try CC first.
|
|
47
|
+
if len(self.cc) > 0:
|
|
48
|
+
return self.cc.final
|
|
49
|
+
elif len(self.mp) > 0:
|
|
50
|
+
return self.mp.final
|
|
51
|
+
else:
|
|
52
|
+
return self.scf.final
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def from_parser(self, parser):
|
|
56
|
+
"""
|
|
57
|
+
Get an Energies object from an output file parser.
|
|
58
|
+
|
|
59
|
+
:param parser: An output file parser.
|
|
60
|
+
:return: The populated Energies object.
|
|
61
|
+
"""
|
|
62
|
+
return self(
|
|
63
|
+
cc = CC_energy_list.from_parser(parser),
|
|
64
|
+
mp = MP_energy_list.list_from_parser(parser),
|
|
65
|
+
scf = SCF_energy_list.from_parser(parser)
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def dump(self, digichem_options):
|
|
69
|
+
"""
|
|
70
|
+
Get a representation of this result object in primitive format.
|
|
71
|
+
"""
|
|
72
|
+
dump = {
|
|
73
|
+
"final": {
|
|
74
|
+
"value": float(self.final),
|
|
75
|
+
"units": "eV"
|
|
76
|
+
},
|
|
77
|
+
"scf": self.scf.dump(digichem_options),
|
|
78
|
+
"mp": self.mp.dump(digichem_options),
|
|
79
|
+
"cc": self.cc.dump(digichem_options)
|
|
80
|
+
}
|
|
81
|
+
dump.update({"mp{}".format(index+2): energy.dump(digichem_options) for index, energy in enumerate(self.mp_energies)})
|
|
82
|
+
return dump
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_dump(self, data, result_set, options):
|
|
86
|
+
"""
|
|
87
|
+
Get an instance of this class from its dumped representation.
|
|
88
|
+
|
|
89
|
+
:param data: The data to parse.
|
|
90
|
+
:param result_set: The partially constructed result set which is being populated.
|
|
91
|
+
"""
|
|
92
|
+
scf = SCF_energy_list.from_dump(data['scf'], result_set, options)
|
|
93
|
+
#mp = MP_energy_list.from_dump(data['mp'], result_set, options)
|
|
94
|
+
cc = CC_energy_list.from_dump(data['cc'], result_set, options)
|
|
95
|
+
|
|
96
|
+
# TODO: consider using a dict so list indices make sense?
|
|
97
|
+
mp_energies = []
|
|
98
|
+
|
|
99
|
+
# Other MP energies.
|
|
100
|
+
for mp_order in itertools.count(2):
|
|
101
|
+
if "mp{}".format(mp_order) in data:
|
|
102
|
+
mp_energies.append(MP_energy_list.from_dump(data["mp{}".format(mp_order)], result_set, options))
|
|
103
|
+
|
|
104
|
+
else:
|
|
105
|
+
break
|
|
106
|
+
|
|
107
|
+
return self(scf, mp_energies, cc)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Energy_list(Result_container, Unmergeable_container_mixin):
|
|
111
|
+
"""
|
|
112
|
+
Class that represents a list of calculated energies.
|
|
113
|
+
|
|
114
|
+
Storing energies as a list is useful because optimisations will print energies at each step, and it can be useful to look back and see how the opt has progressed.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
# The type of energy; corresponds to the name of the attribute provided by cclib.
|
|
118
|
+
cclib_energy_type = ""
|
|
119
|
+
|
|
120
|
+
def __init__(self, *args, **kwargs):
|
|
121
|
+
super().__init__(*args, **kwargs)
|
|
122
|
+
|
|
123
|
+
def __float__(self):
|
|
124
|
+
"""
|
|
125
|
+
Our float representation, which is the last energy in our list.
|
|
126
|
+
"""
|
|
127
|
+
return self.final
|
|
128
|
+
|
|
129
|
+
def __str__(self):
|
|
130
|
+
"""
|
|
131
|
+
Our string representation, same as the float but in text form.
|
|
132
|
+
"""
|
|
133
|
+
return str(self.__float__())
|
|
134
|
+
|
|
135
|
+
def assign_levels(self):
|
|
136
|
+
"""
|
|
137
|
+
(Re)assign total levels of the objects in this list.
|
|
138
|
+
|
|
139
|
+
The contents of this list will be modified in place.
|
|
140
|
+
"""
|
|
141
|
+
# Energies don't have levels.
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def human_energy_type(self):
|
|
146
|
+
"""
|
|
147
|
+
Human readable name of this type of energy (for example, self-consistent field).
|
|
148
|
+
"""
|
|
149
|
+
if self.energy_type == "SCF":
|
|
150
|
+
return "self-consistent field"
|
|
151
|
+
elif self.energy_type == "MP":
|
|
152
|
+
return "Møller–Plesset"
|
|
153
|
+
elif self.energy_type == "CC":
|
|
154
|
+
return "coupled-cluster"
|
|
155
|
+
else:
|
|
156
|
+
raise ValueError("Unrecognised energy type {}".format(self.energy_type))
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def final(self):
|
|
160
|
+
"""
|
|
161
|
+
The 'final' energy in this list, useful for getting the final optimised energy.
|
|
162
|
+
|
|
163
|
+
:raises Result_unavailable_error: If this list is empty.
|
|
164
|
+
"""
|
|
165
|
+
try:
|
|
166
|
+
return self[-1]
|
|
167
|
+
except IndexError:
|
|
168
|
+
raise Result_unavailable_error(self.energy_type + ' energy', 'there is no {} energy'.format(self.energy_type))
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def eV_to_kJ(self, eV):
|
|
172
|
+
"""
|
|
173
|
+
Convert a value in eV to kJ.
|
|
174
|
+
|
|
175
|
+
:param eV: The value in electron volts.
|
|
176
|
+
:return: The value in kilojoules
|
|
177
|
+
"""
|
|
178
|
+
return eV * 1.602176634e-22
|
|
179
|
+
|
|
180
|
+
@classmethod
|
|
181
|
+
def kJ_to_kJmol(self, kJ):
|
|
182
|
+
"""
|
|
183
|
+
Convert a value in kJ to kJmol-1.
|
|
184
|
+
|
|
185
|
+
:param kJ: The value in kilojoules.
|
|
186
|
+
:return: The value in kilojoules per mol
|
|
187
|
+
"""
|
|
188
|
+
return kJ * scipy.constants.Avogadro
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def eV_to_kJmol(self, eV):
|
|
192
|
+
"""
|
|
193
|
+
Convert a value in eV to kJmol-1.
|
|
194
|
+
|
|
195
|
+
:param eV: The value in electron volts.
|
|
196
|
+
:return: The value in kilojoules per mol
|
|
197
|
+
"""
|
|
198
|
+
return self.kJ_to_kJmol(self.eV_to_kJ(eV))
|
|
199
|
+
|
|
200
|
+
@classmethod
|
|
201
|
+
def from_parser(self, parser):
|
|
202
|
+
"""
|
|
203
|
+
Get an Energy_list from an output file parser.
|
|
204
|
+
|
|
205
|
+
:param parser: An output file parser.
|
|
206
|
+
:return: The populated Energy_list object. The object will be empty if the energy is not available.
|
|
207
|
+
"""
|
|
208
|
+
try:
|
|
209
|
+
return self(getattr(parser.data, self.cclib_energy_type))
|
|
210
|
+
except AttributeError:
|
|
211
|
+
return self()
|
|
212
|
+
|
|
213
|
+
def dump(self, digichem_options):
|
|
214
|
+
"""
|
|
215
|
+
Get a representation of this result object in primitive format.
|
|
216
|
+
"""
|
|
217
|
+
return {
|
|
218
|
+
"num_steps": len(self),
|
|
219
|
+
"final": {
|
|
220
|
+
"value": float(self.final) if len(self) > 0 else None,
|
|
221
|
+
"units": "eV"
|
|
222
|
+
},
|
|
223
|
+
"values": [{"value": float(energy), "units": "eV"} for energy in self]
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def from_dump(self, data, result_set, options, **kwargs):
|
|
228
|
+
"""
|
|
229
|
+
Get a list of instances of this class from its dumped representation.
|
|
230
|
+
|
|
231
|
+
:param data: The data to parse.
|
|
232
|
+
:param result_set: The partially constructed result set which is being populated.
|
|
233
|
+
"""
|
|
234
|
+
return self([energy['value'] for energy in data['values']], **kwargs)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class SCF_energy_list(Energy_list):
|
|
238
|
+
"""
|
|
239
|
+
List of Self-consistent field energies.
|
|
240
|
+
"""
|
|
241
|
+
cclib_energy_type = "scfenergies"
|
|
242
|
+
energy_type = "SCF"
|
|
243
|
+
|
|
244
|
+
# A warning issued when attempting to merge non-equivalent objects
|
|
245
|
+
MERGE_WARNING = "Attempting to merge list of SCF energies that are not identical; non-equivalent energies will be ignored"
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class CC_energy_list(Energy_list):
|
|
249
|
+
"""
|
|
250
|
+
List of coupled-cluster energies.
|
|
251
|
+
"""
|
|
252
|
+
cclib_energy_type = "ccenergies"
|
|
253
|
+
energy_type = "CC"
|
|
254
|
+
|
|
255
|
+
# A warning issued when attempting to merge non-equivalent objects
|
|
256
|
+
MERGE_WARNING = "Attempting to merge list of CC energies that are not identical; non-equivalent energies will be ignored"
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class MP_energy_list(Energy_list):
|
|
260
|
+
"""
|
|
261
|
+
List of Moller-Plesset energies.
|
|
262
|
+
"""
|
|
263
|
+
cclib_energy_type = "mpenergies"
|
|
264
|
+
energy_type = "MP"
|
|
265
|
+
|
|
266
|
+
# A warning issued when attempting to merge non-equivalent objects
|
|
267
|
+
MERGE_WARNING = "Attempting to merge list of MP energies that are not identical; non-equivalent energies will be ignored"
|
|
268
|
+
|
|
269
|
+
def __init__(self, items, order):
|
|
270
|
+
super().__init__(items)
|
|
271
|
+
self.order = order
|
|
272
|
+
|
|
273
|
+
def dump(self, digichem_options):
|
|
274
|
+
"""
|
|
275
|
+
Get a representation of this result object in primitive format.
|
|
276
|
+
"""
|
|
277
|
+
dump = super().dump(digichem_options)
|
|
278
|
+
dump['order'] = self.order
|
|
279
|
+
return dump
|
|
280
|
+
|
|
281
|
+
@classmethod
|
|
282
|
+
def from_dump(self, data, result_set, options):
|
|
283
|
+
"""
|
|
284
|
+
Get a list of instances of this class from its dumped representation.
|
|
285
|
+
|
|
286
|
+
:param data: The data to parse.
|
|
287
|
+
:param result_set: The partially constructed result set which is being populated.
|
|
288
|
+
"""
|
|
289
|
+
return super().from_dump(data, result_set, options, order = data['order'])
|
|
290
|
+
|
|
291
|
+
@classmethod
|
|
292
|
+
def list_from_parser(self, parser):
|
|
293
|
+
"""
|
|
294
|
+
Get a list of MP_energy_list objects from an output file parser.
|
|
295
|
+
|
|
296
|
+
Note that unlike other calculated energies, MP energies are calculated sequentially up to the requested order. So for example, MP4 first calculates the MP1 energy (which is the same as the uncorrected energy), then MP2, MP3 and finally MP4.
|
|
297
|
+
|
|
298
|
+
:param parser: An output file parser.
|
|
299
|
+
:return: The populated Energy_list object. The object will be empty if the energy is not available.
|
|
300
|
+
"""
|
|
301
|
+
# First, split our list of lists (for each opt step and each MP energy).
|
|
302
|
+
mp_energies = []
|
|
303
|
+
|
|
304
|
+
try:
|
|
305
|
+
parser_energies = getattr(parser.data, self.cclib_energy_type)
|
|
306
|
+
|
|
307
|
+
for energy_step in parser_energies:
|
|
308
|
+
for index, energy in enumerate(energy_step):
|
|
309
|
+
try:
|
|
310
|
+
mp_energies[index].append(energy)
|
|
311
|
+
|
|
312
|
+
except IndexError:
|
|
313
|
+
mp_energies.append([energy])
|
|
314
|
+
|
|
315
|
+
except AttributeError:
|
|
316
|
+
if not hasattr(parser.data, self.cclib_energy_type):
|
|
317
|
+
return []
|
|
318
|
+
|
|
319
|
+
else:
|
|
320
|
+
raise
|
|
321
|
+
|
|
322
|
+
return [self(energies, index+2) for index, energies in enumerate(mp_energies)]
|
|
323
|
+
|