Advanced Features
Green’s functions for systems with many orbitals
-
greensfunc_op_t diverge_largemat_gf(const diverge_model_t *model, complex128_t Lambda, complex128_t *buf)
[source] Green’s function generator that is faster than the default
diverge_greensfunc_generator_default()for systems with a significant number of orbitals. Performs actual BLAS calls to GEMM instead of manually passing through the (o,b,p) loop. Shared memory GFs as well as 32bit floating point precision not supported.
Green’s functions for subspace systems
When only a certain orbital subspace is considered as “correlated”, a custom
Green’s function generator can be defined to only calculate the Green’s function
for those orbitals. We provide a GPU (and CPU) subspace GF generator that is
most conveniently used when both the full system and the subspace system are
separate diverge_model_t instances.
Due to the GPU capability, the functions provided here must operate on a handle
(subspace_gfill_multi_t). The actual Green’s function calculation is
carried out using subspace_gfill_multi_exec(); the documentation
includes an example of how to use it as a greensfunc_generator_t.
-
subspace_gfill_multi_t *subspace_gfill_multi_init(double *E, complex128_t *U, index_t nk, const index_t *orbs, index_t n_orbs, index_t nb, index_t b_per_bb)
[source] initialize the
subspace_gfill_multi_thandle, which must be free’d usingsubspace_gfill_multi_free().- Parameters:
E (double*) – dispersion array of the full model
U (complex128_t*) – orbital to band transformation of the full model
nk (index_t) – number of kpoints (
kdimtot(nk, nkf))orbs (const index_t*) – selection of orbital/spin indices to construct subspace for
n_orbs (index_t) – size of subspace
nb (index_t) – number of bands in the full model
b_per_bb (index_t) – number of bands to consider in a single CUDA thread (for the hand-written GEMM). Note that the maximum number of threads per block is not checked against, so make this large enough to accomodate
dim3(nb/b_per_bb, n_orbs, n_orbs)threads per block.
-
void subspace_gfill_multi_free(subspace_gfill_multi_t *m)
[source] free the
subspace_gfill_multi_thandle.
-
void subspace_gfill_multi_exec(subspace_gfill_multi_t *m, complex128_t *dest, complex128_t Lambda)
[source] calculate subspace GFs using the handle obtained with
subspace_gfill_multi_init(). Safe to call multiple times, but not safe to use in a scenario where the target buffer resides in shared memory.Example:
static greensfunc_op_t subspace_gf( const diverge_model_t* model, complex128_t Lambda, complex128_t* buf ); int main(int argc, char** argv) { diverge_init( &argc, &argv ); // some initialization, other code, ... diverge_model_t* fullmodel = ...; // set up the full model for kinetics diverge_model_t* subspace = ...; // set up the subspace model for interactions index_t orbital_selection[] = { 0, 1, 5, 6 }; // choice of orbitals index_t n_orbital_selection = sizeof(orbital_selection)/sizeof(orbital_selection[0]); index_t b_per_bb = 3; // adjust accordingly // before calling the function below, diverge_model_internals_common() // must have been called on fullmodel subspace_gfill_multi_t* subspace_gf_data = subspace_gfill_multi_init( diverge_model_internals_get_E(fullmodel), diverge_model_internals_get_U(fullmodel), kdimtot(fullmodel->nk, fullmodel->nkf), orbital_selection, n_orbital_selection, fullmodel->n_orb * fullmodel->n_spin, b_per_bb ); subspace->data = subspace_gf_data; subspace->gfill = &subspace_gf; // do something with the subspace model subspace_gfill_multi_free( subspace_gf_data ); diverge_finalize(); } static greensfunc_op_t subspace_gf( const diverge_model_t* model, complex128_t Lambda, complex128_t* buf ) { subspace_gfill_multi_exec( model->data, buf, Lambda ); return greensfunc_op_cpu; }
-
void subspace_gfill_multi_exec_mu(subspace_gfill_multi_t *m, complex128_t *dest, complex128_t Lambda, double mu_add)
[source] same as
subspace_gfill_multi_exec()except for an additional chemical potential that is subtracted from the eigenvalues. Useful for GPU calculations, because there, the eigenvalue buffer is copied to the device and not automatically updated.
Unique Distances
Sometimes it may be useful to generate all uniquely defined distances in a
divERGe model, i.e., in order to set on-site, nearest-neighbor,
next-nearest-neighbor, etc. interactions. We provide a function to do so in the
unstable interface, which can be included with #include
<misc/unique_distances.h>. This header comprises two functions with the
following signatures:
-
double *diverge_model_unique_distances(diverge_model_t *m, int Rmax, int dim)
[source] given a
diverge_model_twith lattice vectors and positions, this function calculates all unique distances. Useful if e.g. interactions of first, second, etc. nearest neighbors should be initialized.- Parameters:
m (diverge_model_t*) – model to operate on
Rmax (int) – maximum integer distance of lattice vectors. For each dimension, the loop walks through \(-R_\mathrm{max}..R_\mathrm{max}\) for the calculation of all possible distances
dim (int) – dimension of the model. The first
dimlattice vectors are considered in the iteration viaRmax.
- Returns:
allocated vector of unique distances terminated by an IEEE 754 Quiet NaN. Must be free’d manually using
free.
-
void diverge_model_unique_distances_set_precision(double prec)
[source] set the precision used to calculate unique distances. not thread safe. useful in case the model has very large values as lattice constant.
- Parameters:
prec (double) – precision to use. if prec > 0, use absolute value. if prec < 0, use relative value with respect to the model’s first lattice vector length. if qnan_isnan(prec) (see
qnan_isnan()), reset to initial value DIVERGE_EPS_MESH (see Compilation DEFINES).
-
index_t diverge_model_unique_distances_length(double *dists)
[source] return the length of the unique distance array by checking for quiet NaN (see src/misc/qnan.h). In practice, unique distances can be obtained as follows:
diverge_model_t* m = ...; double* dists = diverge_model_unique_distances( m, 3, 2 ); // for a 2D model index_t n_dists = diverge_model_unique_distances_length( dists ); // do sth with dists here free( dists );
Hopping Parameters from Hamiltonians
The inverse Fourier transform to get hopping parameters from Hamiltonian arrays is implemented in the following function:
-
rs_hopping_t *diverge_model_ham2hop(const diverge_model_t *m, double hoplim, index_t *n_hop)
[source] transforms hamiltonian \(H(\boldsymbol{k})\) of a
diverge_model_tinto an array of realspace hopping parametersrs_hopping_t, i.e., an inverse Fourier transform.- Parameters:
model (const diverge_model_t*) – the divERGe model to operate on. needs to have common internals set (
diverge_model_internals_common()), such that the hamiltonian buffer is allocated and filled.hoplim (double) – minimum absolute value that a hopping element must have in order to be included.
n_hop (index_t*) – output for the resulting length of the
rs_hopping_tarray
- Returns:
rs_hopping_tarray that contains the real-space version of the input Bloch Hamiltonian (obtained via lattice Fourier transform).
-
rs_hopping_t *diverge_model_ham2hop_fg(const diverge_model_t *m, double hoplim, double distlim, index_t *n_hop, const complex128_t *H0)
[source] same as
diverge_model_ham2hop(), but with explicit control over the buffer which is used for the Hamiltonian (H0) and distance limitation (distlim; set negative to ignore). Very useful to, e.g., extract the selfenergy in efficient representation at the end of the flow.
-
int diverge_model_ham2hop_swap_orbs(void)
[source] not thread-safe, swap orbital convention. return whether swapping in future calls to
diverge_model_ham2hop().
Hamiltonians at Specific Momentum Points
To obtain a tight-binding Hamiltonian (from hopping parameters
diverge_model_t.hop) at a specific point in momentum space without
setting it up in the entire BZ (as done in diverge_model_t.hfill),
one can use the function diverge_model_ham_at_kpt(). In addition, we
provide wrappers for the coarse and fine mesh indices—these wrappers rely on
the model internals structure to be set up (via
diverge_model_internals_common()).
-
void diverge_model_ham_at_kpt(const diverge_model_t *m, const double *k, complex128_t *buf)
[source] generate the Hamiltonian at the momentum vector \(\boldsymbol{k}\) (described by the array
k[3]) and write it intobuf(which needs to be of the sizePOW2(m->n_orb * m->n_spin)). The chemical potential \(\mu\) is not included; to do so you have to subtract it from the diagonal. The matrix pointed to bybufis overwritten.
-
void diverge_model_ham_at_kcidx(const diverge_model_t *m, index_t k, complex128_t *buf)
[source] generate the Hamiltonian at the coarse index
kand write it intobuf.krefers to a coarse mesh index, andbufmust be sized the same way as indiverge_model_ham_at_kpt().
-
void diverge_model_ham_at_kfidx(const diverge_model_t *m, index_t k, complex128_t *buf)
[source] generate the Hamiltonian at the fine index
kand write it intobuf.krefers to a fine mesh index, andbufmust be sized the same way as indiverge_model_ham_at_kpt().
Density of States
-
double *diverge_linspace(double min, double max, index_t num)
[source] create a linearly spaced array from
mintomaxwithnumentries. returned array must be free’d by user withfreeordiverge_mem_free(). Whennumis negative, the endpoint is excluded. Otherwise it’s included.
-
double *diverge_filling_to_energy(const diverge_model_t *m, const double *E, index_t nb, const double *nu, index_t n_nu)
[source] Calculate an energy array given a filling array, i.e., do the transformation \(\nu \rightarrow E(\nu)\) for all
n_nuvalues in thenuarray. Allocates and frees sorted copy of energy array.- Parameters:
m (const diverge_model_t*) – the model to operate on with common internals set via
diverge_model_internals_common().E (const double*) – an optional energy array, may be
NULLin which case the internal energy array is used.nb (index_t) – an optional number of bands. is ignored if
E == NULLor ifnb <= 0nu (const double*) – filling array of size
n_nuwith values between zero and one (everything else is truncated to zero-one)n_nu (index_t) – length of the filling array.
- Returns:
doublearray with the energies corresponding to the fillings (sizen_nu) that must be free’d by the user viafreeordiverge_mem_free().
-
double *diverge_energy_fill_gaps(double *omega, index_t *p_n_omega, double d_omega_min)
[source] fill the gaps of a frequency array such that the spacing is always larger than
d_omega_min. return the reallocated array, and change*p_n_omegaaccording to the new size
-
double *diverge_model_dos(const diverge_model_t *m, const double *E, index_t nb, double *omega, index_t n_omega, double eta)
[source] calculate the DOS given an array of energies or a model that has its internals set: \(\rho(\omega) = \sum_{k,b} \Im[ 1/(\omega - i\eta - E_{kb}) ]\).
- Parameters:
m (const diverge_model_t*) – the model to operate on with common internals set via
diverge_model_internals_common().E (const double*) – an optional energy array, may be
NULLin which case the internal energy array is used.nb (index_t) – an optional number of bands. is ignored if
E == NULLor ifnb <= 0omega (const double*) – frequency array in ascending order (else it is modified and sorted).
n_omega (index_t) – number of frequencies. If negative, don’t allocate the memory for the result but instead reallocate
omegato a region large enough to holdomegaand the result (subsequently in memory). The new pointer is returned. Works only for the case whereomegais allocated withmallocand friends.eta (double) – smearing. If
eta < 0, use an optimized algorithm that only considers energies within a small window for DOS calculation at each frequency, assumes linearly spaced array foromega.
- Returns:
doublearray with the density of states (shape n_omega). Result must be free’d with call tofreeordiverge_mem_free().
-
double *diverge_model_ldos(const diverge_model_t *m, const double *E, const complex128_t *U, index_t nb, double *omega, index_t n_omega, double eta)
[source] calculate the LDOS given an array of energies and orbital to band matrices or a model that has its internals set: \(\rho(\omega,o) = \sum_{k,b} \Im[ |U_{kb}^o|^2/(\omega - i\eta - E_{kb}) ]\).
- Parameters:
m (const diverge_model_t*) – the model to operate on with common internals set via
diverge_model_internals_common().E (const double*) – an optional energy array, may be
NULLin which case the internal energy array is used.U (const complex128_t*) – an optional orbital to band array, may be
NULLin which case the internal o2b array is used.nb (index_t) – an optional number of bands. is ignored if
E == NULLor ifnb <= 0omega (const double*) – frequency array in ascending order (else it is modified and sorted).
n_omega (index_t) – number of frequencies. If negative, don’t allocate the memory for the result but instead reallocate
omegato a region large enough to holdomegaand the result (subsequently in memory). The new pointer is returned. Works only for the case whereomegais allocated withmallocand friends.eta (double) – smearing. If
eta < 0, use an optimized algorithm that only considers energies within a small window for LDOS calculation at each frequency, assumes linearly spaced array foromega.
- Returns:
doublearray with the local density of states (shape (n_omega,nb)). Result must be free’d with call tofreeordiverge_mem_free().
-
void diverge_dos_set_eta_factor(double eta_factor)
[source] set the factor \(e\) that determines the width of energies \(W\) to be considered for summation at a given frequency \(\omega\), i.e.,
\(W = [\omega - e\eta, \omega + e\eta]\)
Defaults to \(e = 15\), which is good enough for most features in a regular DOS, but not good enough for excellent convergence of the Lorentzian Kernel (which only falls off quadratically).
Hartree Fock
Since divERGe includes self-energy diagrams in the TU backend, we chose to also
provide building blocks for self-consistent Hartree Fock simulations using
models built in divERGe. In order to use these facilities, you must initialize
the model with diverge_model_internals_common() and
diverge_model_internals_tu(). Moreover, only standard Hamiltonian-based
models (i.e., default GF generator, no shared-memory GFs, etc) are supported;
each HF step requires a full rediagonalization of \(H(\boldsymbol{k}) +
\Sigma(\boldsymbol{k})\) and setting a filling value \(\nu\).
-
diverge_hartree_fock_t *diverge_hartree_fock_init(diverge_model_t *model, double nu, const char *chans)
[source] initialize a
diverge_hartree_fock_thandle given a model that has both the TU and common internals set. The user additionally has to provide a filling value \(\nu\) and the interaction channels that should be taken into account (equivalent to the vertex specific channels indiverge_flow_step_init()). Must be freed with a call todiverge_hartree_fock_free().- Parameters:
m (diverge_model_t*) – diverge model
nu (double) – filling value (0…1)
chans (const char*) – interaction channels as string
-
int diverge_hartree_fock_normalize_configure(int normalize)
[source] change default behavior of always calling
diverge_hartree_fock_normalize_sigma()withindiverge_hartree_fock_step()to run slightly faster and be compatible with previous versions. returns previous setting.Note
The default behavior is now changed to always normalize; you’d have to explicitly turn it off before performing the first
diverge_hartree_fock_step().
-
diverge_flow_step_t *diverge_hartree_fock_get_flow_step(diverge_hartree_fock_t *h)
[source] return the flow step backend of a HF calculation, s.t. one can access the vertices etc
-
void diverge_hartree_fock_step(diverge_hartree_fock_t *h, double T)
[source] perform a step of the Hartre-Fock self-consistency iteration (at temperature T). “Step” here refers to the fact that the current self-energy (see
diverge_hartree_fock_get_sigma()) is used for calculating the Green’s function via \(G(\boldsymbol{k})^{-1} = i\omega - H(\boldsymbol{k}) - \Sigma(\boldsymbol{k})\), which is used to evaluate the diagrams. On exit, the resulting “new” self-energy is stored in the buffer pointed to bydiverge_hartree_fock_get_sigma(), and the (previous) self-energy that acted as input to calculating the diagrams gets copied to the buffer pointed to bydiverge_hartree_fock_get_sigma_prev().
-
void diverge_hartree_fock_normalize_sigma(diverge_hartree_fock_t *h)
[source] move the constant part (\(\mu\)) from the selfenergy to the dispersion
-
complex128_t *diverge_hartree_fock_get_sigma(diverge_hartree_fock_t *h)
[source] return the current self-energy buffer. Can be used to e.g. set a seed or output of the final self-energy.
-
complex128_t *diverge_hartree_fock_get_sigma_prev(diverge_hartree_fock_t *h)
[source] return the self-energy buffer of the previous iteration. Do not put a seed in here. Useful to combine with
diverge_hartree_fock_get_sigma()for mixing schemes or assessing convergence.
-
double diverge_hartree_fock_get_E_tot(diverge_hartree_fock_t *h)
[source] return the total energy of the state evaluated during the previous step. Does probably not work together with the normalization in
diverge_hartree_fock_normalize_sigma()(untested).
-
void diverge_hartree_fock_free(diverge_hartree_fock_t *h)
[source] free the
diverge_hartree_fock_thandle.