qdk_chemistry.utils package

QDK/Chemistry Utilities Module.

class qdk_chemistry.utils.CaseInsensitiveStrEnum(new_class_name, /, names, *, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: StrEnum

StrEnum that allows case-insensitive lookup of values.

class qdk_chemistry.utils.CubeGenerator

Bases: pybind11_object

Evaluate molecular orbitals and densities on a grid using the native backend.

Atomic orbital ordering

Coefficient and density-matrix indices follow the canonical qdk-chemistry atomic orbital ordering: atom-major, and within an atom by ascending angular momentum and then descending leading exponent. s and p shells are always Cartesian, so p functions appear as x, y, z. Shells with angular momentum of 2 or more follow gauXC’s component convention.

Effective core potentials

ECP projector shells are not basis functions and take no part in evaluation, so a field built from an ECP basis is valence-only: it omits the core density that the potential replaces. Cube files written from such a basis record this in their comment line.

__init__(self: qdk_chemistry.utils.CubeGenerator, basis_set: qdk_chemistry.data.BasisSet) → None
Parameters:

basis_set – Basis set defining the atomic orbitals and the molecule.

density(self: qdk_chemistry.utils.CubeGenerator, density_matrix: Annotated[numpy.typing.ArrayLike, numpy.float64, '[m, n]'], grid: qdk_chemistry.utils.CubeGrid, outfile: str = '', comment: str = '') → numpy.typing.NDArray[numpy.float64]

Evaluate a density on a grid as sum_uv D_uv phi_u(r) phi_v(r).

The matrix is used exactly as supplied. It is not scaled, symmetrised, or spin-summed, so the caller decides which physical quantity results: pass Da + Db for the total electron density, or a single spin block for that spin density. A restricted calculation that stores a spatial density matrix without its factor of two yields a field that is uniformly half the total density. Both matrices have identical shapes, so this cannot be detected automatically.

Parameters:
  • density_matrix – nbf by nbf matrix indexed by atomic orbital in the canonical ordering described on this class.

  • grid – Grid to evaluate on.

  • outfile – Path of the cube file to write. If empty, nothing is written and the field is only returned.

  • comment – First comment line of the cube file.

Returns:

Field of shape (grid.nx, grid.ny, grid.nz).

Return type:

numpy.ndarray

orbital(self: qdk_chemistry.utils.CubeGenerator, mo_coeff: Annotated[numpy.typing.ArrayLike, numpy.float64, '[m, 1]'], grid: qdk_chemistry.utils.CubeGrid, outfile: str = '', comment: str = '') → numpy.typing.NDArray[numpy.float64]

Evaluate a single molecular orbital on a grid.

Parameters:
  • mo_coeff – One coefficient per atomic orbital, in the canonical ordering described on this class. Must have exactly nbf entries.

  • grid – Grid to evaluate on.

  • outfile – Path of the cube file to write. If empty, nothing is written and the field is only returned.

  • comment – First comment line of the cube file.

Returns:

Field of shape (grid.nx, grid.ny, grid.nz).

Return type:

numpy.ndarray

Examples

>>> generator = CubeGenerator(basis_set)
>>> grid = CubeGrid.from_basis_set(basis_set)
>>> field = generator.orbital(coeff, grid, outfile="homo.cube")
class qdk_chemistry.utils.CubeGrid

Bases: pybind11_object

Regular Cartesian grid on which orbitals and densities are evaluated.

All lengths are in Bohr, matching the Gaussian cube-file convention.

__init__(*args, **kwargs)

Overloaded function.

  1. __init__(self: qdk_chemistry.utils.CubeGrid) -> None

  2. __init__(self: qdk_chemistry.utils.CubeGrid, origin: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, “[3, 1]”], spacing: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, “[3, 1]”], nx: typing.SupportsInt | typing.SupportsIndex = 80, ny: typing.SupportsInt | typing.SupportsIndex = 80, nz: typing.SupportsInt | typing.SupportsIndex = 80) -> None

static from_basis_set(basis_set: qdk_chemistry.data.BasisSet, nx: SupportsInt | SupportsIndex = 80, ny: SupportsInt | SupportsIndex = 80, nz: SupportsInt | SupportsIndex = 80, margin: SupportsFloat | SupportsIndex = 3.0) → qdk_chemistry.utils.CubeGrid

Build a grid that encloses the molecule with a uniform margin.

Parameters:
  • basis_set – Basis set carrying the molecular structure.

  • nx – Number of grid points along each axis.

  • ny – Number of grid points along each axis.

  • nz – Number of grid points along each axis.

  • margin – Padding in Bohr added around the nuclear bounding box.

Returns:

Grid spanning the padded bounding box.

Return type:

CubeGrid

num_points(self: qdk_chemistry.utils.CubeGrid) → int

Total number of grid points (nx * ny * nz).

property nx

Number of points along x.

property ny

Number of points along y.

property nz

Number of points along z.

property origin

Cartesian position of the first grid point, in Bohr.

property spacing

Grid step along each axis, in Bohr.

qdk_chemistry.utils.compute_valence_space_parameters(wavefunction: qdk_chemistry.data.Wavefunction, charge: SupportsInt | SupportsIndex, include_double_d_shell: bool = False) → tuple[int, int]

Get the default number of active electrons and active orbitals, which are obtained from the valence electrons and orbitals of the atomic element types in the structure. The structure is automatically extracted from the wavefunction.

Parameters:
  • wavefunction – The input wavefunction (the molecular structure is taken from wavefunction.orbitals.basis_set.structure).

  • charge – The total charge of the molecular system. Should match the charge used in the upstream SCF calculation.

  • include_double_d_shell – When True, add 5 correlating d’ orbitals per d-block atom (Sc-Zn, Y-Cd, Hf-Hg) to capture the strong nd / (n+1)d’ radial correlation in transition metals (the “double d-shell” effect). Defaults to False to preserve the historical sizing.

Returns:

Pair of ( n_active_electrons, n_active_orbitals )

Return type:

tuple

Examples

>>> nele, norb = compute_valence_space_parameters(wavefunction, charge)
>>> nele, norb = compute_valence_space_parameters(wavefunction, charge, include_double_d_shell=True)
qdk_chemistry.utils.generate_orbital_cubes(orbitals: qdk_chemistry.data.Orbitals, indices: collections.abc.Sequence[SupportsInt | SupportsIndex], output_dir: str, grid: qdk_chemistry.utils.CubeGrid, label_prefix: str = 'orbital_') → list[str]

Write one cube file per requested orbital.

Orbital indices are zero-based, matching the numbering used throughout qdk-chemistry, and the emitted file names embed that same zero-based index as <label_prefix>%04d. Restricted orbitals produce a single spatial cube per index with no spin suffix. Unrestricted orbitals produce an _a and a _b cube per index.

Parameters:
  • orbitals – Orbitals supplying the basis set and coefficients.

  • indices – Zero-based orbital indices to write.

  • output_dir – Existing directory to write the cube files into.

  • grid – Grid to evaluate on.

  • label_prefix – Prefix of the generated file names.

Returns:

Paths of the cube files written, in the order written.

Return type:

list[str]

Examples

>>> paths = generate_orbital_cubes(orbitals, [0, 1], "cubes", grid)
qdk_chemistry.utils.rotate_orbitals(orbitals: qdk_chemistry.data.Orbitals, rotation_vector: Annotated[numpy.typing.ArrayLike, numpy.float64, '[m, 1]'], num_alpha_occupied_orbitals: SupportsInt | SupportsIndex, num_beta_occupied_orbitals: SupportsInt | SupportsIndex, restricted_external: bool = False) → qdk_chemistry.data.Orbitals

Rotate molecular orbitals using a rotation vector.

This function takes Orbitals and applies orbital rotations using a rotation vector, typically taken from stability analysis eigenvectors.

The rotation is performed by: 1. Unpacking the rotation vector into an anti-Hermitian matrix 2. Computing the unitary rotation matrix via matrix exponential 3. Applying the rotation to the molecular orbital coefficients

Parameters:
  • orbitals (qdk_chemistry.data.Orbitals) – The Orbitals to rotate

  • rotation_vector (numpy.ndarray) – The rotation vector (typically from stability analysis, corresponding to the lowest eigenvalue)

  • num_alpha_occupied_orbitals (int) – Number of alpha occupied orbitals

  • num_beta_occupied_orbitals (int) – Number of beta occupied orbitals

  • restricted_external (bool, optional) – If True and orbitals are restricted, creates unrestricted orbitals with rotated coefficients for alpha spin and unrotated coefficients for beta spin. Default is False.

Returns:

A new Orbitals object with rotated molecular orbital coefficients

Return type:

qdk_chemistry.data.Orbitals

Notes

  • restricted_external can break spin symmetry and solve external instabilities of RHF/RKS.

  • For unrestricted calculations, the rotation vector should contain alpha rotations first (n_occ_alpha * n_vir_alpha elements), then beta rotations (n_occ_beta * n_vir_beta elements).

  • This function assumes aufbau filling for occupation numbers.

  • Orbital energies are invalidated by rotation and set to null.

Raises:

RuntimeError – If rotation vector size is invalid

Examples

>>> # After stability analysis that finds instability
>>> rotation_vector = ...  # eigenvector from stability analysis
>>> rotated_orbitals = rotate_orbitals(orbitals, rotation_vector,
...                                     num_alpha_occupied_orbitals,
...                                     num_beta_occupied_orbitals)

Subpackages

Submodules