Source code for iodata.formats.gaussianlog
# IODATA is an input and output module for quantum chemistry.
# Copyright (C) 2011-2019 The IODATA Development Team
#
# This file is part of IODATA.
#
# IODATA is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# IODATA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>
# --
"""Gaussian Log file format.
To write out the integrals in a Gaussian log file, which can be loaded with this module,
you need to use the following Gaussian command line:
.. code-block ::
scf(conventional) iop(3/33=5) extralinks=l316 iop(3/27=999)
"""
import numpy as np
from numpy.typing import NDArray
from ..docstrings import document_load_one
from ..utils import LineIterator, set_four_index_element
__all__ = ()
PATTERNS = ["*.log"]
LOAD_ONE_NOTES = """\
Note that Gaussian writes four-center integrals in chemists' notation.
They will be reordered into physicists' notation when loading them with IOData.
"""
[docs]
@document_load_one("Gaussian Log", [], ["one_ints", "two_ints"], notes=LOAD_ONE_NOTES)
def load_one(lit: LineIterator) -> dict:
"""Do not edit this docstring. It will be overwritten."""
# First get the line with the number of orbital basis functions
for line in lit:
if line.startswith(" NBasis ="):
nbasis = int(line[12:18])
break
# Then load the two- and four-index operators. This part is written such
# that it does not make any assumptions about the order in which these
# operators are printed.
one_ints = {}
two_ints = {}
while True:
line = next(lit)
if line.startswith(" Normal termination of Gaussian"):
break
if line.startswith(" *** Overlap ***"):
one_ints["olp"] = _load_twoindex_g09(lit, nbasis)
elif line.startswith(" *** Kinetic Energy ***"):
one_ints["kin_ao"] = _load_twoindex_g09(lit, nbasis)
elif line.startswith(" ***** Potential Energy *****"):
one_ints["na_ao"] = _load_twoindex_g09(lit, nbasis)
elif line.startswith(" *** Dumping Two-Electron integrals ***"):
two_ints["er_ao"] = _load_fourindex_g09(lit, nbasis)
result = {}
if one_ints:
result["one_ints"] = one_ints
if two_ints:
result["two_ints"] = two_ints
return result
def _load_twoindex_g09(lit: LineIterator, nbasis: int) -> NDArray[float]:
"""Load a two-index operator from a GAUSSIAN LOG file format.
Parameters
----------
lit
The line iterator to read the data from.
nbasis
The number of atomic orbital basis functions.
Returns
-------
Operator array with shape ``(nbasis, nbasis)``.
"""
result = np.zeros((nbasis, nbasis))
block_counter = 0
while block_counter < nbasis:
# skip the header line
next(lit)
# determine the number of rows in this part
nrow = nbasis - block_counter
for i in range(nrow):
words = next(lit).split()[1:]
for j, word in enumerate(words):
value = float(word.replace("D", "E"))
result[i + block_counter, j + block_counter] = value
result[j + block_counter, i + block_counter] = value
block_counter += 5
return result
def _load_fourindex_g09(lit: LineIterator, nbasis: int) -> NDArray[float]:
"""Load a four-index operator from a GAUSSIAN LOG file.
Parameters
----------
lit
The line iterator to read the data from.
nbasis
The number of atomic orbital basis functions.
Returns
-------
Operator array with shape ``(nbasis, nbasis, nbasis, nbasis)``.
"""
result = np.zeros((nbasis, nbasis, nbasis, nbasis))
# Skip first six lines
for _i in range(6):
next(lit)
# Start reading elements until a line is encountered that does not start
# with ' I='
for line in lit:
if not line.startswith(" I="):
break
# print line[3:7], line[9:13], line[15:19], line[21:25], line[28:].replace('D', 'E')
i0 = int(line[3:7]) - 1
i1 = int(line[9:13]) - 1
i2 = int(line[15:19]) - 1
i3 = int(line[21:25]) - 1
value = float(line[29:].replace("D", "E"))
# Gaussian uses the chemists' notation for the 4-center indexes. IOdata
# uses the physicists' notation.
set_four_index_element(result, i0, i2, i1, i3, value)
return result