1# This file is part of cclib (http://cclib.github.io), a library for parsing
2# and interpreting the results of computational chemistry packages.
3#
4# Copyright (C) 2020, the cclib development team
5#
6# The library is free software, distributed under the terms of
7# the GNU Lesser General Public version 2.1 or later. You should have
8# received a copy of the license along with cclib. You can also access
9# the full license online at http://www.gnu.org/copyleft/lgpl.html.
10
11"""A regression framework for parsing and testing logfiles.
12
13The intention here is to make it easy to add new datafiles as bugs
14are fixed and to write specific tests in the form of test functions.
15
16In short, the file called regressionfiles.txt contains a list of regression
17logfiles, which is compared to the files found on disk. All these files
18should be parsed correctly, and if there is an appropriately named function
19defined, that function will be used as a test.
20
21There is also a mechanism for running unit tests on old logfiles, which
22have been moved here from the cclib repository when newer versions
23became available. We still want those logfiles to parse and test correctly,
24although sometimes special modification will be needed.
25
26To run the doctest, run `python -m test.regression` from the top level
27directory in the cclib repository.
28
29Running all regression can take anywhere from 10-20s to several minutes
30depending in your hardware. To aid debugging, there are two ways to limit
31which regressions to parse and test. You can limit the test to a specific
32parse, for example:
33    python -m test.regression Gaussian
34You can also limit a run to a single output file, using it's relative path
35inside the data directory, like so:
36    python -m test.regression Gaussian/Gaussian03/borane-opt.log
37"""
38
39import glob
40import logging
41import os
42import sys
43import traceback
44import unittest
45import datetime
46import numpy
47from packaging.version import parse as parse_version
48from packaging.version import Version
49
50from cclib.parser.utils import convertor
51
52from cclib.parser import ccData
53
54from cclib.parser import ADF
55from cclib.parser import DALTON
56from cclib.parser import FChk
57from cclib.parser import GAMESS
58from cclib.parser import GAMESSUK
59from cclib.parser import Gaussian
60from cclib.parser import Jaguar
61from cclib.parser import Molcas
62from cclib.parser import Molpro
63from cclib.parser import MOPAC
64from cclib.parser import NWChem
65from cclib.parser import ORCA
66from cclib.parser import Psi3
67from cclib.parser import Psi4
68from cclib.parser import QChem
69from cclib.parser import Turbomole
70
71from cclib.io import ccopen, ccread, moldenwriter
72
73# This assume that the cclib-data repository is located at a specific location
74# within the cclib repository. It would be better to figure out a more natural
75# way to import the relevant tests from cclib here.
76test_dir = os.path.realpath(os.path.dirname(__file__)) + "/../../test"
77# This is safer than sys.path.append, and isn't sys.path.insert(0, ...) so
78# virtualenvs work properly. See https://stackoverflow.com/q/10095037.
79sys.path.insert(1, os.path.abspath(test_dir))
80from .test_data import all_modules
81from .test_data import all_parsers
82from .test_data import module_names
83from .test_data import parser_names
84from .test_data import get_program_dir
85
86
87# We need this to point to files relative to this script.
88__filedir__ = os.path.abspath(os.path.dirname(__file__))
89__regression_dir__ = os.path.join(__filedir__, "../data/regression/")
90
91
92# The following regression test functions were manually written, because they
93# contain custom checks that were determined on a per-file basis. Care needs to be taken
94# that the function name corresponds to the path of the logfile, with some characters
95# changed according to normalisefilename().
96
97# ADF #
98
99def testADF_ADF2004_01_Fe_ox3_final_out(logfile):
100    """Make sure HOMOS are correct."""
101    assert logfile.data.homos[0] == 59 and logfile.data.homos[1] == 54
102
103    assert logfile.data.metadata["legacy_package_version"] == "2004.01"
104    assert logfile.data.metadata["package_version"] == "2004.01+200410211341"
105    assert isinstance(
106        parse_version(logfile.data.metadata["package_version"]), Version
107    )
108
109
110def testADF_ADF2013_01_dvb_gopt_b_unconverged_adfout(logfile):
111    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
112    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
113
114    assert logfile.data.metadata["legacy_package_version"] == "2013.01"
115    assert logfile.data.metadata["package_version"] == "2013.01+201309012319"
116    assert isinstance(
117        parse_version(logfile.data.metadata["package_version"]), Version
118    )
119
120
121def testADF_ADF2013_01_stopiter_dvb_sp_adfout(logfile):
122    """This logfile has not SCF test lines so we have no way to check what happens."""
123    # This is what we would have checked:
124    # len(logfile.data.scfvalues[0]) == 10
125    assert not hasattr(logfile.data, "scfvalues")
126
127    assert logfile.data.metadata["package_version"] == "2013.01+201309012319"
128
129
130def testADF_ADF2013_01_stopiter_dvb_sp_b_adfout(logfile):
131    """Check to ensure that an incomplete SCF is handled correctly."""
132    # Why is this not 3?
133    assert len(logfile.data.scfvalues[0]) == 2
134
135    assert logfile.data.metadata["package_version"] == "2013.01+201309012319"
136
137
138def testADF_ADF2013_01_stopiter_dvb_sp_c_adfout(logfile):
139    """This logfile has not SCF test lines so we have no way to check what happens."""
140    # This is what we would have checked:
141    # len(logfile.data.scfvalues[0]) == 6
142    assert not hasattr(logfile.data, "scfvalues")
143
144    assert logfile.data.metadata["package_version"] == "2013.01+201309012319"
145
146
147def testADF_ADF2013_01_stopiter_dvb_sp_d_adfout(logfile):
148    """This logfile has not SCF test lines so we have no way to check what happens."""
149    # This is what we would have checked:
150    # len(logfile.data.scfvalues[0]) == 7
151    assert not hasattr(logfile.data, "scfvalues")
152
153    assert logfile.data.metadata["package_version"] == "2013.01+201309012319"
154
155
156def testADF_ADF2013_01_stopiter_dvb_un_sp_adfout(logfile):
157    """This logfile has not SCF test lines so we have no way to check what happens."""
158    # This is what we would have checked:
159    # len(logfile.data.scfvalues[0]) == 7
160    assert not hasattr(logfile.data, "scfvalues")
161
162    assert logfile.data.metadata["package_version"] == "2013.01+201309012319"
163
164
165def testADF_ADF2013_01_stopiter_dvb_un_sp_c_adfout(logfile):
166    """This logfile has not SCF test lines so we have no way to check what happens."""
167    # This is what we would have checked:
168    # len(logfile.data.scfvalues[0]) == 10
169    assert not hasattr(logfile.data, "scfvalues")
170
171    assert logfile.data.metadata["package_version"] == "2013.01+201309012319"
172
173
174def testADF_ADF2013_01_stopiter_MoOCl4_sp_adfout(logfile):
175    """This logfile has not SCF test lines so we have no way to check what happens."""
176    # This is what we would have checked:
177    # len(logfile.data.scfvalues[0]) == 11
178    assert not hasattr(logfile.data, "scfvalues")
179
180    assert logfile.data.metadata["package_version"] == "2013.01+201309012319"
181
182
183def testADF_ADF2014_01_DMO_ORD_orig_out(logfile):
184    """In lieu of a unit test, make sure the polarizability (and
185    potentially later the optical rotation) is properly parsed.
186    """
187    assert hasattr(logfile.data, 'polarizabilities')
188    assert len(logfile.data.polarizabilities) == 1
189    assert logfile.data.polarizabilities[0].shape == (3, 3)
190
191    # isotropic polarizability
192    isotropic_calc = numpy.average(numpy.diag(logfile.data.polarizabilities[0]))
193    isotropic_ref = 51.3359
194    assert abs(isotropic_calc - isotropic_ref) < 1.0e-4
195
196    assert logfile.data.metadata["legacy_package_version"] == "2014"
197    assert logfile.data.metadata["package_version"] == "2014dev42059"
198    assert isinstance(
199        parse_version(logfile.data.metadata["package_version"]), Version
200    )
201    assert logfile.data.metadata["package_version_date"] == "2014-06-11"
202    assert logfile.data.metadata["package_version_description"] == "development version"
203
204
205def testADF_ADF2016_166_tddft_0_31_new_out(logfile):
206    """This file led to StopIteration (#430)."""
207    assert logfile.data.metadata["legacy_package_version"] == "2016"
208    assert logfile.data.metadata["package_version"] == "2016dev53619"
209    assert isinstance(
210        parse_version(logfile.data.metadata["package_version"]), Version
211    )
212    assert logfile.data.metadata["package_version_date"] == "2016-07-21"
213    assert "package_version_description" not in logfile.data.metadata
214
215
216def testADF_ADF2016_fa2_adf_out(logfile):
217    """This logfile, without symmetry, should get atombasis parsed."""
218    assert hasattr(logfile.data, "atombasis")
219    assert [b for ab in logfile.data.atombasis for b in ab] == list(range(logfile.data.nbasis))
220
221    assert logfile.data.metadata["legacy_package_version"] == "2016"
222    assert logfile.data.metadata["package_version"] == "2016dev50467"
223    assert isinstance(
224        parse_version(logfile.data.metadata["package_version"]), Version
225    )
226    assert logfile.data.metadata["package_version_date"] == "2016-02-17"
227    assert logfile.data.metadata["package_version_description"] == "branches/AndrewAtkins/ADF-Shar"
228
229
230# DALTON #
231
232
233def testDALTON_DALTON_2013_dvb_td_normalprint_out(logfile):
234    r"""This original unit test prints a DFT-specific version of the excitation
235    eigenvectors, which we do not parse.
236
237    Here is an example of the general output (requiring `**RESPONSE/.PRINT 4`
238    for older versions of DALTON), followed by "PBHT MO Overlap Diagnostic"
239    which only appears for DFT calculations. Note that the reason we cannot
240    parse this for etsyms is it doesn't contain the necessary
241    coefficient. "K_IA" and "(r s) operator", which is $\kappa_{rs}$, the
242    coefficient for excitation from the r -> s MO in the response vector, is
243    not what most programs print; it is "(r s) scaled", which is $\kappa_{rs}
244    * \sqrt{S_{rr} - S_{ss}}$. Because this isn't available from the PBHT
245    output, we cannot parse it.
246
247         Eigenvector for state no.  1
248
249             Response orbital operator symmetry = 1
250             (only scaled elements abs greater than   10.00 % of max abs value)
251
252              Index(r,s)      r      s        (r s) operator      (s r) operator      (r s) scaled        (s r) scaled
253              ----------    -----  -----      --------------      --------------      --------------      --------------
254                 154        27(2)  28(2)        0.5645327267        0.0077924161        0.7983698385        0.0110201405
255                 311        58(4)  59(4)       -0.4223079545        0.0137981027       -0.5972336367        0.0195134639
256
257        ...
258
259                                    PBHT MO Overlap Diagnostic
260                                    --------------------------
261
262              I    A    K_IA      K_AI   <|I|*|A|> <I^2*A^2>    Weight   Contrib
263
264             27   28  0.564533  0.007792  0.790146  0.644560  0.309960  0.244913
265             58   59 -0.422308  0.013798  0.784974  0.651925  0.190188  0.149293
266
267    In the future, if `aooverlaps` and `mocoeffs` are available, it may be
268    possible to calculate the necessary scaled coefficients for `etsecs`.
269    """
270    assert hasattr(logfile.data, "etenergies")
271    assert not hasattr(logfile.data, "etsecs")
272    assert hasattr(logfile.data, "etsyms")
273    assert hasattr(logfile.data, "etoscs")
274
275    assert logfile.data.metadata["legacy_package_version"] == "2013.4"
276    assert logfile.data.metadata["package_version"] == "2013.4+7abef2ada27562fe5e02849d6caeaa67c961732f"
277    assert isinstance(
278        parse_version(logfile.data.metadata["package_version"]), Version
279    )
280
281
282def testDALTON_DALTON_2015_dalton_atombasis_out(logfile):
283    """This logfile didn't parse due to the absence of a line in the basis
284    set section.
285    """
286    assert hasattr(logfile.data, "nbasis")
287    assert logfile.data.nbasis == 37
288    assert hasattr(logfile.data, "atombasis")
289
290    assert logfile.data.metadata["legacy_package_version"] == "2015.0"
291    assert logfile.data.metadata["package_version"] == "2015.0+d34efb170c481236ad60c789dea90a4c857c6bab"
292    assert isinstance(
293        parse_version(logfile.data.metadata["package_version"]), Version
294    )
295
296
297def testDALTON_DALTON_2015_dalton_intgrl_out(logfile):
298    """This logfile didn't parse due to the absence of a line in the basis
299    set section.
300    """
301    assert hasattr(logfile.data, "nbasis")
302    assert logfile.data.nbasis == 4
303    assert hasattr(logfile.data, "atombasis")
304
305    assert logfile.data.metadata["package_version"] == "2015.0+d34efb170c481236ad60c789dea90a4c857c6bab"
306
307
308def testDALTON_DALTON_2015_dvb_td_normalprint_out(logfile):
309    """This original unit test prints a DFT-specific version of the excitation
310    eigenvectors, which we do not parse.
311    """
312    assert hasattr(logfile.data, "etenergies")
313    assert not hasattr(logfile.data, "etsecs")
314    assert hasattr(logfile.data, "etsyms")
315    assert hasattr(logfile.data, "etoscs")
316
317    assert logfile.data.metadata["package_version"] == "2015.0+d34efb170c481236ad60c789dea90a4c857c6bab"
318
319
320def testDALTON_DALTON_2015_stopiter_dalton_dft_out(logfile):
321    """Check to ensure that an incomplete SCF is handled correctly."""
322    assert len(logfile.data.scfvalues[0]) == 8
323
324    assert logfile.data.metadata["package_version"] == "2015.0+d34efb170c481236ad60c789dea90a4c857c6bab"
325
326
327def testDALTON_DALTON_2015_stopiter_dalton_hf_out(logfile):
328    """Check to ensure that an incomplete SCF is handled correctly."""
329    assert len(logfile.data.scfvalues[0]) == 5
330
331    assert logfile.data.metadata["package_version"] == "2015.0+d34efb170c481236ad60c789dea90a4c857c6bab"
332
333
334def testDALTON_DALTON_2016_huge_neg_polar_freq_out(logfile):
335    """This is an example of a multiple frequency-dependent polarizability
336    calculation.
337    """
338    assert hasattr(logfile.data, "polarizabilities")
339    assert len(logfile.data.polarizabilities) == 3
340    assert abs(logfile.data.polarizabilities[2][0, 0] - 183.6308) < 1.0e-5
341
342    assert logfile.data.metadata["legacy_package_version"] == "2016.2"
343    assert logfile.data.metadata["package_version"] == "2016.2+7db4647eac203e51aae7da3cbc289f55146b30e9"
344    assert isinstance(
345        parse_version(logfile.data.metadata["package_version"]), Version
346    )
347
348
349def testDALTON_DALTON_2016_huge_neg_polar_stat_out(logfile):
350    """This logfile didn't parse due to lack of spacing between
351    polarizability tensor elements.
352    """
353    assert hasattr(logfile.data, "polarizabilities")
354    assert len(logfile.data.polarizabilities) == 1
355    assert abs(logfile.data.polarizabilities[0][1, 1] + 7220.150408) < 1.0e-7
356
357    assert logfile.data.metadata["package_version"] == "2016.2+7db4647eac203e51aae7da3cbc289f55146b30e9"
358
359
360def testDALTON_DALTON_2016_Trp_polar_response_diplnx_out(logfile):
361    """Check that only the xx component of polarizability is defined and
362    all others are NaN even after parsing a previous file with full tensor.
363    """
364    full_tens_path = os.path.join(__regression_dir__, "DALTON/DALTON-2015/Trp_polar_response.out")
365    DALTON(full_tens_path, loglevel=logging.ERROR).parse()
366    assert hasattr(logfile.data, "polarizabilities")
367    assert abs(logfile.data.polarizabilities[0][0, 0] - 95.11540019) < 1.0e-8
368    assert numpy.count_nonzero(numpy.isnan(logfile.data.polarizabilities)) == 8
369
370    assert logfile.data.metadata["package_version"] == "2016.2+7db4647eac203e51aae7da3cbc289f55146b30e9"
371
372
373def testDALTON_DALTON_2018_dft_properties_nosym_H2O_cc_pVDZ_out(logfile):
374    """The "simple" version string in newer development versions of DALTON wasn't
375    being parsed properly.
376
377    This file is in DALTON-2018, rather than DALTON-2019, because 2018.0 was
378    just released.
379    """
380    assert logfile.data.metadata["legacy_package_version"] == "2019.alpha"
381    assert logfile.data.metadata["package_version"] == "2019.alpha"
382    assert isinstance(
383        parse_version(logfile.data.metadata["package_version"]), Version
384    )
385
386
387def testDALTON_DALTON_2018_tdhf_2000_out(logfile):
388    """Ensure etsecs are being parsed from a TDHF calculation without symmetry and
389    a big print level.
390    """
391    assert hasattr(logfile.data, "etsecs")
392    for attr in ("etenergies", "etsecs", "etsyms", "etoscs"):
393        assert len(getattr(logfile.data, attr)) == 9
394    assert logfile.data.etsecs[0][0] == [(1, 0), (2, 0), -0.9733558768]
395
396    assert logfile.data.metadata["legacy_package_version"] == "2019.alpha"
397    assert logfile.data.metadata["package_version"] == "2019.alpha+25947a3d842ee2ebb42bff87a4dd64adbbd3ec5b"
398    assert isinstance(
399        parse_version(logfile.data.metadata["package_version"]), Version
400    )
401
402
403def testDALTON_DALTON_2018_tdhf_2000_sym_out(logfile):
404    """Ensure etsecs are being parsed from a TDHF calculation with symmetry and a
405    big print level.
406    """
407    assert hasattr(logfile.data, "etsecs")
408    for attr in ("etenergies", "etsecs", "etsyms", "etoscs"):
409        assert len(getattr(logfile.data, attr)) == 3
410    assert logfile.data.etsecs[0][0] == [(1, 0), (2, 0), 0.9733562358]
411
412    assert logfile.data.metadata["package_version"] == "2019.alpha+25947a3d842ee2ebb42bff87a4dd64adbbd3ec5b"
413
414
415def testDALTON_DALTON_2018_tdhf_normal_out(logfile):
416    """Ensure etsecs are being parsed from a TDHF calculation without symmetry and
417    a normal print level.
418    """
419    assert hasattr(logfile.data, "etsecs")
420    for attr in ("etenergies", "etsecs", "etsyms", "etoscs"):
421        assert len(getattr(logfile.data, attr)) == 9
422    assert logfile.data.etsecs[0][0] == [(1, 0), (2, 0), -0.9733558768]
423
424    assert logfile.data.metadata["package_version"] == "2019.alpha+25947a3d842ee2ebb42bff87a4dd64adbbd3ec5b"
425
426
427def testDALTON_DALTON_2018_tdhf_normal_sym_out(logfile):
428    """Ensure etsecs are being parsed from a TDHF calculation with symmetry and a
429    normal print level.
430    """
431    assert hasattr(logfile.data, "etsecs")
432    for attr in ("etenergies", "etsecs", "etsyms", "etoscs"):
433        assert len(getattr(logfile.data, attr)) == 3
434    assert logfile.data.etsecs[0][0] == [(1, 0), (2, 0), 0.9733562358]
435
436    assert logfile.data.metadata["package_version"] == "2019.alpha+25947a3d842ee2ebb42bff87a4dd64adbbd3ec5b"
437
438
439def testDALTON_DALTON_2018_tdpbe_2000_out(logfile):
440    """Ensure etsecs are being parsed from a TDDFT calculation without symmetry
441    and a big print level.
442    """
443    assert hasattr(logfile.data, "etsecs")
444    for attr in ("etenergies", "etsecs", "etsyms", "etoscs"):
445        assert len(getattr(logfile.data, attr)) == 9
446    assert logfile.data.etsecs[0][0] == [(1, 0), (2, 0), 0.9992665559]
447
448    assert logfile.data.metadata["package_version"] == "2019.alpha+25947a3d842ee2ebb42bff87a4dd64adbbd3ec5b"
449
450
451def testDALTON_DALTON_2018_tdpbe_2000_sym_out(logfile):
452    """Ensure etsecs are being parsed from a TDDFT calculation with symmetry and a
453    big print level.
454    """
455    assert hasattr(logfile.data, "etsecs")
456    for attr in ("etenergies", "etsecs", "etsyms", "etoscs"):
457        assert len(getattr(logfile.data, attr)) == 3
458    assert logfile.data.etsecs[0][0] == [(1, 0), (2, 0), 0.9992672154]
459
460    assert logfile.data.metadata["package_version"] == "2019.alpha+25947a3d842ee2ebb42bff87a4dd64adbbd3ec5b"
461
462
463def testDALTON_DALTON_2018_tdpbe_normal_out(logfile):
464    """Ensure etsecs are being parsed from a TDDFT calculation without symmetry
465    and a normal print level.
466    """
467    assert hasattr(logfile.data, "etsecs")
468    for attr in ("etenergies", "etsecs", "etsyms", "etoscs"):
469        assert len(getattr(logfile.data, attr)) == 9
470    assert logfile.data.etsecs[0][0] == [(1, 0), (2, 0), 0.9992665559]
471
472    assert logfile.data.metadata["package_version"] == "2019.alpha+25947a3d842ee2ebb42bff87a4dd64adbbd3ec5b"
473
474
475def testDALTON_DALTON_2018_tdpbe_normal_sym_out(logfile):
476    """Ensure etsecs are being parsed from a TDDFT calculation with symmetry and a
477    normal print level.
478    """
479    assert hasattr(logfile.data, "etsecs")
480    for attr in ("etenergies", "etsecs", "etsyms", "etoscs"):
481        assert len(getattr(logfile.data, attr)) == 3
482    assert logfile.data.etsecs[0][0] == [(1, 0), (2, 0), 0.9992672154]
483
484    assert logfile.data.metadata["package_version"] == "2019.alpha+25947a3d842ee2ebb42bff87a4dd64adbbd3ec5b"
485
486
487# Firefly #
488
489
490def testGAMESS_Firefly8_0_dvb_gopt_a_unconverged_out(logfile):
491    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
492    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
493
494    assert logfile.data.metadata["legacy_package_version"] == "8.0.1"
495    assert logfile.data.metadata["package_version"] == "8.0.1+8540"
496    assert isinstance(
497        parse_version(logfile.data.metadata["package_version"]), Version
498    )
499
500
501def testGAMESS_Firefly8_0_h2o_log(logfile):
502    """Check that molecular orbitals are parsed correctly (cclib/cclib#208)."""
503    assert logfile.data.mocoeffs[0][0][0] == -0.994216
504
505    assert logfile.data.metadata["legacy_package_version"] == "8.0.0"
506    assert logfile.data.metadata["package_version"] == "8.0.0+7651"
507    assert isinstance(
508        parse_version(logfile.data.metadata["package_version"]), Version
509    )
510
511
512def testGAMESS_Firefly8_0_stopiter_firefly_out(logfile):
513    """Check to ensure that an incomplete SCF is handled correctly."""
514    assert len(logfile.data.scfvalues[0]) == 6
515
516    assert logfile.data.metadata["package_version"] == "8.0.1+8540"
517
518
519def testGAMESS_Firefly8_1_benzene_am1_log(logfile):
520    """Molecular orbitals were not parsed (cclib/cclib#228)."""
521    assert hasattr(logfile.data, 'mocoeffs')
522
523    assert logfile.data.metadata["legacy_package_version"] == "8.1.0"
524    assert logfile.data.metadata["package_version"] == "8.1.0+9035"
525    assert isinstance(
526        parse_version(logfile.data.metadata["package_version"]), Version
527    )
528
529
530def testGAMESS_Firefly8_1_naphtalene_t_0_out(logfile):
531    """Molecular orbitals were not parsed (cclib/cclib#228)."""
532    assert hasattr(logfile.data, 'mocoeffs')
533
534    assert logfile.data.metadata["legacy_package_version"] == "8.1.1"
535    assert logfile.data.metadata["package_version"] == "8.1.1+9295"
536    assert isinstance(
537        parse_version(logfile.data.metadata["package_version"]), Version
538    )
539
540
541def testGAMESS_Firefly8_1_naphtalene_t_0_SP_out(logfile):
542    """Molecular orbitals were not parsed (cclib/cclib#228)."""
543    assert hasattr(logfile.data, 'mocoeffs')
544
545    assert logfile.data.metadata["package_version"] == "8.1.1+9295"
546
547
548# GAMESS #
549
550
551def testGAMESS_GAMESS_US2008_N2_UMP2_out(logfile):
552    """Check that the new format for GAMESS MP2 is parsed."""
553    assert hasattr(logfile.data, "mpenergies")
554    assert len(logfile.data.mpenergies) == 1
555    assert abs(logfile.data.mpenergies[0] + 2975.97) < 0.01
556
557    assert logfile.data.metadata["legacy_package_version"] == "2008R1"
558    assert logfile.data.metadata["package_version"] == "2008.r1"
559    assert isinstance(
560        parse_version(logfile.data.metadata["package_version"]), Version
561    )
562
563
564def testGAMESS_GAMESS_US2008_N2_ROMP2_out(logfile):
565    """Check that the new format for GAMESS MP2 is parsed."""
566    assert hasattr(logfile.data, "mpenergies")
567    assert len(logfile.data.mpenergies) == 1
568    assert abs(logfile.data.mpenergies[0] + 2975.97) < 0.01
569
570    assert logfile.data.metadata["package_version"] == "2008.r1"
571
572
573def testGAMESS_GAMESS_US2009_open_shell_ccsd_test_log(logfile):
574    """Parse ccenergies from open shell CCSD calculations."""
575    assert hasattr(logfile.data, "ccenergies")
576    assert len(logfile.data.ccenergies) == 1
577    assert abs(logfile.data.ccenergies[0] + 3501.50) < 0.01
578
579    assert logfile.data.metadata["legacy_package_version"] == "2009R3"
580    assert logfile.data.metadata["package_version"] == "2009.r3"
581    assert isinstance(
582        parse_version(logfile.data.metadata["package_version"]), Version
583    )
584
585
586def testGAMESS_GAMESS_US2009_paulo_h2o_mp2_out(logfile):
587    """Check that the new format for GAMESS MP2 is parsed."""
588    assert hasattr(logfile.data, "mpenergies")
589    assert len(logfile.data.mpenergies) == 1
590    assert abs(logfile.data.mpenergies[0] + 2072.13) < 0.01
591
592    assert logfile.data.metadata["package_version"] == "2009.r3"
593
594
595def testGAMESS_GAMESS_US2012_dvb_gopt_a_unconverged_out(logfile):
596    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
597    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
598
599    assert logfile.data.metadata["legacy_package_version"] == "2012R2"
600    assert logfile.data.metadata["package_version"] == "2012.r2"
601    assert isinstance(
602        parse_version(logfile.data.metadata["package_version"]), Version
603    )
604
605
606def testGAMESS_GAMESS_US2012_stopiter_gamess_out(logfile):
607    """Check to ensure that an incomplete SCF is handled correctly."""
608    assert len(logfile.data.scfvalues[0]) == 10
609
610    assert logfile.data.metadata["package_version"] == "2012.r1"
611
612
613def testGAMESS_GAMESS_US2013_N_UHF_out(logfile):
614    """An UHF job that has an LZ value analysis between the alpha and beta orbitals."""
615    assert len(logfile.data.moenergies) == 2
616
617    assert logfile.data.metadata["legacy_package_version"] == "2013R1"
618    assert logfile.data.metadata["package_version"] == "2013.r1"
619    assert isinstance(
620        parse_version(logfile.data.metadata["package_version"]), Version
621    )
622
623
624def testGAMESS_GAMESS_US2014_CdtetraM1B3LYP_log(logfile):
625    """This logfile had coefficients for only 80 molecular orbitals."""
626    assert len(logfile.data.mocoeffs) == 2
627    assert numpy.count_nonzero(logfile.data.mocoeffs[0][79-1:, :]) == 258
628    assert numpy.count_nonzero(logfile.data.mocoeffs[0][80-1: 0:]) == 0
629    assert logfile.data.mocoeffs[0].all() == logfile.data.mocoeffs[1].all()
630
631    assert logfile.data.metadata["legacy_package_version"] == "2014R1"
632    assert logfile.data.metadata["package_version"] == "2014.r1"
633    assert isinstance(
634        parse_version(logfile.data.metadata["package_version"]), Version
635    )
636
637
638def testGAMESS_GAMESS_US2018_exam45_log(logfile):
639    """This logfile has EOM-CC electronic transitions (not currently supported)."""
640    assert not hasattr(logfile.data, 'etenergies')
641
642    assert logfile.data.metadata["legacy_package_version"] == "2018R2"
643    assert logfile.data.metadata["package_version"] == "2018.r2"
644    assert isinstance(
645        parse_version(logfile.data.metadata["package_version"]), Version
646    )
647
648def testGAMESS_GAMESS_US2018_exam46_log(logfile):
649    """
650    This logfile has >100 scf iterations, which used to cause
651    a parsing error.
652    """
653    assert len(logfile.data.scfvalues[0]) == 113
654    assert logfile.data.metadata["legacy_package_version"] == "2018R3"
655    assert logfile.data.metadata["package_version"] == "2018.r3"
656    assert isinstance(
657        parse_version(logfile.data.metadata["package_version"]), Version
658    )
659
660
661def testGAMESS_WinGAMESS_dvb_td_trplet_2007_03_24_r1_out(logfile):
662    """Do some basic checks for this old unit test that was failing.
663
664    The unit tests are not run automatically on this old unit logfile,
665    because we know the output has etsecs whose sum is way off.
666    So, perform a subset of the basic assertions for GenericTDTesttrp.
667    """
668    number = 5
669    assert len(logfile.data.etenergies) == number
670    idx_lambdamax = [i for i, x in enumerate(logfile.data.etoscs) if x == max(logfile.data.etoscs)][0]
671    assert abs(logfile.data.etenergies[idx_lambdamax] - 24500) < 100
672    assert len(logfile.data.etoscs) == number
673    assert abs(max(logfile.data.etoscs) - 0.0) < 0.01
674    assert len(logfile.data.etsecs) == number
675
676    assert logfile.data.metadata["legacy_package_version"] == "2007R1"
677    assert logfile.data.metadata["package_version"] == "2007.r1"
678    assert isinstance(
679        parse_version(logfile.data.metadata["package_version"]), Version
680    )
681
682def testnoparseGAMESS_WinGAMESS_H2O_def2SVPD_triplet_2019_06_30_R1_out(logfile):
683    """Check if the molden writer can handle an unrestricted case
684    """
685    data = ccread(os.path.join(__filedir__,logfile))
686    writer = moldenwriter.MOLDEN(data)
687    # Check size of Atoms section.
688    assert len(writer._mo_from_ccdata()) == (data.nbasis + 4) * (data.nmo * 2)
689    # check docc orbital
690    beta_idx = (data.nbasis + 4) * data.nmo
691    assert "Beta" in writer._mo_from_ccdata()[beta_idx + 2]
692    assert "Occup=   1.000000" in writer._mo_from_ccdata()[beta_idx + 3]
693    assert "0.989063" in writer._mo_from_ccdata()[beta_idx + 4]
694
695
696# GAMESS-UK #
697
698
699def testGAMESS_UK_GAMESS_UK8_0_dvb_gopt_hf_unconverged_out(logfile):
700    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
701
702    assert logfile.data.metadata["legacy_package_version"] == "8.0"
703    assert logfile.data.metadata["package_version"] == "8.0+6248"
704    assert isinstance(
705        parse_version(logfile.data.metadata["package_version"]), Version
706    )
707
708
709def testGAMESS_UK_GAMESS_UK8_0_stopiter_gamessuk_dft_out(logfile):
710    """Check to ensure that an incomplete SCF is handled correctly."""
711    assert len(logfile.data.scfvalues[0]) == 7
712
713    assert logfile.data.metadata["package_version"] == "8.0+6248"
714
715
716def testGAMESS_UK_GAMESS_UK8_0_stopiter_gamessuk_hf_out(logfile):
717    """Check to ensure that an incomplete SCF is handled correctly."""
718    assert len(logfile.data.scfvalues[0]) == 5
719
720    assert logfile.data.metadata["package_version"] == "8.0+6248"
721
722
723# Gaussian #
724
725def testGaussian_Gaussian98_C_bigmult_log(logfile):
726    """
727    This file failed first becuase it had a double digit multiplicity.
728    Then it failed because it had no alpha virtual orbitals.
729    """
730    assert logfile.data.charge == -3
731    assert logfile.data.mult == 10
732    assert logfile.data.homos[0] == 8
733    assert logfile.data.homos[1] == -1 # No occupied beta orbitals
734
735    assert logfile.data.metadata["legacy_package_version"] == "98revisionA.11.3"
736    assert logfile.data.metadata["package_version"] == "1998+A.11.3"
737    assert isinstance(
738        parse_version(logfile.data.metadata["package_version"]), Version
739    )
740
741
742def testGaussian_Gaussian98_NIST_CCCBDB_1himidaz_m21b0_out(logfile):
743    """A G3 computation is a sequence of jobs."""
744
745    # All steps deal with the same molecule, so we extract the coordinates
746    # from all steps.
747    assert len(logfile.data.atomcoords) == 10
748
749    # Different G3 steps do perturbation to different orders, and so
750    # we expect only the last MP2 energy to be extracted.
751    assert len(logfile.data.mpenergies) == 1
752
753    assert logfile.data.metadata["legacy_package_version"] == "98revisionA.7"
754    assert logfile.data.metadata["package_version"] == "1998+A.7"
755    assert isinstance(
756        parse_version(logfile.data.metadata["package_version"]), Version
757    )
758
759
760def testGaussian_Gaussian98_NIST_CCCBDB_1himidaz_m23b6_out(logfile):
761    """A job that was killed before it ended, should have several basic attributes parsed."""
762    assert hasattr(logfile.data, 'charge')
763    assert hasattr(logfile.data, 'metadata')
764    assert hasattr(logfile.data, 'mult')
765
766    assert logfile.data.metadata["package_version"] == "1998+A.7"
767
768
769def testGaussian_Gaussian98_test_Cu2_log(logfile):
770    """An example of the number of basis set function changing."""
771    assert logfile.data.nbasis == 38
772
773    assert logfile.data.metadata["cpu_time"] == [datetime.timedelta(seconds=25, microseconds=800000)]
774    assert "wall_time" not in logfile.data.metadata
775    assert logfile.data.metadata["legacy_package_version"] == "98revisionA.11.4"
776    assert logfile.data.metadata["package_version"] == "1998+A.11.4"
777    assert isinstance(
778        parse_version(logfile.data.metadata["package_version"]), Version
779    )
780
781
782def testGaussian_Gaussian98_test_H2_log(logfile):
783    """
784    The atomic charges from a natural population analysis were
785    not parsed correctly, and they should be zero for dihydrogen.
786    """
787    assert logfile.data.atomcharges['natural'][0] == 0.0
788    assert logfile.data.atomcharges['natural'][1] == 0.0
789
790    assert logfile.data.metadata["package_version"] == "1998+A.11.4"
791
792
793def testGaussian_Gaussian98_water_zmatrix_nosym_log(logfile):
794    """This file is missing natom.
795
796    This file had no atomcoords as it did not contain either an
797    "Input orientation" or "Standard orientation section".
798    As a result it failed to parse. Fixed in r400.
799    """
800    assert len(logfile.data.atomcoords) == 1
801    assert logfile.data.natom == 3
802
803    assert logfile.data.metadata["package_version"] == "1998+A.11.3"
804
805
806def testGaussian_Gaussian03_AM1_SP_out(logfile):
807    """Previously, caused scfvalue parsing to fail."""
808    assert len(logfile.data.scfvalues[0]) == 13
809
810    assert logfile.data.metadata["legacy_package_version"] == "03revisionE.01"
811    assert logfile.data.metadata["package_version"] == "2003+E.01"
812    assert isinstance(
813        parse_version(logfile.data.metadata["package_version"]), Version
814    )
815
816
817def testGaussian_Gaussian03_anthracene_log(logfile):
818    """This file exposed a bug in extracting the vibsyms."""
819    assert len(logfile.data.vibsyms) == len(logfile.data.vibfreqs)
820
821    assert logfile.data.metadata["legacy_package_version"] == "03revisionC.02"
822    assert logfile.data.metadata["package_version"] == "2003+C.02"
823    assert isinstance(
824        parse_version(logfile.data.metadata["package_version"]), Version
825    )
826
827
828def testGaussian_Gaussian03_borane_opt_log(logfile):
829    """An example of changing molecular orbital count."""
830    assert logfile.data.optstatus[-1] == logfile.data.OPT_DONE
831    assert logfile.data.nmo == 609
832
833    assert logfile.data.metadata["package_version"] == "2003+E.01"
834
835
836def testGaussian_Gaussian03_chn1_log(logfile):
837    """
838    This file failed to parse, due to the use of 'pop=regular'.
839    We have decided that mocoeffs should not be defined for such calculations.
840    """
841    assert not hasattr(logfile.data, "mocoeffs")
842
843    assert logfile.data.metadata["legacy_package_version"] == "03revisionB.04"
844    assert logfile.data.metadata["package_version"] == "2003+B.04"
845    assert isinstance(
846        parse_version(logfile.data.metadata["package_version"]), Version
847    )
848
849
850def testGaussian_Gaussian03_cyclopropenyl_rhf_g03_cut_log(logfile):
851    """
852    Not using symmetry at all (option nosymm) means standard orientation
853    is not printed. In this case inputcoords are copied by the parser,
854    which up till now stored the last coordinates.
855    """
856    assert len(logfile.data.atomcoords) == len(logfile.data.geovalues)
857
858    assert logfile.data.metadata["package_version"] == "2003+C.02"
859
860
861def testGaussian_Gaussian03_DCV4T_C60_log(logfile):
862    """This is a test for a very large Gaussian file with > 99 atoms.
863
864    The log file is too big, so we are just including the start.
865    Previously, parsing failed in the pseudopotential section.
866    """
867    assert len(logfile.data.coreelectrons) == 102
868    assert logfile.data.coreelectrons[101] == 2
869
870    assert logfile.data.metadata["legacy_package_version"] == "03revisionD.02"
871    assert logfile.data.metadata["package_version"] == "2003+D.02"
872    assert isinstance(
873        parse_version(logfile.data.metadata["package_version"]), Version
874    )
875
876
877def testGaussian_Gaussian03_dvb_gopt_symmfollow_log(logfile):
878    """Non-standard treatment of symmetry.
879
880    In this case the Standard orientation is also printed non-standard,
881    which caused only the first coordinates to be read previously.
882    """
883    assert len(logfile.data.atomcoords) == len(logfile.data.geovalues)
884
885    assert logfile.data.metadata["cpu_time"] == [datetime.timedelta(seconds=99)]
886    assert "wall_time" not in logfile.data.metadata
887    assert logfile.data.metadata["legacy_package_version"] == "03revisionC.01"
888    assert logfile.data.metadata["package_version"] == "2003+C.01"
889    assert isinstance(
890        parse_version(logfile.data.metadata["package_version"]), Version
891    )
892
893
894def testGaussian_Gaussian03_mendes_out(logfile):
895    """Previously, failed to extract coreelectrons."""
896    centers = [9, 10, 11, 27]
897    for i, x in enumerate(logfile.data.coreelectrons):
898        if i in centers:
899            assert x == 10
900        else:
901            assert x == 0
902
903    assert logfile.data.metadata["package_version"] == "2003+C.02"
904
905
906def testGaussian_Gaussian03_Mo4OSibdt2_opt_log(logfile):
907    """
908    This file had no atomcoords as it did not contain any
909    "Input orientation" sections, only "Standard orientation".
910    """
911    assert logfile.data.optstatus[-1] == logfile.data.OPT_DONE
912    assert hasattr(logfile.data, "atomcoords")
913
914    assert logfile.data.metadata["package_version"] == "2003+C.02"
915
916
917def testGaussian_Gaussian03_orbgs_log(logfile):
918    """Check that the pseudopotential is being parsed correctly."""
919    assert hasattr(logfile.data, "coreelectrons"), "Missing coreelectrons"
920    assert logfile.data.coreelectrons[0] == 28
921    assert logfile.data.coreelectrons[15] == 10
922    assert logfile.data.coreelectrons[20] == 10
923    assert logfile.data.coreelectrons[23] == 10
924
925    assert logfile.data.metadata["package_version"] == "2003+C.02"
926
927
928def testGaussian_Gaussian09_100_g09(logfile):
929    """Check that the final system is the one parsed (cclib/cclib#243)."""
930    assert logfile.data.natom == 54
931    assert logfile.data.homos == [104]
932
933    assert logfile.data.metadata["legacy_package_version"] == "09revisionB.01"
934    assert logfile.data.metadata["package_version"] == "2009+B.01"
935    assert isinstance(
936        parse_version(logfile.data.metadata["package_version"]), Version
937    )
938
939
940def testGaussian_Gaussian09_25DMF_HRANH_log(logfile):
941    """Check that the anharmonicities are being parsed correctly."""
942    assert hasattr(logfile.data, "vibanharms"), "Missing vibanharms"
943    anharms = logfile.data.vibanharms
944    N = len(logfile.data.vibfreqs)
945    assert 39 == N == anharms.shape[0] == anharms.shape[1]
946    assert abs(anharms[0][0] + 43.341) < 0.01
947    assert abs(anharms[N-1][N-1] + 36.481) < 0.01
948
949    assert logfile.data.metadata["package_version"] == "2009+B.01"
950
951
952def testGaussian_Gaussian09_2D_PES_all_converged_log(logfile):
953    """Check that optstatus has no UNCOVERGED values."""
954    assert ccData.OPT_UNCONVERGED not in logfile.data.optstatus
955
956    assert logfile.data.metadata["legacy_package_version"] == "09revisionD.01"
957    assert logfile.data.metadata["package_version"] == "2009+D.01"
958    assert isinstance(
959        parse_version(logfile.data.metadata["package_version"]), Version
960    )
961
962    # The energies printed in the scan summary are misformated.
963    assert numpy.all(numpy.isnan(logfile.data.scanenergies))
964
965
966def testGaussian_Gaussian09_2D_PES_one_unconverged_log(logfile):
967    """Check that optstatus contains UNCOVERGED values."""
968    assert ccData.OPT_UNCONVERGED in logfile.data.optstatus
969
970    assert logfile.data.metadata["package_version"] == "2009+D.01"
971
972
973def testGaussian_Gaussian09_534_out(logfile):
974    """Previously, caused etenergies parsing to fail."""
975    assert logfile.data.etsyms[0] == "Singlet-?Sym"
976    assert abs(logfile.data.etenergies[0] - 20920.55328) < 1.0
977
978    assert logfile.data.metadata["legacy_package_version"] == "09revisionA.02"
979    assert logfile.data.metadata["package_version"] == "2009+A.02"
980    assert isinstance(
981        parse_version(logfile.data.metadata["package_version"]), Version
982    )
983
984
985def testGaussian_Gaussian09_BSL_opt_freq_DFT_out(logfile):
986    """Failed for converting to CJSON when moments weren't parsed for
987    Gaussian.
988    """
989    assert hasattr(logfile.data, 'moments')
990    # dipole Y
991    assert logfile.data.moments[1][1] == 0.5009
992    # hexadecapole ZZZZ
993    assert logfile.data.moments[4][-1] == -77.9600
994
995    assert logfile.data.metadata["package_version"] == "2009+D.01"
996
997
998def testGaussian_Gaussian09_dvb_gopt_unconverged_log(logfile):
999    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
1000    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
1001    assert logfile.data.optstatus[-1] == logfile.data.OPT_UNCONVERGED
1002
1003    assert logfile.data.metadata["cpu_time"] == [datetime.timedelta(seconds=27, microseconds=700000)]
1004    assert "wall_time" not in logfile.data.metadata
1005    assert logfile.data.metadata["package_version"] == "2009+D.01"
1006
1007
1008def testGaussian_Gaussian09_dvb_lowdin_log(logfile):
1009    """Check if both Mulliken and Lowdin charges are parsed."""
1010    assert "mulliken" in logfile.data.atomcharges
1011    assert "lowdin" in logfile.data.atomcharges
1012
1013    assert logfile.data.metadata["package_version"] == "2009+A.02"
1014
1015
1016def testGaussian_Gaussian09_Dahlgren_TS_log(logfile):
1017    """Failed to parse ccenergies for a variety of reasons"""
1018    assert hasattr(logfile.data, "ccenergies")
1019    assert abs(logfile.data.ccenergies[0] - (-11819.96506609)) < 0.001
1020
1021    assert logfile.data.metadata["package_version"] == "2009+A.02"
1022
1023
1024def testGaussian_Gaussian09_irc_point_log(logfile):
1025    """Failed to parse vibfreqs except for 10, 11"""
1026    assert hasattr(logfile.data, "vibfreqs")
1027    assert len(logfile.data.vibfreqs) == 11
1028
1029    assert logfile.data.metadata["package_version"] == "2009+D.01"
1030
1031
1032def testGaussian_Gaussian09_issue_460_log(logfile):
1033    """Lots of malformed lines when parsing for scfvalues:
1034
1035    RMSDP=3.79D-04 MaxDP=4.02D-02              OVMax= 4.31D-02
1036    RMSDP=1.43D-06 MaxDP=5.44D-04 DE=-6.21D-07 OVMax= 5.76D-04
1037    RMSDP=2.06D-05 MaxDP=3.84D-03 DE= 4.82D-04 O E= -2574.14897924075     Delta-E=        0.000439804468 Rises=F Damp=F
1038    RMSDP=8.64D-09 MaxDP=2.65D-06 DE=-1.67D-10 OVMax= 3. E= -2574.14837678675     Delta-E=       -0.000000179038 Rises=F Damp=F
1039    RMSDP= E= -2574.14931865182     Delta-E=       -0.000000019540 Rises=F Damp=F
1040    RMSDP=9.34D- E= -2574.14837612206     Delta-E=       -0.000000620705 Rises=F Damp=F
1041    RMSDP=7.18D-05 Max E= -2574.14797761904     Delta-E=       -0.000000000397 Rises=F Damp=F
1042    RMSDP=1.85D-06 MaxD E= -2574.14770506975     Delta-E=       -0.042173156160 Rises=F Damp=F
1043    RMSDP=1.69D-06 MaxDP= E= -2574.14801776548     Delta-E=        0.000023521317 Rises=F Damp=F
1044    RMSDP=3.80D-08 MaxDP=1 E= -2574.14856570920     Delta-E=       -0.000002960194 Rises=F Damp=F
1045    RMSDP=4.47D-09 MaxDP=1.40 E= -2574.14915435699     Delta-E=       -0.000255709558 Rises=F Damp=F
1046    RMSDP=5.54D-08 MaxDP=1.55D-05 DE=-2.55D-0 E= -2574.14854319757     Delta-E=       -0.000929740010 Rises=F Damp=F
1047    RMSDP=7.20D-09 MaxDP=1.75D-06 DE=- (Enter /QFsoft/applic/GAUSSIAN/g09d.01_pgi11.9-ISTANBUL/g09/l703.exe)
1048    RMSDP=5.24D-09 MaxDP=1.47D-06 DE=-1.82D-11 OVMax= 2.15 (Enter /QFsoft/applic/GAUSSIAN/g09d.01_pgi11.9-ISTANBUL/g09/l703.exe)
1049    RMSDP=1.71D-04 MaxDP=1.54D-02    Iteration    2 A^-1*A deviation from unit magnitude is 1.11D-15 for    266.
1050    """
1051    assert hasattr(logfile.data, 'scfvalues')
1052    assert logfile.data.scfvalues[0][0, 0] == 3.37e-03
1053    assert numpy.isnan(logfile.data.scfvalues[0][0, 2])
1054
1055    assert logfile.data.metadata["package_version"] == "2009+D.01"
1056
1057
1058def testGaussian_Gaussian09_OPT_td_g09_out(logfile):
1059    """Couldn't find etrotats as G09 has different output than G03."""
1060    assert len(logfile.data.etrotats) == 10
1061    assert logfile.data.etrotats[0] == -0.4568
1062
1063    assert logfile.data.metadata["package_version"] == "2009+A.02"
1064
1065
1066def testGaussian_Gaussian09_OPT_td_out(logfile):
1067    """Working fine - adding to ensure that CD is parsed correctly."""
1068    assert len(logfile.data.etrotats) == 10
1069    assert logfile.data.etrotats[0] == -0.4568
1070
1071    assert logfile.data.metadata["package_version"] == "2003+B.05"
1072
1073
1074def testGaussian_Gaussian09_OPT_oniom_log(logfile):
1075    """AO basis extraction broke with ONIOM"""
1076
1077    assert logfile.data.metadata["package_version"] == "2009+D.01"
1078
1079
1080def testGaussian_Gaussian09_oniom_IR_intensity_log(logfile):
1081    """Problem parsing IR intensity from mode 192"""
1082    assert hasattr(logfile.data, 'vibirs')
1083    assert len(logfile.data.vibirs) == 216
1084
1085    assert logfile.data.metadata["package_version"] == "2009+C.01"
1086
1087
1088def testGaussian_Gaussian09_Ru2bpyen2_H2_freq3_log(logfile):
1089    """Here atomnos wans't added to the gaussian parser before."""
1090    assert len(logfile.data.atomnos) == 69
1091
1092    assert logfile.data.metadata["package_version"] == "2009+A.02"
1093
1094
1095def testGaussian_Gaussian09_benzene_HPfreq_log(logfile):
1096    """Check that higher precision vib displacements obtained with freq=hpmodes) are parsed correctly."""
1097    assert abs(logfile.data.vibdisps[0,0,2] - (-0.04497)) < 0.00001
1098
1099    assert logfile.data.metadata["package_version"] == "2009+C.01"
1100
1101
1102def testGaussian_Gaussian09_benzene_freq_log(logfile):
1103    """Check that default precision vib displacements are parsed correctly."""
1104    assert abs(logfile.data.vibdisps[0,0,2] - (-0.04)) < 0.00001
1105
1106    assert logfile.data.metadata["package_version"] == "2009+C.01"
1107
1108
1109def testGaussian_Gaussian09_relaxed_PES_testH2_log(logfile):
1110    """Check that all optimizations converge in a single step."""
1111    atomcoords = logfile.data.atomcoords
1112    optstatus = logfile.data.optstatus
1113    assert len(optstatus) == len(atomcoords)
1114
1115    assert all(s == ccData.OPT_DONE + ccData.OPT_NEW for s in optstatus)
1116
1117    assert logfile.data.metadata["package_version"] == "2009+D.01"
1118
1119
1120def testGaussian_Gaussian09_relaxed_PES_testCO2_log(logfile):
1121    """A relaxed PES scan with some uncoverged and some converged runs."""
1122    atomcoords = logfile.data.atomcoords
1123    optstatus = logfile.data.optstatus
1124    assert len(optstatus) == len(atomcoords)
1125
1126    new_points = numpy.where(optstatus & ccData.OPT_NEW)[0]
1127
1128    # The first new point is just the beginning of the scan.
1129    assert new_points[0] == 0
1130
1131    # The next two new points are at the end of unconverged runs.
1132    assert optstatus[new_points[1]-1] == ccData.OPT_UNCONVERGED
1133    assert all(optstatus[i] == ccData.OPT_UNKNOWN for i in range(new_points[0]+1, new_points[1]-1))
1134    assert optstatus[new_points[2]-1] == ccData.OPT_UNCONVERGED
1135    assert all(optstatus[i] == ccData.OPT_UNKNOWN for i in range(new_points[1]+1, new_points[2]-1))
1136
1137    # The next new point is after a convergence.
1138    assert optstatus[new_points[3]-1] == ccData.OPT_DONE
1139    assert all(optstatus[i] == ccData.OPT_UNKNOWN for i in range(new_points[2]+1, new_points[3]-1))
1140
1141    # All subsequent point are both new and converged, since they seem
1142    # to have converged in a single step.
1143    assert all(s == ccData.OPT_DONE + ccData.OPT_NEW for s in optstatus[new_points[3]:])
1144
1145    assert logfile.data.metadata["package_version"] == "2009+D.01"
1146
1147
1148def testGaussian_Gaussian09_stopiter_gaussian_out(logfile):
1149    """Check to ensure that an incomplete SCF is handled correctly."""
1150    assert len(logfile.data.scfvalues[0]) == 4
1151
1152    assert logfile.data.metadata["package_version"] == "2009+D.01"
1153
1154def testGaussian_Gaussian09_benzene_excited_states_optimization_issue889_log(logfile):
1155    """Check that only converged geometry excited states properties are reported."""
1156    assert logfile.data.etdips.shape == (20,3)
1157    assert len(logfile.data.etenergies) == 20
1158    assert logfile.data.etmagdips.shape == (20,3)
1159    assert len(logfile.data.etoscs) == 20
1160    assert len(logfile.data.etrotats) == 20
1161    assert len(logfile.data.etsecs) == 20
1162    assert logfile.data.etveldips.shape == (20,3)
1163
1164def testGaussian_Gaussian16_H3_natcharge_log(logfile):
1165    """A calculation with natural charges calculated. Test issue 1055 where
1166    only the beta set of charges was parsed rather than the spin independent"""
1167
1168    assert isinstance(logfile.data.atomcharges, dict)
1169    assert "mulliken" in logfile.data.atomcharges
1170    assert "natural" in logfile.data.atomcharges
1171    assert numpy.all(logfile.data.atomcharges["natural"] == [ 0.0721, -0.1442,  0.0721])
1172
1173def testGaussian_Gaussian16_naturalspinorbitals_parsing_log(logfile):
1174    """A UHF calculation with natural spin orbitals."""
1175
1176    assert isinstance(logfile.data.nsocoeffs, list)
1177    assert isinstance(logfile.data.nsocoeffs[0], numpy.ndarray)
1178    assert isinstance(logfile.data.nsocoeffs[1], numpy.ndarray)
1179    assert isinstance(logfile.data.nsooccnos, list)
1180    assert isinstance(logfile.data.nsooccnos[0], list)
1181    assert isinstance(logfile.data.nsooccnos[1], list)
1182    assert isinstance(logfile.data.aonames,list)
1183    assert isinstance(logfile.data.atombasis,list)
1184
1185    assert numpy.shape(logfile.data.nsocoeffs) == (2,logfile.data.nmo,logfile.data.nmo)
1186    assert len(logfile.data.nsooccnos[0]) == logfile.data.nmo
1187    assert len(logfile.data.nsooccnos[1]) == logfile.data.nmo
1188    assert len(logfile.data.aonames) == logfile.data.nbasis
1189    assert len(numpy.ravel(logfile.data.atombasis)) == logfile.data.nbasis
1190
1191    assert logfile.data.nsooccnos[0][14] == 0.00506
1192    assert logfile.data.nsooccnos[1][14] == 0.00318
1193    assert logfile.data.nsocoeffs[0][14,12] == 0.00618
1194    assert logfile.data.nsocoeffs[1][14,9] == 0.79289
1195    assert logfile.data.aonames[41] == 'O2_9D 0'
1196    assert logfile.data.atombasis[1][0] == 23
1197
1198    assert logfile.data.metadata["cpu_time"] == [datetime.timedelta(seconds=74, microseconds=400000)]
1199    assert logfile.data.metadata["wall_time"] == [datetime.timedelta(seconds=3, microseconds=500000)]
1200    assert logfile.data.metadata["legacy_package_version"] == "16revisionA.03"
1201    assert logfile.data.metadata["package_version"] == "2016+A.03"
1202    assert isinstance(
1203        parse_version(logfile.data.metadata["package_version"]), Version
1204    )
1205
1206def testGaussian_Gaussian16_issue851_log(logfile):
1207    """Surface scan from cclib/cclib#851 where attributes were not lists."""
1208
1209    assert isinstance(logfile.data.scannames, list)
1210    assert isinstance(logfile.data.scanparm, list)
1211    assert isinstance(logfile.data.scanenergies, list)
1212
1213def testGaussian_Gaussian16_issue962_log(logfile):
1214    """For issue 962, this shouldn't have scftargets but should parse fully"""
1215
1216    assert not hasattr(logfile.data, "scftargets")
1217
1218# Jaguar #
1219
1220# It would be good to have an unconverged geometry optimization so that
1221# we can test that optdone is set properly.
1222#def testJaguarX.X_dvb_gopt_unconverged:
1223#    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
1224
1225
1226def testJaguar_Jaguar8_3_stopiter_jaguar_dft_out(logfile):
1227    """Check to ensure that an incomplete SCF is handled correctly."""
1228    assert len(logfile.data.scfvalues[0]) == 4
1229
1230    assert logfile.data.metadata["legacy_package_version"] == "8.3"
1231    assert logfile.data.metadata["package_version"] == "8.3+13"
1232    assert isinstance(
1233        parse_version(logfile.data.metadata["package_version"]), Version
1234    )
1235
1236
1237def testJaguar_Jaguar8_3_stopiter_jaguar_hf_out(logfile):
1238    """Check to ensure that an incomplete SCF is handled correctly."""
1239    assert len(logfile.data.scfvalues[0]) == 3
1240
1241    assert logfile.data.metadata["package_version"] == "8.3+13"
1242
1243
1244# Molcas #
1245
1246
1247def testMolcas_Molcas18_test_standard_000_out(logfile):
1248    """Don't support parsing MOs for multiple symmetry species."""
1249    assert not hasattr(logfile.data, "moenergies")
1250    assert not hasattr(logfile.data, "mocoeffs")
1251
1252    assert logfile.data.metadata["legacy_package_version"] == "18.09"
1253    assert logfile.data.metadata["package_version"] == "18.09+52-ge15dc38.81d3fb3dc6a5c5df6b3791ef1ef3790f"
1254    assert isinstance(
1255        parse_version(logfile.data.metadata["package_version"]), Version
1256    )
1257
1258
1259def testMolcas_Molcas18_test_standard_001_out(logfile):
1260    """This logfile has two calculations, and we currently only want to parse the first."""
1261    assert logfile.data.natom == 8
1262
1263    # There are also four symmetry species, and orbital count should cover all of them.
1264    assert logfile.data.nbasis == 30
1265    assert logfile.data.nmo == 30
1266
1267    assert logfile.data.metadata["package_version"] == "18.09+52-ge15dc38.81d3fb3dc6a5c5df6b3791ef1ef3790f"
1268
1269
1270def testMolcas_Molcas18_test_standard_003_out(logfile):
1271    """This logfile has extra charged monopoles (not part of the molecule)."""
1272    assert logfile.data.charge == 0
1273
1274    assert logfile.data.metadata["package_version"] == "18.09+52-ge15dc38.81d3fb3dc6a5c5df6b3791ef1ef3790f"
1275
1276
1277def testMolcas_Molcas18_test_standard_005_out(logfile):
1278    """Final geometry in optimization has fewer atoms due to symmetry, and so is ignored."""
1279    assert len(logfile.data.atomcoords) == 2
1280
1281    assert logfile.data.metadata["package_version"] == "18.09+52-ge15dc38.81d3fb3dc6a5c5df6b3791ef1ef3790f"
1282
1283
1284def testMolcas_Molcas18_test_stevenv_001_out(logfile):
1285    """Don't support parsing MOs for RAS (active space)."""
1286    assert not hasattr(logfile.data, "moenergies")
1287    assert not hasattr(logfile.data, "mocoeffs")
1288
1289    assert logfile.data.metadata["package_version"] == "18.09+52-ge15dc38.81d3fb3dc6a5c5df6b3791ef1ef3790f"
1290
1291
1292def testMolcas_Molcas18_test_stevenv_desym_out(logfile):
1293    """This logfile has iterations interrupted by a Fermi aufbau procedure."""
1294    assert len(logfile.data.scfvalues) == 1
1295    assert len(logfile.data.scfvalues[0]) == 26
1296
1297    assert logfile.data.metadata["package_version"] == "18.09+52-ge15dc38.81d3fb3dc6a5c5df6b3791ef1ef3790f"
1298
1299
1300# Molpro #
1301
1302
1303def testMolpro_Molpro2008_ch2o_molpro_casscf_out(logfile):
1304    """A CASSCF job with symmetry and natural orbitals."""
1305
1306    # The last two atoms are equivalent, so the last ends up having no
1307    # functions asigned. This is not obvious, because the functions are
1308    # distributed between the last two atoms in the block where gbasis
1309    # is parsed, but it seems all are assigned to the penultimate atom later.
1310    assert logfile.data.atombasis[-1] == []
1311    assert len(logfile.data.aonames) == logfile.data.nbasis
1312
1313    # The MO coefficients are printed in several block, each corresponding
1314    # to one irrep, so make sure we have reconstructed the coefficients correctly.
1315    assert len(logfile.data.moenergies) == 1
1316    assert logfile.data.moenergies[0].shape == (logfile.data.nmo, )
1317    assert len(logfile.data.mocoeffs) == 1
1318    assert logfile.data.mocoeffs[0].shape == (logfile.data.nmo, logfile.data.nbasis)
1319
1320    # These coefficients should be zero due to symmetry.
1321    assert logfile.data.mocoeffs[0][-2][0] == 0.0
1322    assert logfile.data.mocoeffs[0][0][-2] == 0.0
1323
1324    assert isinstance(logfile.data.nocoeffs, numpy.ndarray)
1325    assert isinstance(logfile.data.nooccnos, numpy.ndarray)
1326    assert logfile.data.nocoeffs.shape == logfile.data.mocoeffs[0].shape
1327    assert len(logfile.data.nooccnos) == logfile.data.nmo
1328    assert logfile.data.nooccnos[27] == 1.95640
1329
1330    assert logfile.data.metadata["legacy_package_version"] == "2012.1"
1331    assert logfile.data.metadata["package_version"] == "2012.1"
1332    assert isinstance(
1333        parse_version(logfile.data.metadata["package_version"]), Version
1334    )
1335
1336
1337def testMolpro_Molpro2012_CHONHSH_HF_STO_3G_out(logfile):
1338    """Formatting of the basis function is slightly different than expected."""
1339    assert len(logfile.data.gbasis) == 7
1340    assert len(logfile.data.gbasis[0]) == 3 # C
1341    assert len(logfile.data.gbasis[1]) == 3 # N
1342    assert len(logfile.data.gbasis[2]) == 3 # O
1343    assert len(logfile.data.gbasis[3]) == 5 # S
1344    assert len(logfile.data.gbasis[4]) == 1 # H
1345    assert len(logfile.data.gbasis[5]) == 1 # H
1346    assert len(logfile.data.gbasis[6]) == 1 # H
1347
1348    assert logfile.data.metadata["legacy_package_version"] == "2012.1"
1349    assert logfile.data.metadata["package_version"] == "2012.1.23+f8cfea266908527a8826bdcd5983aaf62e47d3bf"
1350    assert isinstance(
1351        parse_version(logfile.data.metadata["package_version"]), Version
1352    )
1353
1354
1355def testMolpro_Molpro2012_dvb_gopt_unconverged_out(logfile):
1356    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
1357    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
1358
1359    assert logfile.data.metadata["legacy_package_version"] == "2012.1"
1360    assert logfile.data.metadata["package_version"] == "2012.1.12+e112a8ab93d81616c1987a1f1ef3707d874b6803"
1361    assert isinstance(
1362        parse_version(logfile.data.metadata["package_version"]), Version
1363    )
1364
1365
1366def testMolpro_Molpro2012_stopiter_molpro_dft_out(logfile):
1367    """Check to ensure that an incomplete SCF is handled correctly."""
1368    assert len(logfile.data.scfvalues[0]) == 6
1369
1370    assert logfile.data.metadata["legacy_package_version"] == "2012.1"
1371    assert logfile.data.metadata["package_version"] == "2012.1+c18f7d37f9f045f75d4f3096db241dde02ddca0a"
1372    assert isinstance(
1373        parse_version(logfile.data.metadata["package_version"]), Version
1374    )
1375
1376
1377def testMolpro_Molpro2012_stopiter_molpro_hf_out(logfile):
1378    """Check to ensure that an incomplete SCF is handled correctly."""
1379    assert len(logfile.data.scfvalues[0]) == 6
1380
1381    assert logfile.data.metadata["package_version"] == "2012.1+c18f7d37f9f045f75d4f3096db241dde02ddca0a"
1382
1383
1384# MOPAC #
1385
1386
1387def testMOPAC_MOPAC2016_9S3_uuu_Cs_cation_freq_PM7_out(logfile):
1388    """There was a syntax error in the frequency parsing."""
1389    assert hasattr(logfile.data, 'vibfreqs')
1390
1391    assert logfile.data.metadata["legacy_package_version"] == "2016"
1392    assert logfile.data.metadata["package_version"] == "16.175"
1393    assert isinstance(
1394        parse_version(logfile.data.metadata["package_version"]), Version
1395    )
1396
1397
1398# NWChem #
1399
1400
1401def testNWChem_NWChem6_0_dvb_gopt_hf_unconverged_out(logfile):
1402    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
1403    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
1404
1405    assert logfile.data.metadata["legacy_package_version"] == "6.0"
1406    assert logfile.data.metadata["package_version"] == "6.0"
1407    assert isinstance(
1408        parse_version(logfile.data.metadata["package_version"]), Version
1409    )
1410
1411
1412def testNWChem_NWChem6_0_dvb_sp_hf_moments_only_quadrupole_out(logfile):
1413    """Quadrupole moments are printed/parsed, but not lower moments (no shape)."""
1414    assert hasattr(logfile.data, 'moments') and len(logfile.data.moments) == 3
1415    assert len(logfile.data.moments[0]) == 3
1416    assert not logfile.data.moments[1].shape
1417    assert len(logfile.data.moments[2]) == 6
1418
1419    assert logfile.data.metadata["package_version"] == "6.0"
1420
1421
1422def testNWChem_NWChem6_0_dvb_sp_hf_moments_only_octupole_out(logfile):
1423    """Quadrupole moments are printed/parsed, but not lower moments (no shape)."""
1424    assert hasattr(logfile.data, 'moments') and len(logfile.data.moments) == 4
1425    assert len(logfile.data.moments[0]) == 3
1426    assert not logfile.data.moments[1].shape
1427    assert not logfile.data.moments[2].shape
1428    assert len(logfile.data.moments[3]) == 10
1429
1430    assert logfile.data.metadata["package_version"] == "6.0"
1431
1432
1433def testNWChem_NWChem6_0_hydrogen_atom_ROHF_cc_pVDZ_out(logfile):
1434    """A lone hydrogen atom is a common edge case; it has no beta
1435    electrons.
1436    """
1437    assert logfile.data.charge == 0
1438    assert logfile.data.natom == 1
1439    assert logfile.data.nbasis == 5
1440    assert logfile.data.nmo == 5
1441    assert len(logfile.data.moenergies) == 1
1442    assert logfile.data.moenergies[0].shape == (5,)
1443    assert logfile.data.homos.shape == (2,)
1444    assert logfile.data.homos[0] == 0
1445    assert logfile.data.homos[1] == -1
1446
1447    assert logfile.data.metadata["package_version"] == "6.0"
1448
1449
1450def testNWChem_NWChem6_0_hydrogen_atom_UHF_cc_pVDZ_out(logfile):
1451    """A lone hydrogen atom is a common edge case; it has no beta
1452    electrons.
1453
1454    Additionally, this calculations has no title, which caused some
1455    issues with skip_lines().
1456    """
1457    assert logfile.data.charge == 0
1458    assert logfile.data.natom == 1
1459    assert logfile.data.nbasis == 5
1460    assert logfile.data.nmo == 5
1461    assert len(logfile.data.moenergies) == 2
1462    assert logfile.data.moenergies[0].shape == (5,)
1463    assert logfile.data.moenergies[1].shape == (5,)
1464    assert logfile.data.homos.shape == (2,)
1465    assert logfile.data.homos[0] == 0
1466    assert logfile.data.homos[1] == -1
1467
1468    assert logfile.data.metadata["package_version"] == "6.0"
1469
1470
1471def testNWChem_NWChem6_5_stopiter_nwchem_dft_out(logfile):
1472    """Check to ensure that an incomplete SCF is handled correctly."""
1473    assert len(logfile.data.scfvalues[0]) == 3
1474
1475    assert logfile.data.metadata["legacy_package_version"] == "6.5"
1476    assert logfile.data.metadata["package_version"] == "6.5+26243"
1477    assert isinstance(
1478        parse_version(logfile.data.metadata["package_version"]), Version
1479    )
1480
1481
1482def testNWChem_NWChem6_5_stopiter_nwchem_hf_out(logfile):
1483    """Check to ensure that an incomplete SCF is handled correctly."""
1484    assert len(logfile.data.scfvalues[0]) == 2
1485
1486    assert logfile.data.metadata["package_version"] == "6.5+26243"
1487
1488
1489def testNWChem_NWChem6_8_526_out(logfile):
1490    """If `print low` is present in the input, SCF iterations are not
1491    printed.
1492    """
1493    assert not hasattr(logfile.data, "scftargets")
1494    assert not hasattr(logfile.data, "scfvalues")
1495
1496    assert logfile.data.metadata["legacy_package_version"] == "6.8.1"
1497    assert logfile.data.metadata["package_version"] == "6.8.1+g08bf49b"
1498    assert isinstance(
1499        parse_version(logfile.data.metadata["package_version"]), Version
1500    )
1501
1502
1503# ORCA #
1504
1505
1506def testORCA_ORCA2_8_co_cosmo_out(logfile):
1507    """This is related to bug 3184890.
1508
1509    The scfenergies were not being parsed correctly for this geometry
1510    optimization run, for two reasons.
1511    First, the printing of SCF total energies is different inside
1512    geometry optimization steps than for single point calculations,
1513    which also affects unit tests.
1514    However, this logfile uses a setting that causes an SCF run to
1515    terminate prematurely when a set maximum number of cycles is reached.
1516    In this case, the last energy reported should probably be used,
1517    and the number of values in scfenergies preserved.
1518    """
1519    assert hasattr(logfile.data, "scfenergies") and len(logfile.data.scfenergies) == 4
1520
1521    assert logfile.data.metadata["legacy_package_version"] == "2.8"
1522    assert logfile.data.metadata["package_version"] == "2.8+2287"
1523    assert isinstance(
1524        parse_version(logfile.data.metadata["package_version"]), Version
1525    )
1526
1527
1528def testORCA_ORCA2_9_job_out(logfile):
1529    """First output file and request to parse atomic spin densities.
1530
1531    Make sure that the sum of such densities is one in this case (or reasonaby close),
1532    but remember that this attribute is a dictionary, so we must iterate.
1533    """
1534    assert all([abs(sum(v)-1.0) < 0.0001 for k, v in logfile.data.atomspins.items()])
1535
1536    assert logfile.data.metadata["legacy_package_version"] == "2.9.0"
1537    assert logfile.data.metadata["package_version"] == "2.9.0"
1538    assert isinstance(
1539        parse_version(logfile.data.metadata["package_version"]), Version
1540    )
1541
1542
1543def testORCA_ORCA2_9_qmspeedtest_hf_out(logfile):
1544    """Check precision of SCF energies (cclib/cclib#210)."""
1545    energy = logfile.data.scfenergies[-1]
1546    expected = -17542.5188694
1547    assert abs(energy - expected) < 10**-6
1548
1549    assert logfile.data.metadata["legacy_package_version"] == "2.9.1"
1550    assert logfile.data.metadata["package_version"] == "2.9.1"
1551    assert isinstance(
1552        parse_version(logfile.data.metadata["package_version"]), Version
1553    )
1554
1555
1556def testORCA_ORCA3_0_chelpg_out(logfile):
1557    """ORCA file with chelpg charges"""
1558    assert 'chelpg' in logfile.data.atomcharges
1559    charges = logfile.data.atomcharges['chelpg']
1560    assert len(charges) == 9
1561    assert charges[0] == 0.363939
1562    assert charges[1] == 0.025695
1563
1564
1565def testORCA_ORCA3_0_dvb_gopt_unconverged_out(logfile):
1566    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
1567    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
1568
1569    assert logfile.data.metadata["legacy_package_version"] == "3.0.1"
1570    assert logfile.data.metadata["package_version"] == "3.0.1"
1571    assert isinstance(
1572        parse_version(logfile.data.metadata["package_version"]), Version
1573    )
1574
1575
1576def testORCA_ORCA3_0_polar_rhf_cg_out(logfile):
1577    """Alternative CP-SCF solver for the polarizability wasn't being detected."""
1578    assert hasattr(logfile.data, 'polarizabilities')
1579
1580    assert logfile.data.metadata["legacy_package_version"] == "3.0.3"
1581    assert logfile.data.metadata["package_version"] == "3.0.3"
1582    assert isinstance(
1583        parse_version(logfile.data.metadata["package_version"]), Version
1584    )
1585
1586
1587def testORCA_ORCA3_0_polar_rhf_diis_out(logfile):
1588    """Alternative CP-SCF solver for the polarizability wasn't being detected."""
1589    assert hasattr(logfile.data, 'polarizabilities')
1590
1591    assert logfile.data.metadata["package_version"] == "3.0.3"
1592
1593
1594def testORCA_ORCA3_0_stopiter_orca_scf_compact_out(logfile):
1595    """Check to ensure that an incomplete SCF is handled correctly."""
1596    assert len(logfile.data.scfvalues[0]) == 1
1597
1598    assert logfile.data.metadata["package_version"] == "3.0.1"
1599
1600
1601def testORCA_ORCA3_0_stopiter_orca_scf_large_out(logfile):
1602    """Check to ensure that an incomplete SCF is handled correctly."""
1603    assert len(logfile.data.scfvalues[0]) == 9
1604
1605    assert logfile.data.metadata["package_version"] == "2.9.1"
1606
1607
1608def testORCA_ORCA4_0_1_ttt_td_out(logfile):
1609    """RPA is slightly different from TDA, see #373."""
1610    assert hasattr(logfile.data, 'etsyms')
1611    assert len(logfile.data.etsecs) == 24
1612    assert len(logfile.data.etsecs[0]) == 1
1613    assert numpy.isnan(logfile.data.etsecs[0][0][2])
1614    assert len(logfile.data.etrotats) == 24
1615    assert logfile.data.etrotats[13] == -0.03974
1616
1617    assert logfile.data.metadata["legacy_package_version"] == "4.0.0"
1618    assert logfile.data.metadata["package_version"] == "4.0.0"
1619    assert isinstance(
1620        parse_version(logfile.data.metadata["package_version"]), Version
1621    )
1622
1623
1624def testORCA_ORCA4_0_hydrogen_fluoride_numfreq_out(logfile):
1625    """Frequencies from linear molecules weren't parsed correctly (#426)."""
1626    numpy.testing.assert_equal(logfile.data.vibfreqs, [4473.96])
1627
1628
1629def testORCA_ORCA4_0_hydrogen_fluoride_usesym_anfreq_out(logfile):
1630    """Frequencies from linear molecules weren't parsed correctly (#426)."""
1631    numpy.testing.assert_equal(logfile.data.vibfreqs, [4473.89])
1632
1633
1634def testORCA_ORCA4_0_invalid_literal_for_float_out(logfile):
1635    """MO coefficients are glued together, see #629."""
1636    assert hasattr(logfile.data, 'mocoeffs')
1637    assert logfile.data.mocoeffs[0].shape == (logfile.data.nmo, logfile.data.nbasis)
1638
1639    # Test the coefficients from this line where things are glued together:
1640    # 15C   6s       -154.480939-111.069870-171.460819-79.052025241.536860-92.159399
1641    assert logfile.data.mocoeffs[0][102][378] == -154.480939
1642    assert logfile.data.mocoeffs[0][103][378] == -111.069870
1643    assert logfile.data.mocoeffs[0][104][378] == -171.460819
1644    assert logfile.data.mocoeffs[0][105][378] == -79.052025
1645    assert logfile.data.mocoeffs[0][106][378] == 241.536860
1646    assert logfile.data.mocoeffs[0][107][378] == -92.159399
1647
1648    assert logfile.data.metadata["legacy_package_version"] == "4.0.1.2"
1649    assert logfile.data.metadata["package_version"] == "4.0.1.2"
1650    assert isinstance(
1651        parse_version(logfile.data.metadata["package_version"]), Version
1652    )
1653
1654
1655def testORCA_ORCA4_0_IrCl6_sp_out(logfile):
1656    """Tests ECP and weird SCF printing."""
1657    assert hasattr(logfile.data, 'scfvalues')
1658    assert len(logfile.data.scfvalues) == 1
1659    vals_first = [0.000000000000, 28.31276975, 0.71923638]
1660    vals_last = [0.000037800796, 0.00412549, 0.00014041]
1661    numpy.testing.assert_almost_equal(logfile.data.scfvalues[0][0], vals_first)
1662    numpy.testing.assert_almost_equal(logfile.data.scfvalues[0][-1], vals_last)
1663
1664def testORCA_ORCA4_0_comment_or_blank_line_out(logfile):
1665    """Coordinates with blank lines or comments weren't parsed correctly (#747)."""
1666    assert hasattr(logfile.data,"atomcoords")
1667    assert logfile.data.atomcoords.shape == (1, 8, 3)
1668
1669    assert logfile.data.metadata["legacy_package_version"] == "4.0.1.2"
1670    assert logfile.data.metadata["package_version"] == "4.0.1.2"
1671    assert isinstance(
1672        parse_version(logfile.data.metadata["package_version"]), Version
1673    )
1674
1675
1676def testORCA_ORCA4_1_725_out(logfile):
1677    """This file uses embedding potentials, which requires `>` after atom names in
1678    the input file and that confuses different parts of the parser.
1679
1680    In #725 we decided to not include these potentials in the parsed results.
1681    """
1682    assert logfile.data.natom == 7
1683    numpy.testing.assert_equal(logfile.data.atomnos, numpy.array([20, 17, 17, 17, 17, 17, 17], dtype=int))
1684    assert len(logfile.data.atomcharges["mulliken"]) == 7
1685    assert len(logfile.data.atomcharges["lowdin"]) == 7
1686
1687    assert logfile.data.metadata["legacy_package_version"] == "4.1.x"
1688    assert logfile.data.metadata["package_version"] == "4.1dev+13440"
1689    assert isinstance(
1690        parse_version(logfile.data.metadata["package_version"]), Version
1691    )
1692
1693
1694def testORCA_ORCA4_1_orca_from_issue_736_out(logfile):
1695    """ORCA file with no whitespace between SCF iteration columns."""
1696    assert len(logfile.data.scfvalues) == 23
1697    # The first iteration in the problematic block:
1698    # ITER       Energy         Delta-E        Max-DP      RMS-DP      [F,P]     Damp
1699    #           ***  Starting incremental Fock matrix formation  ***
1700    # 0   -257.0554667435   0.000000000000537.42184135  4.76025534  0.4401076 0.8500
1701    assert abs(logfile.data.scfvalues[14][0][1] - 537) < 1.0, logfile.data.scfvalues[14][0]
1702
1703
1704def testORCA_ORCA4_1_porphine_out(logfile):
1705    """ORCA optimization with multiple TD-DFT gradients and absorption spectra."""
1706    assert len(logfile.data.etenergies) == 1
1707
1708
1709def testORCA_ORCA4_1_single_atom_freq_out(logfile):
1710    """ORCA frequency with single atom."""
1711    assert len(logfile.data.vibdisps) == 0
1712    assert len(logfile.data.vibfreqs) == 0
1713    assert len(logfile.data.vibirs) == 0
1714    # These values are different from what ORCA prints as the total enthalpy,
1715    # because for single atoms that includes a spurious correction. We build the
1716    # enthalpy ourselves from electronic and translational energies (see #817 for details).
1717    numpy.testing.assert_almost_equal(logfile.data.enthalpy, -460.14376, 5)
1718    numpy.testing.assert_almost_equal(logfile.data.entropy, 6.056e-5, 8)
1719    numpy.testing.assert_almost_equal(logfile.data.freeenergy, -460.16182, 6)
1720
1721
1722def testORCA_ORCA4_2_947_out(logfile):
1723    """A constrained geometry optimization which prints the extra line
1724
1725    WARNING: THERE ARE 5 CONSTRAINED CARTESIAN COORDINATES
1726
1727    just before the gradient.
1728    """
1729    assert len(logfile.data.atomcoords) == 7
1730    assert len(logfile.data.grads) == 6
1731
1732
1733def testORCA_ORCA4_2_MP2_gradient_out(logfile):
1734    """ORCA numerical frequency calculation with gradients."""
1735    assert logfile.data.metadata["package_version"] == "4.2.0"
1736    assert hasattr(logfile.data, 'grads')
1737    assert logfile.data.grads.shape == (1, 3, 3)
1738    # atom 2, y-coordinate.
1739    idx = (0, 1, 1)
1740    assert logfile.data.grads[idx] == -0.00040549
1741
1742def testORCA_ORCA4_2_long_input_out(logfile):
1743    """Long ORCA input file (#804)."""
1744    assert logfile.data.metadata["package_version"] == "4.2.0"
1745    assert hasattr(logfile.data, 'atomcoords')
1746    assert logfile.data.atomcoords.shape == (100, 12, 3)
1747
1748
1749def testORCA_ORCA4_2_water_dlpno_ccsd_out(logfile):
1750    """DLPNO-CCSD files have extra lines between E(0) and E(TOT) than normal CCSD
1751    outputs:
1752
1753        ----------------------
1754        COUPLED CLUSTER ENERGY
1755        ----------------------
1756
1757        E(0)                                       ...    -74.963574242
1758        E(CORR)(strong-pairs)                      ...     -0.049905771
1759        E(CORR)(weak-pairs)                        ...      0.000000000
1760        E(CORR)(corrected)                         ...     -0.049905771
1761        E(TOT)                                     ...    -75.013480013
1762        Singles Norm <S|S>**1/2                    ...      0.013957180
1763        T1 diagnostic                              ...      0.004934608
1764    """
1765    assert hasattr(logfile.data, 'ccenergies')
1766
1767
1768def testORCA_ORCA4_2_longer_input_out(logfile):
1769    """Longer ORCA input file (#1034)."""
1770    assert logfile.data.metadata['input_file_contents'][-47:-4] == 'H   1.066878310   1.542378768  -0.602599044'
1771
1772
1773def testORCA_ORCA4_2_casscf_out(logfile):
1774    """ORCA casscf input file (#1044)."""
1775    assert numpy.isclose(logfile.data.etenergies[0], 28271.0)
1776
1777
1778# PSI 3 #
1779
1780
1781def testPsi3_Psi3_4_water_psi3_log(logfile):
1782    """An RHF for water with D orbitals and C2v symmetry.
1783
1784    Here we can check that the D orbitals are considered by checking atombasis and nbasis.
1785    """
1786    assert logfile.data.nbasis == 25
1787    assert [len(ab) for ab in logfile.data.atombasis] == [15, 5, 5]
1788
1789    assert logfile.data.metadata["legacy_package_version"] == "3.4"
1790    assert logfile.data.metadata["package_version"] == "3.4alpha"
1791    assert isinstance(
1792        parse_version(logfile.data.metadata["package_version"]), Version
1793    )
1794
1795
1796# PSI 4 #
1797
1798
1799def testPsi4_Psi4_beta5_dvb_gopt_hf_unconverged_out(logfile):
1800    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
1801    assert logfile.data.metadata["legacy_package_version"] == "beta5"
1802    assert logfile.data.metadata["package_version"] == "0!0.beta5"
1803    assert isinstance(
1804        parse_version(logfile.data.metadata["package_version"]), Version
1805    )
1806    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
1807
1808
1809def testPsi4_Psi4_beta5_sample_cc54_0_01_0_1_0_1_out(logfile):
1810    """TODO"""
1811    assert logfile.data.metadata["legacy_package_version"] == "beta2+"
1812    assert logfile.data.metadata["package_version"] == "0!0.beta2.dev+fa5960b375b8ca2a5e4000a48cb95e7f218c579a"
1813    assert isinstance(
1814        parse_version(logfile.data.metadata["package_version"]), Version
1815    )
1816
1817
1818def testPsi4_Psi4_beta5_stopiter_psi_dft_out(logfile):
1819    """Check to ensure that an incomplete SCF is handled correctly."""
1820    assert logfile.data.metadata["package_version"] == "0!0.beta5"
1821    assert isinstance(
1822        parse_version(logfile.data.metadata["package_version"]), Version
1823    )
1824    assert len(logfile.data.scfvalues[0]) == 7
1825
1826
1827def testPsi4_Psi4_beta5_stopiter_psi_hf_out(logfile):
1828    """Check to ensure that an incomplete SCF is handled correctly."""
1829    assert logfile.data.metadata["package_version"] == "0!0.beta5"
1830    assert len(logfile.data.scfvalues[0]) == 6
1831
1832
1833def testPsi4_Psi4_0_5_sample_scf5_out(logfile):
1834    assert logfile.data.metadata["legacy_package_version"] == "0.5"
1835    assert logfile.data.metadata["package_version"] == "1!0.5.dev+master-dbe9080"
1836    assert isinstance(
1837        parse_version(logfile.data.metadata["package_version"]), Version
1838    )
1839
1840
1841def testPsi4_Psi4_0_5_water_fdgrad_out(logfile):
1842    """Ensure that finite difference gradients are parsed."""
1843    assert logfile.data.metadata["legacy_package_version"] == "1.2a1.dev429"
1844    assert logfile.data.metadata["package_version"] == "1!1.2a1.dev429+fixsym-7838fc1-dirty"
1845    assert isinstance(
1846        parse_version(logfile.data.metadata["package_version"]), Version
1847    )
1848    assert hasattr(logfile.data, 'grads')
1849    assert logfile.data.grads.shape == (1, 3, 3)
1850    assert abs(logfile.data.grads[0, 0, 2] - 0.05498126903657) < 1.0e-12
1851    # In C2v symmetry, there are 5 unique displacements for the
1852    # nuclear gradient, and this is at the MP2 level.
1853    assert logfile.data.mpenergies.shape == (5, 1)
1854
1855
1856def testPsi4_Psi4_1_2_ch4_hf_opt_freq_out(logfile):
1857    """Ensure that molecular orbitals and normal modes are parsed in Psi4 1.2"""
1858    assert logfile.data.metadata["legacy_package_version"] == "1.2.1"
1859    assert logfile.data.metadata["package_version"] == "1!1.2.1.dev+HEAD-406f4de"
1860    assert isinstance(
1861        parse_version(logfile.data.metadata["package_version"]), Version
1862    )
1863    assert hasattr(logfile.data, 'mocoeffs')
1864    assert hasattr(logfile.data, 'vibdisps')
1865    assert hasattr(logfile.data, 'vibfreqs')
1866
1867
1868# Q-Chem #
1869
1870
1871def testQChem_QChem4_2_CH3___Na__RS_out(logfile):
1872    """An unrestricted fragment job with BSSE correction.
1873
1874    Contains only the Roothaan step energies for the CP correction.
1875
1876    The fragment SCF sections are printed.
1877
1878    This is to ensure only the supersystem is parsed.
1879    """
1880
1881    assert logfile.data.metadata["legacy_package_version"] == "4.2.2"
1882    assert logfile.data.metadata["package_version"] == "4.2.2"
1883    assert isinstance(
1884        parse_version(logfile.data.metadata["package_version"]), Version
1885    )
1886
1887    assert logfile.data.charge == 1
1888    assert logfile.data.mult == 2
1889    assert len(logfile.data.moenergies) == 2
1890    assert len(logfile.data.atomcoords[0]) == 5
1891    assert len(logfile.data.atomnos) == 5
1892
1893    # Fragments: A, B, RS_CP(A), RS_CP(B), Full
1894    assert len(logfile.data.scfenergies) == 1
1895    scfenergy = convertor(-201.9388745658, "hartree", "eV")
1896    assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10
1897
1898    assert logfile.data.nbasis == logfile.data.nmo == 40
1899    assert len(logfile.data.moenergies[0]) == 40
1900    assert len(logfile.data.moenergies[1]) == 40
1901    assert type(logfile.data.moenergies) == type([])
1902    assert type(logfile.data.moenergies[0]) == type(numpy.array([]))
1903    assert type(logfile.data.moenergies[1]) == type(numpy.array([]))
1904
1905
1906def testQChem_QChem4_2_CH3___Na__RS_SCF_out(logfile):
1907    """An unrestricted fragment job with BSSE correction.
1908
1909    Contains both the Roothaan step and full SCF energies for the CP correction.
1910
1911    The fragment SCF sections are printed.
1912
1913    This is to ensure only the supersystem is printed.
1914    """
1915
1916    assert logfile.data.metadata["legacy_package_version"] == "4.1.0.1"
1917    assert logfile.data.metadata["package_version"] == "4.1.0.1"
1918    assert isinstance(
1919        parse_version(logfile.data.metadata["package_version"]), Version
1920    )
1921
1922    assert logfile.data.charge == 1
1923    assert logfile.data.mult == 2
1924    assert len(logfile.data.moenergies) == 2
1925    assert len(logfile.data.atomcoords[0]) == 5
1926    assert len(logfile.data.atomnos) == 5
1927
1928    # Fragments: A, B, RS_CP(A), RS_CP(B), SCF_CP(A), SCF_CP(B), Full
1929    assert len(logfile.data.scfenergies) == 1
1930    scfenergy = convertor(-201.9396979324, "hartree", "eV")
1931    assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10
1932
1933    assert logfile.data.nbasis == logfile.data.nmo == 40
1934    assert len(logfile.data.moenergies[0]) == 40
1935    assert len(logfile.data.moenergies[1]) == 40
1936    assert type(logfile.data.moenergies) == type([])
1937    assert type(logfile.data.moenergies[0]) == type(numpy.array([]))
1938    assert type(logfile.data.moenergies[1]) == type(numpy.array([]))
1939
1940
1941def testQChem_QChem4_2_CH4___Na__out(logfile):
1942    """A restricted fragment job with no BSSE correction.
1943
1944    The fragment SCF sections are printed.
1945
1946    This is to ensure only the supersystem is parsed.
1947    """
1948
1949    assert logfile.data.metadata["legacy_package_version"] == "4.2.0"
1950    assert logfile.data.metadata["package_version"] == "4.2.0"
1951    assert isinstance(
1952        parse_version(logfile.data.metadata["package_version"]), Version
1953    )
1954
1955    assert logfile.data.charge == 1
1956    assert logfile.data.mult == 1
1957    assert len(logfile.data.moenergies) == 1
1958    assert len(logfile.data.atomcoords[0]) == 6
1959    assert len(logfile.data.atomnos) == 6
1960
1961    # Fragments: A, B, Full
1962    assert len(logfile.data.scfenergies) == 1
1963    scfenergy = convertor(-202.6119443654, "hartree", "eV")
1964    assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10
1965
1966    assert logfile.data.nbasis == logfile.data.nmo == 42
1967    assert len(logfile.data.moenergies[0]) == 42
1968    assert type(logfile.data.moenergies) == type([])
1969    assert type(logfile.data.moenergies[0]) == type(numpy.array([]))
1970
1971
1972def testQChem_QChem4_2_CH3___Na__RS_SCF_noprint_out(logfile):
1973    """An unrestricted fragment job with BSSE correction.
1974
1975    Contains both the Roothaan step and full SCF energies for the CP correction.
1976
1977    The fragment SCF sections are not printed.
1978
1979    This is to ensure only the supersystem is parsed.
1980    """
1981
1982    assert logfile.data.metadata["legacy_package_version"] == "4.3.0"
1983    assert logfile.data.metadata["package_version"] == "4.3.0"
1984    assert isinstance(
1985        parse_version(logfile.data.metadata["package_version"]), Version
1986    )
1987
1988    assert logfile.data.charge == 1
1989    assert logfile.data.mult == 2
1990    assert len(logfile.data.moenergies) == 2
1991    assert len(logfile.data.atomcoords[0]) == 5
1992    assert len(logfile.data.atomnos) == 5
1993
1994    assert len(logfile.data.scfenergies) == 1
1995    scfenergy = convertor(-201.9396979324, "hartree", "eV")
1996    assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10
1997
1998    assert logfile.data.nbasis == logfile.data.nmo == 40
1999    assert len(logfile.data.moenergies[0]) == 40
2000    assert len(logfile.data.moenergies[1]) == 40
2001    assert type(logfile.data.moenergies) == type([])
2002    assert type(logfile.data.moenergies[0]) == type(numpy.array([]))
2003    assert type(logfile.data.moenergies[1]) == type(numpy.array([]))
2004
2005
2006def testQChem_QChem4_2_CH3___Na__RS_noprint_out(logfile):
2007    """An unrestricted fragment job with BSSE correction.
2008
2009    Contains only the Roothaan step energies for the CP correction.
2010
2011    The fragment SCF sections are not printed.
2012
2013    This is to ensure only the supersystem is parsed.
2014    """
2015
2016    assert logfile.data.metadata["package_version"] == "4.3.0"
2017
2018    assert logfile.data.charge == 1
2019    assert logfile.data.mult == 2
2020    assert len(logfile.data.moenergies) == 2
2021    assert len(logfile.data.atomcoords[0]) == 5
2022    assert len(logfile.data.atomnos) == 5
2023
2024    assert len(logfile.data.scfenergies) == 1
2025    scfenergy = convertor(-201.9388582085, "hartree", "eV")
2026    assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10
2027
2028    assert logfile.data.nbasis == logfile.data.nmo == 40
2029    assert len(logfile.data.moenergies[0]) == 40
2030    assert len(logfile.data.moenergies[1]) == 40
2031    assert type(logfile.data.moenergies) == type([])
2032    assert type(logfile.data.moenergies[0]) == type(numpy.array([]))
2033    assert type(logfile.data.moenergies[1]) == type(numpy.array([]))
2034
2035
2036def testQChem_QChem4_2_CH4___Na__noprint_out(logfile):
2037    """A restricted fragment job with no BSSE correction.
2038
2039    The fragment SCF sections are not printed.
2040
2041    This is to ensure only the supersystem is parsed.
2042    """
2043
2044    assert logfile.data.metadata["package_version"] == "4.3.0"
2045
2046    assert logfile.data.charge == 1
2047    assert logfile.data.mult == 1
2048    assert len(logfile.data.moenergies) == 1
2049    assert len(logfile.data.atomcoords[0]) == 6
2050    assert len(logfile.data.atomnos) == 6
2051
2052    assert len(logfile.data.scfenergies) == 1
2053    scfenergy = convertor(-202.6119443654, "hartree", "eV")
2054    assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10
2055
2056    assert logfile.data.nbasis == logfile.data.nmo == 42
2057    assert len(logfile.data.moenergies[0]) == 42
2058    assert type(logfile.data.moenergies) == type([])
2059    assert type(logfile.data.moenergies[0]) == type(numpy.array([]))
2060
2061
2062def testQChem_QChem4_2_CO2_out(logfile):
2063    """A job containing a specific number of orbitals requested for
2064    printing.
2065    """
2066
2067    assert logfile.data.metadata["package_version"] == "4.2.2"
2068
2069    nbasis = 45
2070    nmo = 45
2071    nalpha = 11
2072    assert logfile.data.nbasis == nbasis
2073    assert logfile.data.nmo == nmo
2074    assert len(logfile.data.mocoeffs) == 1
2075    assert logfile.data.mocoeffs[0].shape == (nmo, nbasis)
2076    assert logfile.data.mocoeffs[0][0, 0] == -0.0001434
2077    assert logfile.data.mocoeffs[0][nalpha + 5 - 1, nbasis - 1] == -0.0000661
2078    assert len(logfile.data.moenergies) == 1
2079    assert len(logfile.data.moenergies[0]) == nmo
2080
2081
2082def testQChem_QChem4_2_CO2_cation_UHF_out(logfile):
2083    """A job containing a specific number of orbitals requested for
2084    printing."""
2085
2086    assert logfile.data.metadata["package_version"] == "4.2.2"
2087
2088    nbasis = 45
2089    nmo = 45
2090    nalpha = 11
2091    nbeta = 10
2092    assert logfile.data.nbasis == nbasis
2093    assert logfile.data.nmo == nmo
2094    assert len(logfile.data.mocoeffs) == 2
2095    assert logfile.data.mocoeffs[0].shape == (nmo, nbasis)
2096    assert logfile.data.mocoeffs[1].shape == (nmo, nbasis)
2097    assert logfile.data.mocoeffs[0][0, 0] == -0.0001549
2098    assert logfile.data.mocoeffs[0][nalpha + 5 - 1, nbasis - 1] == -0.0000985
2099    assert logfile.data.mocoeffs[1][0, 0] == -0.0001612
2100    assert logfile.data.mocoeffs[1][nbeta + 5 - 1, nbasis - 1] == -0.0027710
2101    assert len(logfile.data.moenergies) == 2
2102    assert len(logfile.data.moenergies[0]) == nmo
2103    assert len(logfile.data.moenergies[1]) == nmo
2104
2105
2106def testQChem_QChem4_2_CO2_cation_ROHF_bigprint_allvirt_out(logfile):
2107    """A job containing a specific number of orbitals requested for
2108    printing."""
2109
2110    assert logfile.data.metadata["package_version"] == "4.2.2"
2111
2112    nbasis = 45
2113    nmo = 45
2114    nalpha = 11
2115    nbeta = 10
2116    assert logfile.data.nbasis == nbasis
2117    assert logfile.data.nmo == nmo
2118    assert len(logfile.data.mocoeffs) == 2
2119    assert logfile.data.mocoeffs[0].shape == (nmo, nbasis)
2120    assert logfile.data.mocoeffs[1].shape == (nmo, nbasis)
2121    assert logfile.data.mocoeffs[0][0, 0] == -0.0001543
2122    assert logfile.data.mocoeffs[0][nalpha + 5 - 3, nbasis - 1] == -0.0132848
2123    assert logfile.data.mocoeffs[1][2, 0] == 0.9927881
2124    assert logfile.data.mocoeffs[1][nbeta + 5 - 1, nbasis - 1] == 0.0018019
2125    assert len(logfile.data.moenergies) == 2
2126    assert len(logfile.data.moenergies[0]) == nmo
2127    assert len(logfile.data.moenergies[1]) == nmo
2128
2129
2130def testQChem_QChem4_2_CO2_linear_dependence_printall_out(logfile):
2131    """A job with linear dependency and all MOs printed."""
2132
2133    assert logfile.data.metadata["package_version"] == "4.2.2"
2134
2135    nbasis = 138
2136    nmo = 106
2137    assert logfile.data.nbasis == nbasis
2138    assert logfile.data.nmo == nmo
2139    assert len(logfile.data.mocoeffs) == 1
2140    assert logfile.data.mocoeffs[0].shape == (nmo, nbasis)
2141    assert logfile.data.mocoeffs[0].T[59, 15] == -0.28758
2142    assert logfile.data.mocoeffs[0].T[59, 16] == -0.00000
2143
2144
2145def testQChem_QChem4_2_CO2_linear_dependence_printall_final_out(logfile):
2146    """A job with linear dependency and all MOs printed.
2147
2148    The increased precision is due to the presence of `scf_final_print
2149    = 3` giving a separate block with more decimal places.
2150    """
2151
2152    assert logfile.data.metadata["package_version"] == "4.2.2"
2153
2154    nbasis = 138
2155    nmo = 106
2156    assert logfile.data.nbasis == nbasis
2157    assert logfile.data.nmo == nmo
2158    assert len(logfile.data.mocoeffs) == 1
2159    assert logfile.data.mocoeffs[0].shape == (nmo, nbasis)
2160    assert logfile.data.mocoeffs[0].T[59, 15] == -0.2875844
2161    # Even though all MO coefficients are printed in the less precise
2162    # block, they aren't parsed.
2163    # assert logfile.data.mocoeffs[0].T[59, 16] == -0.00000
2164    assert numpy.isnan(logfile.data.mocoeffs[0].T[59, 16])
2165
2166
2167def testQChem_QChem4_2_CO2_linear_dependence_printdefault_out(logfile):
2168    """A job with linear dependency and the default number of MOs printed
2169    (all occupieds and 5 virtuals).
2170    """
2171
2172    assert logfile.data.metadata["package_version"] == "4.2.2"
2173
2174    nbasis = 138
2175    nmo = 106
2176    assert logfile.data.nbasis == nbasis
2177    assert logfile.data.nmo == nmo
2178    assert len(logfile.data.mocoeffs) == 1
2179    assert logfile.data.mocoeffs[0].shape == (nmo, nbasis)
2180    assert logfile.data.mocoeffs[0].T[59, 15] == -0.28758
2181    assert numpy.isnan(logfile.data.mocoeffs[0].T[59, 16])
2182
2183
2184def testQChem_QChem4_2_dvb_gopt_unconverged_out(logfile):
2185    """An unconverged geometry optimization to test for empty optdone (see #103 for details)."""
2186    assert logfile.data.metadata["package_version"] == "4.2.0"
2187    assert hasattr(logfile.data, 'optdone') and not logfile.data.optdone
2188
2189
2190def testQChem_QChem4_2_dvb_sp_multipole_10_out(logfile):
2191    """Multipole moments up to the 10-th order.
2192
2193    Since this example has various formats for the moment ranks, we can test
2194    the parser by making sure the first moment (pure X) is as expected.
2195    """
2196    assert logfile.data.metadata["package_version"] == "4.2.0"
2197    assert hasattr(logfile.data, 'moments') and len(logfile.data.moments) == 11
2198    tol = 1.0e-6
2199    assert logfile.data.moments[1][0] < tol
2200    assert abs(logfile.data.moments[2][0] - -50.9647) < tol
2201    assert abs(logfile.data.moments[3][0] - 0.0007) < tol
2202    assert abs(logfile.data.moments[4][0] - -1811.1540) < tol
2203    assert abs(logfile.data.moments[5][0] - 0.0159) < tol
2204    assert abs(logfile.data.moments[6][0] - -57575.0744) < tol
2205    assert abs(logfile.data.moments[7][0] - 0.3915) < tol
2206    assert numpy.isnan(logfile.data.moments[8][0])
2207    assert abs(logfile.data.moments[9][0] - 10.1638) < tol
2208    assert numpy.isnan(logfile.data.moments[10][0])
2209
2210
2211def testQChem_QChem4_2_MoOCl4_sp_noprint_builtin_mixed_all_Cl_out(logfile):
2212    """ECP on all Cl atoms, but iprint is off, so coreelectrons must be
2213    guessed.
2214    """
2215    assert logfile.data.metadata["package_version"] == "4.2.0"
2216    assert logfile.data.charge == -2
2217    assert logfile.data.mult == 1
2218    assert hasattr(logfile.data, 'coreelectrons')
2219    coreelectrons = numpy.array([0, 0, 10, 10, 10, 10], dtype=int)
2220    assert numpy.all(coreelectrons == logfile.data.coreelectrons)
2221
2222
2223def testQChem_QChem4_2_MoOCl4_sp_noprint_builtin_mixed_both_out(logfile):
2224    """ECP on Mo and all Cl atoms, but iprint is off, so coreelectrons
2225    can't be guessed.
2226
2227    Uses `ecp = gen`.
2228    """
2229    assert logfile.data.metadata["package_version"] == "4.2.0"
2230    assert logfile.data.charge == -2
2231    assert logfile.data.mult == 1
2232    assert not hasattr(logfile.data, 'coreelectrons')
2233
2234
2235def testQChem_QChem4_2_MoOCl4_sp_noprint_builtin_mixed_single_Mo_out(logfile):
2236    """ECP on Mo, but iprint is off, so coreelectrons must be guessed."""
2237    assert logfile.data.metadata["package_version"] == "4.2.0"
2238    assert logfile.data.charge == -2
2239    assert logfile.data.mult == 1
2240    assert hasattr(logfile.data, 'coreelectrons')
2241    coreelectrons = numpy.array([28, 0, 0, 0, 0, 0], dtype=int)
2242    assert numpy.all(coreelectrons == logfile.data.coreelectrons)
2243
2244
2245def testQChem_QChem4_2_MoOCl4_sp_noprint_builtin_out(logfile):
2246    """ECP on Mo and all Cl atoms, but iprint is off, so coreelectrons
2247    can't be guessed.
2248
2249    Uses `ecp = <builtin>`.
2250    """
2251    assert logfile.data.metadata["package_version"] == "4.2.0"
2252    assert logfile.data.charge == -2
2253    assert logfile.data.mult == 1
2254    assert not hasattr(logfile.data, 'coreelectrons')
2255
2256
2257def testQChem_QChem4_2_MoOCl4_sp_noprint_user_Mo_builtin_all_Cl_out(logfile):
2258    """ECP on Mo and all Cl atoms, but iprint is off; the coreelectrons
2259    count is given for Mo, and Cl can be guessed.
2260    """
2261    assert logfile.data.metadata["package_version"] == "4.2.0"
2262    assert logfile.data.charge == -2
2263    assert logfile.data.mult == 1
2264    assert hasattr(logfile.data, 'coreelectrons')
2265    coreelectrons = numpy.array([28, 0, 10, 10, 10, 10], dtype=int)
2266    assert numpy.all(coreelectrons == logfile.data.coreelectrons)
2267
2268
2269def testQChem_QChem4_2_MoOCl4_sp_print_builtin_mixed_single_Mo_single_Cl_out(logfile):
2270    """ECP on Mo and all Cl atoms; iprint is on, so coreelectrons can be
2271    calculated.
2272
2273    This was intended to only have an ECP on a single Cl, but Q-Chem
2274    silently puts it on all.
2275    """
2276    assert logfile.data.metadata["package_version"] == "4.2.0"
2277    assert logfile.data.charge == -2
2278    assert logfile.data.mult == 1
2279    assert hasattr(logfile.data, 'coreelectrons')
2280    coreelectrons = numpy.array([28, 0, 10, 10, 10, 10], dtype=int)
2281    assert numpy.all(coreelectrons == logfile.data.coreelectrons)
2282
2283
2284def testQChem_QChem4_2_print_frgm_false_opt_out(logfile):
2285    """Fragment calculation: geometry optimization.
2286
2287    Fragment sections are not printed.
2288    """
2289
2290    assert logfile.data.metadata["package_version"] == "4.3.0"
2291
2292    assert logfile.data.charge == -1
2293    assert logfile.data.mult == 1
2294
2295    assert len(logfile.data.scfenergies) == 11
2296    assert len(logfile.data.grads) == 11
2297
2298
2299def testQChem_QChem4_2_print_frgm_true_opt_out(logfile):
2300    """Fragment calculation: geometry optimization.
2301
2302    Fragment sections are printed.
2303    """
2304
2305    assert logfile.data.metadata["package_version"] == "4.3.0"
2306
2307    assert logfile.data.charge == -1
2308    assert logfile.data.mult == 1
2309
2310    assert len(logfile.data.scfenergies) == 11
2311    assert len(logfile.data.grads) == 11
2312
2313
2314def testQChem_QChem4_2_print_frgm_false_sp_out(logfile):
2315    """Fragment calculation: single point energy.
2316
2317    Fragment sections are not printed.
2318    """
2319
2320    assert logfile.data.metadata["package_version"] == "4.3.0"
2321
2322    assert logfile.data.charge == -1
2323    assert logfile.data.mult == 1
2324
2325    assert len(logfile.data.scfenergies) == 1
2326
2327
2328def testQChem_QChem4_2_print_frgm_true_sp_out(logfile):
2329    """Fragment calculation: single point energy.
2330
2331    Fragment sections are printed.
2332    """
2333
2334    assert logfile.data.metadata["package_version"] == "4.3.0"
2335
2336    assert logfile.data.charge == -1
2337    assert logfile.data.mult == 1
2338
2339    assert len(logfile.data.scfenergies) == 1
2340
2341
2342def testQChem_QChem4_2_print_frgm_true_sp_ccsdt_out(logfile):
2343    """Fragment calculation: single point energy, CCSD(T).
2344
2345    Fragment sections are printed.
2346    """
2347
2348    assert logfile.data.metadata["package_version"] == "4.3.0"
2349
2350    assert len(logfile.data.mpenergies[0]) == 1
2351    assert len(logfile.data.ccenergies) == 1
2352
2353
2354def testQChem_QChem4_2_qchem_tddft_rpa_out(logfile):
2355    """An RPA/TD-DFT job.
2356
2357    Here Q-Chem prints both the TDA and RPA results. These differ somewhat, since
2358    TDA allows only X vectors (occupied-virtual transitions) whereas RPA also
2359    allows Y vectors (virtual-occupied deexcitations), and the formatting in these
2360    two cases is subtly different (see cclib/cclib#154 for details).
2361
2362    Currently cclib will store the second set of transitions (RPA), but this
2363    could change in the future if we support multistep jobs.
2364    """
2365
2366    assert logfile.data.metadata["package_version"] == "4.2.0"
2367
2368    assert len(logfile.data.etsecs) == 10
2369    assert len(logfile.data.etsecs[0]) == 13
2370
2371    # Check a few vectors manually, since we know the output. X vectors are transitions
2372    # from occupied to virtual orbitals, whereas Y vectors the other way around, so cclib
2373    # should be switching the indices. Here is the corresponding fragment in the logfile:
2374    #     Excited state 1: excitation energy (eV) = 3.1318
2375    #     Total energy for state 1: -382.185270280389
2376    #     Multiplicity: Triplet
2377    #     Trans. Mom.: 0.0000 X 0.0000 Y 0.0000 Z
2378    #     Strength : 0.0000
2379    #     X: D( 12) --> V( 13) amplitude = 0.0162
2380    #     X: D( 28) --> V( 5) amplitude = 0.1039
2381    #     Y: D( 28) --> V( 5) amplitude = 0.0605
2382    assert logfile.data.etsecs[0][0] == [(11, 0), (47, 0), 0.0162]
2383    assert logfile.data.etsecs[0][1] == [(27, 0), (39, 0), 0.1039]
2384    assert logfile.data.etsecs[0][2] == [(39, 0), (27, 0), 0.0605]
2385
2386
2387def testQChem_QChem4_2_read_molecule_out(logfile):
2388    """A two-calculation output with the charge/multiplicity not specified
2389    in the user section."""
2390
2391    assert logfile.data.metadata["package_version"] == "4.3.0"
2392
2393    # These correspond to the second calculation.
2394    assert logfile.data.charge == 1
2395    assert logfile.data.mult == 2
2396    assert len(logfile.data.moenergies) == 2
2397
2398    # However, we currently take data from both, since they aren't
2399    # exactly fragment calculations.
2400    assert len(logfile.data.scfenergies) == 2
2401
2402
2403def testQChem_QChem4_2_stopiter_qchem_out(logfile):
2404    """Check to ensure that an incomplete SCF is handled correctly."""
2405    assert logfile.data.metadata["legacy_package_version"] == "4.0.0.1"
2406    assert logfile.data.metadata["package_version"] == "4.0.0.1"
2407    assert isinstance(
2408        parse_version(logfile.data.metadata["package_version"]), Version
2409    )
2410    assert len(logfile.data.scfvalues[0]) == 7
2411
2412
2413def testQChem_QChem4_3_R_propylene_oxide_force_ccsd_out(logfile):
2414    """Check to see that the CCSD gradient (not the HF gradient) is being
2415    parsed.
2416    """
2417    assert logfile.data.metadata["package_version"] == "4.3.0"
2418    assert hasattr(logfile.data, 'grads')
2419    assert logfile.data.grads.shape == (1, logfile.data.natom, 3)
2420    # atom 9, y-coordinate.
2421    idx = (0, 8, 1)
2422    assert logfile.data.grads[idx] == 0.00584973
2423
2424
2425def testQChem_QChem4_3_R_propylene_oxide_force_hf_numerical_energies_out(logfile):
2426    """Check to see that the HF numerical gradient (from energies) is
2427    being parsed.
2428    """
2429    assert logfile.data.metadata["package_version"] == "4.3.0"
2430    # This isn't implemented yet.
2431    assert not hasattr(logfile.data, "grads")
2432
2433
2434def testQChem_QChem4_3_R_propylene_oxide_force_mp2_out(logfile):
2435    """Check to see that the MP2 gradient (not the HF gradient) is
2436    being parsed.
2437    """
2438    assert logfile.data.metadata["package_version"] == "4.3.0"
2439    assert hasattr(logfile.data, 'grads')
2440    assert logfile.data.grads.shape == (1, logfile.data.natom, 3)
2441    # atom 9, y-coordinate.
2442    idx = (0, 8, 1)
2443    assert logfile.data.grads[idx] == 0.00436177
2444
2445
2446def testQChem_QChem4_3_R_propylene_oxide_force_rimp2_out(logfile):
2447    """Check to see that the RI-MP2 gradient (not the HF gradient) is
2448    being parsed.
2449    """
2450    assert logfile.data.metadata["package_version"] == "4.3.0"
2451    assert hasattr(logfile.data, 'grads')
2452    assert logfile.data.grads.shape == (1, logfile.data.natom, 3)
2453    # atom 9, y-coordinate.
2454    idx = (0, 8, 1)
2455    assert logfile.data.grads[idx] == 0.00436172
2456
2457
2458def testQChem_QChem4_3_R_propylene_oxide_freq_ccsd_out(logfile):
2459    """Check to see that the CCSD (numerical) Hessian is being parsed.
2460    """
2461    assert logfile.data.metadata["package_version"] == "4.3.0"
2462    # The gradient of the initial geometry in a Hessian calculated
2463    # from finite difference of gradients should be the same as in a
2464    # force calculation.
2465    assert hasattr(logfile.data, 'grads')
2466    ngrads = 1 + 6*logfile.data.natom
2467    assert logfile.data.grads.shape == (ngrads, logfile.data.natom, 3)
2468    # atom 9, y-coordinate.
2469    idx = (0, 8, 1)
2470    assert logfile.data.grads[idx] == 0.00584973
2471
2472    assert hasattr(logfile.data, 'hessian')
2473    assert logfile.data.hessian.shape == (3*logfile.data.natom, 3*logfile.data.natom)
2474    # atom 4, x-coordinate.
2475    idx = (9, 9)
2476    assert logfile.data.hessian[idx] == 0.3561243
2477
2478
2479def testQChem_QChem4_3_R_propylene_oxide_freq_hf_numerical_gradients_out(logfile):
2480    """Check to see that the HF Hessian (from gradients) is being parsed.
2481    """
2482    assert logfile.data.metadata["package_version"] == "4.3.0"
2483    # This isn't implemented yet.
2484    assert not hasattr(logfile.data, "freq")
2485
2486
2487def testQChem_QChem4_3_R_propylene_oxide_freq_mp2_out(logfile):
2488    """Check to see that the MP2 (numerical) Hessian is being parsed.
2489    """
2490    assert logfile.data.metadata["package_version"] == "4.3.0"
2491    # The gradient of the initial geometry in a Hessian calculated
2492    # from finite difference of gradients should be the same as in a
2493    # force calculation.
2494    assert hasattr(logfile.data, 'grads')
2495    ngrads = 1 + 6*logfile.data.natom
2496    assert logfile.data.grads.shape == (ngrads, logfile.data.natom, 3)
2497    # atom 9, y-coordinate.
2498    idx = (0, 8, 1)
2499    assert logfile.data.grads[idx] == 0.00436177
2500
2501    assert hasattr(logfile.data, 'hessian')
2502    assert logfile.data.hessian.shape == (3*logfile.data.natom, 3*logfile.data.natom)
2503    # atom 4, x-coordinate.
2504    idx = (9, 9)
2505    assert logfile.data.hessian[idx] == 0.3520255
2506
2507
2508def testQChem_QChem4_3_R_propylene_oxide_freq_rimp2_out(logfile):
2509    """Check to see that the RI-MP2 (numerical) Hessian is being parsed.
2510    """
2511    assert logfile.data.metadata["package_version"] == "4.3.0"
2512    # The gradient of the initial geometry in a Hessian calculated
2513    # from finite difference of gradients should be the same as in a
2514    # force calculation.
2515    assert hasattr(logfile.data, 'grads')
2516    ngrads = 1 + 6*logfile.data.natom
2517    assert logfile.data.grads.shape == (ngrads, logfile.data.natom, 3)
2518    # atom 9, y-coordinate.
2519    idx = (0, 8, 1)
2520    # Well, not quite in this case...
2521    assert logfile.data.grads[idx] == 0.00436167
2522
2523    assert hasattr(logfile.data, 'hessian')
2524    assert logfile.data.hessian.shape == (3*logfile.data.natom, 3*logfile.data.natom)
2525    # atom 4, x-coordinate.
2526    idx = (9, 9)
2527    assert logfile.data.hessian[idx] == 0.3520538
2528
2529
2530def testQChem_QChem4_4_full_2_out(logfile):
2531    """The polarizability section may not be parsed due to something
2532    appearing just beforehand from a frequency-type calculation.
2533    """
2534    assert logfile.data.metadata["legacy_package_version"] == "4.4.2"
2535    assert logfile.data.metadata["package_version"] == "4.4.2"
2536    assert isinstance(
2537        parse_version(logfile.data.metadata["package_version"]), Version
2538    )
2539    assert hasattr(logfile.data, 'polarizabilities')
2540
2541
2542def testQChem_QChem4_4_srtlg_out(logfile):
2543    """Some lines in the MO coefficients require fixed-width parsing. See
2544    #349 and #381.
2545    """
2546    assert logfile.data.metadata["legacy_package_version"] == "4.4.0"
2547    assert logfile.data.metadata["package_version"] == "4.4.0"
2548    assert isinstance(
2549        parse_version(logfile.data.metadata["package_version"]), Version
2550    )
2551    # There is a linear dependence problem.
2552    nbasis, nmo = 1129, 1115
2553    assert len(logfile.data.mocoeffs) == 2
2554    assert logfile.data.mocoeffs[0].shape == (nmo, nbasis)
2555    assert logfile.data.mocoeffs[1].shape == (nmo, nbasis)
2556    index_ao = 151 - 1
2557    indices_mo = [index_mo - 1 for index_mo in (493, 494, 495, 496, 497, 498)]
2558    # line 306371:
2559    #  151  C 7   s      -54.24935 -36.37903-102.67529  32.37428-150.40380-103.24478
2560    ref = numpy.asarray([-54.24935, -36.37903, -102.67529, 32.37428, -150.40380, -103.24478])
2561    res = logfile.data.mocoeffs[1][indices_mo, index_ao]
2562    numpy.testing.assert_allclose(ref, res, atol=1.0e-5, rtol=0.0)
2563
2564
2565def testQChem_QChem4_4_Trp_polar_ideriv0_out(logfile):
2566    """Ensure that the polarizability section is being parsed, but don't
2567    compare to reference results as 2nd-order finite difference can have
2568    large errors.
2569    """
2570    assert logfile.data.metadata["package_version"] == "4.4.2"
2571    assert hasattr(logfile.data, 'polarizabilities')
2572
2573
2574def testQChem_QChem4_4_top_out(logfile):
2575    """This job has fewer MOs (7) than would normally be printed (15)."""
2576    assert logfile.data.metadata["package_version"] == "4.4.2"
2577    nbasis = 7
2578    nmo = 7
2579    assert logfile.data.nbasis == nbasis
2580    assert logfile.data.nmo == nmo
2581    assert len(logfile.data.mocoeffs) == 1
2582    assert logfile.data.mocoeffs[0].shape == (nmo, nbasis)
2583    assert logfile.data.mocoeffs[0].T[6, 5] == 0.8115082
2584
2585
2586def testQChem_QChem5_0_438_out(logfile):
2587    """This job has an ECP on Pt, replacing 60 of 78 electrons, and was
2588    showing the charge as 60.
2589    """
2590    assert logfile.data.metadata["legacy_package_version"] == "5.0.0"
2591    assert logfile.data.metadata["package_version"] == "5.0.0"
2592    assert isinstance(
2593        parse_version(logfile.data.metadata["package_version"]), Version
2594    )
2595    assert logfile.data.charge == 0
2596    assert logfile.data.coreelectrons[0] == 60
2597
2598
2599def testQChem_QChem5_0_argon_out(logfile):
2600    """This job has unit specifications at the end of 'Total energy for
2601    state' lines.
2602    """
2603    assert logfile.data.metadata["legacy_package_version"] == "5.0.1"
2604    assert logfile.data.metadata["package_version"] == "5.0.1"
2605    assert isinstance(
2606        parse_version(logfile.data.metadata["package_version"]), Version
2607    )
2608    nroots = 12
2609    assert len(logfile.data.etenergies) == nroots
2610    state_0_energy = -526.6323968555
2611    state_1_energy = -526.14663738
2612    assert logfile.data.scfenergies[0] == convertor(state_0_energy, 'hartree', 'eV')
2613    assert abs(logfile.data.etenergies[0] - convertor(state_1_energy - state_0_energy, 'hartree', 'wavenumber')) < 1.0e-1
2614
2615def testQChem_QChem5_0_Si_out(logfile):
2616    """
2617    This job includes MOs as a test for this version. This fist MO coefficient is checked to ensure they were parsed.
2618    """
2619    assert logfile.data.metadata["legacy_package_version"] == "5.0.2"
2620    assert logfile.data.metadata["package_version"] == "5.0.2"
2621    assert isinstance(
2622        parse_version(logfile.data.metadata["package_version"]), Version
2623    )
2624    assert logfile.data.mocoeffs[0][0,0] == 1.00042
2625
2626def testQChem_QChem5_1_old_final_print_1_out(logfile):
2627    """This job has was run from a development version."""
2628    assert logfile.data.metadata["legacy_package_version"] == "5.1.0"
2629    assert logfile.data.metadata["package_version"] == "5.1.0dev+branches_libresponse-27553"
2630    assert isinstance(
2631        parse_version(logfile.data.metadata["package_version"]), Version
2632    )
2633
2634
2635def testQChem_QChem5_2_HSO2F_TS_out(logfile):
2636    """This file consists of three parts: an initial frequency calculation, a
2637    transition state search, then a final frequency calculation for TS
2638    confirmation.  The last set of vibrational analysis information should be
2639    saved, not the first set.
2640    """
2641    assert logfile.data.vibfreqs[0] == -1388.93
2642
2643
2644def testQChem_QChem5_3_ccman2_soc_cisd_out(logfile):
2645    """This file has its atomcoords in bohr, which need to be converted."""
2646    convfac = 0.5291772109
2647    assert logfile.data.atomcoords[0, 0, 2] == -0.24685 * convfac
2648    assert logfile.data.atomcoords[0, 1, 2] == 1.72795 * convfac
2649
2650
2651# Turbomole
2652
2653
2654def testTurbomole_Turbomole7_2_dvb_gopt_b3_lyp_Gaussian__(logfile):
2655    assert logfile.data.metadata["legacy_package_version"] == "7.2"
2656    assert logfile.data.metadata["package_version"] == "7.2.r21471"
2657    assert isinstance(
2658        parse_version(logfile.data.metadata["package_version"]), Version
2659    )
2660    assert logfile.data.natom == 20
2661
2662
2663# These regression tests are for logfiles that are not to be parsed
2664# for some reason, and the function should start with 'testnoparse'.
2665
2666
2667def testnoparseADF_ADF2004_01_mo_sp_adfout(filename):
2668    """This is an ADF file that has a different number of AO functions
2669    and SFO functions. Currently nbasis parses the SFO count. This will
2670    be discussed and resolved in the future (see issue #170), and can
2671    this to get rid of the error in the meantime.
2672    """
2673    pass
2674
2675
2676def testnoparseGaussian_Gaussian09_coeffs_log(filename):
2677    """This is a test for a Gaussian file with more than 999 basis functions.
2678
2679    The log file is too big, so we are just including a section. Before
2680    parsing, we set some attributes of the parser so that it all goes smoothly.
2681    """
2682
2683    parser = Gaussian(os.path.join(__filedir__, filename), loglevel=logging.ERROR)
2684    parser.nmo = 5
2685    parser.nbasis = 1128
2686
2687    data = parser.parse()
2688    assert data.mocoeffs[0].shape == (5, 1128)
2689    assert data.aonames[-1] == "Ga71_19D-2"
2690    assert data.aonames[0] == "Mn1_1S"
2691
2692
2693def flatten(seq):
2694    """Converts a list of lists [of lists] to a single flattened list.
2695
2696    Taken from the web.
2697    """
2698    res = []
2699    for item in seq:
2700        if (isinstance(item, (tuple, list))):
2701            res.extend(flatten(item))
2702        else:
2703            res.append(item)
2704    return res
2705
2706
2707def normalisefilename(filename):
2708    """Replace all non-alphanumeric symbols by underscores.
2709
2710    >>> from . import regression
2711    >>> for x in [ "Gaussian/Gaussian03/Mo4OSibdt2-opt.log" ]:
2712    ...     print(regression.normalisefilename(x))
2713    ...
2714    Gaussian_Gaussian03_Mo4OSibdt2_opt_log
2715    """
2716    ans = []
2717    for y in filename:
2718        x = y.lower()
2719        if (x >= 'a' and x <= 'z') or (x >= '0' and x <= '9'):
2720            ans.append(y)
2721        else:
2722            ans.append("_")
2723    return "".join(ans)
2724
2725# When a unit test is removed or replaced by a newer version, we normally want
2726# the old logfile to become a regression, namely to run the unit test as part of
2727# the regression suite. To this end, add the logfile path to the dictionary
2728# below along with the appropriate unit test class to use, and the appropriate
2729# regression test function will be created automatically. If modifications
2730# are necessary due to developments in the unit test class, tweak it here
2731# and provide the modified version of the test class.
2732
2733# Although there is probably a cleaner way to do this, making the unit class test names
2734# global makes reading the dictionary of old unit tests much easier, especially it
2735# will contain some classes defined here.
2736for m, module in all_modules.items():
2737    for name in dir(module):
2738        if name[-4:] == "Test":
2739            globals()[name] = getattr(module, name)
2740
2741
2742class ADFGeoOptTest_noscfvalues(ADFGeoOptTest):
2743    @unittest.skip('Cannot parse scfvalues from this file.')
2744    def testgeovalues_scfvalues(self):
2745        """SCF cycles were not printed here."""
2746
2747    @unittest.skip('Cannot parse scfvalues from this file.')
2748    def testscftargetdim(self):
2749        """SCF cycles were not printed here."""
2750
2751    @unittest.skip('Cannot parse scfvalues from this file.')
2752    def testscfvaluetype(self):
2753        """SCF cycles were not printed here."""
2754
2755
2756class ADFSPTest_noscfvalues(ADFSPTest):
2757    @unittest.skip('Cannot parse scfvalues from this file.')
2758    def testscftargetdim(self):
2759        """SCF cycles were not printed here."""
2760
2761    @unittest.skip('Cannot parse scfvalues from this file.')
2762    def testscfvaluetype(self):
2763        """SCF cycles were not printed here."""
2764
2765    @unittest.skip('Cannot parse aooverlaps from this file.')
2766    def testaooverlaps(self):
2767        """AO overlaps were not printed here."""
2768
2769
2770class ADFSPTest_nosyms(ADFSPTest, GenericSPTest):
2771    foverlap00 = 1.00000
2772    foverlap11 = 0.99999
2773    foverlap22 = 0.99999
2774    @unittest.skip('Symmetry labels were not printed here')
2775    def testsymlabels(self):
2776        """Symmetry labels were not printed here."""
2777
2778
2779class ADFSPTest_nosyms_noscfvalues(ADFSPTest_nosyms):
2780    @unittest.skip('Cannot parse scfvalues from this file.')
2781    def testscftargetdim(self):
2782        """SCF cycles were not printed here."""
2783
2784    @unittest.skip('Cannot parse scfvalues from this file.')
2785    def testscfvaluetype(self):
2786        """SCF cycles were not printed here."""
2787
2788    @unittest.skip('Cannot parse aooverlaps from this file.')
2789    def testaooverlaps(self):
2790        """AO overlaps were not printed here."""
2791
2792
2793class ADFSPTest_nosyms_valence(ADFSPTest_nosyms):
2794    def testlengthmoenergies(self):
2795        """Only valence orbital energies were printed here."""
2796        self.assertEqual(len(self.data.moenergies[0]), 45)
2797        self.assertEqual(self.data.moenergies[0][0], 99999.0)
2798
2799
2800class ADFSPTest_nosyms_valence_noscfvalues(ADFSPTest_nosyms_valence):
2801    @unittest.skip('Cannot parse scfvalues from this file.')
2802    def testscftargetdim(self):
2803        """SCF cycles were not printed here."""
2804
2805    @unittest.skip('Cannot parse scfvalues from this file.')
2806    def testscfvaluetype(self):
2807        """SCF cycles were not printed here."""
2808
2809    @unittest.skip('Cannot parse aooverlaps from this file.')
2810    def testaooverlaps(self):
2811        """AO overlaps were not printed here."""
2812
2813# DATLON #
2814
2815
2816class DALTONBigBasisTest_aug_cc_pCVQZ(GenericBigBasisTest):
2817    contractions = { 6: 29 }
2818    spherical = True
2819
2820
2821class DALTONSPTest_nosymmetry(GenericSPTest):
2822
2823    def testsymlabels(self):
2824        """Are all the symmetry labels either Ag/u or Bg/u?"""
2825        # A calculation without symmetry, meaning it belongs to the C1 point
2826        # group, only has the `A` irreducible representation.
2827        sumwronglabels = sum(x not in {'A'} for x in self.data.mosyms[0])
2828        self.assertEqual(sumwronglabels, 0)
2829
2830    def testmetadata_symmetry_detected(self):
2831        """Does metadata have expected keys and values?"""
2832        self.assertEqual(self.data.metadata["symmetry_detected"], "c1")
2833
2834    def testmetadata_symmetry_used(self):
2835        """Does metadata have expected keys and values?"""
2836        self.assertEqual(self.data.metadata["symmetry_used"], "c1")
2837
2838
2839class DALTONTDTest_noetsecs(DALTONTDTest):
2840    @unittest.skip("etsecs cannot be parsed from this file")
2841    def testsecs(self):
2842        pass
2843    @unittest.skip("etsecs cannot be parsed from this file")
2844    def testsecs_transition(self):
2845        pass
2846
2847# GAMESS #
2848
2849
2850class GAMESSUSSPunTest_charge0(GenericSPunTest):
2851    def testcharge_and_mult(self):
2852        """The charge in the input was wrong."""
2853        self.assertEqual(self.data.charge, 0)
2854    @unittest.skip('HOMOs were incorrect due to charge being wrong')
2855    def testhomos(self):
2856        """HOMOs were incorrect due to charge being wrong."""
2857
2858
2859class GAMESSUSIRTest_ts(GenericIRimgTest):
2860    @unittest.skip('This is a transition state with different intensities')
2861    def testirintens(self):
2862        """This is a transition state with different intensities."""
2863
2864
2865class GAMESSUSCISTest_dets(GenericCISTest):
2866    nstates = 10
2867    @unittest.skip('This gives unexpected coeficcients, also for current unit tests.')
2868    def testetsecsvalues(self):
2869        """This gives unexpected coeficcients, also for current unit tests."""
2870
2871
2872class GAMESSSPTest_noaooverlaps(GenericSPTest):
2873    @unittest.skip('Cannot parse aooverlaps from this file.')
2874    def testaooverlaps(self):
2875        """aooverlaps were not printed here."""
2876
2877# Gaussian #
2878
2879class GaussianSPunTest_nomosyms(GaussianSPunTest):
2880    @unittest.skip('Cannot parse mosyms from this file.')
2881    def testmosyms(self):
2882        """mosyms were not printed here."""
2883
2884
2885class GaussianSPunTest_nonaturalorbitals(GaussianCISTest):
2886    @unittest.skip('Cannot parse natrual orbitals from this file.')
2887    def testnocoeffs(self):
2888        """natural orbitals were not printed here."""
2889
2890    @unittest.skip('Cannot parse natrual orbital occupation numbers from this file.')
2891    def testnooccnos(self):
2892        """natural orbital occupation numbers were not printed here."""
2893
2894
2895class GaussianPolarTest(ReferencePolarTest):
2896    """Customized static polarizability unittest, meant for calculations
2897    with symmetry enabled.
2898    """
2899
2900    # Reference values are from Q-Chem 4.2/trithiolane_freq.out, since
2901    # with symmetry enabled Q-Chem reorients molecules similarly to
2902    # Gaussian.
2903    isotropic = 66.0955766
2904    principal_components = [46.71020322, 75.50778705, 76.06873953]
2905    # Make the thresholds looser because these test jobs use symmetry,
2906    # and the polarizability is orientation dependent.
2907    isotropic_delta = 2.0
2908    principal_components_delta = 0.7
2909
2910# Jaguar #
2911
2912
2913class JaguarSPTest_6_31gss(JaguarSPTest):
2914    """AO counts and some values are different in 6-31G** compared to STO-3G."""
2915    nbasisdict = {1: 5, 6: 15}
2916    b3lyp_energy = -10530
2917    overlap01 = 0.22
2918
2919    def testmetadata_basis_set(self):
2920        """This calculation did not use STO-3G for the basis set."""
2921        self.assertEqual(self.data.metadata["basis_set"].lower(), "6-31g**")
2922
2923
2924class JaguarSPTest_6_31gss_nomosyms(JaguarSPTest_6_31gss):
2925    @unittest.skip('Cannot parse mosyms from this file.')
2926    def testsymlabels(self):
2927        """mosyms were not printed here."""
2928
2929
2930class JaguarSPunTest_nomosyms(JaguarSPunTest):
2931    @unittest.skip('Cannot parse mosyms from this file.')
2932    def testmosyms(self):
2933        """mosyms were not printed here."""
2934
2935
2936class JaguarSPunTest_nmo_all(JaguarSPunTest):
2937    def testmoenergies(self):
2938        """Some tests printed all MO energies apparently."""
2939        self.assertEqual(len(self.data.moenergies[0]), self.data.nmo)
2940
2941
2942class JaguarSPunTest_nmo_all_nomosyms(JaguarSPunTest_nmo_all):
2943    @unittest.skip('Cannot parse mosyms from this file.')
2944    def testmosyms(self):
2945        """mosyms were not printed here."""
2946
2947
2948class JaguarGeoOptTest_nmo45(GenericGeoOptTest):
2949    def testlengthmoenergies(self):
2950        """Without special options, Jaguar only print Homo+10 orbital energies."""
2951        self.assertEqual(len(self.data.moenergies[0]), 45)
2952
2953
2954class JaguarSPTest_nmo45(GenericSPTest):
2955    def testlengthmoenergies(self):
2956        """Without special options, Jaguar only print Homo+10 orbital energies."""
2957        self.assertEqual(len(self.data.moenergies[0]), 45)
2958
2959    @unittest.skip('Cannot parse mos from this file.')
2960    def testfornoormo(self):
2961        """mos were not printed here."""
2962
2963    @unittest.skip('Cannot parse scftargets from this file.')
2964    def testscftargets(self):
2965        """scftargets were not parsed correctly here."""
2966
2967    @unittest.skip('Cannot parse atomcharges from this file.')
2968    def testatomcharges(self):
2969        """atomcharges were not parsed correctly here."""
2970
2971    @unittest.skip('Cannot parse atombasis from this file.')
2972    def testatombasis(self):
2973        """atombasis was not parsed correctly here."""
2974
2975
2976class JaguarSPunTest_nmo45(GenericSPunTest):
2977    def testlengthmoenergies(self):
2978        """Without special options, Jaguar only print Homo+10 orbital energies."""
2979        self.assertEqual(len(self.data.moenergies[0]), 45)
2980
2981
2982class JaguarGeoOptTest_nmo45(GenericGeoOptTest):
2983    def testlengthmoenergies(self):
2984        """Without special options, Jaguar only print Homo+10 orbital energies."""
2985        self.assertEqual(len(self.data.moenergies[0]), 45)
2986
2987
2988class JaguarGeoOptTest_nmo45_nogeo(JaguarGeoOptTest_nmo45):
2989    @unittest.skip('Cannot parse geotargets from this file.')
2990    def testgeotargets(self):
2991        """geotargets were not printed here."""
2992
2993    @unittest.skip('Cannot parse geovalues from this file.')
2994    def testgeovalues_atomcoords(self):
2995        """geovalues were not printed here."""
2996
2997    @unittest.skip('Cannot parse geovalues from this file.')
2998    def testgeovalues_scfvalues(self):
2999        """geovalues were not printed here."""
3000
3001    @unittest.skip('Cannot parse optdone from this file.')
3002    def testoptdone(self):
3003        """optdone does not exist for this file."""
3004
3005
3006class JaguarGeoOptTest_6_31gss(GenericGeoOptTest):
3007    nbasisdict = {1: 5, 6: 15}
3008    b3lyp_energy = -10530
3009
3010
3011class MolcasBigBasisTest_nogbasis(MolcasBigBasisTest):
3012    @unittest.skip('gbasis was not printed in this output file')
3013    def testgbasis(self):
3014        """gbasis was not parsed for this file"""
3015
3016    @unittest.skip('gbasis was not printed in this output file')
3017    def testnames(self):
3018        """gbasis was not parsed for this file"""
3019
3020    @unittest.skip('gbasis was not printed in this output file')
3021    def testprimitives(self):
3022        """gbasis was not parsed for this file"""
3023
3024    @unittest.skip('gbasis was not printed in this output file')
3025    def testsizeofbasis(self):
3026        """gbasis was not parsed for this file"""
3027
3028# Molpro #
3029
3030
3031class MolproBigBasisTest_cart(MolproBigBasisTest):
3032    spherical = False
3033
3034# ORCA #
3035
3036
3037class OrcaSPTest_3_21g(OrcaSPTest, GenericSPTest):
3038    nbasisdict = {1: 2, 6: 9}
3039    b3lyp_energy = -10460
3040    overlap01 = 0.19
3041    molecularmass = 130190
3042    @unittest.skip('This calculation has no symmetry.')
3043    def testsymlabels(self):
3044        """This calculation has no symmetry."""
3045
3046
3047class OrcaGeoOptTest_3_21g(OrcaGeoOptTest):
3048    nbasisdict = {1: 2, 6: 9}
3049    b3lyp_energy = -10460
3050
3051
3052class OrcaSPunTest_charge0(GenericSPunTest):
3053    def testcharge_and_mult(self):
3054        """The charge in the input was wrong."""
3055        self.assertEqual(self.data.charge, 0)
3056    @unittest.skip('HOMOs were incorrect due to charge being wrong.')
3057    def testhomos(self):
3058        """HOMOs were incorrect due to charge being wrong."""
3059    def testorbitals(self):
3060        """Closed-shell calculation run as open-shell."""
3061        self.assertTrue(self.data.closed_shell)
3062
3063
3064class OrcaTDDFTTest_error(OrcaTDDFTTest):
3065    def testoscs(self):
3066        """These values used to be less accurate, probably due to wrong coordinates."""
3067        self.assertEqual(len(self.data.etoscs), self.number)
3068        self.assertAlmostEqual(max(self.data.etoscs), 1.0, delta=0.2)
3069
3070
3071class OrcaIRTest_old_coordsOK(OrcaIRTest):
3072
3073    zpve = 0.1986
3074
3075    enthalpy_places = -1
3076    entropy_places = 2
3077    freeenergy_places = -1
3078
3079
3080class OrcaIRTest_old(OrcaIRTest):
3081    """The frequency part of this calculation didn't finish, but went ahead and
3082    printed incomplete and incorrect results anyway.
3083    """
3084
3085    zpve = 0.0200
3086
3087    enthalpy_places = -1
3088    entropy_places = 2
3089    freeenergy_places = -1
3090
3091    @unittest.skip('These values were wrong due to wrong input coordinates.')
3092    def testfreqval(self):
3093        """These values were wrong due to wrong input coordinates."""
3094    @unittest.skip('These values were wrong due to wrong input coordinates.')
3095    def testirintens(self):
3096        """These values were wrong due to wrong input coordinates."""
3097
3098# PSI3 #
3099
3100
3101class Psi3SPTest(GenericSPTest):
3102    """Customized restricted single point HF/KS unittest"""
3103
3104    # The final energy is also a bit higher here, I think due to the fact
3105    # that a SALC calculation is done instead of a full LCAO.
3106    b3lyp_energy = -10300
3107
3108    @unittest.skip('atommasses not implemented yet')
3109    def testatommasses(self):
3110        pass
3111
3112    @unittest.skip('Psi3 did not print partial atomic charges')
3113    def testatomcharges(self):
3114        pass
3115
3116    @unittest.skip('MO coefficients are printed separately for each SALC')
3117    def testfornoormo(self):
3118        pass
3119
3120    @unittest.skip('MO coefficients are printed separately for each SALC')
3121    def testdimmocoeffs(self):
3122        pass
3123
3124# PSI4 #
3125
3126
3127class PsiSPTest_noatommasses(PsiSPTest):
3128
3129    @unittest.skip('atommasses were not printed in this file.')
3130    def testatommasses(self):
3131        """These values are not present in this output file."""
3132
3133
3134old_unittests = {
3135
3136    "ADF/ADF2004.01/MoOCl4-sp.adfout":      ADFCoreTest,
3137    "ADF/ADF2004.01/dvb_gopt.adfout":       ADFGeoOptTest_noscfvalues,
3138    "ADF/ADF2004.01/dvb_gopt_b.adfout":     ADFGeoOptTest,
3139    "ADF/ADF2004.01/dvb_sp.adfout":         ADFSPTest_noscfvalues,
3140    "ADF/ADF2004.01/dvb_sp_b.adfout":       ADFSPTest_noscfvalues,
3141    "ADF/ADF2004.01/dvb_sp_c.adfout":       ADFSPTest_nosyms_valence_noscfvalues,
3142    "ADF/ADF2004.01/dvb_sp_d.adfout":       ADFSPTest_nosyms_noscfvalues,
3143    "ADF/ADF2004.01/dvb_un_sp.adfout":      GenericSPunTest,
3144    "ADF/ADF2004.01/dvb_un_sp_c.adfout":    GenericSPunTest,
3145    "ADF/ADF2004.01/dvb_ir.adfout":         ADFIRTest,
3146
3147    "ADF/ADF2006.01/dvb_gopt.adfout":              ADFGeoOptTest_noscfvalues,
3148    "ADF/ADF2013.01/dvb_gopt_b_fullscf.adfout":    ADFGeoOptTest,
3149    "ADF/ADF2014.01/dvb_gopt_b_fullscf.out":       ADFGeoOptTest,
3150
3151    "DALTON/DALTON-2013/C_bigbasis.aug-cc-pCVQZ.out":       DALTONBigBasisTest_aug_cc_pCVQZ,
3152    "DALTON/DALTON-2013/b3lyp_energy_dvb_sp_nosym.out":     DALTONSPTest_nosymmetry,
3153    "DALTON/DALTON-2013/dvb_sp_hf_nosym.out":               DALTONSPTest_nosymmetry,
3154    "DALTON/DALTON-2013/dvb_td_normalprint.out":            DALTONTDTest_noetsecs,
3155    "DALTON/DALTON-2013/sp_b3lyp_dvb.out":                  GenericSPTest,
3156    "DALTON/DALTON-2015/dvb_td_normalprint.out":            DALTONTDTest_noetsecs,
3157    "DALTON/DALTON-2015/trithiolane_polar_abalnr.out":      GaussianPolarTest,
3158    "DALTON/DALTON-2015/trithiolane_polar_response.out":    GaussianPolarTest,
3159    "DALTON/DALTON-2015/trithiolane_polar_static.out":      GaussianPolarTest,
3160    "DALTON/DALTON-2015/Trp_polar_response.out":            ReferencePolarTest,
3161    "DALTON/DALTON-2015/Trp_polar_static.out":              ReferencePolarTest,
3162
3163    "GAMESS/GAMESS-US2005/water_ccd_2005.06.27.r3.out":         GenericCCTest,
3164    "GAMESS/GAMESS-US2005/water_ccsd_2005.06.27.r3.out":        GenericCCTest,
3165    "GAMESS/GAMESS-US2005/water_ccsd(t)_2005.06.27.r3.out":     GenericCCTest,
3166    "GAMESS/GAMESS-US2005/water_cis_dets_2005.06.27.r3.out":    GAMESSUSCISTest_dets,
3167    "GAMESS/GAMESS-US2005/water_cis_saps_2005.06.27.r3.out":    GenericCISTest,
3168    "GAMESS/GAMESS-US2005/MoOCl4-sp_2005.06.27.r3.out":         GenericCoreTest,
3169    "GAMESS/GAMESS-US2005/water_mp2_2005.06.27.r3.out":         GenericMP2Test,
3170
3171    "GAMESS/GAMESS-US2006/C_bigbasis_2006.02.22.r3.out":    GenericBigBasisTest,
3172    "GAMESS/GAMESS-US2006/dvb_gopt_a_2006.02.22.r2.out":    GenericGeoOptTest,
3173    "GAMESS/GAMESS-US2006/dvb_sp_2006.02.22.r2.out":        GenericSPTest,
3174    "GAMESS/GAMESS-US2006/dvb_un_sp_2006.02.22.r2.out":     GenericSPunTest,
3175    "GAMESS/GAMESS-US2006/dvb_ir.2006.02.22.r2.out":        GenericIRTest,
3176    "GAMESS/GAMESS-US2006/nh3_ts_ir.2006.2.22.r2.out":      GAMESSUSIRTest_ts,
3177
3178    "GAMESS/GAMESS-US2010/dvb_gopt.log":    GenericGeoOptTest,
3179    "GAMESS/GAMESS-US2010/dvb_sp.log":      GAMESSSPTest_noaooverlaps,
3180    "GAMESS/GAMESS-US2010/dvb_sp_un.log":   GAMESSUSSPunTest_charge0,
3181    "GAMESS/GAMESS-US2010/dvb_td.log":      GAMESSUSTDDFTTest,
3182    "GAMESS/GAMESS-US2010/dvb_ir.log":      GenericIRTest,
3183
3184    "GAMESS/GAMESS-US2014/Trp_polar_freq.out":         ReferencePolarTest,
3185    "GAMESS/GAMESS-US2014/trithiolane_polar_freq.out": GaussianPolarTest,
3186    "GAMESS/GAMESS-US2014/trithiolane_polar_tdhf.out": GenericPolarTest,
3187    "GAMESS/GAMESS-US2014/C_bigbasis.out" : GenericBigBasisTest,
3188    "GAMESS/GAMESS-US2014/dvb_gopt_a.out" : GenericGeoOptTest,
3189    "GAMESS/GAMESS-US2014/dvb_ir.out" : GamessIRTest,
3190    "GAMESS/GAMESS-US2014/dvb_sp.out" : GenericBasisTest,
3191    "GAMESS/GAMESS-US2014/dvb_sp.out" : GenericSPTest,
3192    "GAMESS/GAMESS-US2014/dvb_td.out" : GAMESSUSTDDFTTest,
3193    "GAMESS/GAMESS-US2014/dvb_td_trplet.out" : GenericTDDFTtrpTest,
3194    "GAMESS/GAMESS-US2014/dvb_un_sp.out" : GenericSPunTest,
3195    "GAMESS/GAMESS-US2014/MoOCl4-sp.out" : GenericCoreTest,
3196    "GAMESS/GAMESS-US2014/nh3_ts_ir.out" : GenericIRimgTest,
3197    "GAMESS/GAMESS-US2014/water_ccd.out" : GenericCCTest,
3198    "GAMESS/GAMESS-US2014/water_ccsd.out" : GenericCCTest,
3199    "GAMESS/GAMESS-US2014/water_ccsd(t).out" : GenericCCTest,
3200    "GAMESS/GAMESS-US2014/water_cis_saps.out" : GAMESSCISTest,
3201    "GAMESS/GAMESS-US2014/water_mp2.out" : GenericMP2Test,
3202
3203
3204    "GAMESS/PCGAMESS/C_bigbasis.out":       GenericBigBasisTest,
3205    "GAMESS/PCGAMESS/dvb_gopt_b.out":       GenericGeoOptTest,
3206    "GAMESS/PCGAMESS/dvb_ir.out":           FireflyIRTest,
3207    "GAMESS/PCGAMESS/dvb_raman.out":        GenericRamanTest,
3208    "GAMESS/PCGAMESS/dvb_sp.out":           GenericSPTest,
3209    "GAMESS/PCGAMESS/dvb_td.out":           GenericTDTest,
3210    "GAMESS/PCGAMESS/dvb_td_trplet.out":    GenericTDDFTtrpTest,
3211    "GAMESS/PCGAMESS/dvb_un_sp.out":        GenericSPunTest,
3212    "GAMESS/PCGAMESS/water_mp2.out":        GenericMP2Test,
3213    "GAMESS/PCGAMESS/water_mp3.out":        GenericMP3Test,
3214    "GAMESS/PCGAMESS/water_mp4.out":        GenericMP4SDQTest,
3215    "GAMESS/PCGAMESS/water_mp4_sdtq.out":   GenericMP4SDTQTest,
3216
3217    "GAMESS/WinGAMESS/dvb_td_2007.03.24.r1.out":    GAMESSUSTDDFTTest,
3218
3219    "Gaussian/Gaussian03/CO_TD_delta.log":    GenericTDunTest,
3220    "Gaussian/Gaussian03/C_bigbasis.out":     GaussianBigBasisTest,
3221    "Gaussian/Gaussian03/dvb_gopt.out":       GenericGeoOptTest,
3222    "Gaussian/Gaussian03/dvb_ir.out":         GaussianIRTest,
3223    "Gaussian/Gaussian03/dvb_raman.out":      GaussianRamanTest,
3224    "Gaussian/Gaussian03/dvb_sp.out":         GaussianSPTest,
3225    "Gaussian/Gaussian03/dvb_sp_basis.log":   GenericBasisTest,
3226    "Gaussian/Gaussian03/dvb_sp_basis_b.log": GenericBasisTest,
3227    "Gaussian/Gaussian03/dvb_td.out":         GaussianTDDFTTest,
3228    "Gaussian/Gaussian03/dvb_un_sp.out":      GaussianSPunTest_nomosyms,
3229    "Gaussian/Gaussian03/dvb_un_sp_b.log":    GaussianSPunTest,
3230    "Gaussian/Gaussian03/Mo4OCl4-sp.log":     GenericCoreTest,
3231    "Gaussian/Gaussian03/water_ccd.log":      GenericCCTest,
3232    "Gaussian/Gaussian03/water_ccsd(t).log":  GenericCCTest,
3233    "Gaussian/Gaussian03/water_ccsd.log":     GenericCCTest,
3234    "Gaussian/Gaussian03/water_cis.log":      GaussianSPunTest_nonaturalorbitals,
3235    "Gaussian/Gaussian03/water_cisd.log":     GaussianSPunTest_nonaturalorbitals,
3236    "Gaussian/Gaussian03/water_mp2.log":      GaussianMP2Test,
3237    "Gaussian/Gaussian03/water_mp3.log":      GaussianMP3Test,
3238    "Gaussian/Gaussian03/water_mp4.log":      GaussianMP4SDTQTest,
3239    "Gaussian/Gaussian03/water_mp4sdq.log":   GaussianMP4SDQTest,
3240    "Gaussian/Gaussian03/water_mp5.log":      GenericMP5Test,
3241
3242    "Gaussian/Gaussian09/dvb_gopt_revA.02.out":         GenericGeoOptTest,
3243    "Gaussian/Gaussian09/dvb_ir_revA.02.out":           GaussianIRTest,
3244    "Gaussian/Gaussian09/dvb_raman_revA.02.out":        GaussianRamanTest,
3245    "Gaussian/Gaussian09/dvb_scan_revA.02.log":         GaussianRelaxedScanTest,
3246    "Gaussian/Gaussian09/dvb_sp_basis_b_gfprint.log":   GenericBasisTest,
3247    "Gaussian/Gaussian09/dvb_sp_basis_gfinput.log":     GenericBasisTest,
3248    "Gaussian/Gaussian09/dvb_sp_revA.02.out":           GaussianSPTest,
3249    "Gaussian/Gaussian09/dvb_td_revA.02.out":           GaussianTDDFTTest,
3250    "Gaussian/Gaussian09/dvb_un_sp_revA.02.log":        GaussianSPunTest_nomosyms,
3251    "Gaussian/Gaussian09/dvb_un_sp_b_revA.02.log":      GaussianSPunTest,
3252    "Gaussian/Gaussian09/trithiolane_polar.log":        GaussianPolarTest,
3253
3254    "Jaguar/Jaguar4.2/dvb_gopt.out":    JaguarGeoOptTest_nmo45,
3255    "Jaguar/Jaguar4.2/dvb_gopt_b.out":  GenericGeoOptTest,
3256    "Jaguar/Jaguar4.2/dvb_sp.out":      JaguarSPTest_nmo45,
3257    "Jaguar/Jaguar4.2/dvb_sp_b.out":    JaguarSPTest_nmo45,
3258    "Jaguar/Jaguar4.2/dvb_un_sp.out":   JaguarSPunTest_nmo_all_nomosyms,
3259    "Jaguar/Jaguar4.2/dvb_ir.out":      JaguarIRTest,
3260
3261    "Jaguar/Jaguar6.0/dvb_gopt.out":    JaguarGeoOptTest_6_31gss,
3262    "Jaguar/Jaguar6.0/dvb_sp.out":      JaguarSPTest_6_31gss_nomosyms,
3263    "Jaguar/Jaguar6.0/dvb_un_sp.out" :  JaguarSPunTest_nmo_all_nomosyms,
3264
3265    "Jaguar/Jaguar6.5/dvb_gopt.out":    JaguarGeoOptTest_nmo45,
3266    "Jaguar/Jaguar6.5/dvb_sp.out":      JaguarSPTest_nmo45,
3267    "Jaguar/Jaguar6.5/dvb_un_sp.out":   JaguarSPunTest_nomosyms,
3268    "Jaguar/Jaguar6.5/dvb_ir.out":      JaguarIRTest,
3269
3270    "Molcas/Molcas8.0/dvb_sp.out":      MolcasSPTest,
3271    "Molcas/Molcas8.0/dvb_sp_un.out":   GenericSPunTest,
3272    "Molcas/Molcas8.0/C_bigbasis.out":  MolcasBigBasisTest_nogbasis,
3273
3274    "Molpro/Molpro2006/C_bigbasis_cart.out":    MolproBigBasisTest_cart,
3275    "Molpro/Molpro2012/trithiolane_polar.out":  GenericPolarTest,
3276
3277    "NWChem/NWChem6.6/trithiolane_polar.out": GaussianPolarTest,
3278
3279    "ORCA/ORCA2.6/dvb_gopt.out":    OrcaGeoOptTest_3_21g,
3280    "ORCA/ORCA2.6/dvb_sp.out":      OrcaSPTest_3_21g,
3281    "ORCA/ORCA2.6/dvb_td.out":      OrcaTDDFTTest_error,
3282    "ORCA/ORCA2.6/dvb_ir.out":      OrcaIRTest_old_coordsOK,
3283
3284    "ORCA/ORCA2.8/dvb_gopt.out":    OrcaGeoOptTest,
3285    "ORCA/ORCA2.8/dvb_sp.out":      GenericBasisTest,
3286    "ORCA/ORCA2.8/dvb_sp.out":      OrcaSPTest,
3287    "ORCA/ORCA2.8/dvb_sp_un.out":   OrcaSPunTest_charge0,
3288    "ORCA/ORCA2.8/dvb_td.out":      OrcaTDDFTTest,
3289    "ORCA/ORCA2.8/dvb_ir.out":      OrcaIRTest_old,
3290
3291    "ORCA/ORCA2.9/dvb_gopt.out":    OrcaGeoOptTest,
3292    "ORCA/ORCA2.9/dvb_ir.out":      OrcaIRTest,
3293    "ORCA/ORCA2.9/dvb_raman.out":   GenericRamanTest,
3294    "ORCA/ORCA2.9/dvb_scan.out":    OrcaRelaxedScanTest,
3295    "ORCA/ORCA2.9/dvb_sp.out":      GenericBasisTest,
3296    "ORCA/ORCA2.9/dvb_sp.out":      OrcaSPTest,
3297    "ORCA/ORCA2.9/dvb_sp_un.out":   GenericSPunTest,
3298    "ORCA/ORCA2.9/dvb_td.out":      OrcaTDDFTTest,
3299
3300    "ORCA/ORCA3.0/dvb_bomd.out":          GenericBOMDTest,
3301    "ORCA/ORCA3.0/dvb_gopt.out":          OrcaGeoOptTest,
3302    "ORCA/ORCA3.0/dvb_ir.out":            OrcaIRTest,
3303    "ORCA/ORCA3.0/dvb_raman.out":         GenericRamanTest,
3304    "ORCA/ORCA3.0/dvb_scan.out":          OrcaRelaxedScanTest,
3305    "ORCA/ORCA3.0/dvb_sp_un.out":         GenericSPunTest,
3306    "ORCA/ORCA3.0/dvb_sp.out":            GenericBasisTest,
3307    "ORCA/ORCA3.0/dvb_sp.out":            OrcaSPTest,
3308    "ORCA/ORCA3.0/dvb_td.out":            OrcaTDDFTTest,
3309    "ORCA/ORCA3.0/Trp_polar.out":         ReferencePolarTest,
3310    "ORCA/ORCA3.0/trithiolane_polar.out": GaussianPolarTest,
3311
3312    "ORCA/ORCA4.0/dvb_sp.out":            GenericBasisTest,
3313    "ORCA/ORCA4.0/dvb_gopt.out":          OrcaGeoOptTest,
3314    "ORCA/ORCA4.0/Trp_polar.out":         ReferencePolarTest,
3315    "ORCA/ORCA4.0/dvb_sp.out":            OrcaSPTest,
3316    "ORCA/ORCA4.0/dvb_sp_un.out":         GenericSPunTest,
3317    "ORCA/ORCA4.0/dvb_td.out":            OrcaTDDFTTest,
3318    "ORCA/ORCA4.0/dvb_rocis.out":         OrcaROCIS40Test,
3319    "ORCA/ORCA4.0/dvb_ir.out":            GenericIRTest,
3320    "ORCA/ORCA4.0/dvb_raman.out":         OrcaRamanTest,
3321
3322    "Psi3/Psi3.4/dvb_sp_hf.out":          Psi3SPTest,
3323
3324    "Psi4/Psi4-1.0/C_bigbasis.out":     Psi4BigBasisTest,
3325    "Psi4/Psi4-1.0/dvb_gopt_rhf.out":   Psi4GeoOptTest,
3326    "Psi4/Psi4-1.0/dvb_gopt_rks.out":   Psi4GeoOptTest,
3327    "Psi4/Psi4-1.0/dvb_ir_rhf.out":     Psi4IRTest,
3328    "Psi4/Psi4-1.0/dvb_sp_rhf.out":     PsiSPTest_noatommasses,
3329    "Psi4/Psi4-1.0/dvb_sp_rks.out":     PsiSPTest_noatommasses,
3330    "Psi4/Psi4-1.0/dvb_sp_rohf.out":    GenericROSPTest,
3331    "Psi4/Psi4-1.0/dvb_sp_uhf.out":     GenericSPunTest,
3332    "Psi4/Psi4-1.0/dvb_sp_uks.out":     GenericSPunTest,
3333    "Psi4/Psi4-1.0/water_ccsd(t).out":  GenericCCTest,
3334    "Psi4/Psi4-1.0/water_ccsd.out":     GenericCCTest,
3335    "Psi4/Psi4-1.0/water_mp2.out":      GenericMP2Test,
3336    "Psi4/Psi4-beta5/C_bigbasis.out":   GenericBigBasisTest,
3337    "Psi4/Psi4-beta5/dvb_gopt_hf.out":  Psi4GeoOptTest,
3338    "Psi4/Psi4-beta5/dvb_sp_hf.out":    GenericBasisTest,
3339    "Psi4/Psi4-beta5/dvb_sp_hf.out":    PsiSPTest_noatommasses,
3340    "Psi4/Psi4-beta5/dvb_sp_ks.out":    GenericBasisTest,
3341    "Psi4/Psi4-beta5/dvb_sp_ks.out":    PsiSPTest_noatommasses,
3342    "Psi4/Psi4-beta5/water_ccsd.out":   GenericCCTest,
3343    "Psi4/Psi4-beta5/water_mp2.out":    GenericMP2Test,
3344
3345    "QChem/QChem4.2/Trp_freq.out":           ReferencePolarTest,
3346    "QChem/QChem4.2/trithiolane_polar.out":  GaussianPolarTest,
3347    "QChem/QChem4.2/trithiolane_freq.out":   GaussianPolarTest,
3348    "QChem/QChem4.4/Trp_polar_ideriv1.out":  ReferencePolarTest,
3349    "QChem/QChem4.4/Trp_polar_response.out": ReferencePolarTest,
3350
3351}
3352
3353def make_regression_from_old_unittest(test_class):
3354    """Return a regression test function from an old unit test logfile."""
3355
3356    def old_unit_test(logfile):
3357        test_class.logfile = logfile
3358        test_class.data = logfile.data
3359        devnull = open(os.devnull, 'w')
3360        return unittest.TextTestRunner(stream=devnull).run(unittest.makeSuite(test_class))
3361
3362    return old_unit_test
3363
3364
3365def test_regressions(which=[], opt_traceback=True, regdir=__regression_dir__, loglevel=logging.ERROR):
3366
3367    # Build a list of regression files that can be found. If there is a directory
3368    # on the third level, then treat all files within it as one job.
3369    try:
3370        filenames = {}
3371        for p in parser_names:
3372            filenames[p] = []
3373            pdir = os.path.join(regdir, get_program_dir(p))
3374            for version in os.scandir(pdir):
3375                if version.is_file():
3376                    continue
3377
3378                for job in os.listdir(version.path):
3379                    path = os.path.join(version.path, job)
3380                    if os.path.isdir(path):
3381                        filenames[p].append(os.path.join(path, "*"))
3382                    else:
3383                        filenames[p].append(path)
3384    except OSError as e:
3385        print(e)
3386        print("\nERROR: At least one program direcory is missing.")
3387        print("Run 'git pull' or regression_download.sh in cclib to update.")
3388        sys.exit(1)
3389
3390    # This file should contain the paths to all regresssion test files we have gathered
3391    # over the years. It is not really necessary, since we can discover them on the disk,
3392    # but we keep it as a legacy and a way to track the regression tests.
3393    regfile = open(os.path.join(regdir, "regressionfiles.txt"), "r")
3394    regfilenames = [os.sep.join(x.strip().split("/")) for x in regfile.readlines()]
3395    regfile.close()
3396
3397    # We will want to print a warning if you haven't downloaded all of the regression
3398    # test files, or when, vice versa, not all of the regression test files found on disk
3399    # are included in filenames. However, gather that data here and print the warnings
3400    # at the end so that we test all available files and the messages are displayed
3401    # prominently at the end.
3402    missing_on_disk = []
3403    missing_in_list = []
3404    for fn in regfilenames:
3405        if not os.path.exists(os.path.join(regdir, fn)):
3406            missing_on_disk.append(fn)
3407    for fn in glob.glob(os.path.join(regdir, '*', '*', '*')):
3408        fn = fn.replace(regdir, '').strip('/')
3409        if fn not in regfilenames:
3410            missing_in_list.append(fn)
3411
3412    # Create the regression test functions from logfiles that were old unittests.
3413    for path, test_class in old_unittests.items():
3414        funcname = "test" + normalisefilename(path)
3415        func = make_regression_from_old_unittest(test_class)
3416        globals()[funcname] = func
3417
3418    # Gather orphaned tests - functions starting with 'test' and not corresponding
3419    # to any regression file name.
3420    orphaned_tests = []
3421    for pn in parser_names:
3422        prefix = "test%s_%s" % (pn, pn)
3423        tests = [fn for fn in globals() if fn[:len(prefix)] == prefix]
3424        normalized = [normalisefilename(fn.replace(__regression_dir__, '')) for fn in filenames[pn]]
3425        orphaned = [t for t in tests if t[4:] not in normalized]
3426        orphaned_tests.extend(orphaned)
3427
3428    # Assume that if a string is not a parser name it'll be a relative
3429    # path to a specific logfile.
3430    # TODO: filter out things that are not parsers or files, and maybe
3431    # raise an error in that case as well.
3432    which_parsers = [w for w in which if w in parser_names]
3433    which_filenames = [w for w in which if w not in which_parsers]
3434
3435    failures = errors = total = 0
3436    for pn in parser_names:
3437
3438        parser_class = eval(pn)
3439
3440        # Continue to next iteration if we are limiting the regression and the current
3441        #   name was not explicitely chosen (that is, passed as an argument).
3442        if which_parsers and pn not in which_parsers:
3443            continue;
3444
3445        parser_total = 0
3446        current_filenames = filenames[pn]
3447        current_filenames.sort()
3448        for fname in current_filenames:
3449            relative_path = fname[len(regdir):]
3450            if which_filenames and relative_path not in which_filenames:
3451                continue;
3452
3453            parser_total += 1
3454            if parser_total == 1:
3455                print("Are the %s files ccopened and parsed correctly?" % pn)
3456
3457            total += 1
3458            print("  %s ..."  % fname, end=" ")
3459
3460            # Check if there is a test (needs to be an appropriately named function).
3461            # If not, there can also be a test that does not assume the file is
3462            # correctly parsed (for fragments, for example), and these test need
3463            # to be additionaly prepended with 'testnoparse'.
3464            test_this = test_noparse = False
3465            fname_norm = normalisefilename(fname.replace(__regression_dir__, ''))
3466
3467            funcname = "test" + fname_norm
3468            test_this = funcname in globals()
3469
3470            funcname_noparse = "testnoparse" + fname_norm
3471            test_noparse = not test_this and funcname_noparse in globals()
3472
3473            if not test_noparse:
3474                datatype = parser_class.datatype if hasattr(parser_class, 'datatype') else ccData
3475                job_filenames = glob.glob(fname)
3476                try:
3477                    if len(job_filenames) == 1:
3478                        logfile = ccopen(job_filenames[0], datatype=datatype, loglevel=loglevel)
3479                    else:
3480                        logfile = ccopen(job_filenames, datatype=datatype, loglevel=loglevel)
3481                except Exception as e:
3482                    errors += 1
3483                    print("ccopen error: ", e)
3484                    if opt_traceback:
3485                        print(traceback.format_exc())
3486                else:
3487                    if type(logfile) == parser_class:
3488                        try:
3489                            logfile.data = logfile.parse()
3490                        except KeyboardInterrupt:
3491                            sys.exit(1)
3492                        except Exception as e:
3493                            print("parse error:", e)
3494                            errors += 1
3495                            if opt_traceback:
3496                                print(traceback.format_exc())
3497                        else:
3498                            if test_this:
3499                                try:
3500                                    res = eval(funcname)(logfile)
3501                                    if res and len(res.failures) > 0:
3502                                        failures += len(res.failures)
3503                                        print("%i test(s) failed" % len(res.failures))
3504                                        if opt_traceback:
3505                                            for f in res.failures:
3506                                                print("Failure for", f[0])
3507                                                print(f[1])
3508                                        continue
3509                                    elif res and len(res.errors) > 0:
3510                                        errors += len(res.errors)
3511                                        print("{:d} test(s) had errors".format(len(res.errors)))
3512                                        if opt_traceback:
3513                                            for f in res.errors:
3514                                                print("Error for", f[0])
3515                                                print(f[1])
3516                                        continue
3517                                except AssertionError:
3518                                    print("test failed")
3519                                    failures += 1
3520                                    if opt_traceback:
3521                                        print(traceback.format_exc())
3522                                else:
3523                                    print("parsed and tested")
3524                            else:
3525                                print("parsed")
3526                    else:
3527                        print("ccopen failed")
3528                        failures += 1
3529            else:
3530                try:
3531                    eval(funcname_noparse)(fname)
3532                except AssertionError:
3533                    print("test failed")
3534                    failures += 1
3535                except:
3536                    print("parse error")
3537                    errors += 1
3538                    if opt_traceback:
3539                        print(traceback.format_exc())
3540                else:
3541                    print("test passed")
3542
3543        if parser_total:
3544            print()
3545
3546    print("Total: %d   Failed: %d  Errors: %d" % (total, failures, errors))
3547    if not opt_traceback and failures + errors > 0:
3548        print("\nFor more information on failures/errors, add --traceback as an argument.")
3549
3550    # Show these warnings at the end, so that they're easy to notice. Notice that the lists
3551    # were populated at the beginning of this function.
3552    if len(missing_on_disk) > 0:
3553        print("\nWARNING: You are missing %d regression file(s)." % len(missing_on_disk))
3554        print("Run regression_download.sh in the ../data directory to update.")
3555        print("Missing files:")
3556        print("\n".join(missing_on_disk))
3557    if len(missing_in_list) > 0:
3558        print("\nWARNING: The list in 'regressionfiles.txt' is missing %d file(s)." % len(missing_in_list))
3559        print("Add these files paths to the list and commit the change.")
3560        print("Missing files:")
3561        print("\n".join(missing_in_list))
3562    if len(orphaned_tests) > 0:
3563        print("\nWARNING: There are %d orphaned regression test functions." % len(orphaned_tests))
3564        print("Please make sure these function names correspond to regression files:")
3565        print("\n".join(orphaned_tests))
3566
3567    if failures + errors > 0:
3568        sys.exit(1)
3569
3570if __name__ == "__main__":
3571
3572    import argparse
3573
3574    parser = argparse.ArgumentParser()
3575
3576    parser.add_argument("--traceback", action="store_true")
3577    parser.add_argument("--debug", action="store_true")
3578    parser.add_argument(
3579        "parser_or_module",
3580        nargs="*",
3581        help="Limit the test to the packages/parsers passed as arguments. "
3582             "No arguments implies all parsers."
3583    )
3584
3585    args = parser.parse_args()
3586
3587    loglevel = logging.DEBUG if args.debug else logging.ERROR
3588
3589    test_regressions(args.parser_or_module, args.traceback, loglevel=loglevel)
3590