Manual for steady-state Kadanoff-Baym equations
Steady state Keldysh formalism
Another framework for solving the KB equations is the Keldysh formalism for non-equilibrium steady states (NESSs). In comparison to two-time functions defined on the three-legged KB contour \(\mathcal C = \mathcal C_1 \cup \mathcal C_2 \cup \mathcal C_3\), the main assumption in the steady-state formalism is the absence of correlations with the initial noninteracting state on the imaginary time branch \(\mathcal C_3\), such that the mixed self-energies \(\Sigma^{\rceil}\) and \(\Sigma^{\lceil}\) vanish. The vertical branch can then be shifted to \(t = - \infty\) and is eliminated from the equations, such that time arguments are restricted to the two-branch contour \(\mathcal C_K = \mathcal C_1 \cup \mathcal C_2\). Second, any contour-ordered two-time Green’s function \(G(t,t') = -i \langle \mathcal{T}_{\mathcal C} c(t) c^{\dagger}(t') \rangle\) in a NESS exhibits time-translational invariance \(G(t,t') = G(t-t')\), so that a numerical treatment is possible in Fourier representation.
Green’s functions
To represent NESS Green’s functions, we keep the retarded component \(G^R(t)\) and lesser component \(G^<(t)\) on an equidistant real-time grid as the two non-redundant components. Frequency-dependent Green’s functions are given by the spectral representation
with the spectral function
In equilibrium at temperature \(1/\beta\), the fluctuation dissipation function implies
where the sign \(\xi\) is \(\xi=\pm1\) for bosonic (fermionic) Green’s functions, and the distribution function is \(F_\mu(\omega) =1/(e^{\beta(\omega-\mu)}-\xi)\).
Dyson equation
In order to solve the Dyson equation in the steady state, we rewrite the Kadanoff-Baym equations in the time-translationally invariant case. The equation for the retarded Green’s function becomes
in Fourier representation and the lesser component is given by
Overview
The current implementation of the steady state extension to NESSi has two versions, which are structured into two different namespaces ness and ness2. We suggest to the user to start with the newer version ness2, it covers and extends all functionalities of the older version. For the sake of completeness, the old version ness is also documented on this page.
|
Namespace for current implementation of the NESS code, recommended version. |
|
Namespace for old implementation of the NESS code. |
ness2
This is a quick overview over the most important classes and functions in the ness2 namespace:
|
Basic class containing the data structure for holding arrays of matrices for frequency and time domain, supports element access and algebraic manipulations. |
Section ness2::fft_array |
|
Class to represent steady state Green’s function (lesser and retarded component), supports element access, Fourier transforms, equilibrium Green’s function construction and reading and writing to file and two-time functions and other utilities. |
Section ness2::herm_matrix_ness |
|
Solve the Dyson equation in the steady state. |
Section Dyson equation |
|
Construct equilibrium Green’s function from a given density of states. |
Section Equilibrium Green’s functions |
|
Calculate particle-hole bubble diagram for two given Green’s functions. |
Section Diagram utilities |
|
Calculate particle-particle bubble diagram for two given Green’s functions. |
Section Diagram utilities |
|
Write from two-time function into a steady state Green’s function, also vice versa is supported. |
ness
This is a quick overview over the most important classes and functions in the ness namespace:
|
Class to represent steady state Green’s function (lesser and retarded component), supports element access, Fourier transforms, equilibrium Green’s function construction and reading and writing to file and two-time functions and other utilities (either frequency or time domain). |
Section ness::GF |
|
Class to represent steady state Green’s function (lesser and retarded component), both in frequency and time domain, helper class |
Section ness::GF_pair |
|
Helper class to provide Fourier forward and back transform. |
Section ness::fft_solver |
|
Solve the Dyson equation in the steady state. |
Section Dyson equation |
|
Construct equilibrium Green’s function from a given density of states. |
Section Equilibrium Green’s functions |
|
Calculate particle-hole bubble diagram for two given Green’s functions. |
Section Diagram utilities |
|
Calculate particle-particle bubble diagram for two given Green’s functions. |
Section Diagram utilities |
Green’s functions
ness2::fft_array
Overview
class |
|
This class is a basic data structure for an object C containing two arrays C.time_ and C.freq_, which hold Nft square matrices stored as consecutive complex numbers. The class provides plans to perform a (non-normalized) discrete Fourier transform
using the FFT algorithm. In addition, the class offers routines for standard element access and basic algebraic operations. The ness2::fft_array models an array that is periodic in both time and frequency dimensions, with a period of Nft. This periodic wrapping is handled automatically when accessing array elements. For most efficient performance of the FFT, the size Nft should be a power of two. An object of the class is characterized by the following two arguments:
Nft(integer): FFT array length.size(integer): matrix size (size x size).
Constructors
|
Default constructor, with |
|
Standard constructor. |
|
Copy constructor given a |
The constructor has an optional third argument FFTW_FLAG, which chooses the plan for the construction of the plan in the FFTW library used to do the Fourier transforms (default is FFTW_ESTIMATE).
Accessing individual elements
General element access:
The following member functions read and set elements of the time (ness2::fft_array::time_) or frequency (ness2::fft_array::freq_) part of the ness2::fft_array, specified by the domain argument, which can take the values ness2::fft_domain::freq or ness2::fft_domain::time. The parameter M is a Matrix type (complex eigen matrices are supported). For [set|get]_element, time or frequency arguments outside the interval [0, Nft-1] are mapped back into this interval by adding an integer multiple of Nft.
|
\((C_{\rm time|freq})[i]\) set to matrix |
|
Matrix |
To set a matrix element of \((C_{\rm time|freq})\) one can use the following utility, which operates on all Nft entries:
|
\((C_{\rm time|freq})_{i_1,i_2}\) set to \((B_{\rm time|freq})_{j_1,j_2}\). |
Simple Algebra
The following methods cover basic algebraic operations on the ness2::fft_array object. The domain argument is set to ness2::fft_domain::time or ness2::fft_domain::freq to specify whether the operation applies to C.time_ or C.freq_.
All routines operate on all Nft entries. The parameter M is a Matrix type (complex eigen matrices are supported).
|
\(C_{\rm time|freq}\) set to \(C_{\rm time|freq}+aB_{\rm time|freq}\). |
|
\(C_{\rm time|freq}\) set to \(aC_{\rm time|freq}\). |
|
\(C_{\rm time|freq}\) set to 0 for all entries. |
|
\(C_{\rm time|freq}\) set to \(MC_{\rm time|freq}\). |
|
\(C_{\rm time|freq}\) set to \(C_{\rm time|freq}M\). |
|
\(C_{\rm time|freq}\) set to \(M^\dagger C_{\rm time|freq}\). |
|
\(C_{\rm time|freq}\) set to \(C_{\rm time|freq}M^\dagger\). |
Fourier transform
The following member functions perform the discrete Fourier transforms (34) and (35) using FFT:
|
Set \(C_{\rm time}\) to \(\bar{\mathcal{F}}\{C_{\rm freq}\}\) using (35) and FFT. |
|
Set \(C_{\rm freq}\) to \({\mathcal{F}}\{C_{\rm time}\}\) using (34) and FFT. |
Example:
int N_grid = 100;
int size = 2;
double h = 0.1;
int ex_id = 25;
// create arrays
fft_array new_array(N_grid, size);
fft_array new_array2(N_grid, size);
// matrices for operations
cdmatrix A(size,size);
cdmatrix B(size,size);
cdmatrix C(size,size);
A(1,0) = 1;
A(0,1) = II; // fill A with values
// element access
new_array.set_element(ex_id,A,ness2::fft_domain::time); // read into new_array from A
new_array.get_element(ex_id,B,ness2::fft_domain::time); // read into B from new_array
new_array2.set_matrixelement(1,1, new_array, 0, 1, ness2::fft_domain::time); // write one matrix element in new_array2 from new_array
// example operations
new_array.incr(new_array2, 0.5, ness2::fft_domain::time);
new_array.smul(2.0, ness2::fft_domain::time);
new_array.left_multiply(A, ness2::fft_domain::time);
new_array.right_multiply(B, ness2::fft_domain::time);
new_array2.set_zero(ness2::fft_domain::time);
new_array.fft_to_freq(); // FFT to frequency
new_array.get_element(ex_id,C,ness2::fft_domain::freq); // e.g. read into C
Grid info
class |
|
This helper class describes the time and frequency grids with steps h and dw and length Nft used in ness2::fft_array and ness2::herm_matrix_ness.
|
Constructor to initialize grid with time step |
|
Update time step |
|
Update frequency step |
|
Get time value \(t\) at grid index |
|
Get frequency value \(\omega\) at grid index |
|
Generate the full wrapped time grid ( |
|
Generate the full wrapped frequency grid ( |
Example:
int N_grid = 100;
double h = 0.1;
double new_h = 0.2;
double new_dw = 0.1;
int ex_id = 25;
// manipulate and show grid info
grid_info new_grid(N_grid, h); // create a grid
cout << "Number of grid points: " << new_grid.Nft_ << endl;
cout << "Time step: " << new_grid.h_ << endl;
cout << "Frequency step: " << new_grid.dw_ << endl;
new_grid.set_h(new_h); // update time step
cout << "New time step: " << new_grid.h_ << endl;
cout << "New frequency step: " << new_grid.dw_ << endl;
new_grid.set_dw(new_dw); // update frequency step
cout << "New time step: " << new_grid.h_ << endl;
cout << "New frequency step: " << new_grid.dw_ << endl;
cout << "Time at example index: " << new_grid.time_at(ex_id) << endl;
cout << "Frequency at example index: " << new_grid.freq_at(ex_id) << endl;
std::vector<double> full_time_grid = new_grid.time_grid(); // store full time grid in vector
std::vector<double> full_freq_grid = new_grid.freq_grid(); // store full frequency grid in vector
ness2::herm_matrix_ness
Overview
class |
|
The data type ness2::herm_matrix_ness is used to represent a steady-state function G with hermitian symmetry (non-hermitian Green’s functions are not supported in the current extension of libcntr).
An object of this class is initialized by:
Nft(integer): FFT array length.size(integer): matrix size (size x size).
An object G of type ness2::herm_matrix_ness contains a pair of two members ness2::herm_matrix_ness::ret_ and ness2::herm_matrix_ness::les_ of type ness2::fft_array, representing \(G^R\) and \(G^<\) in time and frequency. Time arguments thereby correspond to an equidistant grid
and the frequencies represent the dual FFT grid
We require \(N_{\rm ft}\) to be even, and use the conventional layout of the arrays where \(G^{<|R}(jh)\) is represented by the \(j\)-th element of G.[les|ret]_.time_, if \(0\le j< N_{\rm ft}/2\), and by the \((j+N_{\rm ft})\)-th element if \(-N_{\rm ft}/2\le j< 0\) (analogous for frequency). For convenience we provide a small helper class ness2::fft_grid, see Grid info.
Constructors
|
Default constructor, with |
|
Standard constructor. |
|
Copy constructor given a |
The constructor again has an optional third argument FFTW_FLAG, for the plan of the FFT construction on FFTW.
Accessing individual elements
General element access:
The following member functions read and set elements of the time or frequency part (domain argument set to ness2::fft_domain::freq or ness2::fft_domain::time) of the retarded or lesser component of the ness2::herm_matrix_ness object. The parameter M is a Matrix type (complex eigen matrices are supported). As for ness2::fft_array [set|get]_element, time or frequency (i) arguments outside the interval [0, Nft-1] are mapped back into this interval by adding an integer multiple of Nft.
|
\((G_{\rm time|freq}^{<|R})[i]\) set to matrix |
|
Matrix |
|
Return reference to |
|
Return reference to |
Simple Algebra
The same functions as for ness2::fft_array are also defined for ness2::herm_matrix_ness, the operation is performed for both retarded and lesser component.
|
\(G^{R,<}_{\rm time|freq}\) set to \(G^{R,<}_{\rm time|freq}+aB^{R,<}_{\rm time|freq}\). |
|
\(G^{R,<}_{\rm time|freq}\) set to \(a G^{R,<}_{\rm time|freq}\). |
|
\(G^{R,<}_{\rm time|freq}\) set to 0 for all entries. |
|
\(G^{R,<}_{\rm time|freq}\) set to \(M G^{R,<}_{\rm time|freq}\). |
|
\(G^{R,<}_{\rm time|freq}\) set to \(G^{R,<}_{\rm time|freq}M\). |
|
\(G^{R,<}_{\rm time|freq}\) set to \(M^\dagger G^{R,<}_{\rm time|freq}\). |
|
\(G^{R,<}_{\rm time|freq}\) set to \(G^{R,<}_{\rm time|freq}M^\dagger\). |
Integral transforms
For the Fourier transform of Green’s functions, we must distinguish between plain DFT, which can be accessed by the call [ret|les]_.to_[time|freq]() to the members of ness2::herm_matrix_ness, and approximations to the GFs integral transforms.
The transformation G.transform_to_freq(h, METHOD) computes an approximation to the integral transforms (28), (30) on the frequency grid (37), assuming a time grid with timestep h. The integrals are computed with boundaries [0,T] (for \(G^R\)) and [-T, T] (for \(G^<\)), with \(T = (Nft/2 - 1)h\). If the argument METHOD is omitted or given by the keyword FFT_TRAPEZ (default), we compute the Fourier integral in the trapezoidal rule. The reverse transformation G.transform_to_time(h, METHOD) computes an approximation to the Fourier integrals (27), (29) on the time grid (36). For both directions, we also provide an implementation METHOD=FFT_CUBIC, where the integrals are approximated by the exact Fourier transform of a piecewise cubic interpolating function.
|
Compute the frequency-domain Fourier integrals (28), (30) of the Green’s function, assuming a timestep |
|
Compute the time-domain Fourier integrals (27), (29) of the Green’s function, assuming a timestep |
Density matrix
The density matrix in the steady state is directly evaluated by calculating the lesser component of the Green’s function:
with \(\xi=\pm1\) for bosonic (fermionic) Green’s functions. The equal-time convolution
can be obtained from the Fourier transform of \(C=A\ast B\).
The corresponding function calls are ness2::density_matrix and ness2::convolution_density_matrix:
|
|
|
|
File I/O
File input and output from text files and also HDF5 files is supported.
Reading and writing to text files:
Text files start with an initial header line # Nft size precision containing apart from the size properties also the optional accuracy argument. The data is structured into blocks for the retarded and lesser component. Reading expects the same format as writing to text files.
|
Print the |
|
Read |
Reading and writing to HDF5 files:
To store a ness2::herm_matrix_ness or read it from a HDF5 file, one can use the member functions ness2::herm_matrix_ness::write_to_hdf5 and ness2::herm_matrix_ness::read_from_hdf5. This stores/reads the attributes Nft, size1, and the Green’s function component’s data sorted in groups ret, les.
|
Stores the |
|
Stores the |
|
Write data and attributes from the |
|
Reads the |
|
Reads the |
|
Read all data and attributes from an HDF5 file from a given group into the |
Note
The HDF5 reading functions have a third optional argument FFTW_FLAG (default is FFTW_ESTIMATE) to set the FFT plan of object G manually.
Example:
int N_grid = 100;
int size = 2;
double h = 0.1;
int ex_id = 25;
// Green's function object
herm_matrix_ness G(N_grid, size);
// complex matrices
cdmatrix M1(size,size);
cdmatrix M2(size,size);
// Do something with G ...
G.set_zero(ness2::fft_domain::freq);
G.get_les(ex_id,M1,ness2::fft_domain::time); // read in from G into M1
density_matrix(M2, -1, G); // get (fermionic) density matrix from G, save in M2
G.integral_transform_to_freq(h, FFT_TRAPEZ); // evaluate frequency-domain Fourier integrals
// save G in hdf5 file
hid_t file_id = open_hdf5_file(flout); // char *flout points to the filename
store_int_attribute_to_hid(file_id, "N_grid", N_grid); // write N_grid to group "/N_grid"
// same for size, h ...
G.write_to_hdf5(file_id, "G"); // new group "/G" in file
close_hdf5_file(file_id);
ness::GF
Overview
class |
|
This class contains the data structures for representing one-time contour Green’s functions \(G(t)\) on the equidistantly discretized real-time Keldysh contour \(\mathcal{C}_K\) with points \(\{i h: i=0,1,2,...,{\tt nt-1}\}\) or equivalently on an equidistant real-frequency grid \(\{ i d \omega: i=0,1,2,...,{\tt nfreq}-1\}\) with spacing \(h\) or \(d \omega\) respectively. Note that the time argument of a Green’s function object \(G(t)\) is understood as a time difference in Keldysh steady state theory and the class ness::GF stores the positive time part. The Green’s functions are initialized by the following parameters:
dgrid(double): spacing of the time or frequency discretization.ngrid(integer): number of discretization points on the time or frequency axis.size1(integer): first orbital or any quantum number dimension.size2(integer): second orbital or any quantum number dimension. Each Green’s function \(G(t)\) is a matrix of dimensionsize1\(\times\)size2.sig(integer): takes the values-1(fermion) or+1(boson).gf_type(integer): documents the type of the Green’s function and takes0(time type:time_gf) or1(frequency type:freq_gf).
Constructors
|
Default constructor, does not allocate memory, sets all parameters to |
|
Allocates memory and sets all entries to |
|
Allocates memory and sets all entries to |
|
Constructs a |
Accessing individual elements
|
Return reference to retarded component. |
|
Return reference to lesser component. |
The following member functions read and set components or submatrices of a Green’s function G from another Green’s function gf:
|
Set |
|
Set |
|
Set |
|
Set |
Scalar multiplication and incrementation
|
|
|
|
Size consistency
G.ngrid_==gf.ngrid_andG.size1_\(\cdot\)G.size2_==gf.size1_\(\cdot\)gf.size2_as well asG.gf_type_==gf.gf_type_required.
Density matrix
|
Density matrix \(\rho_{ab} = i \xi G^<_{a,b}(0)\) (\(\xi\) is the bosonic/fermionic sign). |
File I/O
|
Writes the specified Green’s function |
|
Reads the contents of a text file |
The output or input text file is ordered: Frequency / time, \(\Re \{G^{\mathrm{R}}\}\), \(\Im \{G^{\mathrm{R}}\}\), \(\Im \{G^{<}\}\), \(\Re \{G^{<}\}\), … (row-major order for orbital indices size1_, size2_).
ness::fft_solver
Overview
class |
|
This class contains the data structures for transforming a Green’s function \(G(t)\) on the equidistantly discretized real-time Keldysh contour \(\mathcal{C}_K\) with points \(\{i h: i=0,1,2,...,{\tt nt-1}\}\) to a Green’s function \(G(\omega)\) on an equidistant real-frequency grid \(\{ i d \omega: i=0,1,2,...,{\tt nfreq}-1\}\) with spacing \(h\) or \(d \omega\) respectively. We use the fast Fourier transform (FFT) library FFTW3. The class is defined by two parameters:
nt(integer): number of time points of theGFobject.FFTW_FLAG(size_t): The FFTW3 flag, this argument is usually eitherFFTW_MEASUREorFFTW_ESTIMATE.
Constructor
|
Default constructor, creates necessary FFTW3 structures (input and output array, FFT plans). |
Member functions
|
Transforms the contents of the Green’s function |
|
Transforms the contents of the Green’s function |
ness::GF_pair
Overview
class |
|
This class contains the data structures for simultaneously handling a time Green’s function object and frequency Green’s function object. The advantage of this class is that both objects (freq and time) are constructed with the necessary amount of data points for a Fourier transform. The Fourier transform can be called as a member function (to_time|to_freq) on the members of the class. The class is thus defined by all the parameters of a time GF object.
Constructors
|
Default constructor, does not allocate memory. |
|
Allocates memory and sets all entries to |
|
Constructs a |
Accessing members
|
Frequency |
|
Time |
Member functions
|
Fourier transforms |
|
Fourier transforms |
Equilibrium Green’s functions
Also in the steady state we provide tools for calculating the Green’s function
from a given spectral function solving the integrals (27), (29) or to force a given Green’s function into equilibrium using relation (31). The provided functions also work in the namespace ness.
Constructing a Green’s function from a given DOS
As defined in the manual, we can construct a Green’s function from a given density of states \(A(\omega)\) in the steady state:
where \(g_\omega(t)\) is the single-orbital noninteracting Green’s function with energy \(\omega\). The latter is defined as (\(F_\xi(x)=1/(e^{\beta x}-\xi )\) is the Fermi/Bose distribution):
\(g_\omega^R (t) = -i e^{-i t \omega}\)
\(g_\omega^< (t) = -i\xi e^{-i t \omega} F_\xi(\omega-\mu)\)
For the class ness2::herm_matrix_ness this is accomplished by the following call of ness2::green_equilibrium_ness:
|
Set \(G^{<|R}(t)\) to equilibrium Green’s function for Bosons ( |
The user provides the inverse temperature beta, the time step h and the chemical potential mu (set to 0.0 by default). DOS is a class representing \(A(\omega)\), which provides an operation dos(double omega) to return \(A(\omega)\), and the numbers dos.lo_ and dos.hi_ representing the lower and upper bound of the support of \(A(\omega)\). One may use keywords BOSON and FERMION for the sign \(\pm 1\). METHOD can be FFT_TRAPEZ or FFT_ADAPTIVE, for FFT_TRAPEZ arguments nn and limit are ignored.
If the argument
METHODisFFT_TRAPEZthe integral is computed as intransform_to_time, after initializing the imaginary part of the frequency-dependent componentsret_.freq_andles_.freq_using thedosfunction on the frequency grid (37). Note that the routine is implemented only for scalar \(A(\omega)\); if \(G\) is matrix-valued, it is set to a diagonal matrix.Alternatively, if
METHOD = FFT_ADAPTIVE, integrals are computed using the adaptive Fourier integral oflibcntr, with a subdivision of the domain of \(A(\omega)\) in at mostlimitintervals ofnnpoints (default islimit=100andnn=20). The adaptive Fourier integration is more accurate but slower, because it does not exploit the FFT algorithm.
Example:
int N_grid = 100;
int size = 2;
double h = 0.1;
double beta= 0.1;
double mu= 0.0;
int sign= -1;
herm_matrix_ness G(N_grid, size);
cntr::bethedos dos;
dos.V_ = 0.25;
dos.lo_ = -0.5;
dos.hi_ = 0.5;
ness2::green_equilibrium_ness(-1, G, dos, beta, mu, h, FFT_TRAPEZ);
Setting a Green’s function to thermal equilibrium
Also for this class, we provide a method ness2::herm_matrix_ness::force_equilibrium, which does a Fourier transform of \(G^R(t)\) to frequency (analogous to ness2::herm_matrix_ness::integral_transform_to_freq with METHOD = FFT_TRAPEZ) to initialize \(G^<(\omega)\) on the frequency grid (37) according to the equilibrium dissipation fluctuation relation (31), and transforms \(G^<(\omega)\) to \(G^<(t)\) analogous to ness2::herm_matrix_ness::integral_transform_to_time.
|
Set \(G^<(t)\) according to (29) and the equilibrium dissipation fluctuation relation (31) for Bosons ( |
Diagram utilities
Bubble diagrams
Apart from algebraic manipulations there is also a steady state implementation of the bubble products \(C(t)=iA_{a,a'}(t) B_{b',b}(-t)\) and \(C(t)=iA_{a,a'}(t) B_{b,b'}(t)\), see the Diagrams section in the main code. Applying the Langreth rules we can provide the two basic functions, ness2::Bubble1_ness and ness2::Bubble2_ness, as in the main code, which work also in the namespace ness.
|
\(C_{c1,c2}(t)=i A_{a1,a2}(t) B_{b2,b1}(-t)\) is calculated for given |
|
\(C(t)=i A(t) B(-t)\) is calculated for given scalar |
|
\(C_{c1,c2}(t)=i A_{a1,a2}(t) B_{b1,b2}(t)\) is calculated for given |
|
\(C(t)=i A(t) B(t)\) is calculated for given scalar |
Example:
The following example calculates the second-order self-energy for a general time-dependent interaction \(U(t)\) out of a scalar local Green’s function, \(\Sigma(t,t') = U(t) G(t,t') G(t',t) U(t') G(t,t')\). The diagram is factorized in a particle-hole bubble \(\chi\) and a particle-particle bubble:
int N_grid = 100;
int size = 1;
double h = 0.1;
int sign= -1;
cdmatrix U(size,size);
herm_matrix_ness G(N_grid, size);
herm_matrix_ness Sigma(N_grid, size);
herm_matrix_ness W(N_grid, size);
// set G and U ...
// compute Sigma
ness2::Bubble1_ness(W,G,G); // W(t) is set to chi=ii*G(t)G(-t);
W.left_multiply(U, ness2::fft_domain::time); // set W to W(t)=U chi(t) U:
W.right_multiply(U, ness2::fft_domain::time);
ness2::Bubble2_ness(Sigma,G,W); // Sigma(t) is set to Sigma=ii*G(t)W(t);
Sigma.smul(-1.0, ness2::fft_domain::time); // the final -1 sign
Dyson equation
At present, for the solution of the Dyson equation we provide only one method METHOD=FFT_TRAPEZ, which is based on a straightforward discrete Fourier transform: The self energy is transformed to the frequency grid (37) using the integral transform ness2::herm_matrix_ness::integral_transform_to_freq(), corresponding to a trapezoidal evaluation of (28) and (30). Then the frequency-dependent functions \(G^{<|R}(\omega)\) are computed on the grid (37) using (32) and (33). For the back-transform to (27) and (29), we again use the implementation ness2::herm_matrix_ness::integral_transform_to_time().
Note
In order to reduce Fourier artifacts from the large frequency region we only use \(G^{<|R}(\omega)\) at frequency grid points \(-(N_{\rm freq}/2-1),...,N_{\rm freq}/2-1\), with \(N_{\rm freq}=N_{\rm ft}/3\), and set \(G^{<|R}(\omega)\) to zero outside this interval. With the stepsize \(\Delta_\omega\), the maximum frequency is therefore \(\omega_{\rm max} = \frac{2\pi}{6h}\). An accurate solution of the Dyson equation requires \(h\) to be small enough such that spectral functions are sufficiently decayed outside \([-\omega_{\rm max},\omega_{\rm max}]\). Moreover, \(N_{\rm ft}\) must be sufficiently large such that the functions \(G^{R|<}(t)\) decay at the largest time \(t_{\rm max} = \frac{hN_{\rm ft}}{2}\), and \(\Delta_\omega\) can resolve the most narrow structures in frequency.
|
Solve the frequency Dyson equation with timestep |
GandSigmaare the Green’s functions of typeness2::herm_matrix_nesswhich must be defined on the same gridsizeNftand must have the same matrix dimension.epsilonis a complex Eigen matrix.[ETA]summarizes further optional parameters which introduce a long-time regularization of the Dyson equation. Possible options areREG_CONST,REG_GAUSS,REG_OHMICThis routine is also implemented in the namespace
nessusing the function callness::dyson_ness(GF & G, GF & Sigma, const cdmatrix & H, double eta).
Example:
int N_grid = 100;
int size = 1;
double h = 0.1;
double mu=0;
cdmatrix Ham(size,size);
herm_matrix_ness G(N_grid, size);
herm_matrix_ness Sigma(N_grid, size);
// Initialize G, Sigma, Ham, ...
ness2::dyson(G, mu, Ham, Sigma, h, FFT_TRAPEZ);
VIE2
In the old namespace ness, there is also an explicit implementation for solving a VIE2, the involved Green’s functions need to match in their size1_, size2_ and ngrid_ properties and need to be hermitian.
|
\((1 + F) \ast G = Q\), |
|
\((1 + F) \ast G = Q\), |
Parallelization with OMP
class |
|
The Fourier transforms can be parallelized using a shared-memory parallelization, using the built in functionalities of the FFTW library. In order to make this functionality available, we provide a small helper class ness2::FFT_OMP_Manager. ness2::FFT_OMP_Manager::initialize must be called for initialization at the beginning of the program. Before creating an ness2::fft_array or ness2::herm_matrix_ness object (which contains an fft_plan of the FFTW library), one needs to call ness2::FFT_OMP_Manager::set_threads_for_new_plans. All plans which are created after this call will be generated such that their execution spans over a specified number of nomp threads. Note that new plans are also created once a new ness2::fft_array or ness2::herm_matrix_ness is created via an assignment and or copy assignment. At the end of the program, call ness2::FFT_OMP_Manager::finalize.
|
Initialize parallelization helper class, call at beginning of program. |
|
Fix amount of threads |
|
Finalize, call at end of program. |
Inside the code, you can access the number of threads currently used in the construction of plans from the variable FFT_OMP_Manager::current_threads. To test the parallel setup, we provide a notebook utils/test_ness2_omp.ipynb.
Note
This functionality is added automatically when the library is built with
omp=ONandness=ON. In addition it requires the FFTW library to be compiled with--enable-threads. If only the non-threaded FFTW library is available (or ifomp=OFF), the calls to the FFT OMP Manager have simply no effect, and all Fourier transforms are single threaded.The generation of plans (i.e., the creation of any
fft_herm_matrix_nessorfft_array) is not thread-safe, and should be called from a serial region of the code.In general, one should avoid nesting outer parallelization and parallelization of the Fourier transforms. Using outer parallelization in combination with FFT plans with more than one thread may lead to oversubscription. If outer parallelization is used, plans should therefore simply be created with
nomp=1threads.
Utilities
Comparing Green’s functions
To compare the data of two Green’s functions, e.g. for convergence checks, one can analyze the difference using the \(L_2\)-norm difference \(|| M ||\) for \(M=A-B\) of the individual elements. The difference is defined as the \(L_2\)-norm difference, summed over all time or frequency points:
\(|| M ||\) is the standard matrix \(L_2\) norm, \(\Delta x = \Delta \omega\) for domain=ness2::fft_domain::freq and \(\Delta x = h\) for domain=ness2::fft_domain::time. The corresponding function call is ness2::distance_norm2:
|
Returns difference norm \(\|A-B\|_2\) (double) for |
In the old namespace the function call is double ness::GF2norm(GF &g1, GF &g2), the type of g1 and g2 has to match and they must have equal size1_, size2_ and ngrid_.
Example:
int N_grid = 100;
int size = 1;
double h = 0.1;
herm_matrix_ness G(N_grid, size);
// some iterative procedure to determine G
{
herm_matrix_ness tG(N_grid, size); //temporary variable
double convergence_error;
int iter_max=100;
for(int iter=0;iter<=iter_max;iter++){
tG = G; // store values of G before iteration
// ... some code to update G ...
convergence_error = ness2::distance_norm2(tG,G,ness2::fft_domain::time);
if( convergence_error < some_sufficiently_small_number) break;
}
if(iter>iter_max){
cout << "no convergence!" << endl;
}
}
Data exchange with two-time functions
Data exchange between two-time and steady state functions is enabled by the following functions:
The function ness2::cntr2ness allows to read the ness2::fft_domain::time data of a steady state function \(G_{\rm ness}\) from a given timeslice \(t_0\) of a two-time object \(G\), such that \(G_{\rm ness}^{R|<}(t)\leftarrow G_{\rm cntr}^{R|<}(t_0,t_0-t)\) for all \(t\).
At negative times \(t\), \(\bar G\) is set assuming hermitian symmetry; if tstp is smaller than the maximum time \(N_{\rm ft}/2-1\) in \(G_{\rm ness}\), the remaining entries in \(G_{\rm ness}\) are left zero.
The reverse function ness2::ness2cntr sets \(G_{\rm cntr}^{R|<}(t,t')\leftarrow G_{\rm ness}^{R|<}(t-t')\) for all arguments \((t,t')\) where \(t-t'\) is in the domain of \(G_{\rm ness}\), and zero otherwise. The two function calls are:
|
Set values \(G^{<|R}\) of a |
|
Set \(G^{<|R}\) of a two-time function |
Gcntrcan becntr::herm_matrix,cntr::herm_matrix_timestep,cntr::herm_matrix_movingorcntr::herm_matrix_timestep_moving.For the latter three types, the argument
tstpincntr2nessis ignored and can be omitted, because always the leading physical timestep is addressed.If the argument
tstpis omitted forGcntrof typecntr::herm_matrix, it defaults to the largest physical time (Gcntr.nt).
Resampling
In the steady state, calculations on much finer time grids are possible than in two-time calculations. Therefore downsampling and upsampling routines are necessary to read and write Green’s functions defined on different grids effectively between the two interfaces. The following routines resample steady state ness2::herm_matrix_ness objects, so that they can be brought into the same shape as their cntr counterpart and be processed with the ness2::cntr2ness and ness2::ness2cntr functions.
Upsampling:
Upsampling a ness2::herm_matrix_ness object to one with finer time grid is equivalent to increasing the maximum frequency on frequency domain. One can thus transform the ness2::herm_matrix_ness object of length Nft to frequency using integral_transform_to_freq and enlarge the frequency interval by adding zeros until the desired length Nft*factor is achieved. Then a back-transform to time using integral_transform_to_time on the new grid Nft*factor returns the upsampled object in time.
|
Upsample a |
Downsampling:
Downsampling a ness2::herm_matrix_ness object to one with coarser time grid is equivalent to keeping only every factor-th element in a Green’s function of length Nft in time domain to reduce it to the length Nft/factor. In frequency space this corresponds to dropping all high frequency elements outside the length Nft/factor of the resampled object. Returns ness2::herm_matrix_ness or ness2::fft_array.
|
Downsample a |
HDF5 python utilities
Also for the steady state code we provide python tools, which include scripts for reading and post-processing Green’s functions from HDF5 format via the h5py python package.
The python tools can be found in libcntr/python3 in the file ReadNESS.py. An example usage is demonstrated in the example programs Steady-state Dyson equation: Anderson Impurity model and DMFT in the steady state.
Note
To make the python module available to a python script, the module needs to be in the python include path. This is achieved by setting export PYTHONPATH=<path>/nessi/libcntr/python3.