digichem-core 6.10.1__py3-none-any.whl → 7.0.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.
- digichem/__init__.py +2 -2
- digichem/config/base.py +11 -2
- digichem/config/util.py +3 -2
- digichem/file/prattle.py +9 -7
- digichem/image/render.py +6 -4
- digichem/image/spectroscopy.py +17 -4
- digichem/input/__init__.py +1 -1
- digichem/input/digichem_input.py +39 -34
- digichem/misc/io.py +11 -0
- digichem/parse/base.py +8 -6
- digichem/parse/cclib.py +57 -17
- digichem/parse/dump.py +31 -35
- digichem/parse/gaussian.py +2 -2
- digichem/parse/pyscf.py +13 -3
- digichem/parse/turbomole.py +2 -3
- digichem/parse/util.py +6 -5
- digichem/result/alignment/base.py +2 -2
- digichem/result/atom.py +4 -4
- digichem/result/base.py +53 -5
- digichem/result/dipole_moment.py +1 -1
- digichem/result/emission.py +5 -5
- digichem/result/energy.py +8 -8
- digichem/result/excited_state.py +20 -13
- digichem/result/ground_state.py +2 -2
- digichem/result/metadata.py +51 -25
- digichem/result/nmr.py +37 -28
- digichem/result/orbital.py +3 -3
- digichem/result/result.py +14 -14
- digichem/result/soc.py +3 -3
- digichem/result/spectroscopy.py +5 -4
- digichem/result/tdm.py +5 -5
- digichem/result/vibration.py +15 -6
- digichem/test/conftest.py +5 -0
- digichem/test/mock/cubegen +87172 -0
- digichem/test/mock/formchk +9456 -0
- digichem/test/test_image.py +54 -42
- digichem/test/test_input.py +17 -3
- digichem/test/test_parsing.py +9 -0
- digichem/test/test_prattle.py +31 -2
- digichem/test/util.py +2 -0
- {digichem_core-6.10.1.dist-info → digichem_core-7.0.0.dist-info}/METADATA +1 -1
- {digichem_core-6.10.1.dist-info → digichem_core-7.0.0.dist-info}/RECORD +45 -43
- {digichem_core-6.10.1.dist-info → digichem_core-7.0.0.dist-info}/WHEEL +0 -0
- {digichem_core-6.10.1.dist-info → digichem_core-7.0.0.dist-info}/licenses/COPYING.md +0 -0
- {digichem_core-6.10.1.dist-info → digichem_core-7.0.0.dist-info}/licenses/LICENSE +0 -0
digichem/parse/dump.py
CHANGED
|
@@ -25,19 +25,19 @@ class Dump_multi_parser_abc(File_parser_abc):
|
|
|
25
25
|
ABC for classes that can read multiple result sets from dumped data.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
def __init__(self, input_file, *other_log_files, raw_data = None, **auxiliary_files):
|
|
28
|
+
def __init__(self, input_file, *other_log_files, raw_data = None, options , **auxiliary_files):
|
|
29
29
|
"""
|
|
30
30
|
Top level constructor for calculation parsers.
|
|
31
31
|
|
|
32
32
|
:param input_file: The path to read from.
|
|
33
33
|
"""
|
|
34
34
|
# Neither other_log_files nor auxiliary_files are currently used...
|
|
35
|
-
super().__init__(input_file, raw_data = raw_data)
|
|
35
|
+
super().__init__(input_file, raw_data = raw_data, options = options)
|
|
36
36
|
self.all_results = []
|
|
37
37
|
|
|
38
38
|
@classmethod
|
|
39
|
-
def from_data(self, input_file, data):
|
|
40
|
-
return self(input_file, raw_data = data)
|
|
39
|
+
def from_data(self, input_file, data, options):
|
|
40
|
+
return self(input_file, raw_data = data, options = options)
|
|
41
41
|
|
|
42
42
|
@property
|
|
43
43
|
def results(self):
|
|
@@ -63,26 +63,24 @@ class Dump_multi_parser_abc(File_parser_abc):
|
|
|
63
63
|
def get_sub_parser(self):
|
|
64
64
|
raise NotImplementedError("Implement in subclass")
|
|
65
65
|
|
|
66
|
-
def process_all(self
|
|
66
|
+
def process_all(self):
|
|
67
67
|
"""
|
|
68
68
|
Get all the Result set objects produced by this parser.
|
|
69
69
|
|
|
70
|
-
:param options: A Digichem options nested dictionary containing options to control parsing.
|
|
71
70
|
:return: A list of the populated result sets.
|
|
72
71
|
"""
|
|
73
72
|
# Unlike most other parsers, our data can actually contain lots of results.
|
|
74
|
-
self.all_results = [self.get_sub_parser()(self.log_file_path, raw_data = data).process(
|
|
73
|
+
self.all_results = [self.get_sub_parser()(self.log_file_path, raw_data = data, options = self.options).process() for data in self.data]
|
|
75
74
|
|
|
76
75
|
return self.all_results
|
|
77
76
|
|
|
78
|
-
def process(self
|
|
77
|
+
def process(self):
|
|
79
78
|
"""
|
|
80
79
|
Get a Result set object from this parser.
|
|
81
80
|
|
|
82
|
-
:param options: A Digichem options nested dictionary containing options to control parsing.
|
|
83
81
|
:return: The populated result set.
|
|
84
82
|
"""
|
|
85
|
-
self.process_all(
|
|
83
|
+
self.process_all()
|
|
86
84
|
return self.results
|
|
87
85
|
|
|
88
86
|
|
|
@@ -127,65 +125,63 @@ class Dump_parser_abc(File_parser_abc):
|
|
|
127
125
|
ABC for parsers that read dumped data.
|
|
128
126
|
"""
|
|
129
127
|
|
|
130
|
-
def __init__(self, input_file, *other_log_files, raw_data = None, **auxiliary_files):
|
|
128
|
+
def __init__(self, input_file, *other_log_files, raw_data = None, options, **auxiliary_files):
|
|
131
129
|
"""
|
|
132
130
|
Top level constructor for calculation parsers.
|
|
133
131
|
|
|
134
132
|
:param input_file: The path to the input file to read.
|
|
135
133
|
"""
|
|
136
134
|
# Neither other_log_files nor auxiliary_files are currently used...
|
|
137
|
-
super().__init__(input_file, raw_data = raw_data)
|
|
135
|
+
super().__init__(input_file, raw_data = raw_data, options = options)
|
|
138
136
|
|
|
139
137
|
@classmethod
|
|
140
|
-
def from_data(self, input_file, data):
|
|
141
|
-
return self(input_file, raw_data = data)
|
|
138
|
+
def from_data(self, input_file, data, options):
|
|
139
|
+
return self(input_file, raw_data = data, options = options)
|
|
142
140
|
|
|
143
|
-
def process_all(self
|
|
141
|
+
def process_all(self):
|
|
144
142
|
"""
|
|
145
143
|
Get all the Result set objects produced by this parser.
|
|
146
144
|
|
|
147
|
-
:param options: A Digichem options nested dictionary containing options to control parsing.
|
|
148
145
|
:return: A list of the populated result sets.
|
|
149
146
|
"""
|
|
150
|
-
self.process(
|
|
147
|
+
self.process()
|
|
151
148
|
return [self.results]
|
|
152
149
|
|
|
153
|
-
def process(self
|
|
150
|
+
def process(self):
|
|
154
151
|
"""
|
|
155
152
|
Get a Result set object from this parser.
|
|
156
153
|
|
|
157
|
-
:param options: A Digichem options nested dictionary containing options to control parsing.
|
|
158
154
|
:return: The populated result set.
|
|
159
155
|
"""
|
|
160
156
|
|
|
161
157
|
# Get our result set.
|
|
162
158
|
self.results = Result_set(
|
|
163
159
|
_id = self.data.get("_id"),
|
|
164
|
-
metadata = Metadata.from_dump(self.data['metadata'], self.results, options)
|
|
160
|
+
metadata = Metadata.from_dump(self.data['metadata'], self.results, self.options)
|
|
165
161
|
)
|
|
166
162
|
|
|
167
163
|
# First get our list of MOs (because we need them for excited states too.)
|
|
168
|
-
self.results.orbitals = Molecular_orbital_list.from_dump(self.data['orbitals'], self.results, options)
|
|
169
|
-
self.results.beta_orbitals = Molecular_orbital_list.from_dump(self.data['beta_orbitals'], self.results, options)
|
|
164
|
+
self.results.orbitals = Molecular_orbital_list.from_dump(self.data['orbitals'], self.results, self.options)
|
|
165
|
+
self.results.beta_orbitals = Molecular_orbital_list.from_dump(self.data['beta_orbitals'], self.results, self.options)
|
|
170
166
|
|
|
171
|
-
alignment_class = Alignment.from_class_handle(options['alignment']) if options['alignment'] is not None else Minimal
|
|
167
|
+
alignment_class = Alignment.from_class_handle(self.options['alignment']) if self.options['alignment'] is not None else Minimal
|
|
172
168
|
|
|
173
169
|
# Our alignment orientation data.
|
|
174
170
|
# The constructor for each alignment class automatically performs realignment.
|
|
175
|
-
self.results.atoms = alignment_class.from_dump(self.data['atoms'], self.results, options)
|
|
176
|
-
self.results.raw_atoms = Atom_list.from_dump(self.data['raw_atoms'], self.results, options)
|
|
171
|
+
self.results.atoms = alignment_class.from_dump(self.data['atoms'], self.results, self.options)
|
|
172
|
+
self.results.raw_atoms = Atom_list.from_dump(self.data['raw_atoms'], self.results, self.options)
|
|
177
173
|
|
|
178
174
|
# TEDM and TMDM.
|
|
179
|
-
self.results.transition_dipole_moments = Transition_dipole_moment.list_from_dump(self.data['excited_states']['values'], self.results, options)
|
|
175
|
+
self.results.transition_dipole_moments = Transition_dipole_moment.list_from_dump(self.data['excited_states']['values'], self.results, self.options)
|
|
180
176
|
|
|
181
177
|
# Excited states.
|
|
182
|
-
self.results.excited_states = Excited_state_list.from_dump(self.data['excited_states'], self.results, options)
|
|
178
|
+
self.results.excited_states = Excited_state_list.from_dump(self.data['excited_states'], self.results, self.options)
|
|
183
179
|
|
|
184
180
|
# Energies.
|
|
185
|
-
self.results.energies = Energies.from_dump(self.data['energies'], self.results, options)
|
|
181
|
+
self.results.energies = Energies.from_dump(self.data['energies'], self.results, self.options)
|
|
186
182
|
|
|
187
183
|
# Our ground state.
|
|
188
|
-
self.results.ground_state = Ground_state.from_dump(self.data['ground_state'], self.results, options)
|
|
184
|
+
self.results.ground_state = Ground_state.from_dump(self.data['ground_state'], self.results, self.options)
|
|
189
185
|
|
|
190
186
|
# And a similar list but also including the ground.
|
|
191
187
|
self.results.energy_states = Excited_state_list()
|
|
@@ -193,24 +189,24 @@ class Dump_parser_abc(File_parser_abc):
|
|
|
193
189
|
self.results.energy_states.extend(self.results.excited_states)
|
|
194
190
|
|
|
195
191
|
# SOC.
|
|
196
|
-
self.results.soc = SOC_list.from_dump(self.data['soc'], self.results, options)
|
|
192
|
+
self.results.soc = SOC_list.from_dump(self.data['soc'], self.results, self.options)
|
|
197
193
|
|
|
198
194
|
# PDM
|
|
199
|
-
self.results.pdm = Dipole_moment.from_dump(self.data['pdm'], self.results, options)
|
|
195
|
+
self.results.pdm = Dipole_moment.from_dump(self.data['pdm'], self.results, self.options)
|
|
200
196
|
|
|
201
197
|
# Frequencies.
|
|
202
|
-
self.results.vibrations = Vibrations_list.from_dump(self.data['vibrations'], self.results, options)
|
|
198
|
+
self.results.vibrations = Vibrations_list.from_dump(self.data['vibrations'], self.results, self.options)
|
|
203
199
|
|
|
204
200
|
# NMR.
|
|
205
201
|
if "nmr" in self.data:
|
|
206
|
-
self.results.nmr = NMR_list.from_dump(self.data['nmr'], self.results, options)
|
|
202
|
+
self.results.nmr = NMR_list.from_dump(self.data['nmr'], self.results, self.options)
|
|
207
203
|
|
|
208
204
|
else:
|
|
209
|
-
self.results.nmr = NMR_list(atoms = self.results.atoms, options = options)
|
|
205
|
+
self.results.nmr = NMR_list(atoms = self.results.atoms, options = self.options)
|
|
210
206
|
|
|
211
207
|
# Finally, try and set emission.
|
|
212
208
|
try:
|
|
213
|
-
self.results.emission = self.results.emission.from_dump(self.data['emission'], self.results, options)
|
|
209
|
+
self.results.emission = self.results.emission.from_dump(self.data['emission'], self.results, self.options)
|
|
214
210
|
|
|
215
211
|
except Exception:
|
|
216
212
|
digichem.log.get_logger().warning("Failed to parse emission data", exc_info = True)
|
digichem/parse/gaussian.py
CHANGED
|
@@ -29,9 +29,9 @@ class Gaussian_parser(Cclib_parser):
|
|
|
29
29
|
CPU_TIME_HEADER = "Job cpu time:"
|
|
30
30
|
CPU_HEADER = "Will use up to"
|
|
31
31
|
|
|
32
|
-
def __init__(self, *log_files, rwfdump = "rwfdump", **auxiliary_files):
|
|
32
|
+
def __init__(self, *log_files, rwfdump = "rwfdump", options, **auxiliary_files):
|
|
33
33
|
self.rwfdump = rwfdump
|
|
34
|
-
super().__init__(*log_files, **auxiliary_files)
|
|
34
|
+
super().__init__(*log_files, options = options, **auxiliary_files)
|
|
35
35
|
|
|
36
36
|
def parse_metadata(self):
|
|
37
37
|
"""
|
digichem/parse/pyscf.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import json
|
|
3
|
+
from uuid import uuid4
|
|
3
4
|
|
|
4
5
|
from cclib.bridge.cclib2pyscf import cclibfrommethods
|
|
5
6
|
|
|
6
7
|
from digichem.parse.base import Parser_abc
|
|
8
|
+
import digichem.log
|
|
7
9
|
|
|
8
10
|
class Pyscf_parser(Parser_abc):
|
|
9
11
|
"""
|
|
@@ -17,9 +19,17 @@ class Pyscf_parser(Parser_abc):
|
|
|
17
19
|
|
|
18
20
|
def _parse(self):
|
|
19
21
|
self.data = cclibfrommethods(**self.methods)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
# Try to generate a checksum from metadata.
|
|
25
|
+
self.data._id = hashlib.sha1(json.dumps(self.data.metadata, sort_keys = True).encode('utf-8')).hexdigest()
|
|
26
|
+
|
|
27
|
+
except Exception:
|
|
28
|
+
# No luck, something in metadata must be unhashable.
|
|
29
|
+
digichem.log.get_logger().error("Unable to generate hash ID from calculation metadata, using random ID instead", exc_info = True)
|
|
30
|
+
# TODO: Think of a better way to do this.
|
|
31
|
+
self.data._id = hashlib.sha1(uuid4().hex.encode('utf-8')).hexdigest()
|
|
32
|
+
|
|
22
33
|
self.data.metadata['name'] = self.mol_name
|
|
23
34
|
self.data._aux = {'methods': self.methods}
|
|
24
|
-
|
|
25
35
|
|
digichem/parse/turbomole.py
CHANGED
|
@@ -98,14 +98,13 @@ class Turbomole_parser(Cclib_parser):
|
|
|
98
98
|
if len(self.data.metadata['cpu_time']) == 0:
|
|
99
99
|
del(self.data.metadata['cpu_time'])
|
|
100
100
|
|
|
101
|
-
def process(self
|
|
101
|
+
def process(self):
|
|
102
102
|
"""
|
|
103
103
|
Get a Result set object from this parser.
|
|
104
104
|
|
|
105
|
-
:param options: A Digichem options nested dictionary containing options to control parsing.
|
|
106
105
|
:return: The populated result set.
|
|
107
106
|
"""
|
|
108
|
-
super().process(
|
|
107
|
+
super().process()
|
|
109
108
|
|
|
110
109
|
# After processing is complete, have a look for excited state density files.
|
|
111
110
|
# These have the general file name:
|
digichem/parse/util.py
CHANGED
|
@@ -60,7 +60,7 @@ def find_log_files_from_hint(hint):
|
|
|
60
60
|
# Remove any 'digichem.log' files as we know these are not calc log files.
|
|
61
61
|
# We don't actually write 'digichem.log' files anymore either (we use digichem.out instead),
|
|
62
62
|
# but older versions did...
|
|
63
|
-
log_files = [log_file for log_file in log_files if log_file.name not in ["digichem.log", "digichem.out", "silico.log", "silico.out"]]
|
|
63
|
+
log_files = [log_file for log_file in log_files if log_file.name not in ["digichem.log", "digichem.out", "silico.log", "silico.out", ".digichem.yaml"]]
|
|
64
64
|
else:
|
|
65
65
|
parent = hint.parent
|
|
66
66
|
log_files = [hint]
|
|
@@ -227,10 +227,10 @@ def parse_calculation(*log_files, options, parse_all = False, format_hint = "aut
|
|
|
227
227
|
open_log_files, open_aux_files = archive.open()
|
|
228
228
|
|
|
229
229
|
if parse_all:
|
|
230
|
-
results = from_log_files(*open_log_files, format_hint = format_hint, parser_options = parser_options, **open_aux_files).process_all(
|
|
230
|
+
results = from_log_files(*open_log_files, format_hint = format_hint, parser_options = parser_options, options = options, **open_aux_files).process_all()
|
|
231
231
|
|
|
232
232
|
else:
|
|
233
|
-
results = from_log_files(*open_log_files, format_hint = format_hint, parser_options = parser_options, **open_aux_files).process(
|
|
233
|
+
results = from_log_files(*open_log_files, format_hint = format_hint, parser_options = parser_options, options = options, **open_aux_files).process()
|
|
234
234
|
|
|
235
235
|
finally:
|
|
236
236
|
if not keep_archive:
|
|
@@ -379,7 +379,6 @@ def parse_and_merge_multiple_calculations(*multiple_results, options, parser_opt
|
|
|
379
379
|
:param multiple_results: A list of two dimensions, where the first dimension is a list of separate results to process, and the second dimension is a list of results that should be merged together.
|
|
380
380
|
:param options: A Digichem options nested dictionary containing options to control parsing.
|
|
381
381
|
:param format_hint: A hint as to the format of the given log files. Either 'auto' (to guess), 'log' (calc log file), 'sir' (digichem result file) or 'sid' (digichem database file).
|
|
382
|
-
:param pool: An optional subprocessing.pool object to use for parallel parsing.
|
|
383
382
|
:param init_func: An optional function to call to init each newly created process.
|
|
384
383
|
:param processes: The max number of processes to create the new pool object with.
|
|
385
384
|
:param auxiliary_files: An optional list of lists of dicts of auxiliary files. Each item in auxiliary_files should match the corresponding log file in multiple_results.
|
|
@@ -388,6 +387,7 @@ def parse_and_merge_multiple_calculations(*multiple_results, options, parser_opt
|
|
|
388
387
|
if auxiliary_files is None:
|
|
389
388
|
auxiliary_files = [None] * len(multiple_results)
|
|
390
389
|
|
|
390
|
+
pool = None
|
|
391
391
|
# Do some parsing.
|
|
392
392
|
# TODO: This parallelization isn't ideal, currently we process each group of to-be merged calcs separately, meaning processes can be wasted.
|
|
393
393
|
try:
|
|
@@ -402,7 +402,8 @@ def parse_and_merge_multiple_calculations(*multiple_results, options, parser_opt
|
|
|
402
402
|
return result_lists
|
|
403
403
|
|
|
404
404
|
finally:
|
|
405
|
-
pool
|
|
405
|
+
if pool:
|
|
406
|
+
pool.__exit__(None, None, None)
|
|
406
407
|
|
|
407
408
|
|
|
408
409
|
class open_for_parsing():
|
|
@@ -240,11 +240,11 @@ class Alignment(Atom_list, Dynamic_parent):
|
|
|
240
240
|
for atom in self:
|
|
241
241
|
print("{}, {}, {}, {}".format(atom.element, atom.coords[0], atom.coords[1], atom.coords[2]))
|
|
242
242
|
|
|
243
|
-
def
|
|
243
|
+
def _dump_(self, digichem_options, all):
|
|
244
244
|
"""
|
|
245
245
|
Get a representation of this result object in primitive format.
|
|
246
246
|
"""
|
|
247
|
-
dump_dict = super().
|
|
247
|
+
dump_dict = super()._dump_(digichem_options, all)
|
|
248
248
|
dump_dict['alignment_method'] = self.human_method_type
|
|
249
249
|
return dump_dict
|
|
250
250
|
|
digichem/result/atom.py
CHANGED
|
@@ -453,7 +453,7 @@ class Atom_list(Result_container, Unmergeable_container_mixin, Molecule_mixin):
|
|
|
453
453
|
"""
|
|
454
454
|
return self(Atom.list_from_coords(coords), charge = coords.charge)
|
|
455
455
|
|
|
456
|
-
def
|
|
456
|
+
def _dump_(self, digichem_options, all):
|
|
457
457
|
"""
|
|
458
458
|
Get a representation of this result object in primitive format.
|
|
459
459
|
"""
|
|
@@ -490,7 +490,7 @@ class Atom_list(Result_container, Unmergeable_container_mixin, Molecule_mixin):
|
|
|
490
490
|
},
|
|
491
491
|
"linearity_ratio": float(self.get_linear_ratio()),
|
|
492
492
|
"planarity_ratio": float(self.get_planar_ratio()),
|
|
493
|
-
"values": super().
|
|
493
|
+
"values": super()._dump_(digichem_options, all),
|
|
494
494
|
}
|
|
495
495
|
return dump_dict
|
|
496
496
|
|
|
@@ -522,7 +522,7 @@ class Atom_list(Result_container, Unmergeable_container_mixin, Molecule_mixin):
|
|
|
522
522
|
"""
|
|
523
523
|
Convert this list of atoms to mol format (useful for reading with rdkit).
|
|
524
524
|
"""
|
|
525
|
-
return Openprattle_converter
|
|
525
|
+
return Openprattle_converter(input_file_buffer = self.to_xyz(), input_file_path = "internal atoms object", input_file_type = "xyz").convert("mol", charge = self.charge)
|
|
526
526
|
|
|
527
527
|
def to_rdkit_molecule(self):
|
|
528
528
|
"""
|
|
@@ -673,7 +673,7 @@ class Atom(Atom_ABC):
|
|
|
673
673
|
"""
|
|
674
674
|
return math.sqrt( (self.coords[0] - foreign_atom.coords[0])**2 + (self.coords[1] - foreign_atom.coords[1])**2 + (self.coords[2] - foreign_atom.coords[2])**2)
|
|
675
675
|
|
|
676
|
-
def
|
|
676
|
+
def _dump_(self, digichem_options, all):
|
|
677
677
|
"""
|
|
678
678
|
Get a representation of this result object in primitive format.
|
|
679
679
|
"""
|
digichem/result/base.py
CHANGED
|
@@ -93,17 +93,55 @@ class Result_object():
|
|
|
93
93
|
|
|
94
94
|
return multiple_objects[0]
|
|
95
95
|
|
|
96
|
+
def calculate(self, item, digichem_options):
|
|
97
|
+
"""
|
|
98
|
+
Retrieve/calculate an on-demand value, caching the value if it has not already been retrieved.
|
|
99
|
+
|
|
100
|
+
This function is a wrapper around _get_dump_(), caching the calculation result to avoid
|
|
101
|
+
expensive recalculation.
|
|
102
|
+
|
|
103
|
+
:param item: The key corresponding to an item in this object's _get_dump_() dict.
|
|
104
|
+
:param digichem_options: Digichem options that will be passed to _get_dump_() (unused on a cache hit).
|
|
105
|
+
"""
|
|
106
|
+
if not hasattr(self, "_dump_cache"):
|
|
107
|
+
self._dump_cache = {}
|
|
108
|
+
|
|
109
|
+
if item in self._dump_cache:
|
|
110
|
+
# Cache hit.
|
|
111
|
+
return self._dump_cache[item]
|
|
112
|
+
|
|
113
|
+
else:
|
|
114
|
+
# Cache miss.
|
|
115
|
+
# Generate (and cache) the data.
|
|
116
|
+
self._dump_cache[item] = self.generate_for_dump()[item](digichem_options)
|
|
117
|
+
|
|
118
|
+
# And return of course.
|
|
119
|
+
return self._dump_cache[item]
|
|
120
|
+
|
|
96
121
|
def generate_for_dump(self):
|
|
97
122
|
"""
|
|
98
123
|
Method used to get a dictionary used to generate on-demand values for dumping.
|
|
99
124
|
|
|
100
125
|
This functionality is useful for hiding expense properties from the normal dump process, while still exposing them when specifically requested.
|
|
101
126
|
|
|
102
|
-
Each key in the returned
|
|
127
|
+
Each key in the returned dict is the name of a dumpable item, each value is a function to call with digichem_options as its only param.
|
|
103
128
|
"""
|
|
104
|
-
|
|
129
|
+
warnings.warn("generate_for_dump() is deprecated, use calculate() or _get_dump_() instead", DeprecationWarning)
|
|
130
|
+
return self._get_dump_()
|
|
105
131
|
|
|
106
|
-
def dump(self, digichem_options):
|
|
132
|
+
def dump(self, digichem_options, all = False):
|
|
133
|
+
# First, get simple key:value pairs.
|
|
134
|
+
base_dict = self._dump_(digichem_options, all)
|
|
135
|
+
|
|
136
|
+
# Then extend with generator ones if we have any.
|
|
137
|
+
if all:
|
|
138
|
+
generators = self._get_dump_()
|
|
139
|
+
for key in generators:
|
|
140
|
+
base_dict[key] = generators[key](digichem_options)
|
|
141
|
+
|
|
142
|
+
return base_dict
|
|
143
|
+
|
|
144
|
+
def _dump_(self, digichem_options, all):
|
|
107
145
|
"""
|
|
108
146
|
Abstract function that is called to dump the value of the result object to a primitive type, suitable for serializing with yaml.
|
|
109
147
|
|
|
@@ -112,6 +150,16 @@ class Result_object():
|
|
|
112
150
|
- 'units': The units of the result (for example, k m^-s).
|
|
113
151
|
"""
|
|
114
152
|
raise NotImplementedError("Implement in subclass")
|
|
153
|
+
|
|
154
|
+
def _get_dump_(self):
|
|
155
|
+
"""
|
|
156
|
+
Method used to get a dictionary used to generate on-demand values for dumping.
|
|
157
|
+
|
|
158
|
+
This functionality is useful for hiding expense properties from the normal dump process, while still exposing them when specifically requested.
|
|
159
|
+
|
|
160
|
+
Each key in the returned dict is the name of a dumpable item, each value is a function to call with digichem_options as its only param.
|
|
161
|
+
"""
|
|
162
|
+
return {}
|
|
115
163
|
|
|
116
164
|
|
|
117
165
|
class Floatable_mixin():
|
|
@@ -253,6 +301,6 @@ class Result_container(list, Result_object):
|
|
|
253
301
|
else:
|
|
254
302
|
return self.merge_default(*multiple_lists, **kwargs)
|
|
255
303
|
|
|
256
|
-
def
|
|
257
|
-
return [item.dump(digichem_options) for item in self]
|
|
304
|
+
def _dump_(self, digichem_options, all):
|
|
305
|
+
return [item.dump(digichem_options, all) for item in self]
|
|
258
306
|
|
digichem/result/dipole_moment.py
CHANGED
|
@@ -182,7 +182,7 @@ class Dipole_moment_ABC(Result_object):
|
|
|
182
182
|
except (FloatingPointError, ZeroDivisionError):
|
|
183
183
|
return 0
|
|
184
184
|
|
|
185
|
-
def
|
|
185
|
+
def _dump_(self, digichem_options, all):
|
|
186
186
|
"""
|
|
187
187
|
Get a representation of this result object in primitive format.
|
|
188
188
|
"""
|
digichem/result/emission.py
CHANGED
|
@@ -27,11 +27,11 @@ class Emissions(Result_object):
|
|
|
27
27
|
self.adiabatic = adiabatic if adiabatic is not None else {}
|
|
28
28
|
self.vertical = vertical if vertical is not None else {}
|
|
29
29
|
|
|
30
|
-
def
|
|
30
|
+
def _dump_(self, digichem_options, all):
|
|
31
31
|
# Several dumpers (JSON, DB backends based on JSON etc) don't support non-string keys...
|
|
32
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()}
|
|
33
|
+
"adiabatic": {str(key):value.dump(digichem_options, all) for key,value in self.adiabatic.items()},
|
|
34
|
+
"vertical": {str(key):value.dump(digichem_options, all) for key,value in self.vertical.items()}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
@classmethod
|
|
@@ -343,12 +343,12 @@ class Relaxed_excited_state(Excited_state):
|
|
|
343
343
|
else:
|
|
344
344
|
raise
|
|
345
345
|
|
|
346
|
-
def
|
|
346
|
+
def _dump_(self, digichem_options, all):
|
|
347
347
|
"""
|
|
348
348
|
Get a representation of this result object in primitive format.
|
|
349
349
|
"""
|
|
350
350
|
|
|
351
|
-
dump_dict = super().
|
|
351
|
+
dump_dict = super()._dump_(digichem_options, all)
|
|
352
352
|
dump_dict['emission_type'] = self.emission_type
|
|
353
353
|
dump_dict['ground_multiplicity'] = self.ground_multiplicity
|
|
354
354
|
dump_dict['excited_energy'] = {
|
digichem/result/energy.py
CHANGED
|
@@ -65,7 +65,7 @@ class Energies(Result_object):
|
|
|
65
65
|
scf = SCF_energy_list.from_parser(parser)
|
|
66
66
|
)
|
|
67
67
|
|
|
68
|
-
def
|
|
68
|
+
def _dump_(self, digichem_options, all):
|
|
69
69
|
"""
|
|
70
70
|
Get a representation of this result object in primitive format.
|
|
71
71
|
"""
|
|
@@ -74,11 +74,11 @@ class Energies(Result_object):
|
|
|
74
74
|
"value": float(self.final),
|
|
75
75
|
"units": "eV"
|
|
76
76
|
},
|
|
77
|
-
"scf": self.scf.dump(digichem_options),
|
|
78
|
-
"mp": self.mp.dump(digichem_options),
|
|
79
|
-
"cc": self.cc.dump(digichem_options)
|
|
77
|
+
"scf": self.scf.dump(digichem_options, all),
|
|
78
|
+
"mp": self.mp.dump(digichem_options, all),
|
|
79
|
+
"cc": self.cc.dump(digichem_options, all)
|
|
80
80
|
}
|
|
81
|
-
dump.update({"mp{}".format(index+2): energy.dump(digichem_options) for index, energy in enumerate(self.mp_energies)})
|
|
81
|
+
dump.update({"mp{}".format(index+2): energy.dump(digichem_options, all) for index, energy in enumerate(self.mp_energies)})
|
|
82
82
|
return dump
|
|
83
83
|
|
|
84
84
|
@classmethod
|
|
@@ -210,7 +210,7 @@ class Energy_list(Result_container, Unmergeable_container_mixin):
|
|
|
210
210
|
except AttributeError:
|
|
211
211
|
return self()
|
|
212
212
|
|
|
213
|
-
def
|
|
213
|
+
def _dump_(self, digichem_options, all):
|
|
214
214
|
"""
|
|
215
215
|
Get a representation of this result object in primitive format.
|
|
216
216
|
"""
|
|
@@ -270,11 +270,11 @@ class MP_energy_list(Energy_list):
|
|
|
270
270
|
super().__init__(items)
|
|
271
271
|
self.order = order
|
|
272
272
|
|
|
273
|
-
def
|
|
273
|
+
def _dump_(self, digichem_options, all):
|
|
274
274
|
"""
|
|
275
275
|
Get a representation of this result object in primitive format.
|
|
276
276
|
"""
|
|
277
|
-
dump = super().
|
|
277
|
+
dump = super()._dump_(digichem_options, all)
|
|
278
278
|
dump['order'] = self.order
|
|
279
279
|
return dump
|
|
280
280
|
|
digichem/result/excited_state.py
CHANGED
|
@@ -230,7 +230,7 @@ class Excited_state_list(Result_container):
|
|
|
230
230
|
merged.assign_levels()
|
|
231
231
|
return merged
|
|
232
232
|
|
|
233
|
-
def
|
|
233
|
+
def _get_dump_(self):
|
|
234
234
|
"""
|
|
235
235
|
Method used to get a dictionary used to generate on-demand values for dumping.
|
|
236
236
|
|
|
@@ -257,14 +257,21 @@ class Excited_state_list(Result_container):
|
|
|
257
257
|
# TODO: It's weird that these spectra are only available in dumped format, there should be some property/function on the class that also returns them...
|
|
258
258
|
spectrum_nm = Absorption_emission_graph.from_excited_states(
|
|
259
259
|
self,
|
|
260
|
-
digichem_options['absorption_spectrum']['fwhm'],
|
|
261
|
-
digichem_options['absorption_spectrum']['gaussian_resolution'],
|
|
262
|
-
digichem_options['absorption_spectrum']['gaussian_cutoff'],
|
|
260
|
+
fwhm = digichem_options['absorption_spectrum']['fwhm'],
|
|
261
|
+
resolution = digichem_options['absorption_spectrum']['gaussian_resolution'],
|
|
262
|
+
cutoff = digichem_options['absorption_spectrum']['gaussian_cutoff'],
|
|
263
|
+
filter = digichem_options['absorption_spectrum']['y_filter'],
|
|
263
264
|
use_jacobian = digichem_options['absorption_spectrum']['use_jacobian']
|
|
264
265
|
)
|
|
265
266
|
|
|
266
267
|
|
|
267
|
-
spectrum_ev = Spectroscopy_graph(
|
|
268
|
+
spectrum_ev = Spectroscopy_graph(
|
|
269
|
+
[(excited_state.energy, excited_state.oscillator_strength) for excited_state in self],
|
|
270
|
+
fwhm = digichem_options['absorption_spectrum']['fwhm'],
|
|
271
|
+
resolution = digichem_options['absorption_spectrum']['gaussian_resolution'],
|
|
272
|
+
cutoff = digichem_options['absorption_spectrum']['gaussian_cutoff'],
|
|
273
|
+
filter = digichem_options['absorption_spectrum']['y_filter']
|
|
274
|
+
)
|
|
268
275
|
|
|
269
276
|
try:
|
|
270
277
|
spectrum_nm_data = spectrum_nm.plot_cumulative_gaussian()
|
|
@@ -298,9 +305,9 @@ class Excited_state_list(Result_container):
|
|
|
298
305
|
}
|
|
299
306
|
}
|
|
300
307
|
|
|
301
|
-
def
|
|
308
|
+
def _dump_(self, digichem_options, all):
|
|
302
309
|
dump_dict = {
|
|
303
|
-
"values": super().
|
|
310
|
+
"values": super()._dump_(digichem_options, all),
|
|
304
311
|
}
|
|
305
312
|
|
|
306
313
|
# Add extra properties.
|
|
@@ -358,7 +365,7 @@ class Excited_state_transition(Result_object):
|
|
|
358
365
|
"""
|
|
359
366
|
return self.coefficient **2
|
|
360
367
|
|
|
361
|
-
def
|
|
368
|
+
def _dump_(self, digichem_options, all):
|
|
362
369
|
"""
|
|
363
370
|
Get a representation of this result object in primitive format.
|
|
364
371
|
"""
|
|
@@ -558,7 +565,7 @@ class Energy_state(Result_object, Floatable_mixin):
|
|
|
558
565
|
"""
|
|
559
566
|
return "{}({})".format(self.multiplicity_symbol, self.multiplicity_level)
|
|
560
567
|
|
|
561
|
-
def
|
|
568
|
+
def _dump_(self, digichem_options, all):
|
|
562
569
|
"""
|
|
563
570
|
Get a representation of this result object in primitive format.
|
|
564
571
|
"""
|
|
@@ -708,11 +715,11 @@ class Excited_state(Energy_state):
|
|
|
708
715
|
# Now convert to 0 -> 255 and return.
|
|
709
716
|
return [int(clr * 255) for clr in rgb]
|
|
710
717
|
|
|
711
|
-
def
|
|
718
|
+
def _dump_(self, digichem_options, all):
|
|
712
719
|
"""
|
|
713
720
|
Get a representation of this result object in primitive format.
|
|
714
721
|
"""
|
|
715
|
-
dump_dict = super().
|
|
722
|
+
dump_dict = super()._dump_(digichem_options, all)
|
|
716
723
|
dump_dict.update({
|
|
717
724
|
"wavelength": {
|
|
718
725
|
"value": float(self.wavelength),
|
|
@@ -725,8 +732,8 @@ class Excited_state(Energy_state):
|
|
|
725
732
|
},
|
|
726
733
|
"symmetry": self.symmetry,
|
|
727
734
|
"oscillator_strength": float(self.oscillator_strength) if self.oscillator_strength is not None else None,
|
|
728
|
-
"tdm": self.transition_dipole_moment.dump(digichem_options) if self.transition_dipole_moment is not None else None,
|
|
729
|
-
"transitions": [tran.dump(digichem_options) for tran in self.transitions],
|
|
735
|
+
"tdm": self.transition_dipole_moment.dump(digichem_options, all) if self.transition_dipole_moment is not None else None,
|
|
736
|
+
"transitions": [tran.dump(digichem_options, all) for tran in self.transitions],
|
|
730
737
|
})
|
|
731
738
|
return dump_dict
|
|
732
739
|
|
digichem/result/ground_state.py
CHANGED
|
@@ -35,11 +35,11 @@ class Ground_state(Energy_state):
|
|
|
35
35
|
"""
|
|
36
36
|
return self.charge == other.charge and self.multiplicity == other.multiplicity and self.energy == other.energy
|
|
37
37
|
|
|
38
|
-
def
|
|
38
|
+
def _dump_(self, digichem_options, all):
|
|
39
39
|
"""
|
|
40
40
|
Get a representation of this result object in primitive format.
|
|
41
41
|
"""
|
|
42
|
-
parent_dict = super().
|
|
42
|
+
parent_dict = super()._dump_(digichem_options, all)
|
|
43
43
|
return {
|
|
44
44
|
"index": parent_dict['index'],
|
|
45
45
|
"symbol": parent_dict['symbol'],
|