Source code for nbed.localizers.system
"""Class defining the data output from Localizers."""
import logging
from dataclasses import dataclass, field
from typing import Literal, Union
import numpy as np
from numpy import dtype
type OneSpinMatrix[M: int] = np.ndarray[tuple[M, M], np.dtype[np.floating]]
type TwoSpinMatrix[M: int] = np.ndarray[tuple[Literal[2], M, M], np.dtype[np.floating]]
type AnySpinMatrix[M: int] = Union[OneSpinMatrix[M], TwoSpinMatrix[M]]
logger = logging.getLogger(__name__)
[docs]
@dataclass
class LocalizedSystem:
"""Required data from localized system.
active_occ_inds (np.array): 1D array of active occupied MO indices
enviro_occ_inds (np.array): 1D array of environment occupied MO indices
c_loc_occ (np.array): C matrix of localized occupied MOs
dm_active (np.array): active system density matrix
dm_enviro (np.array): environment system density matrix
c_loc_virt (np.array | None): C matrix of localized virual MOs.
"""
active_occ_inds: np.ndarray
enviro_occ_inds: np.ndarray
c_loc_occ: np.ndarray
dm_active: np.ndarray
dm_enviro: np.ndarray
c_loc_virt: np.ndarray | None = None
dm_loc_occ: np.ndarray = field(init=False)
def __post_init__(self):
"""Post init for derived attributes."""
self.dm_loc_occ = self.c_loc_occ @ self.c_loc_occ.swapaxes(-1, -2)
logger.debug("LocalizedSystem created.")
logger.debug(f"{self.active_occ_inds}")
logger.debug(f"{self.enviro_occ_inds}")
logger.debug(f"{self.c_loc_occ.shape=}")
logger.debug(f"{self.dm_active.shape=}")
logger.debug(f"{self.dm_enviro.shape=}")
[docs]
@dataclass
class RestrictedLS(LocalizedSystem):
"""Required data from localized system.
active_occ_inds (np.array): 1D array of active occupied MO indices
enviro_occ_inds (np.array): 1D array of environment occupied MO indices
c_active (np.array): C matrix of localized occupied active MOs (columns define MOs)
c_enviro (np.array): C matrix of localized occupied ennironment MOs
c_loc_occ (np.array): C matrix of localized occupied MOs
c_loc_virt (np.array | None): C matrix of localized virual MOs.
dm_active (np.array): active system density matrix
dm_enviro (np.array): environment system density matrix
"""
active_occ_inds: np.ndarray[tuple[int], dtype[np.bool]]
enviro_occ_inds: np.ndarray[tuple[int], dtype[np.bool]]
c_loc_occ: OneSpinMatrix
dm_active: OneSpinMatrix
dm_enviro: OneSpinMatrix
c_loc_virt: OneSpinMatrix | None = None
dm_loc_occ: OneSpinMatrix = field(init=False)
def __post_init__(self):
"""post-init."""
super().__post_init__()
[docs]
@dataclass
class RestrictedOpenLS(LocalizedSystem):
"""Required data from localized system.
active_occ_inds (np.array): 1D array of active occupied MO indices
enviro_occ_inds (np.array): 1D array of environment occupied MO indices
c_active (np.array): C matrix of localized occupied active MOs (columns define MOs)
c_enviro (np.array): C matrix of localized occupied ennironment MOs
c_loc_occ (np.array): C matrix of localized occupied MOs
c_loc_virt (np.array | None): C matrix of localized virual MOs.
dm_active (np.array): active system density matrix
dm_enviro (np.array): environment system density matrix
"""
active_occ_inds: np.ndarray[tuple[int, int], dtype[np.bool]]
enviro_occ_inds: np.ndarray[tuple[int, int], dtype[np.bool]]
c_loc_occ: OneSpinMatrix
dm_active: OneSpinMatrix
dm_enviro: OneSpinMatrix
c_loc_virt: OneSpinMatrix | None = None
dm_loc_occ: OneSpinMatrix = field(init=False)
def __post_init__(self):
"""post-init."""
super().__post_init__()
[docs]
@dataclass
class UnrestrictedLS(LocalizedSystem):
"""Required data from localized system.
active_occ_inds (np.array): 1D array of active occupied MO indices
enviro_occ_inds (np.array): 1D array of environment occupied MO indices
c_active (np.array): C matrix of localized occupied active MOs (columns define MOs)
c_enviro (np.array): C matrix of localized occupied ennironment MOs
c_loc_occ (np.array): C matrix of localized occupied MOs
c_loc_virt (np.array | None): C matrix of localized virual MOs.
dm_active (np.array): active system density matrix
dm_enviro (np.array): environment system density matrix
"""
active_occ_inds: np.ndarray[tuple[int, int], dtype[np.bool]]
enviro_occ_inds: np.ndarray[tuple[int, int], dtype[np.bool]]
c_loc_occ: TwoSpinMatrix
dm_active: TwoSpinMatrix
dm_enviro: TwoSpinMatrix
c_loc_virt: TwoSpinMatrix | None = None
dm_loc_occ: TwoSpinMatrix = field(init=False)
def __post_init__(self):
"""post-init."""
super().__post_init__()
[docs]
@staticmethod
def from_spin_components(
alpha: RestrictedLS, beta: RestrictedLS
) -> "UnrestrictedLS":
"""Construct a spin-aware LocalizedSystem from two spinless ones.
Args:
alpha (LocalizedSystem): The localized alpha spins
beta (LocalizedSystem): The localized beta spins.
Returns:
LocalizedSystem: A combined localized system with spins (alpha, beta).
"""
logger.debug("Creating LocalizedSystem from spin components.")
active_occ_inds = np.array([alpha.active_occ_inds, beta.active_occ_inds])
enviro_occ_inds = np.array([alpha.enviro_occ_inds, beta.enviro_occ_inds])
dm_active: TwoSpinMatrix = np.array([alpha.dm_active, beta.dm_active])
dm_enviro: TwoSpinMatrix = np.array([alpha.dm_enviro, beta.dm_enviro])
c_loc_occ: TwoSpinMatrix = np.array([alpha.c_loc_occ, beta.c_loc_occ])
if alpha.c_loc_virt is not None and beta.c_loc_virt is not None:
c_loc_virt = np.array([alpha.c_loc_virt, beta.c_loc_virt])
else:
c_loc_virt = None
return UnrestrictedLS(
active_occ_inds,
enviro_occ_inds,
c_loc_occ,
dm_active,
dm_enviro,
c_loc_virt,
)