Source code for vibesketch.document.orca

"""ORCA files opened as documents: outputs and Hessian files (#86).

These files hold atoms and coordinates, not a chemical graph. The bonds and
bond orders are inferred from the coordinates with the stated charge
(:mod:`vibesketch.document.coordinates`), a structure whose bond orders do not
fit is left out rather than drawn with guessed bonds, and the document records
that its graph was inferred. Each geometry an optimisation printed is kept as
a conformer of its species, the last first.

ORCA's output vocabulary: ORCA 6.1 manual,
https://www.faccts.de/docs/orca/6.1/manual/contents/quickstartguide/hellowater.html
"""

from __future__ import annotations

import re

from vibesketch.document.coordinates import Structure

__all__ = ["OrcaUnreadable", "hessian_structures", "output_structures"]


[docs] class OrcaUnreadable(ValueError): """The data is not an ORCA file this reader recognises."""
def _text(data: str | bytes, what: str) -> str: if isinstance(data, str): return data try: return data.decode("utf-8") except UnicodeDecodeError: raise OrcaUnreadable(f"an ORCA {what} must be UTF-8 text") from None def _stated(text: str, pattern: str, what: str) -> int: """The one value ORCA states for ``what``; refused when absent or contradictory.""" values = {int(m) for m in re.findall(pattern, text, re.M)} if len(values) != 1: raise OrcaUnreadable( f"the ORCA output states {'no' if not values else 'more than one'} {what}" ) return values.pop()
[docs] def output_structures(data: str | bytes) -> tuple[list[Structure], list[str]]: """Each geometry an ORCA 6 output printed, with its charge and multiplicity, and warnings.""" from vibesketch.document.results import _coordinate_blocks, _same text = _text(data, "output") if not re.search(r"^\s*Program Version\s+6\.", text, re.M): raise OrcaUnreadable("not an ORCA 6 output: it names no ORCA 6 program version") charge = _stated(text, r"^\s*Total Charge\s+Charge\s+\.+\s+(-?\d+)\s*$", "total charge") multiplicity = _stated(text, r"^\s*Multiplicity\s+Mult\s+\.+\s+(\d+)\s*$", "multiplicity") frames: list[tuple[list[str], list[list[float]]]] = [] for _, (symbols, xyz) in _coordinate_blocks(text): if frames and frames[-1][0] == symbols and _same(frames[-1][1], xyz): continue # ORCA prints the geometry it ends on more than once frames.append((symbols, xyz)) if not frames: raise OrcaUnreadable("the ORCA output prints no Cartesian coordinates in angstrom") warnings: list[str] = [] if "ORCA TERMINATED NORMALLY" not in text: warnings.append("the ORCA run did not terminate normally; its last geometry is shown") if "GEOMETRY OPTIMIZATION" in text and "THE OPTIMIZATION HAS CONVERGED" not in text: warnings.append("the optimisation did not converge; its last geometry is shown") structures = [ Structure( id=f"geometry {number}" if len(frames) > 1 else "the geometry", symbols=symbols, positions=xyz, charge=charge, multiplicity=multiplicity, method="orca-output", ) for number, (symbols, xyz) in enumerate(frames, start=1) ] return structures, warnings
[docs] def hessian_structures(data: str | bytes) -> tuple[list[Structure], list[str]]: """The geometry of an ORCA Hessian file, which states no charge or multiplicity.""" from vibesketch.document.results import ResultRefused, _hessian_geometry raw = data.encode("utf-8") if isinstance(data, str) else data try: symbols, xyz = _hessian_geometry(raw) except ResultRefused as error: raise OrcaUnreadable(str(error)) from None structure = Structure( id="the Hessian file", symbols=symbols, positions=xyz, charge=0, method="orca-hess" ) return [structure], [ "an ORCA Hessian file states no charge or multiplicity: it is read as neutral, and its " "spin follows from its electrons" ]