Ground-state density-functional theory (DFT)

The QMol-grid package uses the Kohn-Sham formulation of density functional theory (DFT) [Kohn 1965], where the electronic structure of a polyelectronic atom or molecule is described, in atomic units, by the nonlinear system eigen-state problem

$${\hat{\mathcal{H}} }_{{\mathrm{D}\mathrm{F}\mathrm{T}}} \left\lbrack \lbrace \phi_k \rbrace_k \right\rbrack ~\phi_k (x)=E_k ~\phi_k (x)~~{\mathrm{f}\mathrm{o}\mathrm{r}}~~k=1,2,\ldots~~~~~~(1)$$

often referred to as the self-consistent field (SCF) equation. Formally, the DFT Hamiltonian operator ${\hat{\mathcal{H}} }_{{\mathrm{D}\mathrm{F}\mathrm{T}}}$ is only functionally dependent on the one-body density $\rho$ but some DFT functionals still involve the Kohn-Sham orbitals in their definition. Traditionally, the DFT Hamiltonian is decomposed between the kinetic, external, Hartree, and exchange-correlation operators, each associated with an energy functional

$${\hat{\mathcal{H}} } _{{\mathrm{D}\mathrm{F}\mathrm{T}}} =-\frac{\Delta }{2}+{\hat{\mathcal{V}} } _{{\mathrm{e}\mathrm{x}\mathrm{t}}} +{\hat{\mathcal{V}} } _{{\mathrm{H}}} +{\hat{\mathcal{V}} } _{{\mathrm{X}\mathrm{C}}} .~~~~~~(2)$$

The QMol-grid package provides support both for spin-polarized, where the up- and down-spin electronic components may be different, and spin-polarized, where they are forced to be identical DFT models.

The two classes share very similar interfaces to provide a consistent end-user experience -- see their respective documentation pages for a detailed desciption of the classes and features they support.

DFT components

For clarity and streamlined future development of DFT capabilities in the QMol-grid package, we sort DFT component (classes) into different topical groups. Each component is equally compatible with both spin-polarized and -restricted DFT models

Model discretization

The following classes are used to discretize DFT systems

• QMol_DFT_density is the Cartesian-grid discretization of a one-body density. It also provides support for the computation of density gradient.
• QMol_DFT_orbital is the Cartesian-grid discretization of the Kohn-Sham orbitals.
• QMol_DFT_Vks is the Cartesian-grid discretization of the explicit part of the Kohn-Sham potential. Implicit components are also supported and provide an interface for the computation of the action of the potential operator on arbitrary wave functions.
• QMol_DFT_Vks_grad is the Cartesian-grid discretization of the explicit part of the Kohn-Sham potential gradient. Similar to the Kohn-Sham potential, it also handles implicit components and the computation of the action of the potential gradient operator on arbitrary wave functions.

For basis-set discretization models, with QMol_disc_basis, some of the classes above are redefined (overloaded)

Model components

The following functionals are currently available for DFT models and simulations in the QMol-grid package

• QMol_DFT_Vext describes the external functional and potential ${\hat{\mathcal{V}} }_{{\mathrm{e}\mathrm{x}\mathrm{t}}}$ of Eq. (2).
• QMol_DFT_Vh_conv describes the Hartree functional and potential ${\hat{\mathcal{V}} }_{{\mathrm{H}}}$ of Eq. (2), using an explicit-convolution scheme.
• QMol_DFT_Vh_fft describes the Hartree functional and potential ${\hat{\mathcal{V}} }_{{\mathrm{H}}}$ of Eq. (2), using a fast-Fourier-transform convolution scheme.
• QMol_DFT_Vx_LDA_exp describes local-density-approximation Slater exchange ${\hat{\mathcal{V}} }_{{\mathrm{X}\mathrm{C}}}$ of Eq. (2), for exponential electron-electron interaction potentials.
• QMol_DFT_Vx_LDA_soft describes local-density-approximation Slater exchange ${\hat{\mathcal{V}} }_{{\mathrm{X}\mathrm{C}}}$ of Eq. (2), for soft-Coulomb electron-electron interaction potentials.
• QMol_DFT_Vx_XX_conv describes the exact-exchange functional and potential of Eq. (2), using an explicit-convolution scheme.
• QMol_DFT_Vx_XX_fft describes the exact-exchange functional and potential of Eq. (2), using a fast-Fourier-transform convolution scheme.
• QMol_DFT_Vc_LDA_soft describes local-density-approximation correlation ${\hat{\mathcal{V}} }_{{\mathrm{X}\mathrm{C}}}$ of Eq. (2), for soft-Coulomb electron-electron interaction potentials.

All DFT functionals can be used both for regular grid-based and basis-set deiscretization models, using the same end-user interfaces.

Memory and execution-time profiler

The choice of the domain discretization and DFT components can greatly affect the resources, both in terms of memory and execution time, required to carry out simulations.

Keep in mind that differentiation and (some) convolutions are performed via fast-Fourier transforms. Thus, as a rule of thumb, domain discretization with small prime factor number of grid points tend to produce faster results -- for best performance, prime factors not greater than 7.

Ground-state computation

The DFT ground state, or more generally some DFT eigen state, is computed by numerically solving the SCF problem of Eq. (1). In the QMol-grid package, this can be achieved with

Self-interaction correction (SIC)

Various approaches have been proposed to provide self-interaction correction to the DFT Eq. (1). Currently, the QMol-grid package supports:

No self-interaction correction

In this case, self-interaction is ignored and no SIC is provided. This is the default options for all DFT models in the QMol-grid package.

ADSIC implements an average-density level of SIC [Legrand 2002] that is easy to implement in the general DFT framework of Eq. (1). Unless otherwise specified, all Hartree and exchange-correlation DFT functionals in the QMol-grid package support ADSIC.

Notes for developers

DFT model implementation

The QMol_DFT abstract class defines the common interface and run-time documentation for both spin-polarized (QMol_DFT_spinPol) and spin-restricted (QMol_DFT_spinRes) DFT models.

Many DFT components and methods require convergence tolerance or thresholds in their implementation. Throughout, we parameterize these through class properties (generally named tol). The default configuration of the QMol-grid package roughly aims for $10^{-10}$ as the target tolerance/threshold. Changing the values for the tol parameters may have unintended side effects -- see the respective documentation pages for more details on these tolerance/threshold parameters.

Exchange-correlation functionals

To be compatible with other DFT components of the QMol-grid package, exchange-correlation functionals must fulfill the following requirements:

Class definition

Define exchange-correlation classes by overloading the QMol_suite class. This will facilitate name-value pair assignment for property values in the constructor, set, and clear methods -- see the QMol_suite documentation page for more details.

Class properties

Exchange-correlation classes should define the following member properties (with the specified attributes)

• DFT: with recommended attributes Transient,Hidden,GetAccess=?QMol_suite,SetAccess={?QMol_DFT_###,?QMol_DFT}, where QMol_DFT_### is the name of the exchange-correlation class being implemented, and at minimum such that QMol_DFT can edit the value of DFT. This feature is used by QMol_DFT_profiler to estimate the memory footprint of DFT models without allocating its components.
• type: as a constant character array with public access. This is used by TDDFT propagators to check that the DFT functionals used in the model are supported. Possible values are 'GGA_C' (for GGA exchange), 'GGA_X' (for GGA exchange), 'GGA_XC' (for GGA exchange correlation), 'LDA_C' (for LDA exchange), 'LDA_X' (for LDA exchange), 'LDA_XC' (for LDA exchange correlation), 'XX' (for exact exchange).

Run-time documentation

Implement run-time documentation with the follwing interface

methods (Access=public)
function ref = showDocumentation(obj)
%showDocumentation displays the documentation reflecting member property
%   values

end
end


Each exchange-correlation functional class must implement a run-time documentation as it is automatically called by QMol_DFT in its own run-time documentation.

• If no reference is cited, return ref = {} otherwise ref = {'ref 1','ref 2',___}, where each of the ref corresponds to the bibliographic code for the reference (generally of the form 'name_of_first_author publication_year') and is case insensitive -- see the documentation page for a list of citable references.

Additionally, exchange-correlation functional class should implement an estimator of its memory footprint with the following interface

methods (Access=public)
function mem = getMemoryProfile(obj,opt)
%getMemoryProfile computes and returns an estimate of the total memory
%   footprint (in bytes) of the DFT object with all its components
%   initialized and used.

end
end

• getMemoryProfile must be able to return the memory footprint estimate even if the object has not been initialized. To do so, it can rely on its internal copy of the parent DFT object, that is properly assigned by QMol_DFT_profiler before calling getMemoryProfile.
• Only properties with large memory footprint -- e.g., the discretization of internal properties on the domain discretization grid -- need to be listed. Other small properties (scalar, object handle, flags, etc.) can be ignored; if the class only uses such small properties, it may return mem = 0.
• Use the QMol_DFT_profiler.getMemoryFootprint(N,'real') and QMol_DFT_profiler.getMemoryFootprint(N,'imag') methods to convert the size (number of elements N) of the memory components to the number of bytes they take in memory.
• opt = false requests the memory footprint with no details printed out.
• opt = true should additionally display the details of the memory estimate. Use QMol_DFT_profiler.showMemoryFootprint(msg,mem,lvl) to do this, with msg (character array) the description of the component, mem the estimated number of bytes associated with it, and lvl the indentation level (optional, lvl = 1 and lvl = 2 are the only two levels supported).

Class initialization

Initialize the class with the following interface

methods (Access=public)
function initialize(obj,DFT,SIC)
%initialize initializes the object

% Initialize the functional object

end
end

• the input DFT is a QMol_DFT object containing the DFT model associated with the exchange-correlation functional object to be initialized. For run-time considerations it is often practical to keep a local copy of DFT in the object in the DFT member method.
• The input SIC specifies the flavor of SIC to be used with the exchange-correlation functional. 'none' notify to disable SIC while 'ADSIC' specifies the ADSIC method [Legrand 2002].
• Both DFT and SIC information are systematically passed along by the parent DFT model object when it initializes its exchange-correlation functional components.

Exchange-correlation functional kernel

Implicit functionals may require specific initialization of the exchange-correlation functional object before they can compute the energy, potential, or potential gradient. This is done with

methods (Access=public)
function setPotentialKernel(obj)
%setPotentialKernel sets the kernel to be used for the computation of
%   exact-exchange potentials

% Proper initialization
end
end


This typically involves storing a local copy of the Kohn-Sham orbitals of the parent DFT model. If no kernel initialization is required, include the following block in the class definition

methods (Access=public)
function setPotentialKernel(~)
%setPotentialKernel no kernel to set

end
end


Exchange-correlation energy

Compute and return the exchange-correlation energy with

methods (Access=public)
function E = getEnergy(obj,rho)
%getEnergy returns the exchange-correlation energy

% Exchange-correlation energy computation
end
end


The getEnergy method should support the following computation modes -- see one of the available exchange-correlation functional documentation page for more details.

Get the exchange-correlation energy for the parent DFT object

E = obj.getEnergy;

• This computes the exchange energy associated with the Kohn-Sham orbitals in the parent DFT model. To do so, it should first compute the one-body density associated with the Kohn-Sham orbitals and their occupation parameters.
• This should be equivalent to, but more efficient than, obj.getEnergy(DFT.getDensity).

Get the exchange-correlation energy for a specific one-body density

E = obj.getEnergy(rho);

• Same as above but with using the input one-body-density object rho in the numerical computation of the energy.
• rho should be a QMol_DFT_density object defined over the same domain discretization as the parent DFT model.

Exchange-correlation potential

Compute and return the exchange-correlation potential with

methods (Access=public)
function E = getPotential(obj,rho)
%getPotential returns the exchange-correlation potential

% Exchange-correlation potential computation
end
end


The getPotential method should support the following computation modes -- see one of the available exchange-correlation functional documentation page for more details.

Get the exchange-correlation potential for the parent DFT object with either

V = obj.getPotential;
V = obj.getPotential([]);

• This computes the exchange-correlation potential associated with the Kohn-Sham orbitals in the parent DFT model. To do so, it should first compute the one-body density $\rho$ associated with the Kohn-Sham orbitals and their occupation parameters.
• The output Kohn-Sham potential object contains the numerical evaluation of the exchange-correlation potential.
• For implicit exchange-correlation functionals, it provides the proper function handle to the Kohn-Sham potential class.
• This creates a new Kohn-Sham potential object V in which the exchange-correlation potential is stored.
• Note that getPotential should not initialize the output potential object V.

Get the exchange-correlation potential for a specific one-body density

V = obj.getPotential(rho);

• Same as above but with using the input one-body-density object rho in the numerical computation of the potential.
• rho should be a QMol_DFT_density object defined over the same domain discretization as the parent DFT model.

Overwrite the exchange-correlation potential in an existing Kohn-Sham potential object with any of

obj.getPotential([],V);         % use parent DFT density
obj.getPotential([],V,false);
obj.getPotential(rho,V);        % supply the density
obj.getPotential(rho,V,false);

• This is similar to above without creating a new Kohn-Sham potential object.
• Any content in the input object V is erased before assigning the external potential to it.

Add the exchange-correlation potential to an existing Kohn-Sham potential object

obj.getPotential([],V,true);    % use parent DFT density
obj.getPotential(rho,V,true);   % supply the density

• This is formally equivalent to the in-place addition $\mathcal{V}\gets \mathcal{V}+{\mathcal{V}}_{{\mathrm{X}\mathrm{C}}}$ .

Compute and return the exchange-correlation potential gradient with

methods (Access=public)
function E = getPotentialDerivative(obj,rho)
%getPotentialDerivative returns the exchange-correlation potential

% Exchange-correlation potential computation
end
end


The getPotentialDerivative method should support the following computation modes -- see one of the available exchange-correlation functional documentation page for more details.

Get the exchange-correlation potential gradient for the parent DFT object with either

DV = obj.getPotentialDerivative(dim);
DV = obj.getPotentialDerivative(dim,[]);

• This computes the exchange-correlation potential gradient, along the dimension dim (1 for x, 2 for y, and 3 for z), associated with the Kohn-Sham orbitals in the parent DFT model. To do so, it should first compute the one-body density $\rho$ associated with the Kohn-Sham orbitals and their occupation parameters.
• The output Kohn-Sham potential gradient object contains the numerical evaluation of the exchange-correlation potential gradient.
• For implicit exchange-correlation functionals, it provides the proper function handle to the Kohn-Sham potential gradient class.
• This creates a new Kohn-Sham potential gradient object DV in which the exchange potential gradient is stored.
• Note that getPotentialDerivative does not initialize the output potential gradient object DV.

Get the exchange-correlation potential for a specific one-body density

V = obj.getPotentialDerivative(1,rho);

• Same as above but with using the input one-body-density object rho in the numerical computation of the potential gradient.
• rho should be a QMol_DFT_density object defined over the same domain discretization as the parent DFT model.

Overwrite the exchange-correlation potential gradient in an existing Kohn-Sham potential gradient object with any of

obj.getPotentialDerivative(1,[],DV);        % use parent DFT density
obj.getPotentialDerivative(1,[],DV,false);
obj.getPotentialDerivative(1,rho,DV);       % supply the density
obj.getPotentialDerivative(1,rho,DV,false);

• This is similar to above without creating a new Kohn-Sham potential gradient object.
• Any content in the input object DV is ereased before assigning the exchange-correlation potential gradient to it.

obj.getPotentialDerivative(1,[],DV,true);   % use parent DFT density

• This is formally equivalent to the in-place addition $\nabla \mathcal{V}\gets \nabla \mathcal{V}+\nabla {\mathcal{V}}_{{\mathrm{X}\mathrm{C}}}$ .