diff --git a/cclib/bridge/cclib2pyscf.py b/cclib/bridge/cclib2pyscf.py index c62fc06b9..1aa29aff9 100644 --- a/cclib/bridge/cclib2pyscf.py +++ b/cclib/bridge/cclib2pyscf.py @@ -5,7 +5,7 @@ """Bridge for using cclib data in PySCF (https://github.com/pyscf/pyscf).""" -from cclib.parser.utils import PeriodicTable, find_package +from cclib.parser.utils import PeriodicTable, convertor, find_package import numpy as np @@ -85,7 +85,7 @@ def makepyscf_mos(ccdata, mol): molecular orbital energies in units of Hartree """ inputattrs = ccdata.__dict__ - mo_energies = ccdata.moenergies + mo_energies = convertor(np.asarray(ccdata.moenergies), "eV", "hartree") if "mocoeffs" in inputattrs: mol.build() s = mol.intor("int1e_ovlp") diff --git a/cclib/io/moldenwriter.py b/cclib/io/moldenwriter.py index ae6e7d3aa..db730db5d 100644 --- a/cclib/io/moldenwriter.py +++ b/cclib/io/moldenwriter.py @@ -184,7 +184,7 @@ def _mo_from_ccdata(self, mosyms, moenergies, mooccs, mocoeffs): for j in range(len(mooccs[i])): restricted_spin_idx = i % len(mocoeffs) lines.append(f" Sym= {mosyms[restricted_spin_idx][j]}") - moenergy = moenergies[restricted_spin_idx][j] + moenergy = utils.convertor(moenergies[restricted_spin_idx][j], "eV", "hartree") lines.append(f" Ene= {moenergy:10.4f}") lines.append(f" Spin= {spin}") lines.append(f" Occup= {mooccs[i][j]:10.6f}") diff --git a/cclib/io/wfxwriter.py b/cclib/io/wfxwriter.py index dba05060f..7e75928e1 100644 --- a/cclib/io/wfxwriter.py +++ b/cclib/io/wfxwriter.py @@ -301,10 +301,10 @@ def _mo_energies(self): alpha_elctrons = self._no_alpha_electrons() beta_electrons = self._no_beta_electrons() for mo_energy in self.ccdata.moenergies[0][:alpha_elctrons]: - mo_energies.append(WFX_FIELD_FMT % mo_energy) + mo_energies.append(WFX_FIELD_FMT % (utils.convertor(mo_energy, "eV", "hartree"))) if self.ccdata.mult > 1: for mo_energy in self.ccdata.moenergies[1][:beta_electrons]: - mo_energies.append(WFX_FIELD_FMT % mo_energy) + mo_energies.append(WFX_FIELD_FMT % (utils.convertor(mo_energy, "eV", "hartree"))) return mo_energies def _mo_spin_types(self): @@ -451,7 +451,7 @@ def _energy(self) -> str: energy = self.ccdata.scfenergies[-1] else: raise filewriter.MissingAttributeError("scfenergies/mpenergies/ccenergies") - return WFX_FIELD_FMT % energy + return WFX_FIELD_FMT % (utils.convertor(energy, "eV", "hartree")) def _virial_ratio(self) -> str: """Ratio of kinetic energy to potential energy.""" diff --git a/cclib/parser/data.py b/cclib/parser/data.py index 26487c1bf..64aa8e7eb 100644 --- a/cclib/parser/data.py +++ b/cclib/parser/data.py @@ -28,13 +28,13 @@ class ccData: atommasses -- atom masses (array[1], daltons) atomnos -- atomic numbers (array[1]) atomspins -- atomic spin densities (dict of arrays[1]) - ccenergies -- molecular energies with Coupled-Cluster corrections (array[2], hartree) + ccenergies -- molecular energies with Coupled-Cluster corrections (array[2], eV) charge -- net charge of the system (integer) coreelectrons -- number of core electrons in atom pseudopotentials (array[1]) - dispersionenergies -- dispersion energy corrections (array[1], hartree) + dispersionenergies -- dispersion energy corrections (array[1], eV) enthalpy -- sum of electronic and thermal enthalpies (float, hartree/particle) entropy -- entropy (float, hartree/(particle*kelvin)) - etenergies -- energies of electronic transitions (array[1], hartree) + etenergies -- energies of electronic transitions (array[1], 1/cm) etoscs -- oscillator strengths of electronic transitions (array[1]) etdips -- electric transition dipoles of electronic transitions (array[2], ebohr) etveldips -- velocity-gauge electric transition dipoles of electronic transitions (array[2], ebohr) @@ -55,10 +55,10 @@ class ccData: homos -- molecular orbital indices of HOMO(s) (array[1]) metadata -- various metadata about the package and computation (dict) mocoeffs -- molecular orbital coefficients (list of arrays[2]) - moenergies -- molecular orbital energies (list of arrays[1], hartree) + moenergies -- molecular orbital energies (list of arrays[1], eV) moments -- molecular multipole moments (list of arrays[], a.u.) mosyms -- orbital symmetries (list of lists) - mpenergies -- molecular electronic energies with Møller-Plesset corrections (array[2], hartree) + mpenergies -- molecular electronic energies with Møller-Plesset corrections (array[2], eV) mult -- multiplicity of the system (integer) natom -- number of atoms (integer) nbasis -- number of basis functions (integer) @@ -78,7 +78,7 @@ class ccData: scanenergies -- energies of potential energy surface (list) scannames -- names of variables scanned (list of strings) scanparm -- values of parameters in potential energy surface (list of tuples) - scfenergies -- molecular electronic energies after SCF (Hartree-Fock, DFT) (array[1], hartree) + scfenergies -- molecular electronic energies after SCF (Hartree-Fock, DFT) (array[1], eV) scftargets -- targets for convergence of the SCF (array[2]) scfvalues -- current values for convergence of the SCF (list of arrays[2]) temperature -- temperature used for Thermochemistry (float, kelvin) diff --git a/cclib/parser/logfileparser.py b/cclib/parser/logfileparser.py index f2e73070e..de247fe2f 100644 --- a/cclib/parser/logfileparser.py +++ b/cclib/parser/logfileparser.py @@ -211,6 +211,28 @@ def parse(self, progress=None, fupdate=0.05, cupdate=0.002): if attr not in _nodelete: self.__delattr__(attr) + # Convert from atomic units to convenience units. + for attr in ("ccenergies", "dispersionenergies", "mpenergies", "scfenergies"): + if hasattr(data, attr): + setattr(data, attr, utils.convertor(getattr(data, attr), "hartree", "eV")) + for attr in ("etenergies",): + if hasattr(data, attr): + setattr(data, attr, utils.convertor(getattr(data, attr), "hartree", "wavenumber")) + for attr in ("scanenergies",): + if hasattr(data, attr): + setattr( + data, + attr, + utils.convertor(numpy.asarray(getattr(data, attr)), "hartree", "eV").tolist(), + ) + for attr in ("moenergies",): + if hasattr(data, attr): + setattr( + data, + attr, + [utils.convertor(elem, "hartree", "eV") for elem in getattr(data, attr)], + ) + # Perform final checks on values of attributes. data.check_values(logger=self.logger) diff --git a/cclib/parser/turbomoleparser.py b/cclib/parser/turbomoleparser.py index e80036ab5..bdae2dd46 100644 --- a/cclib/parser/turbomoleparser.py +++ b/cclib/parser/turbomoleparser.py @@ -765,6 +765,7 @@ def extract(self, inputfile, line): info = re.match( r".*eigenvalue=(?P[0-9D\.+-]{20})\s+nsaos=(?P\d+).*", line ) + assert info is not None eigenvalue = utils.float(info.group("moenergy")) moenergies.append(eigenvalue) diff --git a/doc/sphinx/data_notes.rst b/doc/sphinx/data_notes.rst index a9d30bc9c..cef1ca0ad 100644 --- a/doc/sphinx/data_notes.rst +++ b/doc/sphinx/data_notes.rst @@ -149,7 +149,7 @@ However, in *all* cases the dispersion energy for a given geometry will also be etenergies ---------- -This is a rank 1 array that contains the energies of electronic transitions from a reference state to the excited states of the molecule, in hartree. There should be as many elements to this array as there are excited states calculated. Any type of excited state calculation should provide output that can be parsed into this attribute. +This is a rank 1 array that contains the energies of electronic transitions from a reference state to the excited states of the molecule, in ``cm-1``. There should be as many elements to this array as there are excited states calculated. Any type of excited state calculation should provide output that can be parsed into this attribute. etoscs ------ @@ -389,7 +389,7 @@ Note: For restricted calculation, ``mocoeffs`` is still a list, but it only cont moenergies ---------- -A list of rank 1 arrays containing the molecular orbital energies in hartree. The list is of length 1 for restricted calculations, but length 2 for unrestricted calculations. +A list of rank 1 arrays containing the molecular orbital energies in eV. The list is of length 1 for restricted calculations, but length 2 for unrestricted calculations. **GAMESS-UK**: similar to `mocoeffs`_, the directive `FORMAT HIGH`_ needs to be used if you want all of the eigenvalues printed. @@ -568,7 +568,7 @@ A list of lists where each list contains the values scanned for each parameter i scfenergies ----------- -An array containing the converged SCF energies of the calculation, in hartree. For an optimisation log file, there will be as many elements in this array as there were optimisation steps. +An array containing the converged SCF energies of the calculation, in eV. For an optimisation log file, there will be as many elements in this array as there were optimisation steps. If a dispersion correction of any form was used, it is part of the SCF energy and, in the event that it is separable, such as with D3 and similar empirical corrections, it is also available separately under `dispersionenergies`_. diff --git a/test/bridge/testpyscf.py b/test/bridge/testpyscf.py index 8fdf3069b..3bd773482 100644 --- a/test/bridge/testpyscf.py +++ b/test/bridge/testpyscf.py @@ -6,7 +6,7 @@ from test.test_data import getdatafile from cclib.bridge import cclib2pyscf -from cclib.parser.utils import find_package +from cclib.parser.utils import convertor, find_package import numpy as np @@ -31,7 +31,7 @@ def test_makepyscf(self) -> None: mhf = dft.RKS(pyscfmol) mhf.xc = "b3lyp" en = mhf.kernel() - assert abs(en - refen) < 5.0e-5 + assert abs(convertor(en, "hartree", "eV") - refen) < convertor(5.0e-5, "hartree", "eV") # check that default basis is returned if basis is not present. del self.data.gbasis pyscfmol2 = cclib2pyscf.makepyscf(self.data) @@ -40,7 +40,7 @@ def test_makepyscf(self) -> None: def test_makepyscf_mos(self) -> None: pyscfmol = cclib2pyscf.makepyscf(self.data) mo_coeff, mo_occ, mo_syms, mo_energies = cclib2pyscf.makepyscf_mos(self.data, pyscfmol) - assert np.allclose(mo_energies, self.data.moenergies) + assert np.allclose(mo_energies, convertor(np.array(self.data.moenergies), "eV", "hartree")) # check first MO coefficient assert np.allclose(mo_coeff[0][0], self.data.mocoeffs[0][0][0]) # check a random middle MO coefficient @@ -48,7 +48,7 @@ def test_makepyscf_mos(self) -> None: # test unrestricted code. pyscfmol = cclib2pyscf.makepyscf(self.udata) mo_coeff, mo_occ, mo_syms, mo_energies = cclib2pyscf.makepyscf_mos(self.udata, pyscfmol) - assert np.allclose(mo_energies, self.udata.moenergies) + assert np.allclose(mo_energies, convertor(np.array(self.udata.moenergies), "eV", "hartree")) # check first MO coefficient assert np.allclose(mo_coeff[0][0][0], self.udata.mocoeffs[0][0][0]) # check a random middle MO coefficient diff --git a/test/data/testCC.py b/test/data/testCC.py index 9f86c6267..08751aaf8 100644 --- a/test/data/testCC.py +++ b/test/data/testCC.py @@ -5,6 +5,8 @@ """Test coupled cluster logfiles""" +from cclib.parser import utils + import numpy import pytest @@ -33,7 +35,9 @@ def testenergycc2(self, data) -> None: e_scf = data.scfenergies[0] e_cc = data.ccenergies[0] e_corr = e_cc - e_scf - assert pytest.approx(e_corr, rel=self.rel_thresh) == self.corr_energy + assert pytest.approx(e_corr, rel=self.rel_thresh) == utils.convertor( + self.corr_energy, "hartree", "eV" + ) class GenericCCDTest(GenericCCTest): @@ -45,7 +49,9 @@ def testenergyccd(self, data) -> None: e_scf = data.scfenergies[0] e_cc = data.ccenergies[0] e_corr = e_cc - e_scf - assert pytest.approx(e_corr, rel=self.rel_thresh) == self.corr_energy + assert pytest.approx(e_corr, rel=self.rel_thresh) == utils.convertor( + self.corr_energy, "hartree", "eV" + ) class GenericCCSDTest(GenericCCTest): @@ -57,7 +63,9 @@ def testenergyccsd(self, data) -> None: e_scf = data.scfenergies[0] e_cc = data.ccenergies[0] e_corr = e_cc - e_scf - assert pytest.approx(e_corr, rel=self.rel_thresh) == self.corr_energy + assert pytest.approx(e_corr, rel=self.rel_thresh) == utils.convertor( + self.corr_energy, "hartree", "eV" + ) class GenericCCSDPTTest(GenericCCTest): @@ -69,7 +77,9 @@ def testenergyccsdpt(self, data) -> None: e_scf = data.scfenergies[0] e_cc = data.ccenergies[0] e_corr = e_cc - e_scf - assert pytest.approx(e_corr, rel=self.rel_thresh) == self.corr_energy + assert pytest.approx(e_corr, rel=self.rel_thresh) == utils.convertor( + self.corr_energy, "hartree", "eV" + ) class DALTONCCSDPTTest(GenericCCSDPTTest): diff --git a/test/data/testGeoOpt.py b/test/data/testGeoOpt.py index 5ad77ebce..6a883d555 100644 --- a/test/data/testGeoOpt.py +++ b/test/data/testGeoOpt.py @@ -5,6 +5,8 @@ """Test geometry optimization logfiles in cclib""" +from cclib.parser import utils + import numpy from common import get_minimum_carbon_separation from skip import skipForLogfile, skipForParser @@ -23,8 +25,8 @@ class GenericGeoOptTest: extrascfs = 0 # Approximate B3LYP energy of dvb after SCF in STO-3G. - b3lyp_energy = -380.90674109218116 - b3lyp_tolerance = 1.4699729516340807 + scfenergy = -380.90674109218116 + scfenergy_tolerance = 1.4699729516340807 @skipForParser("Molcas", "The parser is still being developed so we skip this test") @skipForParser("MOPAC", "The success status is not parsed yet") @@ -100,11 +102,9 @@ def testscfvaluetype(self, data) -> None: def testscfenergy(self, data) -> None: """Is the SCF energy close to target?""" - scf = data.scfenergies[-1] - ref = self.b3lyp_energy - tol = self.b3lyp_tolerance - msg = f"Final SCF energy: {scf:f} not {int(ref)} +- {int(tol)}eV" - assert abs(scf - ref) < 40, msg + assert abs( + data.scfenergies[-1] - utils.convertor(self.scfenergy, "hartree", "eV") + ) < utils.convertor(self.scfenergy_tolerance, "hartree", "eV") @skipForParser("xTB", "Not implemented yet") def testscfenergydim(self, data) -> None: @@ -231,8 +231,8 @@ class ADFGeoOptTest(GenericGeoOptTest): extracoords = 1 extrascfs = 1 - b3lyp_energy = -5.144905330719283 - b3lyp_tolerance = 0.03674932379085202 + scfenergy = -5.144905330719283 + scfenergy_tolerance = 0.03674932379085202 class DALTONGeoOptTest(GenericGeoOptTest): @@ -307,8 +307,8 @@ class MOPACGeoOptTest(GenericGeoOptTest): """Customized geometry optimization unittest for MOPAC.""" # The geometry optimization unit test logfile uses a PM7 Hamiltonian. - b3lyp_energy = 0.08166294233283113 - b3lyp_tolerance = 1.6e-5 + scfenergy = 0.08166294233283113 + scfenergy_tolerance = 1.6e-5 class NWChemGeoOptTest(GenericGeoOptTest): @@ -335,7 +335,7 @@ class OrcaGeoOptTest(GenericGeoOptTest): # 2) gradient is overachieved and displacement is reasonable (3 x tolerance) # 3) displacement is overachieved and gradient is reasonable (3 x tolerance) # 4) energy, gradients and angles are converged (displacements not considered) - # All these exceptions are signaleld in the output with some comments, and here + # All these exceptions are signaled in the output with some comments, and here # we include the first three exceptions for the pruposes of the unit test. def testgeoconverged(self, data) -> None: """Has the geometry converged and set optdone to True?""" @@ -387,9 +387,8 @@ def testgeoconverged(self, data) -> None: class XTBGeoOptTest(GenericGeoOptTest): """Customized restricted single point unittest""" - def testscfenergy(self, data) -> None: - """Is the SCF energy within the target?""" - assert abs(data.scfenergies[-1] - -26.438242468348) < 1.0e-6 + scfenergy = -26.438242468348 + scfenergy_tolerance = 1.0e-6 class TurbomoleKeepGeoOptTest(GenericGeoOptTest): diff --git a/test/data/testSP.py b/test/data/testSP.py index ffa851d96..2bb7abddd 100644 --- a/test/data/testSP.py +++ b/test/data/testSP.py @@ -7,6 +7,8 @@ import datetime +from cclib.parser import utils + import numpy import packaging from common import get_minimum_carbon_separation @@ -271,7 +273,9 @@ def testscfvaluetype(self, data) -> None: @skipForParser("NBO", "attribute not implemented in this version") def testscfenergy(self, data) -> None: """Is the SCF energy within the target?""" - assert abs(data.scfenergies[-1] - self.scfenergy) < self.scfenergy_delta + assert abs( + data.scfenergies[-1] - utils.convertor(self.scfenergy, "hartree", "eV") + ) < utils.convertor(self.scfenergy_delta, "hartree", "eV") @skipForParser("FChk", "Formatted Checkpoint files do not have a section for SCF convergence") @skipForParser("GAMESSDAT", "Scftargets probably do not exist in the file") @@ -308,7 +312,9 @@ def testtypemoenergies(self, data) -> None: @skipForParser("xTB", "not implemented yet") def testfirstmoenergy(self, data) -> None: """Is the lowest energy molecular orbital within the target?""" - assert abs(data.moenergies[0][0] - self.moenergy) < self.moenergy_delta + assert abs( + data.moenergies[0][0] - utils.convertor(self.moenergy, "hartree", "eV") + ) < utils.convertor(self.moenergy_delta, "hartree", "eV") @skipForParser("DALTON", "mocoeffs not implemented yet") @skipForLogfile( @@ -738,9 +744,8 @@ class TurbomoleHFSPTest(TurbomoleSPTest, GenericHFSPTest): class XTBSPTest(GenericSPTest): """Customized restricted single point unittest""" - def testscfenergy(self, data) -> None: - """Is the SCF energy within the target?""" - assert abs(data.scfenergies[-1] - -26.425939358406) < 1.0e-6 + scfenergy = -26.425939358406 + scfenergy_delta = 1.0e-6 class GenericDispersionTest: @@ -748,11 +753,14 @@ class GenericDispersionTest: # Q-Chem 5.4 dispersionenergy = -0.0147199319 + dispersionenergy_delta = 2.0e-7 def testdispersionenergies(self, data) -> None: """Is the dispersion energy parsed correctly?""" assert len(data.dispersionenergies) == 1 - assert abs(data.dispersionenergies[0] - self.dispersionenergy) < 2.0e-7 + assert abs( + data.dispersionenergies[0] - utils.convertor(self.dispersionenergy, "hartree", "eV") + ) < utils.convertor(self.dispersionenergy_delta, "hartree", "eV") class FireflyDispersionTest(GenericDispersionTest): diff --git a/test/data/testScan.py b/test/data/testScan.py index cbaa0b98a..f4a797d45 100644 --- a/test/data/testScan.py +++ b/test/data/testScan.py @@ -41,7 +41,9 @@ def testscanenergies(self, data) -> None: assert isinstance(data.scanenergies, list) # This checks the order of magnitude, and unit conversion if nothing else. - numpy.testing.assert_array_less(numpy.array(data.scanenergies), -378) + numpy.testing.assert_array_less( + numpy.array(data.scanenergies), cclib.parser.utils.convertor(-378, "hartree", "eV") + ) @skipForParser("ORCA", "Not implemented") @skipForParser("Jaguar", "Not implemented") diff --git a/test/data/testTD.py b/test/data/testTD.py index 7a31fb803..49886db16 100644 --- a/test/data/testTD.py +++ b/test/data/testTD.py @@ -5,6 +5,8 @@ """Test single point time-dependent logfiles in cclib""" +from cclib.parser import utils + import numpy from skip import skipForLogfile, skipForParser @@ -16,6 +18,7 @@ class GenericTDTest: # ??? expected_l_max = 0.18680974536292055 expected_f_max = 0.67 + expected_f_max_thresh = 0.1 symmetries = ["Singlet-Bu", "Singlet-Bu", "Singlet-Ag", "Singlet-Bu", "Singlet-Ag"] sumofsec = 1.0 method = "TD-DFT" @@ -44,7 +47,10 @@ def testenergies(self, data) -> None: # Note that if all oscillator strengths are zero (like for triplets) # then this will simply pick out the first energy. idx_lambdamax = numpy.argmax(data.etoscs) - assert abs(data.etenergies[idx_lambdamax] - self.expected_l_max) < 0.022781676263770798 + assert abs( + data.etenergies[idx_lambdamax] + - utils.convertor(self.expected_l_max, "hartree", "wavenumber") + ) < utils.convertor(0.022781676263770798, "hartree", "wavenumber") @skipForLogfile( "Turbomole/basicTurbomole7.4/CO_cc2_TD_trip", @@ -53,7 +59,7 @@ def testenergies(self, data) -> None: def testoscs(self, data) -> None: """Is the maximum of etoscs in the right range?""" assert len(data.etoscs) == self.number - assert abs(max(data.etoscs) - self.expected_f_max) < 0.1 + assert abs(max(data.etoscs) - self.expected_f_max) < self.expected_f_max_thresh @skipForParser("FChk", "The parser is still being developed so we skip this test") @skipForParser("Molcas", "The parser is still being developed so we skip this test") @@ -205,11 +211,6 @@ class JaguarTDDFTTest(GenericTDTest): expected_l_max = 0.21870409213219966 expected_f_max = 1.2 - def testoscs(self, data) -> None: - """Is the maximum of etoscs in the right range?""" - assert len(data.etoscs) == self.number - assert abs(max(data.etoscs) - 1.0) < 0.2 - class OrcaTDDFTTest(GenericTDTest): """Customized time-dependent HF/DFT unittest""" @@ -243,11 +244,6 @@ class QChemTDDFTTest(GenericTDTest): expected_l_max = 0.21870409213219966 expected_f_max = 0.9 - def testoscs(self, data) -> None: - """Is the maximum of etoscs in the right range?""" - assert len(data.etoscs) == self.number - assert abs(max(data.etoscs) - 0.9) < 0.1 - class GenericTDDFTtrpTest(GenericTDTest): """Generic time-dependent HF/DFT (triplet) unittest""" @@ -273,11 +269,6 @@ class OrcaROCISTest(GenericTDTest): # Do we want to parse ROCIS as its own method? method = "CIS" - def testoscs(self, data) -> None: - """Is the maximum of etoscs in the right range?""" - assert len(data.etoscs) == self.number - assert abs(max(data.etoscs) - 0.015) < 0.1 - def testTransprop(self, data) -> None: """Check the number of spectra parsed""" assert len(data.transprop) == self.n_spectra @@ -313,11 +304,6 @@ class TurbomoleTDTest(GenericTDTest): expected_f_max = 0.19 symmetries = ["Singlet-A"] * 10 - def testoscs(self, data) -> None: - """Is the maximum of etoscs in the right range?""" - assert len(data.etoscs) == self.number - assert abs(max(data.etoscs) - 0.19) < 0.1 - @skipForLogfile("Turbomole/basicTurbomole7.4/CO_cc2_TD", "There are no dipole moments in ricc2") def testetmagdipsshape(self, data) -> None: """Is the shape of etmagdips correct?""" @@ -349,11 +335,6 @@ class TurbomoleTDTripTest(GenericTDTest): symmetries = ["Triplet-A"] * 10 method = "RPA" - def testoscs(self, data) -> None: - """Is the maximum of etoscs in the right range?""" - assert len(data.etoscs) == self.number - assert abs(max(data.etoscs) - 0.84) < 0.1 - class TurbomoleTDCC2TripTest(GenericTDTest): """Customized time-dependent HF/DFT unittest""" diff --git a/test/regression.py b/test/regression.py index fec1c38f3..a668de60f 100644 --- a/test/regression.py +++ b/test/regression.py @@ -39,6 +39,7 @@ from cclib.io import ccread, moldenwriter from cclib.parser import DALTON, Gaussian, ccData +from cclib.parser.utils import convertor import numpy import pytest @@ -652,7 +653,7 @@ def testGAMESS_GAMESS_US2008_N2_UMP2_out(logfile): """Check that the new format for GAMESS MP2 is parsed.""" assert hasattr(logfile.data, "mpenergies") assert len(logfile.data.mpenergies) == 1 - assert abs(logfile.data.mpenergies[0] - -109.3647999161) < 1.0e-10 + assert abs(convertor(logfile.data.mpenergies[0], "eV", "hartree") - -109.3647999161) < 1.0e-10 assert logfile.data.metadata["legacy_package_version"] == "2008R1" assert logfile.data.metadata["package_version"] == "2008.r1" @@ -663,7 +664,7 @@ def testGAMESS_GAMESS_US2008_N2_ROMP2_out(logfile): """Check that the new format for GAMESS MP2 is parsed.""" assert hasattr(logfile.data, "mpenergies") assert len(logfile.data.mpenergies) == 1 - assert abs(logfile.data.mpenergies[0] - -109.3647999184) < 1.0e-10 + assert abs(convertor(logfile.data.mpenergies[0], "eV", "hartree") - -109.3647999184) < 1.0e-10 assert logfile.data.metadata["package_version"] == "2008.r1" @@ -672,7 +673,7 @@ def testGAMESS_GAMESS_US2009_open_shell_ccsd_test_log(logfile): """Parse ccenergies from open shell CCSD calculations.""" assert hasattr(logfile.data, "ccenergies") assert len(logfile.data.ccenergies) == 1 - assert abs(logfile.data.ccenergies[0] - -128.6777922565) < 1.0e-10 + assert abs(convertor(logfile.data.ccenergies[0], "eV", "hartree") - -128.6777922565) < 1.0e-10 assert logfile.data.metadata["legacy_package_version"] == "2009R3" assert logfile.data.metadata["package_version"] == "2009.r3" @@ -683,7 +684,7 @@ def testGAMESS_GAMESS_US2009_paulo_h2o_mp2_out(logfile): """Check that the new format for GAMESS MP2 is parsed.""" assert hasattr(logfile.data, "mpenergies") assert len(logfile.data.mpenergies) == 1 - assert abs(logfile.data.mpenergies[0] - -76.1492222841) < 1.0e-10 + assert abs(convertor(logfile.data.mpenergies[0], "eV", "hartree") - -76.1492222841) < 1.0e-10 assert logfile.data.metadata["package_version"] == "2009.r3" @@ -758,7 +759,11 @@ def testGAMESS_WinGAMESS_dvb_td_trplet_2007_03_24_r1_out(logfile): 0 ] assert ( - abs(logfile.data.etenergies[idx_lambdamax] - (-381.9320539243 - -382.0432999970)) < 1.0e-5 + abs( + convertor(logfile.data.etenergies[idx_lambdamax], "wavenumber", "hartree") + - (-381.9320539243 - -382.0432999970) + ) + < 1.0e-5 ) assert len(logfile.data.etoscs) == number assert abs(max(logfile.data.etoscs) - 0.0) < 0.01 @@ -1060,7 +1065,10 @@ def testGaussian_Gaussian09_2D_PES_one_unconverged_log(logfile): def testGaussian_Gaussian09_534_out(logfile): """Previously, caused etenergies parsing to fail.""" assert logfile.data.etsyms[0] == "Singlet-?Sym" - assert abs(logfile.data.etenergies[0] - 0.09532039604871197) < 1.0e-5 + assert ( + abs(convertor(logfile.data.etenergies[0], "wavenumber", "hartree") - 0.09532039604871197) + < 1.0e-5 + ) assert logfile.data.metadata["legacy_package_version"] == "09revisionA.02" assert logfile.data.metadata["package_version"] == "2009+A.02" @@ -1104,7 +1112,7 @@ def testGaussian_Gaussian09_dvb_lowdin_log(logfile): def testGaussian_Gaussian09_Dahlgren_TS_log(logfile): """Failed to parse ccenergies for a variety of reasons""" assert hasattr(logfile.data, "ccenergies") - assert abs(logfile.data.ccenergies[0] - (-434.37573219)) < 1.0e-6 + assert abs(convertor(logfile.data.ccenergies[0], "eV", "hartree") - (-434.37573219)) < 1.0e-6 assert logfile.data.metadata["package_version"] == "2009+A.02" @@ -1681,7 +1689,7 @@ def testORCA_ORCA2_9_job_out(logfile): def testORCA_ORCA2_9_qmspeedtest_hf_out(logfile): """Check precision of SCF energies (cclib/cclib#210).""" - energy = logfile.data.scfenergies[-1] + energy = convertor(logfile.data.scfenergies[-1], "eV", "hartree") expected = -644.675706036271 assert abs(energy - expected) < 1.0e-8 @@ -1913,7 +1921,7 @@ def testORCA_ORCA4_2_longer_input_out(logfile): def testORCA_ORCA4_2_casscf_out(logfile): """ORCA casscf input file (#1044).""" - assert numpy.isclose(logfile.data.etenergies[0], 0.128812) + assert numpy.isclose(convertor(logfile.data.etenergies[0], "wavenumber", "hartree"), 0.128812) def testORCA_ORCA5_0_ADBNA_Me_Mes_MesCz_log(logfile): @@ -2032,7 +2040,7 @@ def testQChem_QChem4_2_CH3___Na__RS_out(logfile): # Fragments: A, B, RS_CP(A), RS_CP(B), Full assert len(logfile.data.scfenergies) == 1 scfenergy = -201.9388745658 - assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10 + assert abs(convertor(logfile.data.scfenergies[0], "eV", "hartree") - scfenergy) < 1.0e-10 assert logfile.data.nbasis == logfile.data.nmo == 40 assert len(logfile.data.moenergies[0]) == 40 @@ -2065,7 +2073,7 @@ def testQChem_QChem4_2_CH3___Na__RS_SCF_out(logfile): # Fragments: A, B, RS_CP(A), RS_CP(B), SCF_CP(A), SCF_CP(B), Full assert len(logfile.data.scfenergies) == 1 scfenergy = -201.9396979324 - assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10 + assert abs(convertor(logfile.data.scfenergies[0], "eV", "hartree") - scfenergy) < 1.0e-10 assert logfile.data.nbasis == logfile.data.nmo == 40 assert len(logfile.data.moenergies[0]) == 40 @@ -2096,7 +2104,7 @@ def testQChem_QChem4_2_CH4___Na__out(logfile): # Fragments: A, B, Full assert len(logfile.data.scfenergies) == 1 scfenergy = -202.6119443654 - assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10 + assert abs(convertor(logfile.data.scfenergies[0], "eV", "hartree") - scfenergy) < 1.0e-10 assert logfile.data.nbasis == logfile.data.nmo == 42 assert len(logfile.data.moenergies[0]) == 42 @@ -2126,7 +2134,7 @@ def testQChem_QChem4_2_CH3___Na__RS_SCF_noprint_out(logfile): assert len(logfile.data.scfenergies) == 1 scfenergy = -201.9396979324 - assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10 + assert abs(convertor(logfile.data.scfenergies[0], "eV", "hartree") - scfenergy) < 1.0e-10 assert logfile.data.nbasis == logfile.data.nmo == 40 assert len(logfile.data.moenergies[0]) == 40 @@ -2156,7 +2164,7 @@ def testQChem_QChem4_2_CH3___Na__RS_noprint_out(logfile): assert len(logfile.data.scfenergies) == 1 scfenergy = -201.9388582085 - assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10 + assert abs(convertor(logfile.data.scfenergies[0], "eV", "hartree") - scfenergy) < 1.0e-10 assert logfile.data.nbasis == logfile.data.nmo == 40 assert len(logfile.data.moenergies[0]) == 40 @@ -2184,7 +2192,7 @@ def testQChem_QChem4_2_CH4___Na__noprint_out(logfile): assert len(logfile.data.scfenergies) == 1 scfenergy = -202.6119443654 - assert abs(logfile.data.scfenergies[0] - scfenergy) < 1.0e-10 + assert abs(convertor(logfile.data.scfenergies[0], "eV", "hartree") - scfenergy) < 1.0e-10 assert logfile.data.nbasis == logfile.data.nmo == 42 assert len(logfile.data.moenergies[0]) == 42 @@ -2728,8 +2736,14 @@ def testQChem_QChem5_0_argon_out(logfile): assert len(logfile.data.etenergies) == nroots state_0_energy = -526.6323968555 state_1_energy = -526.14663738 - assert logfile.data.scfenergies[0] == state_0_energy - assert abs(logfile.data.etenergies[0] - (state_1_energy - state_0_energy)) < 1.0e-1 + assert convertor(logfile.data.scfenergies[0], "eV", "hartree") == state_0_energy + assert ( + abs( + convertor(logfile.data.etenergies[0], "wavenumber", "hartree") + - (state_1_energy - state_0_energy) + ) + < 1.0e-1 + ) def testQChem_QChem5_0_Si_out(logfile):