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,489 @@
|
|
|
1
|
+
"""Tests for checking the values of parsed results."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import scipy.constants
|
|
6
|
+
|
|
7
|
+
from digichem.parse import parse_calculation
|
|
8
|
+
from digichem.parse.util import parse_and_merge_calculations
|
|
9
|
+
from digichem.test.util import data_directory, digichem_options
|
|
10
|
+
from digichem.test.util import check_float_list, check_dipole, check_orbitals
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture(scope="module")
|
|
14
|
+
def gaussian_SP_result(digichem_options):
|
|
15
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Gaussian 16 Single Point (Singlet) PBE1PBE (GD3BJ) Toluene 6-31G(d,p).tar.gz"), options = digichem_options)
|
|
16
|
+
|
|
17
|
+
@pytest.fixture(scope="module")
|
|
18
|
+
def gaussian_opt_result(digichem_options):
|
|
19
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Gaussian 16 Optimisation Frequencies PBE1PBE (GD3BJ) Toluene 6-31G(d,p)"), options = digichem_options)
|
|
20
|
+
|
|
21
|
+
@pytest.fixture(scope="module")
|
|
22
|
+
def gaussian_radical_anion_result(digichem_options):
|
|
23
|
+
return parse_calculation(Path(data_directory(), "Benzene Anion/Gaussian 16 Optimisation Frequencies PBE1PBE (GD3BJ) Gas Phase 6-31G(d,p).tar.gz"), options = digichem_options)
|
|
24
|
+
|
|
25
|
+
@pytest.fixture(scope="module")
|
|
26
|
+
def gaussian_ES_result(digichem_options):
|
|
27
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Gaussian 16 Excited States TDA 10 Singlets 10 Triplets PBE1PBE (GD3BJ) Toluene 6-31G(d,p).tar.gz"), options = digichem_options)
|
|
28
|
+
|
|
29
|
+
@pytest.fixture(scope="module")
|
|
30
|
+
def gaussian_emission_result(digichem_options):
|
|
31
|
+
return parse_and_merge_calculations(
|
|
32
|
+
Path(data_directory(), "Naphthalene/Gaussian 16 Optimisation Frequencies PBE1PBE (GD3BJ) Toluene 6-31G(d,p)"),
|
|
33
|
+
Path(data_directory(), "Naphthalene/Gaussian 16 Excited States TDA Optimised S(1) PBE1PBE (GD3BJ) Toluene 6-31G(d,p).tar.gz"),
|
|
34
|
+
options = digichem_options
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
@pytest.fixture(scope="module")
|
|
38
|
+
def gaussian_opt_ES_result(digichem_options):
|
|
39
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Gaussian 16 Excited States TDA Optimised S(1) PBE1PBE (GD3BJ) Toluene 6-31G(d,p).tar.gz"), options = digichem_options)
|
|
40
|
+
|
|
41
|
+
@pytest.fixture(scope="module")
|
|
42
|
+
def gaussian_PDM_result(digichem_options):
|
|
43
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Gaussian 16 Optimisation Frequencies PBE1PBE (GD3BJ) Toluene 6-31G(d,p).tar.gz"), options = digichem_options)
|
|
44
|
+
|
|
45
|
+
@pytest.fixture(scope="module")
|
|
46
|
+
def gaussian_TDM_result(digichem_options):
|
|
47
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Gaussian 16 Excited States TDA 10 Singlets 10 Triplets PBE1PBE (GD3BJ) Toluene 6-31G(d,p).tar.gz"), options = digichem_options)
|
|
48
|
+
|
|
49
|
+
@pytest.fixture(scope="module")
|
|
50
|
+
def gaussian_PDM_ES_result(digichem_options):
|
|
51
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Gaussian 16 Excited States TDA Optimised S(1) PBE1PBE (GD3BJ) Toluene 6-31G(d,p).tar.gz"), options = digichem_options)
|
|
52
|
+
|
|
53
|
+
#############
|
|
54
|
+
# Turbomole #
|
|
55
|
+
#############
|
|
56
|
+
|
|
57
|
+
@pytest.fixture(scope="module")
|
|
58
|
+
def turbomole_sp_result(digichem_options):
|
|
59
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Turbomole Single Point DFT PBE0 (GD3BJ) Toluene Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
60
|
+
|
|
61
|
+
@pytest.fixture(scope="module")
|
|
62
|
+
def turbomole_opt_result(digichem_options):
|
|
63
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Turbomole Optimisation Frequency PBE0 (GD3BJ) 6-31G**.tar.gz"), options = digichem_options)
|
|
64
|
+
|
|
65
|
+
@pytest.fixture(scope="module")
|
|
66
|
+
def turbomole_ES_singlets_result(digichem_options):
|
|
67
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Turbomole Excited States TDA 10 Singlets PBE0 (GD3BJ) 6-31G**.tar.gz"), options = digichem_options)
|
|
68
|
+
|
|
69
|
+
@pytest.fixture(scope="module")
|
|
70
|
+
def turbomole_ES_triplets_result(digichem_options):
|
|
71
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Turbomole Excited States TDA 10 Triplets PBE0 (GD3BJ) 6-31G**.tar.gz"), options = digichem_options)
|
|
72
|
+
|
|
73
|
+
@pytest.fixture(scope="module")
|
|
74
|
+
def turbomole_ES_result(digichem_options):
|
|
75
|
+
return parse_and_merge_calculations(
|
|
76
|
+
Path(data_directory(), "Naphthalene/Turbomole Excited States TDA 10 Singlets PBE0 (GD3BJ) 6-31G**.tar.gz"),
|
|
77
|
+
Path(data_directory(), "Naphthalene/Turbomole Excited States TDA 10 Triplets PBE0 (GD3BJ) 6-31G**.tar.gz"),
|
|
78
|
+
options = digichem_options
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
@pytest.fixture(scope="module")
|
|
82
|
+
def turbomole_PDM_result(digichem_options):
|
|
83
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Turbomole Optimisation Frequency PBE0 (GD3BJ) 6-31G**.tar.gz"), options = digichem_options)
|
|
84
|
+
|
|
85
|
+
@pytest.fixture(scope="module")
|
|
86
|
+
def turbomole_TDM_result(digichem_options):
|
|
87
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Turbomole Excited States TDA 10 Singlets PBE0 (GD3BJ) 6-31G**.tar.gz"), options = digichem_options)
|
|
88
|
+
|
|
89
|
+
@pytest.fixture(scope="module")
|
|
90
|
+
def turbomole_radical_anion_result(digichem_options):
|
|
91
|
+
return parse_calculation(Path(data_directory(), "Benzene Anion/Turbomole Optimisation Frequency PBE0 (GD3BJ) 6-31G**.tar.gz"), options = digichem_options)
|
|
92
|
+
|
|
93
|
+
@pytest.fixture(scope="module")
|
|
94
|
+
def turbomole_ADC2_opt_result(digichem_options):
|
|
95
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Turbomole Optimisation ADC(2) cc-pVDZ.tar.gz"), options = digichem_options)
|
|
96
|
+
|
|
97
|
+
@pytest.fixture(scope="module")
|
|
98
|
+
def turbomole_ADC2_singlets_result(digichem_options):
|
|
99
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Turbomole Excited States ADC(2) S(1) and S(2) cc-pVDZ.tar.gz"), options = digichem_options)
|
|
100
|
+
|
|
101
|
+
@pytest.fixture(scope="module")
|
|
102
|
+
def turbomole_ADC2_triplets_result(digichem_options):
|
|
103
|
+
return parse_calculation(Path(data_directory(), "Naphthalene/Turbomole Excited States ADC(2) T(1) and T(2) cc-pVDZ.tar.gz"), options = digichem_options)
|
|
104
|
+
|
|
105
|
+
########
|
|
106
|
+
# ORCA #
|
|
107
|
+
########
|
|
108
|
+
|
|
109
|
+
@pytest.fixture(scope="module")
|
|
110
|
+
def orca_SP_result(digichem_options):
|
|
111
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Orca Single Point PBE0 (GD3BJ) Gas Phase Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
112
|
+
|
|
113
|
+
@pytest.fixture(scope="module")
|
|
114
|
+
def orca_solvent_SP_result(digichem_options):
|
|
115
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Orca Single Point PBE0 (GD3BJ) Toluene Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
116
|
+
|
|
117
|
+
@pytest.fixture(scope="module")
|
|
118
|
+
def orca_grad_result(digichem_options):
|
|
119
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Orca Gradient PBE0 (GD3BJ) Gas Phase Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
120
|
+
|
|
121
|
+
@pytest.fixture(scope="module")
|
|
122
|
+
def orca_opt_result(digichem_options):
|
|
123
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Orca Optimisation PBE0 (GD3BJ) Gas Phase Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
124
|
+
|
|
125
|
+
@pytest.fixture(scope="module")
|
|
126
|
+
def orca_opt_freq_result(digichem_options):
|
|
127
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Orca Optimisation Frequencies PBE0 (GD3BJ) Gas Phase Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
128
|
+
|
|
129
|
+
@pytest.fixture(scope="module")
|
|
130
|
+
def orca_freq_result(digichem_options):
|
|
131
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Orca Frequencies PBE0 (GD3BJ) Gas Phase Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
132
|
+
|
|
133
|
+
@pytest.fixture(scope="module")
|
|
134
|
+
def orca_nmr_result(digichem_options):
|
|
135
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Orca NMR PBE0 (GD3BJ) Gas Phase Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
136
|
+
|
|
137
|
+
@pytest.fixture(scope="module")
|
|
138
|
+
def orca_ES_result(digichem_options):
|
|
139
|
+
return parse_calculation(Path(data_directory(), "Pyridine/Orca Excited States TDA 10 Singlets 10 Triplets PBE0 (GD3BJ) Gas Phase Pople Basis Sets STO-3G.tar.gz"), options = digichem_options)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@pytest.mark.parametrize("result_set, num, final", [
|
|
143
|
+
(pytest.lazy_fixture("gaussian_SP_result"), 1, -10488.990333747),
|
|
144
|
+
(pytest.lazy_fixture("gaussian_opt_result"), 5, -10488.990333747),
|
|
145
|
+
(pytest.lazy_fixture("gaussian_ES_result"), 1, -10488.990333747),
|
|
146
|
+
(pytest.lazy_fixture("gaussian_opt_ES_result"), 4, -10488.883505795338),
|
|
147
|
+
(pytest.lazy_fixture("turbomole_ADC2_opt_result"), 7, -10432.311381999756),
|
|
148
|
+
(pytest.lazy_fixture("turbomole_ADC2_singlets_result"), 1, -10432.311386936175),
|
|
149
|
+
(pytest.lazy_fixture("turbomole_ADC2_triplets_result"), 1, -10432.311386936175)
|
|
150
|
+
])
|
|
151
|
+
def test_SCF_energy(result_set, num, final):
|
|
152
|
+
"""Test the parsed energy is correct"""
|
|
153
|
+
assert result_set.energies.scf.final == pytest.approx(final, abs=1e-5)
|
|
154
|
+
|
|
155
|
+
# Check length, which will be 1 for SP, and >1 for the opts.
|
|
156
|
+
assert len(result_set.energies.scf) == num
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@pytest.mark.parametrize("result_set, num, final", [
|
|
160
|
+
(pytest.lazy_fixture("turbomole_ADC2_opt_result"), 7, -10467.158186939303),
|
|
161
|
+
(pytest.lazy_fixture("turbomole_ADC2_singlets_result"), 1, -10467.158181211305),
|
|
162
|
+
(pytest.lazy_fixture("turbomole_ADC2_triplets_result"), 1, -10467.158181211305)
|
|
163
|
+
])
|
|
164
|
+
def test_MP_energy(result_set, num, final):
|
|
165
|
+
"""Test the parsed energy is correct"""
|
|
166
|
+
assert result_set.energies.mp.final == pytest.approx(final, abs=1e-5)
|
|
167
|
+
|
|
168
|
+
# Check length, which will be 1 for SP, and >1 for the opts.
|
|
169
|
+
assert len(result_set.energies.scf) == num
|
|
170
|
+
assert len(result_set.energies.mp) == num
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@pytest.mark.parametrize("result_set, charge, mult, energy", [
|
|
174
|
+
(pytest.lazy_fixture("gaussian_opt_result"), 0, 1, -10488.990333747),
|
|
175
|
+
(pytest.lazy_fixture("turbomole_ADC2_opt_result"), 0, 1, -10467.158186939303),
|
|
176
|
+
# Radical anions.
|
|
177
|
+
(pytest.lazy_fixture("gaussian_radical_anion_result"), -1, 2, -6310.5380531853125),
|
|
178
|
+
(pytest.lazy_fixture("turbomole_radical_anion_result"), -1, 2, -6310.4572047072043),
|
|
179
|
+
])
|
|
180
|
+
def test_ground_state(result_set, charge, mult, energy):
|
|
181
|
+
"""Test the ground state properties"""
|
|
182
|
+
|
|
183
|
+
assert result_set.ground_state.charge == charge
|
|
184
|
+
assert result_set.ground_state.multiplicity == mult
|
|
185
|
+
# Ground states have zero excited state energy by definition.
|
|
186
|
+
assert result_set.ground_state.energy == 0.0
|
|
187
|
+
# This is the total energy.
|
|
188
|
+
assert result_set.ground_state.absolute_energy == pytest.approx(energy, abs=1e-5)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@pytest.mark.parametrize("result_set", [
|
|
192
|
+
pytest.lazy_fixture("gaussian_SP_result"),
|
|
193
|
+
pytest.lazy_fixture("gaussian_opt_result"),
|
|
194
|
+
pytest.lazy_fixture("gaussian_ES_result"),
|
|
195
|
+
pytest.lazy_fixture("gaussian_opt_ES_result"),
|
|
196
|
+
pytest.lazy_fixture("turbomole_ADC2_opt_result"),
|
|
197
|
+
pytest.lazy_fixture("turbomole_ADC2_singlets_result"),
|
|
198
|
+
pytest.lazy_fixture("turbomole_ADC2_triplets_result"),
|
|
199
|
+
])
|
|
200
|
+
def test_atoms(result_set):
|
|
201
|
+
"""Test the parsed (unaligned) atoms are correct."""
|
|
202
|
+
# The molecule is Naphthalene; C10H8
|
|
203
|
+
# Check num atoms.
|
|
204
|
+
assert len(result_set.raw_atoms) == 18
|
|
205
|
+
|
|
206
|
+
# Check atom types.
|
|
207
|
+
assert result_set.raw_atoms.element_dict['C'] == 10
|
|
208
|
+
assert result_set.raw_atoms.element_dict['H'] == 8
|
|
209
|
+
|
|
210
|
+
# Check mass.
|
|
211
|
+
assert result_set.raw_atoms.molar_mass == pytest.approx(128.1705)
|
|
212
|
+
|
|
213
|
+
# We don't check positions here because these can vary from calc to calc due to reorientation...
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@pytest.mark.parametrize("result_set, length, width, height", [
|
|
217
|
+
(pytest.lazy_fixture("gaussian_SP_result"), 6.739394, 4.972394, 0.000004),
|
|
218
|
+
(pytest.lazy_fixture("gaussian_opt_result"), 6.739394, 4.972394, 0.000004),
|
|
219
|
+
(pytest.lazy_fixture("gaussian_ES_result"), 6.739394, 4.972394, 0.000004),
|
|
220
|
+
(pytest.lazy_fixture("turbomole_ADC2_opt_result"), 6.8000171599, 5.0161488999, 0.0000475622),
|
|
221
|
+
(pytest.lazy_fixture("turbomole_ADC2_singlets_result"), 6.8000171599, 5.0161488999, 0.0000475622),
|
|
222
|
+
(pytest.lazy_fixture("turbomole_ADC2_triplets_result"), 6.8000171599, 5.0161488999, 0.0000475622),
|
|
223
|
+
])
|
|
224
|
+
def test_alignment(result_set, length, width, height):
|
|
225
|
+
"""Test the aligned atom positions are correct."""
|
|
226
|
+
# Rounding errors plague parsing and conversion of atomic coordinates.
|
|
227
|
+
# Much of this error comes from the accuracy printed by the CC programs themselves,
|
|
228
|
+
# so there is not much we can do about it.
|
|
229
|
+
tolerance = 1e-5
|
|
230
|
+
|
|
231
|
+
# Dimensions in angstrom.
|
|
232
|
+
try:
|
|
233
|
+
linear_ratio = 1-(width/length)
|
|
234
|
+
except (FloatingPointError, ZeroDivisionError):
|
|
235
|
+
linear_ratio = 1.0
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
planar_ratio = 1-(height/width)
|
|
239
|
+
except (FloatingPointError, ZeroDivisionError):
|
|
240
|
+
planar_ratio = 1.0
|
|
241
|
+
|
|
242
|
+
# Check dimensions.
|
|
243
|
+
assert result_set.atoms.X_length == pytest.approx(length, abs=tolerance)
|
|
244
|
+
assert result_set.atoms.Y_length == pytest.approx(width, abs=tolerance)
|
|
245
|
+
assert result_set.atoms.Z_length == pytest.approx(height, abs=tolerance)
|
|
246
|
+
|
|
247
|
+
# Check params.
|
|
248
|
+
assert result_set.atoms.get_linear_ratio() == pytest.approx(linear_ratio, abs=tolerance)
|
|
249
|
+
assert result_set.atoms.get_planar_ratio() == pytest.approx(planar_ratio, abs=tolerance)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@pytest.mark.parametrize("result_set, num_occ, num_unocc, homo, lumo", [
|
|
253
|
+
(pytest.lazy_fixture("gaussian_opt_result"), 34, 156, -6.13072481, -0.92437071),
|
|
254
|
+
(pytest.lazy_fixture("turbomole_ADC2_opt_result"), 34, 146, -7.78345591, 2.37048311)
|
|
255
|
+
])
|
|
256
|
+
def test_orbitals(result_set, num_occ, num_unocc, homo, lumo):
|
|
257
|
+
"""Test the energies of the parsed MOs"""
|
|
258
|
+
check_orbitals(result_set.orbitals, num_occ, num_unocc, homo, lumo)
|
|
259
|
+
|
|
260
|
+
# Check spin labels
|
|
261
|
+
assert result_set.orbitals.spin_type == "none"
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@pytest.mark.parametrize("result_set, num_occ, num_unocc, homo, lumo", [
|
|
265
|
+
(pytest.lazy_fixture("gaussian_radical_anion_result"), (22, 21), (98, 99), (3.832451319, -0.0157826027), (6.268142298, 6.34270149)),
|
|
266
|
+
(pytest.lazy_fixture("turbomole_radical_anion_result"), (22, 21), (92, 93), (3.825336056180260069, 0.0034865153882969327284), (6.275672672175910627, 6.387468734183322283))
|
|
267
|
+
])
|
|
268
|
+
def test_unrestricted_orbitals(result_set, num_occ, num_unocc, homo, lumo):
|
|
269
|
+
"""Test the energies of unrestricted orbitals"""
|
|
270
|
+
# Check overall length.
|
|
271
|
+
assert len(result_set.orbitals) == len(result_set.beta_orbitals)
|
|
272
|
+
|
|
273
|
+
# Check each set of orbitals.
|
|
274
|
+
check_orbitals(result_set.orbitals, num_occ[0], num_unocc[0], homo[0], lumo[0])
|
|
275
|
+
check_orbitals(result_set.beta_orbitals, num_occ[1], num_unocc[1], homo[1], lumo[1])
|
|
276
|
+
|
|
277
|
+
# Check spin labels
|
|
278
|
+
assert result_set.orbitals.spin_type == "alpha"
|
|
279
|
+
assert result_set.beta_orbitals.spin_type == "beta"
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@pytest.mark.parametrize("result_set, num, index, frequency, intensity", [
|
|
283
|
+
(pytest.lazy_fixture("gaussian_opt_result"), 48, 13, 806.2853, 121.0015),
|
|
284
|
+
(pytest.lazy_fixture("gaussian_SP_result"), 0, None, None, None),
|
|
285
|
+
(pytest.lazy_fixture("turbomole_opt_result"), 48, 13, 805.28, 103.77),
|
|
286
|
+
])
|
|
287
|
+
def test_frequencies(result_set, num, index, frequency, intensity):
|
|
288
|
+
"""Test the vibrational frequencies are correct"""
|
|
289
|
+
|
|
290
|
+
# Check lengths.
|
|
291
|
+
assert len(result_set.vibrations) == num
|
|
292
|
+
assert len(result_set.vibrations.negative_frequencies) == 0
|
|
293
|
+
|
|
294
|
+
if index != None:
|
|
295
|
+
# Check one of the energies.
|
|
296
|
+
assert result_set.vibrations[index].frequency == pytest.approx(frequency)
|
|
297
|
+
assert result_set.vibrations[index].intensity == pytest.approx(intensity)
|
|
298
|
+
|
|
299
|
+
# Check the frequencies are ordered.
|
|
300
|
+
indices = [freq.level for freq in result_set.vibrations]
|
|
301
|
+
assert indices == list(range(1, num+1))
|
|
302
|
+
|
|
303
|
+
else:
|
|
304
|
+
with pytest.raises(IndexError):
|
|
305
|
+
result_set.vibrations[-1].frequency
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
@pytest.mark.parametrize("result_set, coords, axis_angle, plane_angle", [
|
|
309
|
+
(pytest.lazy_fixture("gaussian_PDM_result"), (0.0, 2.5103, 0.0), 90.0, 0.0),
|
|
310
|
+
(pytest.lazy_fixture("gaussian_PDM_ES_result"), (0.0001, -0.6147, 0.0001), 90.0, 0.0),
|
|
311
|
+
(pytest.lazy_fixture("turbomole_PDM_result"), (-0.000743401, -2.20405438, -0.000494493), 90.0, 0.0),
|
|
312
|
+
])
|
|
313
|
+
def test_pdm(result_set, coords, axis_angle, plane_angle):
|
|
314
|
+
"""Test the permanent dipole moment"""
|
|
315
|
+
|
|
316
|
+
check_dipole(result_set.pdm, coords)
|
|
317
|
+
|
|
318
|
+
# Check angles
|
|
319
|
+
assert float(result_set.pdm.X_axis_angle) == pytest.approx(axis_angle, abs=1e-1)
|
|
320
|
+
assert float(result_set.pdm.XY_plane_angle) == pytest.approx(plane_angle, abs=1e-1)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
@pytest.mark.parametrize("result_set, number, TDM", [
|
|
324
|
+
(pytest.lazy_fixture("gaussian_TDM_result"), 20, (0.0, -0.0003, 0.5879)),
|
|
325
|
+
(pytest.lazy_fixture("turbomole_TDM_result"), 10, (-0.000628, -0.000132, 0.558096))
|
|
326
|
+
])
|
|
327
|
+
def test_tedm(result_set, number, TDM):
|
|
328
|
+
"""Test transition dipole moments"""
|
|
329
|
+
# Check number of dipoles.
|
|
330
|
+
assert len([excited_state.transition_dipole_moment for excited_state in result_set.excited_states if excited_state.transition_dipole_moment.electric is not None]) == number
|
|
331
|
+
|
|
332
|
+
# Check the S1 moments are correct.
|
|
333
|
+
S1_TDM = result_set.excited_states.get_state("S(1)").transition_dipole_moment
|
|
334
|
+
|
|
335
|
+
# Check coords and magnitude.
|
|
336
|
+
check_dipole(S1_TDM.electric, TDM)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
@pytest.mark.parametrize("result_set, number, TDM", [
|
|
340
|
+
(pytest.lazy_fixture("gaussian_TDM_result"), 20, (0.6909, 0.0, 0.0)),
|
|
341
|
+
(pytest.lazy_fixture("turbomole_TDM_result"), 10, (0.673218, -0.000274, -0.000274))
|
|
342
|
+
])
|
|
343
|
+
def test_tmdm(result_set, number, TDM):
|
|
344
|
+
"""Test transition dipole moments"""
|
|
345
|
+
|
|
346
|
+
# Check number of dipoles.
|
|
347
|
+
assert len([excited_state.transition_dipole_moment for excited_state in result_set.excited_states if excited_state.transition_dipole_moment.magnetic is not None]) == number
|
|
348
|
+
|
|
349
|
+
# Check the S1 moments are correct.
|
|
350
|
+
S1_TDM = result_set.excited_states.get_state("S(1)").transition_dipole_moment
|
|
351
|
+
|
|
352
|
+
# Check coords and magnitude.
|
|
353
|
+
check_dipole(S1_TDM.magnetic, TDM, abs = 1e-3)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
@pytest.mark.parametrize("result_set, state, g_lum", [
|
|
357
|
+
(pytest.lazy_fixture("gaussian_TDM_result"), "S(5)", -0.995)
|
|
358
|
+
])
|
|
359
|
+
def test_g_lum(result_set, state, g_lum):
|
|
360
|
+
"""Test calculation of G(lum) values for circularly polarized light."""
|
|
361
|
+
|
|
362
|
+
TDM = result_set.excited_states.get_state(state).transition_dipole_moment
|
|
363
|
+
|
|
364
|
+
TEDM = TDM.electric.gaussian_cgs_vector
|
|
365
|
+
TMDM = TDM.magnetic.gaussian_cgs_vector
|
|
366
|
+
|
|
367
|
+
# Test values in Gaussian-CGS units.))
|
|
368
|
+
check_float_list(TEDM, tuple(254.35e-20 * i for i in TEDM))
|
|
369
|
+
check_float_list(TMDM, tuple(-0.97401e-20 * i for i in TMDM))
|
|
370
|
+
|
|
371
|
+
# Check angle.
|
|
372
|
+
angle = (TEDM[0] * TMDM[0] + TEDM[1] * TMDM[1] + TEDM[2] * TMDM[2]) / ( ((TEDM[0]**2 + TEDM[1] **2 + TEDM[2] **2)**0.5) * ((TMDM[0]**2 + TMDM[1] **2 + TMDM[2] **2)**0.5) )
|
|
373
|
+
assert TDM.cos_angle() == pytest.approx(angle)
|
|
374
|
+
|
|
375
|
+
# Check g_lum
|
|
376
|
+
assert TDM.g_value == pytest.approx(g_lum, abs=1e-3)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
@pytest.mark.parametrize("result_set, num_singlets, num_triplets, dest, state_label, state_index, state_symmetry, state_energy, state_f", [
|
|
380
|
+
(pytest.lazy_fixture("gaussian_ES_result"), 10, 10, 1.6231, "S(2)", 7, "Singlet-B1u", 4.7387, 0.1168),
|
|
381
|
+
(pytest.lazy_fixture("turbomole_ES_result"), 10, 10, 1.6298, "S(2)", 7, "Singlet-A", 4.790868037954573, 0.0805)
|
|
382
|
+
])
|
|
383
|
+
def test_excited_states(result_set, num_singlets, num_triplets, dest, state_label, state_index, state_symmetry, state_energy, state_f):
|
|
384
|
+
"""Test excited states"""
|
|
385
|
+
|
|
386
|
+
# Check number of states.
|
|
387
|
+
assert result_set.excited_states.num_singlets == num_singlets
|
|
388
|
+
assert result_set.excited_states.num_triplets == num_triplets
|
|
389
|
+
|
|
390
|
+
# Check singlet-triplet splitting energy (dE(ST)).
|
|
391
|
+
assert result_set.excited_states.singlet_triplet_energy == pytest.approx(dest, abs=1e-4)
|
|
392
|
+
|
|
393
|
+
# Now check a specific state.
|
|
394
|
+
state = result_set.excited_states.get_state(state_label)
|
|
395
|
+
assert state.level == state_index
|
|
396
|
+
assert state.symmetry == state_symmetry
|
|
397
|
+
assert state.energy == pytest.approx(state_energy, abs=1e-4)
|
|
398
|
+
assert state.oscillator_strength == pytest.approx(state_f, abs=1e-4)
|
|
399
|
+
|
|
400
|
+
# Check wavelength.
|
|
401
|
+
# e in J
|
|
402
|
+
joule_energy = state_energy * scipy.constants.physical_constants['electron volt'][0]
|
|
403
|
+
# wavelength in m
|
|
404
|
+
meter_wavelength = (scipy.constants.Planck * scipy.constants.c) / joule_energy
|
|
405
|
+
# wavelength in nm
|
|
406
|
+
wavelength = meter_wavelength *1000000000
|
|
407
|
+
|
|
408
|
+
assert state.wavelength == pytest.approx(wavelength, abs=1e-4)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@pytest.mark.parametrize("result_set, state_index, transition_index, start_orbital, end_orbital, coefficient", [
|
|
412
|
+
(pytest.lazy_fixture("gaussian_ES_result"), 1, 1, 34, 35, 0.957238734),
|
|
413
|
+
(pytest.lazy_fixture("gaussian_ES_result"), 1, 2, 32, 37, 0.186520627),
|
|
414
|
+
(pytest.lazy_fixture("gaussian_ES_result"), 1, 3, 33, 36, 0.175928167),
|
|
415
|
+
(pytest.lazy_fixture("turbomole_ES_result"), 2, 1, 33, 35, 0.772657751),
|
|
416
|
+
(pytest.lazy_fixture("turbomole_ES_result"), 2, 2, 34, 36, 0.618869938),
|
|
417
|
+
])
|
|
418
|
+
def test_excited_state_transitions(result_set, state_index, transition_index, start_orbital, end_orbital, coefficient):
|
|
419
|
+
"""Test excited state transitions."""
|
|
420
|
+
|
|
421
|
+
state = result_set.excited_states[state_index -1]
|
|
422
|
+
transition = state.transitions[transition_index -1]
|
|
423
|
+
|
|
424
|
+
assert transition.level == transition_index
|
|
425
|
+
assert transition.starting_mo.level == start_orbital
|
|
426
|
+
assert transition.ending_mo.level == end_orbital
|
|
427
|
+
assert transition.coefficient == pytest.approx(coefficient)
|
|
428
|
+
assert transition.probability == pytest.approx(coefficient **2)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
@pytest.mark.parametrize("result_set, transition_type, multiplicity, emission_type, energy, excited_energy, oscillator_strength, rate", [
|
|
432
|
+
(pytest.lazy_fixture("gaussian_emission_result"), "adiabatic", 1, "fluorescence", 4.542828007, -10484.452882954, 0.0, 312658.74889),
|
|
433
|
+
(pytest.lazy_fixture("gaussian_emission_result"), "vertical", 1, "fluorescence", 4.4360, -10484.452882954, 0.0, 291116.171714),
|
|
434
|
+
])
|
|
435
|
+
def test_emission(result_set, transition_type, multiplicity, emission_type, energy, excited_energy, oscillator_strength, rate):
|
|
436
|
+
# TODO: Testing of fluorescence rate should be moved to another module (where other calculated properties can be tested).
|
|
437
|
+
if transition_type == "adiabatic":
|
|
438
|
+
emission = result_set.emission.adiabatic[multiplicity]
|
|
439
|
+
|
|
440
|
+
else:
|
|
441
|
+
emission = result_set.emission.vertical[multiplicity]
|
|
442
|
+
|
|
443
|
+
# Test some general properties.
|
|
444
|
+
assert emission.transition_type == transition_type
|
|
445
|
+
assert emission.emission_type == emission_type
|
|
446
|
+
|
|
447
|
+
# Test numerical properties.
|
|
448
|
+
assert emission.energy == pytest.approx(energy)
|
|
449
|
+
assert emission.excited_energy == pytest.approx(excited_energy)
|
|
450
|
+
assert emission.oscillator_strength == pytest.approx(oscillator_strength)
|
|
451
|
+
assert emission.emission_rate == pytest.approx(rate)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def test_h_nmr_standard(orca_nmr_result):
|
|
455
|
+
reference = 31.68766666666667
|
|
456
|
+
# Check the reference standard is available.
|
|
457
|
+
assert all([nmr_result.shielding.reference == pytest.approx(reference, abs = 1e-4) for nmr_result in orca_nmr_result.nmr if nmr_result.atom.element.symbol == "H"])
|
|
458
|
+
|
|
459
|
+
def test_c_nmr_standard(orca_nmr_result):
|
|
460
|
+
reference = 197.90316666666664
|
|
461
|
+
# Check the reference standard is available.
|
|
462
|
+
assert all([nmr_result.shielding.reference == pytest.approx(reference, abs = 1e-4) for nmr_result in orca_nmr_result.nmr if nmr_result.atom.element.symbol == "C"])
|
|
463
|
+
|
|
464
|
+
def test_nmr_h_isotope_options(orca_nmr_result):
|
|
465
|
+
# Check we have the right options set for H.
|
|
466
|
+
options = orca_nmr_result.nmr.spectrometer.isotope_options(1, 1)
|
|
467
|
+
assert options['frequency'] == 400
|
|
468
|
+
assert options['fwhm'] == 0.005
|
|
469
|
+
assert options['gaussian_resolution'] == 0.0005
|
|
470
|
+
assert options['coupling_filter'] == 0.001
|
|
471
|
+
assert options['pre_merge'] == 0.0005
|
|
472
|
+
|
|
473
|
+
def test_nmr_c_isotope_options(orca_nmr_result):
|
|
474
|
+
# Check we have the right options set for H.
|
|
475
|
+
options = orca_nmr_result.nmr.spectrometer.isotope_options(6, 13)
|
|
476
|
+
assert options['frequency'] == 100.6
|
|
477
|
+
|
|
478
|
+
@pytest.mark.parametrize("result_set", [
|
|
479
|
+
pytest.lazy_fixture("gaussian_SP_result"),
|
|
480
|
+
pytest.lazy_fixture("gaussian_emission_result"),
|
|
481
|
+
pytest.lazy_fixture("turbomole_sp_result"),
|
|
482
|
+
pytest.lazy_fixture("orca_solvent_SP_result"),
|
|
483
|
+
])
|
|
484
|
+
def test_metadata_solvent(result_set):
|
|
485
|
+
"""Can we parse solution metadata correctly?"""
|
|
486
|
+
assert result_set.metadata.solvent.name == "Toluene"
|
|
487
|
+
# A bit of a rudimentary test, but there's already more advanced testing in cclib
|
|
488
|
+
assert result_set.metadata.solvent.model is not None
|
|
489
|
+
assert result_set.metadata.solvent.params['epsilon'] == pytest.approx(2.374, abs = 1e-3)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Tests for translation classes."""
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from digichem.translate import Solvent, Basis_set, Multiplicity, Functional,\
|
|
5
|
+
Cube_grid_points
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_solvent():
|
|
9
|
+
"""
|
|
10
|
+
Test conversions for DCM.
|
|
11
|
+
"""
|
|
12
|
+
# Get some different ways to represent DCM.
|
|
13
|
+
solvents = (Solvent("dcm"), Solvent("DCM"), Solvent("dichloroMethane"), Solvent("Dichloro Methane"))
|
|
14
|
+
|
|
15
|
+
# Check all have equivalent string representations.
|
|
16
|
+
assert all([str(solvents[0]) == str(solvent) for solvent in solvents])
|
|
17
|
+
|
|
18
|
+
# And the correct gaussian name.
|
|
19
|
+
assert all(["DiChloroMethane" == solvent.to_gaussian() for solvent in solvents])
|
|
20
|
+
|
|
21
|
+
# And epsilon
|
|
22
|
+
assert all([pytest.approx(8.93) == solvent.translate("epsilon") for solvent in solvents])
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_631g_str_str():
|
|
26
|
+
"""
|
|
27
|
+
Test conversions for basis sets.
|
|
28
|
+
"""
|
|
29
|
+
# Test both types of 6-31G**.
|
|
30
|
+
basis_sets = (Basis_set("6-31g(d,p)"), Basis_set("6-31G**"))
|
|
31
|
+
|
|
32
|
+
# Check both are equivalent.
|
|
33
|
+
assert str(basis_sets[0]) == str(basis_sets[1])
|
|
34
|
+
|
|
35
|
+
# Check Gaussian version.
|
|
36
|
+
assert all(["6-31G**" == basis_set.to_gaussian() for basis_set in basis_sets])
|
|
37
|
+
|
|
38
|
+
# Check Turbomole version.
|
|
39
|
+
assert all(["6-31G**" == basis_set.to_turbomole() for basis_set in basis_sets])
|
|
40
|
+
|
|
41
|
+
def test_def2_svp_p():
|
|
42
|
+
"""
|
|
43
|
+
Test weird gaussian name for def2-SV(P).
|
|
44
|
+
"""
|
|
45
|
+
assert Basis_set("def2-SV(P)").to_gaussian() == "def2SVPP"
|
|
46
|
+
|
|
47
|
+
@pytest.mark.parametrize("basis_set_name", ["def2-SVP", "def2-TZV", "def2-TZVP", "def2-QZV", "def2-QZVP"])
|
|
48
|
+
def test_karlsruhe(basis_set_name):
|
|
49
|
+
"""
|
|
50
|
+
Test weird gaussian names for Karlsruhe basis sets.
|
|
51
|
+
"""
|
|
52
|
+
assert "-" not in Basis_set(basis_set_name).to_gaussian()
|
|
53
|
+
|
|
54
|
+
def test_ccpvdz():
|
|
55
|
+
assert Basis_set("cc-PvDz").to_gaussian() == "cc-pVDZ"
|
|
56
|
+
assert str(Basis_set("cc-PvDz")) == "cc-pVDZ"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_b3lyp():
|
|
60
|
+
"""
|
|
61
|
+
Test conversions for DFT functionals.
|
|
62
|
+
"""
|
|
63
|
+
funcs = (Functional("b3-LYp"), Functional("B3lyp"))
|
|
64
|
+
|
|
65
|
+
assert all(["b3-lyp" == func.to_turbomole() for func in funcs])
|
|
66
|
+
|
|
67
|
+
assert all(["B3LYP" == func.to_gaussian() for func in funcs])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_pbe0gaussian():
|
|
71
|
+
# Turbomole functionals are case sensitive. This is particularly annoying because functional
|
|
72
|
+
# names are all lower-case, except for the word 'Gaussian'. Check this.
|
|
73
|
+
assert Functional("PBE0 gaussian").to_turbomole() == "pbe0 Gaussian"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_multiplicity():
|
|
77
|
+
"""
|
|
78
|
+
Test conversion for multiplicity.
|
|
79
|
+
"""
|
|
80
|
+
mults = (Multiplicity(1), Multiplicity("1"), Multiplicity("singlet"), Multiplicity("sInGlEt"), Multiplicity("S"))
|
|
81
|
+
|
|
82
|
+
# Check conversions.
|
|
83
|
+
assert all(["Singlet" == mult.to_gaussian() for mult in mults])
|
|
84
|
+
|
|
85
|
+
assert all([1 == mult.to_turbomole() for mult in mults])
|
|
86
|
+
|
|
87
|
+
assert all(["S" == mult.symbol for mult in mults])
|
|
88
|
+
|
|
89
|
+
assert all([1 == mult.number for mult in mults])
|
|
90
|
+
|
|
91
|
+
assert all(["Singlet" == mult.string for mult in mults])
|
|
92
|
+
|
|
93
|
+
def test_grid_points():
|
|
94
|
+
"""
|
|
95
|
+
Test different names for cube grid points.
|
|
96
|
+
"""
|
|
97
|
+
# Check the special 'Default' value is correct.
|
|
98
|
+
default = Cube_grid_points("default")
|
|
99
|
+
|
|
100
|
+
assert default.translate("gaussian") == 0
|
|
101
|
+
assert default.translate("orca") == 100
|
|
102
|
+
assert default.translate("turbomole") == 100
|
|
103
|
+
|
|
104
|
+
# Check the named values.
|
|
105
|
+
for name, value in [("Tiny", 25), ("Small", 50), ("Medium", 100), ("Large", 200), ("Huge", 500)]:
|
|
106
|
+
assert Cube_grid_points(name).translate("points") == value
|
|
107
|
+
|
|
108
|
+
# Check a random value.
|
|
109
|
+
assert Cube_grid_points(123).translate("points") == 123
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|