\documentstyle{article} \begin{document} \title{API for plane-waves in NWChem} \author{Arthur Smith} \date{\today} \maketitle \section{General outline} There are two general features of plane-wave basis sets which justify a substantially different treatment from, for example, Gaussian basis sets. First, the basis set is not linked to the actual atomic positions, other than to the size of the periodic cell in which the atoms are contained, (in fact, for plane waves each individual basis element extends throughout this cell). Second, the basis sets tend to be very large while calculations involving a single basis element (overlaps for example) are essentially trivial, so the computational challenges differ considerably. For plane-wave density-functional theory with separable non-local pseudopotentials, all calculations can be accomplished in a time linear (or $N \log(N)$) in the basis-set size (there are further dependences on the number of atoms and orbitals, of course). Both of these features (independence of atomic positions, and large size with mostly trivial overlaps) can also be said to apply to other types of basis sets that we may wish to implement in the future: pure real-space grid methods (the plane-wave technique already does much of the computation on a real-space grid), multi-grid methods, mixed-basis techniques, or even wavelets. I believe the API should be designed in such a way that programmers will need to make only minimal modifications to a higher-level application code in order to utilize a new basis set when/if one becomes available. \section{Pre-requisites} Plane-wave basis sets are only directly applicable to periodic systems - solids in particular, although other systems can be readily treated by super-cell methods. Thus the application must have previously specified a periodically repeated cell of some sort. In addition, particularly for relative small periodic cells, a collection of special {\bf k}-points must be specified (selected according to the cell symmetry) which will be used to approximate the integration of quantities over the Brillouin zone of the cell with a weighted sum over these {\bf k}-points. For large systems or for molecules/clusters treated in the supercell approximation, it is often appropriate to just use the single point {\bf k = 0}. In any case, the code should assume the {\bf k}-points have been previously specified. \section{Handling the basis sets} There is then a slightly different plane-wave basis set for each {\bf k}-point, and another (usually larger one) for the charge density. These are specified by the dimensions of the periodic cell of the system, and by some sort of cutoff - generally the requirement that: \begin{equation} \hbar^2|{\bf k + G}|^2/2m < E_{cut} \end{equation} for the wavefunction basis sets and: \begin{equation} \hbar^2 |{\bf G}|^2/2m < d \cdot E_{cut} \end{equation} for the charge density, where the parameter $d$ is between 1 and 4 and determines the degree to which the charge density completely reproduces all oscillations in the wavefunctions. The reciprocal lattice vectors {\bf G} are simply integer linear combinations \begin{equation} {\bf G}^{\alpha} = n^{\alpha}_1 {\bf b}_1 + n^{\alpha}_2 {\bf b}_2 + n^{\alpha}_3 {\bf b}_3 \end{equation} of the fundamental reciprocal lattice vectors ${\bf b}_i$, which satisfy \begin{equation} {\bf b}_i \cdot {\bf a}_j = 2 \pi \delta_{ij} \end{equation} and where the ${\bf a}_j$ are the fundamental lattice vectors specifying the periodic cell of the system. The {\bf G} values used (and the corresponding $n^{\alpha}_i$ triplets) are specified by spherical (ellipsoidal) regions surrounding the origin for the charge density and {\bf k = 0} wavefunctions, or by similar regions surrounding points close to the origin for ${\bf k} \neq {\bf 0}$. In order to apply Fast-Fourier-Transform (FFT) techniques to allow transformations between the plane-wave basis set and a real-space grid on which charge density and potential calculations are performed, the triplets $n^{\alpha}_i$ must be mapped to corresponding points in a three-dimensional integer rectangular grid $N_1 \times N_2 \times N_3$. Each of the $N_i$ must be greater than twice the largest absolute value of all the $n_i$, and for most library FFTs must be a power of two. After applying the FFT, the resulting data is associated with a real-space grid at the points: \begin{equation} {\bf r}_{ijk} = {i \over N_1} {\bf a}_1 + {j \over N_2} {\bf a}_2 + {k \over N_3} {\bf a}_3 \end{equation} Note that the point i, j, k in the $N_1 \times N_2 \times N_3$ reciprocal space array is associated with a triplet $n^{\alpha}_l$ close to the origin as follows: \begin{equation} {\rm if\ \ } i < N_1/2 {\rm\ \ then\ \ } n^{\alpha}_1 = i \end{equation} \begin{equation} {\rm if\ \ } i > N_1/2 {\rm\ \ then\ \ } n^{\alpha}_1 = i - N_1 \end{equation} and similarly for j and k. \subsection{Data distribution} Utilizing these FFT methods, the application of the Hamiltonian to a wavefunction involves diagonal operators or products of diagonal operators (see the section on applying H to $\psi_i$ below). One nice aspect of a diagonal operator on a parallel computer is that however the vectors involved are distributed on the machine, application of the operator involves no communication (as long as the components of the operator itself are either distributed in the same way as the vectors, or are calculated when needed). In other words, calculation of \begin{equation} g_i ({\bf r}) = f({\bf r}) \psi_i({\bf r}) \end{equation} is a local operation, no matter where the components $\psi_i({\bf r})$ actually reside. However, communication {\it is}\ required during the FFT operations if $\psi_i({\bf r})/\psi_i({\bf G})$ is distributed in {\bf r}/{\bf G}, and extensive communication is also required during orthogonalization and similar inner-product operations if $\psi_i({\bf r})/\psi_i({\bf G})$ is distributed in the index $i$. In addition, since we are thinking of data-decomposition and not task-decomposition here, steps must be taken to ensure that every process carries roughly the same number of coefficients $\psi_i({\bf G})$, which is best accomplished by some form of interleaving. Note that $\psi_i({\bf r})$ will naturally be evenly distributed in {\bf r} under most decompositions because the {\bf r} lie on a rectangular grid, while the relevant {\bf G} values lie within a sphere, for which block decompositions may leave some processors with few or no {\bf G}-vectors. A further complication in the {\bf k = 0} situation is that the coefficients for {\bf G} and {\bf -G} are complex conjugates, and therefore nearly a factor of two in memory and speed can be gained by keeping only one of the two coefficients. But that means in the data decomposition, {\bf G} and {\bf -G} should be covered by the same process, requiring a reversed interleaving for negative values of the $n_i$. \subsection{The initialization API} Thus the fundamental information needed to initialize a particular plane-wave basis set is: \begin{enumerate} \item The periodic cell vectors ${\bf a}_i$ \item The {\bf k}-vectors used. \item The energy cutoff $E_{cut}$ \item The charge density basis parameter $d$. \item Some information about number of processes, preferred data decomposition, and possibly process communication topology, in order to determine the distribution of G and R vectors among nodes. \item Preferred values of $N_1, N_2, N_3$ (optional) \item The vectors ${\bf b}_i$ (optional - might be useful for modularization). \end{enumerate} Returned from the initialization will be: \begin{enumerate} \item The size of the basis set for each k-point, and for the charge density, including total size, and number allocated to this process. \item Some form of listing of the G-vectors: at least the $n^{\alpha}_i$, preferably also the actual vectors {\bf G} and their (squared?) magnitudes. \item The output values of $N_1, N_2, N_3$ for the whole space and for the sub-blocks (or other arrangement) allocated to this process. \item Optionally, the ${\bf b}_i$ vectors. \end{enumerate} \subsection{The allocation API} Typically, we'll be allocating some number $n_{orbitals}$ of complex coefficients of the $ng({\bf k})$ plane waves for each of the {\bf k}. In addition, there will be several auxiliary arrays individually of approximate size $ng$, including arrays to handle the charge density and components of the potential. And we also need a few complex and real arrays on the $N_1\times N_2 \times N_3$ real-space grid. These would presumably be allocated with GA routines or something similar - for example in our hybrid decomposition approach, the first set of coefficient arrays would be distributed across all the processors. The second set, of auxiliary arrays, would be distributed across the processors within a group (the spatial decomposition subgroups) but duplicated (sometimes with identical data) in all such groups, in order to eliminate all communications except during FFT and orthogonalization (and global operation) routines. Inputs then to an allocator would be: \begin{enumerate} \item A tag specifying the basis set (previously initialized). \item The data type of the coefficients (real or complex, or something else?) \item The number of ($ng$ arrays) of this type to be allocated ($n_{orbitals}$ for example. \item Optionally: A flag indicating whether the data should be initialized with random values or with zeroes. \end{enumerate} Output would be a tag specifying the coefficient matrix, similar to GA matrix allocation, maybe? \subsection{API for basis set operations} Once we have the basis set specifications, there are a number of operations we'll need to do anything with them: \begin{enumerate} \item Copy \item Scale or AXPY \item application of a diagonal operator (GBMV?) \item Inner product \item Send and receive, or get and put to a different process \item Transformation between basis sets \item Computation of basis set overlaps for different basis sets \end{enumerate} Most of these are straightforward: probably only the last two will require much thought. We'll want to do more complicated things with the charge density (at least in calculation of the exchange-correlation energy), but that is probably a special case that can be dealt with separately. There are a couple of transformations between basis sets we might want to consider implementing initially: within a G-space representation, changing form one cutoff energy to a different one is trivial in principle (just chop, or zero-pad) but not necessarily in practice where reading in a starting configuration from an old basis set may misplace coefficients if you are not careful (we have not yet successfully implemented this using our current code, for example). Transformations between G-space and real-space are essential to computation of the charge density and evaluation of the real-space potentials, and this can be viewed as one kind of general basis-set transformation (implemented through fast Fourier transforms). I think computation of overlaps will not be necessary until mixed Gaussian and plane-wave bases are being considered, but it might be worth-while thinking about how to do it now. \section{Applying H to $\psi_i$} We can use various minimization techniques to isolate the lowest $n_{occupied}$ eigenstates of H. Because $ng$ is so much larger, we never want to construct the full $ng\times ng$ matrix, so most of these techniques start from the residual \begin{equation} H \psi_i - \epsilon_i \psi_i. \end{equation} and the most computationally intensive part of the code is going to be evaluation of the Hamiltonian-vector product H$\psi_i$. \subsection{Kinetic energy} The kinetic energy operator is evaluated in the reciprocal space representation: \begin{equation} T \psi_i({\bf G}) = {\hbar^2|{\bf k + G}|^2 \over 2m} \psi_i({\bf G}) \end{equation} The values of $|{\bf k + G}|^2$ should be pre-stored (possibly returned from the initialization routine above) and so this is a straightforward operation. However, since this is peculiar to the plane-wave basis, it might be a good idea to define a kinetic energy API (for example, for pure real-space grids, the kinetic energy could be evaluated using finite-difference techniques). For such an API the input is a basis-set specifier and the coefficient matrix (with an integer specifying how many orbitals to work on at once) and output is the matrix of result vectors (placed in a work area provided). \subsection{The real-space potentials} These are comprised of the local pseudopotential, the Hartree (electron-electron Coulomb) potential and the exchange-correlation potential. The potentials themselves are evaluated as follows: \begin{equation} V_{local}({\bf G}) = \sum_{is} u_{is}({\bf G}) S_{is}({\bf G}) \end{equation} where $is$ is an index counting the atomic species in the system, $u_{is}$ is the potential from a single atom of this species, and $S_{is}$ is a structure factor for the species: \begin{equation} S_{is}({\bf G}) = \sum_{ia} \exp(i {\bf G}\cdot {\bf r}_{ia}) \end{equation} where $ia$ runs over all atoms of species $is$. $u_{is}$ and $S_{is}$ would be distributed in the same fashion as the {\bf G}'s, but with all species $is$ together (not distributed), and so duplicated in the same fashion as $V_{local}({\bf G})$ itself: among processes with the same {\bf G}'s but different collections of orbitals. So this computation involves no communication, except for the FFT required in the end to produce a real-space potential. The electron-electron direct Coulomb interaction is easily evaluated: \begin{equation} V_{Hartree}({\bf G}) = 4\pi \rho(G)/G^2 \end{equation} except for ${\bf G} = {\bf 0}$ where the corresponding term is a constant that is added to the constant electrostatic energy of the periodic system usually evaluated by Ewald summation. Similarly, the only communication required here is the final FFT, although there will be duplication if the orbitals are distributed. Both $V_{local}$ and $V_{Hartree}$ are then FFT'd to real space, and can be added to the exchange correlation potential: \begin{equation} V_{xc}({\bf r}) = V_{xc}(\rho({\bf r}), \nabla \rho({\bf r}), ...) \end{equation} which requires no communication at all, except in the evaluation of the charge density and gradients: The charge density $\rho({\bf r})$ is calculated as the sum \begin{equation} \rho({\bf r}) = \sum_{i} |\psi_i({\bf r})|^2 \end{equation} and the gradient is: \begin{equation} \nabla\rho({\bf r}) = FFT \bigl\{ i {\bf G} \rho({\bf G}) \bigr\} \end{equation} and similarly for higher derivatives. The duplication discussed could be eliminated at the expense of more communication: we should probably study this at some point. In particular since the gradient-dependent exchange correlation potential cannot be done by table-lookup (because it depends on more than one parameter, unlike the LDA) the computation involved may be sufficient to justify distributing it. An API for a set of subroutine calls to evaluate these potentials seems appropriate - what is needed on input is quite a variety of things: for the charge density calculation we probably want to pass the basis set information and the G-space coefficient matrix, and the output would be either the charge density on the real-space grid, or else the fitted charge-density in G-space (or both). For the local potential we need to pass in geometry information and information about the pseudopotential, as well as the basis set - output is the G-space representation of that potential. For the Hartree potential we pass in the charge density and basis set info, output is the G-space potential. For the gradients calculation pass in the G-space charge density, return the real-space charge density and gradients to be passed to an exchange-correlation subroutine, or else just return the real-space exchange-correlation potential. We also need an initialization API for the pseudopotential to generate the $u_{is}({\bf G})$, and for the exchange-correlation potentials (at least to allow choices between the possibilities, and also possibly to allow setting some of their parameters). More on the pseudopotential below... \subsection{The non-local pseudopotential} Using the Kleinman-Bylander separable decomposition, the non-local pseudopotential (for each species $is$!) can be evaluated in reciprocal space as follows (from memory, so bear with me if I missed a minus sign or something): \begin{eqnarray} V_{nl}^{lm} \psi_i ({\bf G}) = C^l &\sum_{ia} U_{nl}^l({\bf k+G})Y_{lm}^*({\bf k + G}) \exp(i {\bf G}\cdot{\bf r}_{ia}) \cdot \cr &\sum_{{\bf G}'} U_{nl}^l({\bf k + G}')Y_{lm}({\bf k + G}') \exp(-i {\bf G}'\cdot{\bf r}_{ia}) \psi_i({\bf G}')\cr \end{eqnarray} where $ia$ is an index over all the atoms of species $is$, and $l$, $m$ are standard angular momentum quantum numbers. The $U_{nl}^l$ and $Y_{lm}$ can be computed at initialization and are $O(N)$ in size so not too bad. This would then be summed over $l$, $m$, and species $is$. One big potential problem data and communication-wise here is the $\exp(i {\bf G}\cdot {\bf r}_{ia})$ matrix, which if precomputed and stored is $O(N^2)$ in size, and yet needs to be present for {\bf all} the orbitals (note that non-local calculation is an $O(N^3)$ operation and thus one of the major time-consuming parts of the computation for large systems). What we do is evaluate the matrix only for {\bf G} vectors along the principal axes ${\bf b}_i$, and then compute the product of three complex numbers to get the final value when needed - this means we need to only store a matrix $O(N^{4/3})$ in size, but we need to ensure the correct sort of data-locality for that matrix. There are other ways of doing the nonlocal pseudopotentials: real-space only evaluations for example, or taking advantage of possible redundancy if a part of the system has a shorter periodicity (for example, the bulk portion of a surface problem) or other symmetry, or using complicated hybrids like the ultra-soft Vanderbilt pseudopotentials, and presumably other methods will come along. So I think two (or possibly three) subroutine calls would be involved that could be standardized on: initialization of the pseudopotential (calculation of the $U_{nl}({\bf k+ G})$ and local $u({\bf G})$ values) and of other needed quantities ($Y_{lm}({\bf k + G})$ and the $\exp(i {\bf G}\cdot {\bf r}_{ia})$ matrix); and application of the pseudopotential to a set of orbitals (either with an ion force calculation, or with forces calculated separately). \subsection{Dealing with the pseudopotentials} There may be several types of pseudopotentials we would want to handle - for example, it might be worth testing the Gaussian-derived ECP's with plane waves (maybe not?) Anyway, we must initially read in some representation of the pseudopotentials about each species of atom in the system, and the input format we currently use most often is a simple radial grid. These then need to be converted to the local $u({\bf G})$ and nonlocal $U_{nl}({\bf k+G})$ forms needed in the actual application of the pseudopotentials. Thus there needs to be some specification of the input representation of the pseudopotentials, and an initialization routine for converting that representation to one appropriate for the basis set. The associated API would have as input the input representation and specification of the (plane-wave) basis set, and as output the converted pseudopotential values. \section{Achieving self-consistency} With plane-wave basis sets the central problem of converging to a self-consistent charge-density (represented by a collection of occupied Kohn-Sham eigenfunctions) is fundamentally the same as for density functional theory with other basis sets. However, the principal constraint imposed by the large size of the plane-wave basis set is that we never know the full matrix $H$, only matrix-vector products $H \psi_i$, meaning that direct diagonalization cannot be performed, and instead iterative approaches are needed. In addition, of course, $H$ itself changes with each iteration because the charge density is changing. Among a wide variety of possibilities there are basically two iterative schemes that have become adopted in plane-wave basis-set methods: Car-Parrinello ``molecular-dynamics'' type iterations, and Teter-Payne-Allen preconditioned gradient iterations (often misnamed ``conjugate gradient'' iterations because the first implementation happened to use a multiple conjugate gradients updating scheme that has since proved inefficient compared to just using a single preconditioned gradient). The Car-Parrinello approach is to treat the energy gradient $H\psi$ as a force on the coefficients of $\psi$, so that in a ``time-step'' $\tau$, \begin{equation} \psi_i(t + \tau) = \psi_i(\tau) - {\tau^2 \over 2 m_{eff}} H\psi_i(tau), \end{equation} after which the new $\psi_i$ are orthogonalized to one another. When doing real dynamics a velocity term may also be included - as stated this is effectively just a steepest-descents algorithm. As such it is simple but rather inefficient for getting self-consistency, but on the other hand it is rather robust (always converging to the lowest occupied subspace, if you wait long enough) and in fact when coupled with atomic dynamics can be competitive with the Born-Oppenheimer approach required when using the preconditioned gradient methods. The preconditioned gradient methods have the following iterative step: \begin{enumerate} \item Generate residual vectors: $ R_i = (H - \epsilon_i) \psi_i$ \item Apply a preconditioner: $B_i = P R_i$. As with the Davidson method, the preconditioner should be close to an inverse of the Hamiltonian. In practice, a rational function of the kinetic energy (approaching 1/K.E. for high energy) works well with a plane-wave basis set. \item Orthogonalize the $B$'s to one another and to the $\psi's$. \item Generate $ H B_i $ and the subspace matrix $ $ where $V_i$ is $\psi_i$ for $i < n$ and $B_{i - n}$ for $i >= n$. \item Diagonalize within the subspace, and let the new $\psi$ vectors be the lowest $n$ eigenvectors. \item Generate the new charge density (generally by mixing in some of the old, otherwise instabilities arise) and the resulting new Hamiltonian, and repeat. \end{enumerate} These methods (there are variants based on whether you let $n = 1$ and have an outer loop over bands, or else let $n =$ all states, or else with different preconditioners) tend to be much faster than the steepest-descent approach to obtain a self-consistent set of electronic states. On the other hand they require more computation per step (twice as many Hamiltonian-vector operations, for example) and experience shows they tend to be less robust. Both methods could be implemented with no knowledge of the underlying basis sets or data decomposition, as long as the following subroutine calls were available: \begin{enumerate} \item Application of $H$ to $\psi$-type vectors \item Application of a preconditioner to $\psi$-type vectors \item AXPY operations on $\psi$-type vectors and $\rho$-type vectors \item Inner products on $\psi$-type vectors (at least for generating the $$ matrix, possibly also for orthogonalization unless that was a separate subroutine call) \item Generating $\rho$ from $\psi_i$, and modifying $V_{xc}$ and $V_{Hartree}$ accordingly, to complete the self-consistent loop. \end{enumerate} In addition, a diagonalization routine for $2 n\times 2 n$ matrices is needed, and probably should be done in parallel in accordance with the orbital decomposition of the data. \section{Energy and forces} At the highest level, an API that calls on the electronic energy minimization to generate the energy and forces for a particular configuration of atoms might be workable, and would certainly be useful. This would facilitate rapid comparison of different methods for a particular problem, in addition to providing a natural interface for standard molecular dynamics codes. Input to such a high level API would include: \begin{enumerate} \item Geometry - atomic configuration \item Basis set, pseudopotential specifications (data decomp?) \item (Optionally) Trial set of orbitals \item Convergence parameters: iteration method, maximum number of iterations, tolerance on the final numbers \end{enumerate} Output would of course be energy and forces, as well as (optionally) a final set of orbitals for restarting, and a flag specifying whether the convergence tolerance was actually reached. In addition, I think it would be important to have callable routines that estimate (or at least keep track of) memory usage and time per iteration, to allow analysis of resource utilization by the calling program. To do the estimate means having some kind of performance model of the code - we do already have such a thing for the memory usage, but have never tried it for timing... \end{document} \bye