Space definition.
ebcc.ham.space.Space(occupied, frozen, active)
Space class.
.. code-block:: none
─┬─ ┌──────────┐
│ │ frozen │
│ ├──────────┤ ─┬─
virtual │ │ active │ │
│ ├──────────┤ │ correlated
│ │ inactive │ │
─┼─ ├══════════┤ ─┼─
│ │ inactive │ │
│ ├──────────┤ │ correlated
occupied │ │ active │ │
│ ├──────────┤ ─┴─
│ │ frozen │
─┴─ └──────────┘
Initialise the space.
Parameters: |
|
---|
Source code in ebcc/ham/space.py
def __init__(
self,
occupied: NDArray[B],
frozen: NDArray[B],
active: NDArray[B],
) -> None:
"""Initialise the space.
Args:
occupied: Array containing boolean flags indicating whether or not each orbital is
occupied.
frozen: Array containing boolean flags indicating whether or not each orbital is frozen.
active: Array containing boolean flags indicating whether or not each orbital is active.
"""
self._occupied = np.asarray(occupied, dtype=np.bool_)
self._frozen = np.asarray(frozen, dtype=np.bool_)
self._active = np.asarray(active, dtype=np.bool_)
# Checks:
if not (self._occupied.size == self._frozen.size == self._active.size):
raise ValueError("The sizes of the space arrays must match.")
if np.any(np.bitwise_and(self._frozen, self._active)):
raise ValueError("Frozen and active orbitals must be mutually exclusive.")
ebcc.ham.space.Space.occupied: NDArray[B]
property
Get a boolean mask of occupied orbitals.
ebcc.ham.space.Space.virtual: NDArray[B]
cached
property
Get a boolean mask of virtual orbitals.
ebcc.ham.space.Space.nmo: int
property
Get the number of orbitals.
ebcc.ham.space.Space.nocc: int
cached
property
Get the number of occupied orbitals.
ebcc.ham.space.Space.nvir: int
cached
property
Get the number of virtual orbitals.
ebcc.ham.space.Space.correlated: NDArray[B]
cached
property
Get a boolean mask of correlated orbitals.
ebcc.ham.space.Space.correlated_occupied: NDArray[B]
cached
property
Get a boolean mask of occupied correlated orbitals.
ebcc.ham.space.Space.correlated_virtual: NDArray[B]
cached
property
Get a boolean mask of virtual correlated orbitals.
ebcc.ham.space.Space.ncorr: int
cached
property
Get the number of correlated orbitals.
ebcc.ham.space.Space.ncocc: int
cached
property
Get the number of occupied correlated orbitals.
ebcc.ham.space.Space.ncvir: int
cached
property
Get the number of virtual correlated orbitals.
ebcc.ham.space.Space.inactive: NDArray[B]
cached
property
Get a boolean mask of inactive orbitals.
ebcc.ham.space.Space.inactive_occupied: NDArray[B]
cached
property
Get a boolean mask of occupied inactive orbitals.
ebcc.ham.space.Space.inactive_virtual: NDArray[B]
cached
property
Get a boolean mask of virtual inactive orbitals.
ebcc.ham.space.Space.ninact: int
cached
property
Get the number of inactive orbitals.
ebcc.ham.space.Space.niocc: int
cached
property
Get the number of occupied inactive orbitals.
ebcc.ham.space.Space.nivir: int
cached
property
Get the number of virtual inactive orbitals.
ebcc.ham.space.Space.frozen: NDArray[B]
property
Get a boolean mask of frozen orbitals.
ebcc.ham.space.Space.frozen_occupied: NDArray[B]
cached
property
Get a boolean mask of occupied frozen orbitals.
ebcc.ham.space.Space.frozen_virtual: NDArray[B]
cached
property
Get a boolean mask of virtual frozen orbitals.
ebcc.ham.space.Space.nfroz: int
cached
property
Get the number of frozen orbitals.
ebcc.ham.space.Space.nfocc: int
cached
property
Get the number of occupied frozen orbitals.
ebcc.ham.space.Space.nfvir: int
cached
property
Get the number of virtual frozen orbitals.
ebcc.ham.space.Space.active: NDArray[B]
property
Get a boolean mask of active orbitals.
ebcc.ham.space.Space.active_occupied: NDArray[B]
cached
property
Get a boolean mask of occupied active orbitals.
ebcc.ham.space.Space.active_virtual: NDArray[B]
cached
property
Get a boolean mask of virtual active orbitals.
ebcc.ham.space.Space.nact: int
cached
property
Get the number of active orbitals.
ebcc.ham.space.Space.naocc: int
cached
property
Get the number of occupied active orbitals.
ebcc.ham.space.Space.navir: int
cached
property
Get the number of virtual active orbitals.
ebcc.ham.space.Space.__repr__()
Get a string representation of the space.
Source code in ebcc/ham/space.py
def __repr__(self) -> str:
"""Get a string representation of the space."""
out = "(%do, %dv)" % (self.nocc, self.nvir)
parts = []
if self.nfroz:
parts.append("(%do, %dv) frozen" % (self.nfocc, self.nfvir))
if self.nact:
parts.append("(%do, %dv) active" % (self.naocc, self.navir))
if len(parts):
out += " [" + ", ".join(parts) + "]"
return out
ebcc.ham.space.Space.size(char)
Convert a character corresponding to a space to the size of that space.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
def size(self, char: str) -> int:
"""Convert a character corresponding to a space to the size of that space.
Args:
char: Character to convert.
Returns:
Size of the space.
"""
return {
"x": self.ncorr,
"o": self.ncocc,
"O": self.naocc,
"i": self.niocc,
"v": self.ncvir,
"V": self.navir,
"a": self.nivir,
}[char]
ebcc.ham.space.Space.mask(char)
Convert a character corresponding to a space to a mask of that space.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
def mask(self, char: str) -> NDArray[B]:
"""Convert a character corresponding to a space to a mask of that space.
Args:
char: Character to convert.
Returns:
Mask of the space.
"""
return {
"x": self.correlated,
"o": self.correlated_occupied,
"O": self.active_occupied,
"i": self.inactive_occupied,
"v": self.correlated_virtual,
"V": self.active_virtual,
"a": self.inactive_virtual,
}[char]
ebcc.ham.space.Space.slice(char)
cached
Convert a character corresponding to a space to a slice of that space.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
@functools.lru_cache(maxsize=128) # noqa: B019
def slice(self, char: str) -> _slice:
"""Convert a character corresponding to a space to a slice of that space.
Args:
char: Character to convert.
Returns:
Slice of the space.
"""
# Check that the respective mask is contiguous
mask = self.mask(char)
first = np.argmax(mask)
size = self.size(char)
if not np.all(mask[first : first + size]):
raise ValueError(
f"Space '{char}' is not contiguous. In order to slice into this space, "
"the `mask` method must be used. If you see this error internally, it is "
"likely that you have constructed a disjoint space. Please reorder the "
"orbitals in the space."
)
return slice(first, first + size)
ebcc.ham.space.Space.omask(char)
Like mask
, but returns only a mask into only the occupied sector.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
def omask(self, char: str) -> NDArray[B]:
"""Like `mask`, but returns only a mask into only the occupied sector.
Args:
char: Character to convert.
Returns:
Mask of the space.
"""
return self.mask(char)[self.occupied]
ebcc.ham.space.Space.vmask(char)
Like mask
, but returns only a mask into only the virtual sector.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
def vmask(self, char: str) -> NDArray[B]:
"""Like `mask`, but returns only a mask into only the virtual sector.
Args:
char: Character to convert.
Returns:
Mask of the space.
"""
return self.mask(char)[self.virtual]
ebcc.ham.space.Space.oslice(char)
Like slice
, but returns only a slice into only the occupied sector.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
def oslice(self, char: str) -> _slice:
"""Like `slice`, but returns only a slice into only the occupied sector.
Args:
char: Character to convert.
Returns:
Slice of the space.
"""
s = self.slice(char)
nocc = self.nocc
return slice(s.start, min(s.stop, nocc))
ebcc.ham.space.Space.vslice(char)
Like slice
, but returns only a slice into only the virtual sector.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
def vslice(self, char: str) -> _slice:
"""Like `slice`, but returns only a slice into only the virtual sector.
Args:
char: Character to convert.
Returns:
Slice of the space.
"""
s = self.slice(char)
nocc = self.nocc
return slice(max(s.start, nocc) - nocc, s.stop - nocc)
ebcc.ham.space.construct_default_space(mf)
Construct a default space.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
def construct_default_space(mf: SCF) -> Union[RConstructSpaceReturnType, UConstructSpaceReturnType]:
"""Construct a default space.
Args:
mf: PySCF mean-field object.
Returns:
The molecular orbital coefficients, the molecular orbital occupation numbers, and the
default space.
"""
def _construct(mo_occ: NDArray[T]) -> Space:
"""Build the default space."""
frozen = np.zeros(mo_occ.shape, dtype=np.bool_)
active = np.zeros(mo_occ.shape, dtype=np.bool_)
space = Space(
occupied=mo_occ > 0,
frozen=frozen,
active=active,
)
return space
# Construct the default space
if mf.mo_occ.ndim == 2:
space_a = _construct(mf.mo_occ[0])
space_b = _construct(mf.mo_occ[1])
return mf.mo_coeff, mf.mo_occ, (space_a, space_b)
else:
return mf.mo_coeff, mf.mo_occ, _construct(mf.mo_occ)
ebcc.ham.space.construct_fno_space(mf, occ_tol=1e-05, occ_frac=None, amplitudes=None)
Construct a frozen natural orbital space.
Parameters: |
|
---|
Returns: |
|
---|
Source code in ebcc/ham/space.py
def construct_fno_space(
mf: SCF,
occ_tol: Optional[float] = 1e-5,
occ_frac: Optional[float] = None,
amplitudes: Optional[Namespace[SpinArrayType]] = None,
) -> Union[RConstructSpaceReturnType, UConstructSpaceReturnType]:
"""Construct a frozen natural orbital space.
Args:
mf: PySCF mean-field object.
occ_tol: Threshold in the natural orbital occupation numbers.
occ_frac: Fraction of the natural orbital occupation numbers to be retained. Overrides
`occ_tol` if both are specified.
amplitudes: Cluster amplitudes. If provided, use these amplitudes when calculating the MP2
1RDM.
Returns:
The natural orbital coefficients, the natural orbital occupation numbers, and the frozen
natural orbital space.
"""
# Get the MP2 1RDM
solver = pyscf.mp.mp2.MP2(mf)
dm1: NDArray[T]
if not amplitudes:
solver.kernel()
dm1 = np.asarray(solver.make_rdm1(), dtype=types[float])
else:
if isinstance(amplitudes.t2, util.Namespace):
t2 = (amplitudes.t2.aaaa, amplitudes.t2.abab, amplitudes.t2.bbbb)
dm1 = np.asarray(solver.make_rdm1(t2=t2), dtype=types[float])
else:
dm1 = np.asarray(solver.make_rdm1(t2=amplitudes.t2), dtype=types[float])
# def _construct(dm1, mo_energy, mo_coeff, mo_occ):
def _construct(
dm1: NDArray[T],
mo_energy: NDArray[T],
mo_coeff: NDArray[T],
mo_occ: NDArray[T],
) -> RConstructSpaceReturnType:
# Get the number of occupied orbitals
nocc = cast(int, np.sum(mo_occ > 0))
# Calculate the natural orbitals
n, c = np.linalg.eigh(dm1[nocc:, nocc:])
n, c = n[::-1], c[:, ::-1]
# Truncate the natural orbitals
if occ_frac is None:
active_vir = n > occ_tol
else:
active_vir = np.cumsum(n / np.sum(n)) <= occ_frac
num_active_vir = cast(int, np.sum(active_vir))
# Canonicalise the natural orbitals
fock_vv = np.diag(mo_energy[nocc:])
fock_vv = util.einsum("ab,au,bv->uv", fock_vv, c, c)
_, c_can = np.linalg.eigh(fock_vv[active_vir][:, active_vir])
# Transform the natural orbitals
no_coeff_avir = util.einsum(
"pi,iq,qj->pj", mo_coeff[:, nocc:], c[:, :num_active_vir], c_can
)
no_coeff_fvir = mo_coeff[:, nocc:] @ c[:, num_active_vir:]
no_coeff_occ = mo_coeff[:, :nocc]
no_coeff = np.concatenate((no_coeff_occ, no_coeff_avir, no_coeff_fvir), axis=1)
# Build the natural orbital space
active = np.zeros(mo_occ.shape, dtype=np.bool_)
frozen = np.concatenate(
(
np.zeros((nocc + num_active_vir,), dtype=np.bool_),
np.ones((mo_occ.size - nocc - num_active_vir,), dtype=np.bool_),
)
)
no_space = Space(
occupied=mo_occ > 0,
frozen=frozen,
active=active,
)
return no_coeff, mo_occ, no_space
# Construct the natural orbitals
if mf.mo_occ.ndim == 2:
coeff_a, occ_a, space_a = _construct(
np.asarray(dm1[0], dtype=types[float]),
np.asarray(mf.mo_energy[0], dtype=types[float]),
np.asarray(mf.mo_coeff[0], dtype=types[float]),
np.asarray(mf.mo_occ[0], dtype=types[float]),
)
coeff_b, occ_b, space_b = _construct(
np.asarray(dm1[1], dtype=types[float]),
np.asarray(mf.mo_energy[1], dtype=types[float]),
np.asarray(mf.mo_coeff[1], dtype=types[float]),
np.asarray(mf.mo_occ[1], dtype=types[float]),
)
return (coeff_a, coeff_b), (occ_a, occ_b), (space_a, space_b)
else:
return _construct(
np.asarray(dm1, dtype=types[float]),
np.asarray(mf.mo_energy, dtype=types[float]),
np.asarray(mf.mo_coeff, dtype=types[float]),
np.asarray(mf.mo_occ, dtype=types[float]),
)