sisl.physics.Bloch

class sisl.physics.Bloch

Bases: object

Bloch’s theorem object containing unfolding factors and unfolding algorithms

This class is a wrapper for expanding any matrix from a smaller matrix cell into a larger, using Bloch’s theorem. The general idea may be summarized in the following equation:

\[\begin{split}\mathbf M_{K}^N =\frac1N \; \sum_{ \substack{j=0\\ k_j=\frac{K+j}N } }^{N-1} \quad \begin{bmatrix} 1 & \cdots & e^{i (1-N)k_j} \\ e^{i k_j} & \cdots & e^{i (2-N)k_j} \\ \vdots & \ddots & \vdots \\ e^{i (N-1)k_j} & \cdots & 1 \end{bmatrix} \otimes \mathbf M_{k_j}^1.\end{split}\]

Notes

When doing a Brillouin-zone average of Bloch-expansions (e.g. self-energies) one can get better performance by using finalize=False and then call a subsequent bloch.unfold_finalize(M).

Only a sub-matrix of the unfolded matrix may be calculated, see the indices argument of unfold and __call__. This greatly reduces the memory requirements when only few elements are needed, e.g. the elements on the edges of a large Bloch expansion.

Parameters:
  • bloch ((3,) int) – Bloch repetitions along each direction

  • finalize – whether the unfold routine also copies out the Toeplitz matrix. If false, the user should call bloch.unfold_finalize(M) on the returned matrix to ensure it is complete, see examples.

Examples

Auto-use finalize of the Toeplitz matrix.

>>> bloch = Bloch([2, 1, 2])
>>> k_unfold = bloch.unfold_points([0] * 3)
>>> M = [func(*args, k=k) for k in k_unfold]
>>> M = bloch.unfold(M, k_unfold)

Manual finalization of the Toeplitz matrix.

>>> bloch = Bloch([2, 1, 2], finalize=False)
>>> k_unfold = bloch.unfold_points([0] * 3)
>>> M = [func(*args, k=k) for k in k_unfold]
>>> M = bloch.unfold(M, k_unfold)
>>> if not bloch.finalize:
...    bloch.unfold_finalize(M)

Only calculate the sub-matrix M[np.ix_(indices, indices)] of the unfolded matrix.

>>> bloch = Bloch([2, 1, 2])
>>> M = bloch(func, [0] * 3, indices=[0, 1, -2, -1])

Methods

unfold(M, k_unfold[, indices])

Unfold the matrix list of matrices M into a corresponding k-point (unfolding k-points are k_unfold)

unfold_finalize(M)

Copy out the Toeplitz matrix from the sub-calculated elements.

unfold_points(k)

Return a list of k-points to be evaluated for this objects unfolding

Attributes

bloch

Number of Bloch expansions along each lattice vector

__call__(func, k, *args, indices=None, **kwargs)[source]

Return a functions return values as the Bloch unfolded equivalent according to this object

Calling the Bloch object is a shorthand for the manual use of the Bloch.unfold_points and Bloch.unfold methods.

This call structure is a shorthand for:

>>> bloch = Bloch([2, 1, 2])
>>> k_unfold = bloch.unfold_points([0] * 3)
>>> M = [func(*args, k=k) for k in k_unfold]
>>> bloch.unfold(M, k_unfold)

Notes

The function passed must have a keyword argument k.

Parameters:
  • func (callable) – method called which returns a matrix.

  • k (Sequence[float]) – k-point to be unfolded

  • *args – arguments passed directly to func

  • indices (TypeAliasForwardRef('~numpy.typing.ArrayLike') | tuple[TypeAliasForwardRef('~numpy.typing.ArrayLike'), TypeAliasForwardRef('~numpy.typing.ArrayLike')] | None) – only calculate this sub-matrix of the unfolded matrix, see unfold. Only the needed elements of the matrices returned by func are stored.

  • **kwargs – keyword arguments passed directly to func

Returns:

unfolded Bloch matrix (or the sub-matrix if indices is specified)

Return type:

numpy.ndarray

unfold(M, k_unfold, indices=None)[source]

Unfold the matrix list of matrices M into a corresponding k-point (unfolding k-points are k_unfold)

Parameters:
  • M ((:, :, :)) – an *-N-M matrix used for unfolding

  • k_unfold (Sequence[Sequence[float]]) – unfolding k-points as returned by Bloch.unfold_points

  • indices (TypeAliasForwardRef('~numpy.typing.ArrayLike') | tuple[TypeAliasForwardRef('~numpy.typing.ArrayLike'), TypeAliasForwardRef('~numpy.typing.ArrayLike')] | None) –

    only calculate this sub-matrix of the unfolded matrix (indices in the unfolded matrix):

    • an array: the sub-matrix unfold(M, k_unfold)[np.ix_(indices, indices)]

    • a tuple (rows, cols): the sub-matrix unfold(M, k_unfold)[np.ix_(rows, cols)]

    Negative indices count from the end. Only the elements of the unique displacements between the Bloch unit-cells are calculated, so the memory scales with the size of the sub-matrix.

Returns:

unfolded matrix of size M[0].shape * k_unfold.shape[0] ** 2, or the sub-matrix if indices is specified (the finalize flag has no effect).

Return type:

numpy.ndarray

unfold_finalize(M)[source]

Copy out the Toeplitz matrix from the sub-calculated elements.

This is necessary to be called if the Bloch object has been initialized with Bloch(..., finalize=False). Otherwise it should not be used.

Parameters:

M – the full matrix, where only the Toeplitz elements are filled.

Return type:

the full matrix with copied out elements.

unfold_points(k)[source]

Return a list of k-points to be evaluated for this objects unfolding

The k-point k is with respect to the unfolded geometry. The return list of k points are the k-points required to be sampled in the folded geometry.

Parameters:

k (Sequence[float]) – k-point evaluation corresponding to the unfolded unit-cell

Returns:

a list of np.prod(self.bloch) k-points used for the unfolding

Return type:

numpy.ndarray

property bloch

Number of Bloch expansions along each lattice vector