# Algorithm overview#

## Self-consistent mean-field loop#

To calculate the mean-field interaction in (5), we require the ground-state density matrix \(\rho_{mn}(R)\). However, (3) is a function of the mean-field interaction \(\hat{V}_{\text{MF}}\) itself. Therefore, we need to solve for both self-consistently.

A single iteration of this self-consistency loop is a function that computes a new mean-field correction from a given one:

which is defined in `mfield`

method.
It performs the following steps:

Calculate the total Hamiltonian \(\hat{H}(R) = \hat{H_0}(R) + \hat{V}_{\text{init, MF}}(R)\) in real-space.

(

`density_matrix`

) Compute the ground-state density matrix \(\rho_{mn}(R)\):(

`tb_to_kgrid`

) Fourier transform the total Hamiltonian to momentum space \(\hat{H}(R) \to \hat{H}(k)\).(

`numpy.linalg.eigh`

) Diagonalize the Hamiltonian \(\hat{H}(R)\) to obtain the eigenvalues and eigenvectors.(

`fermi_on_kgrid`

) Calculate the fermi level given the desired filling of the unit cell.(

`density_matrix_kgrid`

) Calculate the density matrix \(\rho_{mn}(k)\) using the eigenvectors and the fermi level.(

`kgrid_to_tb`

) Inverse Fourier transform the density matrix to real-space \(\rho_{mn}(k) \to \rho_{mn}(R)\).

(

`meanfield`

) Calculate the new mean-field correction \(\hat{V}_{\text{new, MF}}(R)\) using (5).

## Self-consistency criteria#

To define the self-consistency condition, we first introduce an invertible function \(f\) that uniquely maps \(\hat{V}_{\text{MF}}\) to a real-valued vector which minimally parameterizes it:

In the code, \(f\) corresponds to the `tb_to_rparams`

function (inverse is `rparams_to_tb`

).
Currently, \(f\) parameterizes the mean-field interaction by taking only the upper triangular elements of the matrix \(V_{\text{MF}, nm}(R)\) (the lower triangular part is redundant due to the Hermiticity of the Hamiltonian) and splitting it into real and imaginary parts to form a real-valued vector.

With this, we define the self-consistency criterion as a fixed-point problem:

Instead of solving the fixed point problem, we rewrite it as the difference of the two successive self-consistent mean-field iterations in `cost_mf`

.
That re-defines the problem into a root-finding problem which is more consistent with available numerical solvers such as `anderson`

.
That is exactly what we do in the `solver`

function, although we also provide the option to use a custom optimizer.