API Usage#
Summary of user API functions#
The user-facing APIs that can be called from within a DFT code are declared in librpa.h (C), librpa.hpp (C++), and librpa_f03.f90 (Fortran 2003).
These APIs fall into three groups:
global environment management (initialization and finalization)
input parsing
computation
They are centered around two management structures:
LibrpaHandler, which manages input parsing and computations
LibrpaOptions, which stores runtime parameters
Handler object#
The LibrpaHandler (C) / librpa::Handler (C++) / type(LibrpaHandler) (Fortran) is the central object that manages the LibRPA computation. It encapsulates all input data and computation state.
The typical workflow is:
Create a handler using the MPI communicator
Set input data via setter methods
Call computation functions
Free the handler when done
C:
LibrpaHandler *h = librpa_create_handler(MPI_COMM_WORLD);
// ... set input data and compute ...
librpa_destroy_handler(h);
C++:
librpa::Handler h(MPI_COMM_WORLD);
// ... set input data and compute ...
h.free();
Fortran:
type(LibrpaHandler) :: h
call h%init(MPI_COMM_WORLD)
! ... set input data and compute ...
call h%free()
Environment setup#
Runtime environment for LibRPA should be properly setup to parse the input data and call computation functions. They are managed by the environment setup APIs (C/C++/Fortran):
Any calls to input parsing and computation APIs should be surrounded by calls to librpa_init_global and librpa_finalize_global.
To configure runtime parameters for computation, an LibrpaOptions object should be created, modified and passed to computation functions.
Parameters are attributes of LibrpaOptions object, and can be initialized using librpa_init_options.
For example, to configure the number of frequency grids and Green’s function threshold:
// C API
LibrpaOptions opts;
librpa_init_options(&opts);
opts.nfreq = 16;
opts.gf_threshold = 1.e-3;
opts.output_level = LIBRPA_VERBOSE_INFO;
// C++ API
librpa::Options opts;
opts.nfreq = 16;
opts.gf_threshold = 1.e-3;
opts.output_level = librpa::Verbose::LIBRPA_VERBOSE_INFO;
! Fortran API
type(LibrpaOptions) :: opts
call opts%init()
opts%nfreq = 16
opts%gf_threshold = 1.0d-3
opts%output_level = LIBRPA_VERBOSE_INFO
Input parsing#
Input parsing APIs common to all tasks include (C/C++/Fortran):
librpa_set_scf_dimension() / Handler::set_scf_dimension() / handler%set_scf_dimension
librpa_set_wg_ekb_efermi() / Handler::set_wg_ekb_efermi() / handler%set_wg_ekb_efermi
librpa_set_ao_basis_wfc() / Handler::set_ao_basis_wfc() / handler%set_ao_basis_wfc
librpa_set_ao_basis_aux() / Handler::set_ao_basis_aux() / handler%set_ao_basis_aux
librpa_set_latvec_and_G() / Handler::set_latvec_and_G() / handler%set_latvec_and_G
librpa_set_atoms() / Handler::set_atoms() / handler%set_atoms
librpa_set_kgrids_kvec() / Handler::set_kgrids_kvec() / handler%set_kgrids_kvec
librpa_set_ibz_mapping() / Handler::set_ibz_mapping() / handler%set_ibz_mapping
librpa_set_lri_coeff() / Handler::set_lri_coeff() / handler%set_lri_coeff
librpa_set_aux_bare_coulomb_k_atom_pair() / Handler::set_aux_bare_coulomb_k_atom_pair() / handler%set_aux_bare_coulomb_k_atom_pair
librpa_set_aux_cut_coulomb_k_atom_pair() / Handler::set_aux_cut_coulomb_k_atom_pair() / handler%set_aux_cut_coulomb_k_atom_pair
librpa_set_aux_bare_coulomb_k_2d_block() / Handler::set_aux_bare_coulomb_k_2d_block() / handler%set_aux_bare_coulomb_k_2d_block
librpa_set_aux_cut_coulomb_k_2d_block() / Handler::set_aux_cut_coulomb_k_2d_block() / handler%set_aux_cut_coulomb_k_2d_block
librpa_set_band_kvec() / Handler::set_band_kvec() / handler%set_band_kvec
librpa_set_band_occ_eigval() / Handler::set_band_occ_eigval() / handler%set_band_occ_eigval
librpa_set_wfc_band() / Handler::set_wfc_band() / handler%set_wfc_band
These functions parse information from the hosting DFT code to LibRPA, such as:
dimension of lattice vectors, orbital basis and auxiliary basis
k-mesh points, eigenvalues and occupation numbers
wave functions of mean-field calculation
local RI coefficients
Coulomb matrices in auxiliary basis
data for band structure calculation
They have to be called after the runtime environment is initialized, see Environment setup above.
Computation#
After data have been correctly set up by input parsing functions, computation functions can be called to get quantities of interest:
General
librpa_get_imaginary_frequency_grids() / Handler::get_imaginary_frequency_grids() / handler%get_imaginary_frequency_grids
RPA correlation energy:
librpa_get_rpa_correlation_energy() / Handler::get_rpa_correlation_energy() / handler%get_rpa_correlation_energy
Exact exchange:
librpa_build_exx() / Handler::build_exx() / handler%build_exx
librpa_get_exx_pot_kgrid() / Handler::get_exx_pot_kgrid() / handler%get_exx_pot_kgrid
librpa_get_exx_pot_band_k() / Handler::get_exx_pot_band_k() / handler%get_exx_pot_band_k
G0W0 self-energy:
Schematic examples#
C++#
The following C++ code gives an impression of how LibRPA APIs should be called in the host DFT code:
#include <librpa.hpp>
#include <mpi.h>
int main()
{
MPI_Init(...);
// If LibRI is enabled, MPI thread support should be set to MPI_THREAD_MULTIPLE
// MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
// Before: setup and SCF calculation of hosting program
// *** Initialize LibRPA runtime environment ***
librpa::init_global();
// *** Set up runtime parameters ***
librpa::Options opts;
opts.nfreq = 16;
opts.gf_threshold = 1e-3;
opts.output_level = librpa::Verbose::LIBRPA_VERBOSE_INFO;
// *** Create handler ***
librpa::Handler h(MPI_COMM_WORLD);
// *** Input parsing ***
h.set_scf_dimension(nspins, nkpts, nstates, nbasis);
h.set_wg_ekb_efermi(nspins, nkpts, nstates, wg, ekb, efermi);
h.set_latvec_and_G(lat_mat, G_mat);
h.set_kgrids_kvec(nk1, nk2, nk3, kvecs);
h.set_ibz_mapping(ibz_map);
h.set_ao_basis_wfc(nbs_wfc);
h.set_ao_basis_aux(nbs_aux);
// Loop over atoms and R cells to set LRI coefficients
for (int i = 0; i < natoms; ++i) {
for (int j = 0; j < natoms; ++j) {
for (auto& R : r_cells) {
h.set_lri_coeff(LIBRPA_ROUTING_AUTO, i, j, nbasis_i, nbasis_j, naux_mu, R.data(), Cs.data());
}
}
}
// Loop over k-points to set Coulomb matrices
for (int ik = 0; ik < nkpts; ++ik) {
h.set_aux_bare_coulomb_k_atom_pair(ik, i, j, naux_i, naux_j, Vq_real.data(), Vq_imag.data(), vq_threshold);
}
// *** Compute RPA correlation energy ***
std::vector<std::complex<double>> rpa_contrib_ibzk(nkpts_ibz);
double Ec = h.get_rpa_correlation_energy(opts, rpa_contrib_ibzk);
// *** Compute exact exchange ***
h.build_exx(opts);
std::vector<double> vexx = h.get_exx_pot_kgrid(opts, nspins, iks_this, i_state_low, i_state_high);
// *** Compute G0W0 self-energy ***
h.build_g0w0_sigma(opts);
std::vector<std::complex<double>> sigc = h.get_g0w0_sigc_kgrid(opts, nspins, iks_this, i_state_low, i_state_high, vxc, vexx);
// *** Clean up ***
h.free();
librpa::finalize_global();
MPI_Finalize();
}
Fortran#
use librpa_f03
use mpi
implicit none
type(LibrpaOptions) :: opts
type(LibrpaHandler) :: h
integer :: ierr
integer :: comm, nkpts_ibz
complex(dp), allocatable :: contrib_ibzk(:)
call MPI_Init(ierr)
comm = MPI_COMM_WORLD
! Initialize LibRPA
call librpa_init_global()
! Set up options
call opts%init()
opts%nfreq = 16
opts%gf_threshold = 1.0d-3
! Initialize handler
call h%init(comm)
! Input parsing
call h%set_scf_dimension(nspins, nkpts, nstates, nbasis)
call h%set_wg_ekb_efermi(nspins, nkpts, nstates, wg, ekb, efermi)
call h%set_latvec_and_G(lat, recplatt)
! ... more input calls ...
! Compute RPA correlation energy
allocate(contrib_ibzk(nkpts_ibz))
Ec = h%get_rpa_correlation_energy(opts, nkpts_ibz, contrib_ibzk)
! Clean up
call h%free()
! Finalize LibRPA
call librpa_finalize_global()
call MPI_Finalize(ierr)