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.
Files changed (111) hide show
  1. digichem/__init__.py +75 -0
  2. digichem/basis.py +116 -0
  3. digichem/config/README +3 -0
  4. digichem/config/__init__.py +5 -0
  5. digichem/config/base.py +321 -0
  6. digichem/config/locations.py +14 -0
  7. digichem/config/parse.py +90 -0
  8. digichem/config/util.py +117 -0
  9. digichem/data/README +4 -0
  10. digichem/data/batoms/COPYING +18 -0
  11. digichem/data/batoms/LICENSE +674 -0
  12. digichem/data/batoms/README +2 -0
  13. digichem/data/batoms/__init__.py +0 -0
  14. digichem/data/batoms/batoms-renderer.py +351 -0
  15. digichem/data/config/digichem.yaml +714 -0
  16. digichem/data/functionals.csv +15 -0
  17. digichem/data/solvents.csv +185 -0
  18. digichem/data/tachyon/COPYING.md +5 -0
  19. digichem/data/tachyon/LICENSE +30 -0
  20. digichem/data/tachyon/tachyon_LINUXAMD64 +0 -0
  21. digichem/data/vmd/common.tcl +468 -0
  22. digichem/data/vmd/generate_combined_orbital_images.tcl +70 -0
  23. digichem/data/vmd/generate_density_images.tcl +45 -0
  24. digichem/data/vmd/generate_dipole_images.tcl +68 -0
  25. digichem/data/vmd/generate_orbital_images.tcl +57 -0
  26. digichem/data/vmd/generate_spin_images.tcl +66 -0
  27. digichem/data/vmd/generate_structure_images.tcl +40 -0
  28. digichem/datas.py +14 -0
  29. digichem/exception/__init__.py +7 -0
  30. digichem/exception/base.py +133 -0
  31. digichem/exception/uncatchable.py +63 -0
  32. digichem/file/__init__.py +1 -0
  33. digichem/file/base.py +364 -0
  34. digichem/file/cube.py +284 -0
  35. digichem/file/fchk.py +94 -0
  36. digichem/file/prattle.py +277 -0
  37. digichem/file/types.py +97 -0
  38. digichem/image/__init__.py +6 -0
  39. digichem/image/base.py +113 -0
  40. digichem/image/excited_states.py +335 -0
  41. digichem/image/graph.py +293 -0
  42. digichem/image/orbitals.py +239 -0
  43. digichem/image/render.py +617 -0
  44. digichem/image/spectroscopy.py +797 -0
  45. digichem/image/structure.py +115 -0
  46. digichem/image/vmd.py +826 -0
  47. digichem/input/__init__.py +3 -0
  48. digichem/input/base.py +78 -0
  49. digichem/input/digichem_input.py +500 -0
  50. digichem/input/gaussian.py +140 -0
  51. digichem/log.py +179 -0
  52. digichem/memory.py +166 -0
  53. digichem/misc/__init__.py +4 -0
  54. digichem/misc/argparse.py +44 -0
  55. digichem/misc/base.py +61 -0
  56. digichem/misc/io.py +239 -0
  57. digichem/misc/layered_dict.py +285 -0
  58. digichem/misc/text.py +139 -0
  59. digichem/misc/time.py +73 -0
  60. digichem/parse/__init__.py +13 -0
  61. digichem/parse/base.py +220 -0
  62. digichem/parse/cclib.py +138 -0
  63. digichem/parse/dump.py +253 -0
  64. digichem/parse/gaussian.py +130 -0
  65. digichem/parse/orca.py +96 -0
  66. digichem/parse/turbomole.py +201 -0
  67. digichem/parse/util.py +523 -0
  68. digichem/result/__init__.py +6 -0
  69. digichem/result/alignment/AA.py +114 -0
  70. digichem/result/alignment/AAA.py +61 -0
  71. digichem/result/alignment/FAP.py +148 -0
  72. digichem/result/alignment/__init__.py +3 -0
  73. digichem/result/alignment/base.py +310 -0
  74. digichem/result/angle.py +153 -0
  75. digichem/result/atom.py +742 -0
  76. digichem/result/base.py +258 -0
  77. digichem/result/dipole_moment.py +332 -0
  78. digichem/result/emission.py +402 -0
  79. digichem/result/energy.py +323 -0
  80. digichem/result/excited_state.py +821 -0
  81. digichem/result/ground_state.py +94 -0
  82. digichem/result/metadata.py +644 -0
  83. digichem/result/multi.py +98 -0
  84. digichem/result/nmr.py +1086 -0
  85. digichem/result/orbital.py +647 -0
  86. digichem/result/result.py +244 -0
  87. digichem/result/soc.py +272 -0
  88. digichem/result/spectroscopy.py +514 -0
  89. digichem/result/tdm.py +267 -0
  90. digichem/result/vibration.py +167 -0
  91. digichem/test/__init__.py +6 -0
  92. digichem/test/conftest.py +4 -0
  93. digichem/test/test_basis.py +71 -0
  94. digichem/test/test_calculate.py +30 -0
  95. digichem/test/test_config.py +78 -0
  96. digichem/test/test_cube.py +369 -0
  97. digichem/test/test_exception.py +16 -0
  98. digichem/test/test_file.py +104 -0
  99. digichem/test/test_image.py +337 -0
  100. digichem/test/test_input.py +64 -0
  101. digichem/test/test_parsing.py +79 -0
  102. digichem/test/test_prattle.py +36 -0
  103. digichem/test/test_result.py +489 -0
  104. digichem/test/test_translate.py +112 -0
  105. digichem/test/util.py +207 -0
  106. digichem/translate.py +591 -0
  107. digichem_core-6.0.0rc1.dist-info/METADATA +96 -0
  108. digichem_core-6.0.0rc1.dist-info/RECORD +111 -0
  109. digichem_core-6.0.0rc1.dist-info/WHEEL +4 -0
  110. digichem_core-6.0.0rc1.dist-info/licenses/COPYING.md +10 -0
  111. 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
+