Skip to content

Commit

Permalink
revert cclib#1405
Browse files Browse the repository at this point in the history
Part of reverting breaking changes on default
branch (cclib#1482)
  • Loading branch information
berquist committed Oct 23, 2024
1 parent 303c311 commit 891424a
Show file tree
Hide file tree
Showing 14 changed files with 126 additions and 89 deletions.
4 changes: 2 additions & 2 deletions cclib/bridge/cclib2pyscf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion cclib/io/moldenwriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down
6 changes: 3 additions & 3 deletions cclib/io/wfxwriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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."""
Expand Down
12 changes: 6 additions & 6 deletions cclib/parser/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down
22 changes: 22 additions & 0 deletions cclib/parser/logfileparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions cclib/parser/turbomoleparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ def extract(self, inputfile, line):
info = re.match(
r".*eigenvalue=(?P<moenergy>[0-9D\.+-]{20})\s+nsaos=(?P<count>\d+).*", line
)
assert info is not None
eigenvalue = utils.float(info.group("moenergy"))

moenergies.append(eigenvalue)
Expand Down
6 changes: 3 additions & 3 deletions doc/sphinx/data_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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<sup>-1</sup>``. 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
------
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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`_.

Expand Down
8 changes: 4 additions & 4 deletions test/bridge/testpyscf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand All @@ -40,15 +40,15 @@ 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
assert np.allclose(mo_coeff[0][10], self.data.mocoeffs[0][10][0])
# 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
Expand Down
18 changes: 14 additions & 4 deletions test/data/testCC.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

"""Test coupled cluster logfiles"""

from cclib.parser import utils

import numpy
import pytest

Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand All @@ -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):
Expand All @@ -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):
Expand Down
29 changes: 14 additions & 15 deletions test/data/testGeoOpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand All @@ -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?"""
Expand Down Expand Up @@ -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):
Expand Down
20 changes: 14 additions & 6 deletions test/data/testSP.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import datetime

from cclib.parser import utils

import numpy
import packaging
from common import get_minimum_carbon_separation
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -738,21 +744,23 @@ 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:
"""Generic single-geometry dispersion correction unittest"""

# 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):
Expand Down
4 changes: 3 additions & 1 deletion test/data/testScan.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Loading

0 comments on commit 891424a

Please sign in to comment.