Skip to content

Psi4 Engine

psi4

Psi4 quantum mechanics engine backend.

Wraps the Psi4 Python API for QM calculations: energy, Hessian, geometry optimization, and vibrational frequencies.

Requires: conda install psi4 -c conda-forge

Psi4Engine

Psi4Engine(method: str = 'b3lyp', basis: str = '6-31+G(d)', memory: str = '2 GB', n_threads: int = 4, charge: int = 0, multiplicity: int = 1)

Bases: QMEngine

Quantum mechanics engine using Psi4.

Parameters:

Name Type Description Default
method str

DFT functional or method (default: "b3lyp")

'b3lyp'
basis str

Basis set (default: "6-31+G(d)")

'6-31+G(d)'
memory str

Memory allocation (default: "2 GB")

'2 GB'
n_threads int

Number of threads (default: 4)

4
charge int

Molecular charge (default: 0)

0
multiplicity int

Spin multiplicity (default: 1)

1

Initialize the Psi4 engine.

Parameters:

Name Type Description Default
method str

DFT functional or method (e.g. "b3lyp", "mp2").

'b3lyp'
basis str

Basis set (e.g. "6-31+G(d)").

'6-31+G(d)'
memory str

Memory allocation string (e.g. "2 GB").

'2 GB'
n_threads int

Number of threads for parallel computation.

4
charge int

Molecular charge.

0
multiplicity int

Spin multiplicity.

1

Raises:

Type Description
ImportError

If Psi4 is not installed.

Source code in q2mm/backends/qm/psi4.py
def __init__(
    self,
    method: str = "b3lyp",
    basis: str = "6-31+G(d)",
    memory: str = "2 GB",
    n_threads: int = 4,
    charge: int = 0,
    multiplicity: int = 1,
):
    """Initialize the Psi4 engine.

    Args:
        method: DFT functional or method (e.g. ``"b3lyp"``, ``"mp2"``).
        basis: Basis set (e.g. ``"6-31+G(d)"``).
        memory: Memory allocation string (e.g. ``"2 GB"``).
        n_threads: Number of threads for parallel computation.
        charge: Molecular charge.
        multiplicity: Spin multiplicity.

    Raises:
        ImportError: If Psi4 is not installed.
    """
    if not _HAS_PSI4:
        raise ImportError("Psi4 is not installed. Install via: conda install psi4 -c conda-forge")
    self._method = method
    self._basis = basis
    self._charge = charge
    self._multiplicity = multiplicity
    _psi4.set_memory(memory)
    _psi4.set_num_threads(n_threads)
    # Suppress output by default
    self._tmpdir = tempfile.mkdtemp(prefix="q2mm_psi4_")
    _psi4.core.set_output_file(os.path.join(self._tmpdir, "psi4_output.dat"), False)

name property

name: str

Human-readable engine name.

Returns:

Name Type Description
str str

Engine name including method and basis set.

is_available

is_available() -> bool

Check if Psi4 is installed.

Returns:

Name Type Description
bool bool

True if the psi4 package is importable.

Source code in q2mm/backends/qm/psi4.py
def is_available(self) -> bool:
    """Check if Psi4 is installed.

    Returns:
        bool: ``True`` if the ``psi4`` package is importable.
    """
    return _HAS_PSI4

energy

energy(structure, method: str = None, basis: str = None) -> float

Calculate single-point energy in Hartrees.

Parameters:

Name Type Description Default
structure str | tuple

XYZ file path or (atoms, coords) tuple.

required
method str

Override the default QM method.

None
basis str

Override the default basis set.

None

Returns:

Name Type Description
float float

Electronic energy in Hartrees.

Source code in q2mm/backends/qm/psi4.py
def energy(self, structure, method: str = None, basis: str = None) -> float:
    """Calculate single-point energy in Hartrees.

    Args:
        structure (str | tuple): XYZ file path or ``(atoms, coords)`` tuple.
        method: Override the default QM method.
        basis: Override the default basis set.

    Returns:
        float: Electronic energy in Hartrees.
    """
    mol = self._load_molecule(structure)
    m = method or self._method
    if basis:
        _psi4.set_options({"basis": basis})
    return _psi4.energy(m, molecule=mol)

hessian

hessian(structure, method: str = None, basis: str = None) -> ndarray

Calculate Hessian matrix (second derivatives of energy).

Parameters:

Name Type Description Default
structure str | tuple

XYZ file path or (atoms, coords) tuple.

required
method str

Override the default QM method.

None
basis str

Override the default basis set.

None

Returns:

Type Description
ndarray

np.ndarray: Shape (3N, 3N) Hessian in Hartree/Bohr².

Source code in q2mm/backends/qm/psi4.py
def hessian(self, structure, method: str = None, basis: str = None) -> np.ndarray:
    """Calculate Hessian matrix (second derivatives of energy).

    Args:
        structure (str | tuple): XYZ file path or ``(atoms, coords)`` tuple.
        method: Override the default QM method.
        basis: Override the default basis set.

    Returns:
        np.ndarray: Shape ``(3N, 3N)`` Hessian in Hartree/Bohr².
    """
    mol = self._load_molecule(structure)
    m = method or self._method
    if basis:
        _psi4.set_options({"basis": basis})
    _, wfn = _psi4.frequency(m, molecule=mol, return_wfn=True)
    return np.array(wfn.hessian())

optimize

optimize(structure, method: str = None, basis: str = None, opt_type: str = 'min') -> tuple

Optimize geometry.

Parameters:

Name Type Description Default
structure str | tuple

XYZ file path or (atoms, coords) tuple.

required
method str

Override the default QM method.

None
basis str

Override the default basis set.

None
opt_type str

"min" for minimization, "ts" for transition state search.

'min'

Returns:

Type Description
tuple

tuple[float, list[str], np.ndarray]: (energy, atoms, coords_angstrom) with energy in Hartrees.

Source code in q2mm/backends/qm/psi4.py
def optimize(self, structure, method: str = None, basis: str = None, opt_type: str = "min") -> tuple:
    """Optimize geometry.

    Args:
        structure (str | tuple): XYZ file path or ``(atoms, coords)`` tuple.
        method: Override the default QM method.
        basis: Override the default basis set.
        opt_type: ``"min"`` for minimization, ``"ts"`` for transition
            state search.

    Returns:
        tuple[float, list[str], np.ndarray]: ``(energy, atoms, coords_angstrom)`` with energy in Hartrees.
    """
    mol = self._load_molecule(structure)
    m = method or self._method
    if basis:
        _psi4.set_options({"basis": basis})
    _psi4.set_options({"opt_type": opt_type, "geom_maxiter": 100})
    energy = _psi4.optimize(m, molecule=mol)
    coords_bohr = mol.geometry().np
    coords_ang = coords_bohr * 0.529177  # Bohr to Angstrom
    atoms = [mol.symbol(i) for i in range(mol.natom())]
    return energy, atoms, coords_ang

frequencies

frequencies(structure, method: str = None, basis: str = None) -> list[float]

Calculate vibrational frequencies in cm⁻¹.

Parameters:

Name Type Description Default
structure str | tuple

XYZ file path or (atoms, coords) tuple.

required
method str

Override the default QM method.

None
basis str

Override the default basis set.

None

Returns:

Type Description
list[float]

list[float]: Vibrational frequencies in cm⁻¹.

Source code in q2mm/backends/qm/psi4.py
def frequencies(self, structure, method: str = None, basis: str = None) -> list[float]:
    """Calculate vibrational frequencies in cm⁻¹.

    Args:
        structure (str | tuple): XYZ file path or ``(atoms, coords)`` tuple.
        method: Override the default QM method.
        basis: Override the default basis set.

    Returns:
        list[float]: Vibrational frequencies in cm⁻¹.
    """
    mol = self._load_molecule(structure)
    m = method or self._method
    if basis:
        _psi4.set_options({"basis": basis})
    _, wfn = _psi4.frequency(m, molecule=mol, return_wfn=True)
    return list(np.array(wfn.frequencies()))

close

close()

Clean up temporary files created by Psi4.

Source code in q2mm/backends/qm/psi4.py
def close(self):
    """Clean up temporary files created by Psi4."""
    if hasattr(self, "_tmpdir") and os.path.exists(self._tmpdir):
        shutil.rmtree(self._tmpdir, ignore_errors=True)

__enter__

__enter__() -> Psi4Engine

Enter context manager.

Returns:

Name Type Description
Psi4Engine Psi4Engine

This engine instance.

Source code in q2mm/backends/qm/psi4.py
def __enter__(self) -> Psi4Engine:
    """Enter context manager.

    Returns:
        Psi4Engine: This engine instance.
    """
    return self

__exit__

__exit__(*args)

Exit context manager and clean up temporary files.

Source code in q2mm/backends/qm/psi4.py
def __exit__(self, *args):
    """Exit context manager and clean up temporary files."""
    self.close()

__del__

__del__()

Destructor — clean up temporary files.

Source code in q2mm/backends/qm/psi4.py
def __del__(self):
    """Destructor — clean up temporary files."""
    self.close()