Source code for moldenViz.models
"""Public data models used by moldenViz."""
from __future__ import annotations
from dataclasses import dataclass
from math import gamma
from typing import TYPE_CHECKING
import numpy as np
if TYPE_CHECKING:
from numpy.typing import NDArray
__all__ = ['Atom', 'GaussianPrimitive', 'MolecularOrbital', 'Shell']
[docs]
@dataclass
class Atom:
"""A parsed atom and its basis-function shells.
Parameters
----------
label : str
Atomic label from the Molden file.
atomic_number : int
Atomic number of the element.
position : NDArray[np.floating]
Three-dimensional position in Bohr.
shells : list[Shell]
Electron shells associated with the atom.
"""
label: str
atomic_number: int
position: NDArray[np.floating]
shells: list[Shell]
[docs]
@dataclass
class MolecularOrbital:
"""Metadata for a parsed molecular orbital."""
sym: str
energy: float
spin: str
occ: int
[docs]
class GaussianPrimitive:
"""A Gaussian primitive with an exponent and contraction coefficient."""
def __init__(self, exp: float, coeff: float) -> None:
self.exp = exp
self.coeff = coeff
self._norm = 0.0
def _normalize(self, l: int) -> None:
"""Calculate and cache the primitive normalization for angular momentum ``l``."""
self._norm = np.sqrt(2 * (2 * self.exp) ** (l + 1.5) / gamma(l + 1.5))
[docs]
class Shell:
"""An electron shell containing Gaussian primitives."""
def __init__(self, l: int, gtos: list[GaussianPrimitive]) -> None:
self.l = l
self.gtos = gtos
self._norm = 0.0
self._gto_norms = np.empty(len(gtos), dtype=float)
self._gto_exps = np.array([gto.exp for gto in gtos], dtype=float)
self._gto_coeffs = np.array([gto.coeff for gto in gtos], dtype=float)
self._prefactor = np.empty(len(gtos), dtype=float)
def _normalize(self) -> None:
"""Calculate and cache shell and primitive normalization values."""
for idx, gto in enumerate(self.gtos):
gto._normalize(self.l) # ruff:ignore[private-member-access]
self._gto_norms[idx] = gto._norm # ruff:ignore[private-member-access]
overlap = 0.0
for i_gto in self.gtos:
for j_gto in self.gtos:
overlap += (
i_gto.coeff
* j_gto.coeff
* (2 * np.sqrt(i_gto.exp * j_gto.exp) / (i_gto.exp + j_gto.exp)) ** (self.l + 1.5)
)
self._norm = 1 / np.sqrt(overlap)
self._prefactor = self._norm * self._gto_norms * self._gto_coeffs