Source code for iodata.formats.orcalog
# 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/>
# --
"""Orca output file format."""
from typing import TextIO
import numpy as np
from numpy.typing import NDArray
from ..docstrings import document_load_one
from ..utils import LineIterator
__all__ = ()
PATTERNS = ["*.out"]
[docs]
@document_load_one("Orca output", ["atcoords", "atnums", "energy", "moments", "extra"])
def load_one(lit: LineIterator) -> dict:
"""Do not edit this docstring. It will be overwritten."""
result = {}
while True:
try:
line = next(lit)
except StopIteration:
# Read until the end of the file.
break
# Get the total number of atoms
if line.startswith("CARTESIAN COORDINATES (ANGSTROEM)"):
natom = _helper_number_atoms(lit)
# Every Cartesian coordinates found are replaced with the old ones
# to maintain the ones from the final SCF iteration in e.g. optimization run
if line.startswith("CARTESIAN COORDINATES (A.U.)"):
result["atnums"], result["atcoords"] = _helper_geometry(lit, natom)
# Read the energies of each SCF cycle in iodata.extra
if line.startswith("SCF ITERATIONS"):
scf_energies = _helper_scf_energies(lit)
result["extra"] = {"scf_energies": scf_energies}
# The final SCF energy is obtained
if line.startswith("FINAL SINGLE POINT ENERGY"):
words = line.split()
result["energy"] = float(words[4])
# Read also the dipole moment
if line.startswith("Total Dipole Moment"):
words = line.split()
dipole = np.array([float(words[4]), float(words[5]), float(words[6])])
result["moments"] = {(1, "c"): dipole}
return result
def _helper_number_atoms(lit: LineIterator) -> int:
"""Load list of coordinates from an ORCA output file format.
Parameters
----------
lit
The line iterator to read the data from.
Returns
-------
natom: int
Total number of atoms.
"""
# skip the dashed line
next(lit)
natom = 0
# Add until an empty line is found
while next(lit).strip() != "":
natom += 1
return natom
def _helper_geometry(lit: TextIO, natom: int) -> tuple[NDArray[int], NDArray[float]]:
"""Load coordinates form a ORCA output file format.
Parameters
----------
lit
The line iterator to read the data from.
Returns
-------
atnums
The atomic numbers.
atcoords
The atcoords in an array with shape ``(natom, 3)``.
"""
atcoords = np.zeros((natom, 3))
atnums = np.zeros(natom)
# skip the dashed line
next(lit)
# skip the titles in table
next(lit)
# read in the atomic number and coordinates in a.u.
for i in range(natom):
words = next(lit).split()
atnums[i] = int(float(words[2]))
atcoords[i, 0] = float(words[5])
atcoords[i, 1] = float(words[6])
atcoords[i, 2] = float(words[7])
return atnums, atcoords
def _helper_scf_energies(lit: TextIO) -> NDArray[float]:
"""Load energies from each SCF cycle from a ORCA output file format.
Parameters
----------
lit
The line iterator to read the data from.
Returns
-------
energies
The energies of each scf cycle in 1D-array.
"""
energies = []
line = next(lit)
# read the next line until blank line
while line.strip() != "":
words = line.split()
if words[0].isdigit():
energies.append(float(words[1]))
line = next(lit)
return np.asarray(energies)