/* DFT++ is a density functional package developed by the research group of Professor Tomas Arias Copyright 1996-2003 Sohrab Ismail-Beigi This file is part of DFT++. DFT++ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. DFT++ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with DFT++; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Please see the file CREDITS for a list of authors. For academic users, we request that publications using results obtained with this software reference "New algebraic formulation of density functional calculation," by Sohrab Ismail-Beigi and T.A. Arias, Computer Physics Communications 128:1-2, 1-45 (June 2000). and, if using the wavelet basis, further reference "Multiresolution analysis of electronic structure: semicardinal and wavelet bases," T.A. Arias, Reviews of Modern Physics 71:1, 267-311 (January 1999). and "Robust ab initio calculation of condensed matter: transparent convergence through semicardinal multiresolution analysis,'' I.P. Daykov, T.A. Arias, and Torkel D. Engeness, Physical Review Letters, 90:21, 216402 (May 2003). For your convenience, preprints of the above articles may be obtained from http://arXiv.org/abs/cond-mat/9909130, 9805262, and 0204411, respectively. */ #include "header.h" void apply_O(const PW_ComplexColumn &c, PW_ComplexColumn &Oc) { #ifdef DFT_PROFILING timerOn(29); // turn on O timer #endif // DFT_PROFILING if(&c!=&Oc) Oc = c; #ifdef DFT_PROFILING timerOff(29); // turn off O timer #endif // DFT_PROFILING } void apply_Obar(const PW_ComplexColumn &c, PW_ComplexColumn &Obarc) { if(c.representation == REALSPACE) die("Trying to take Obar of realspace column!\n"); if(&c != &Obarc) Obarc = c; Obarc.data.d[0].x = 0.0; return; } void apply_L(const PW_ComplexColumn &c, PW_ComplexColumn &Lc) { #ifdef DFT_PROFILING timerOn(31); // turn on L timer #endif // DFT_PROFILING if(c.representation == REALSPACE) die("Trying to take L of realspace column!\n"); Lc.representation=c.representation; int i,j,k, nbasis; int Nx,Ny,Nz,Nx2,Ny2,Nz2,NyNz, index; real kplusGx,kplusGy,kplusGz,kx,ky,kz; real GGTxx,GGTyy,GGTzz,GGTxy,GGTxz,GGTyz; real kplusG2, G2; Basis *basis = c.basis; Lattice *lattice = basis->basis_spec->lattice; if (basis == NULL) die("apply_L() called with c.basis == NULL\n"); if ( c.length!=Lc.length ) die("apply_L() called with different sizes for c and Lc\n"); GGTxx = lattice->GGT.m[0][0]; GGTyy = lattice->GGT.m[1][1]; GGTzz = lattice->GGT.m[2][2]; GGTxy = lattice->GGT.m[0][1]; GGTxz = lattice->GGT.m[0][2]; GGTyz = lattice->GGT.m[1][2]; /* * we need to decide if we have to compute G vectors, or if they * are stored for us. */ if(basis->Gx == NULL || basis->Gy == NULL || basis->Gz == NULL){ // we compute G vectors Nx = basis->basis_spec->Nx; Nx2 = Nx/2; Ny = basis->basis_spec->Ny; Ny2 = Ny/2; Nz = basis->basis_spec->Nz; Nz2 = Nz/2; NyNz = Ny*Nz; for (i=-Nx2; i < Nx2; i++) for (j=-Ny2; j < Ny2; j++) for (k=-Nz2; k < Nz2; k++) { index = 0; if (k < 0) index += k+Nz; else index += k; if (j < 0) index += Nz*(j+Ny); else index += Nz*j; if (i < 0) index += NyNz*(i+Nx); else index += NyNz*i; G2 = i*i*GGTxx + j*j*GGTyy + k*k*GGTzz + 2*(i*j*GGTxy + i*k*GGTxz + j*k*GGTyz); Lc.data.d[index] = -G2*c.data.d[index]; } } else { // G vectors are stored // make sure we have a quantum number if(basis->qnum == NULL) die("In apply_L() G vectors are not stored and qnum == NULL\n"); kx = basis->qnum->kvec.v[0]; ky = basis->qnum->kvec.v[1]; kz = basis->qnum->kvec.v[2]; nbasis = basis->nbasis; for (j=0; j < nbasis; j++){ kplusGx = kx + basis->Gx[j]; kplusGy = ky + basis->Gy[j]; kplusGz = kz + basis->Gz[j]; kplusG2 = (kplusGx*kplusGx*GGTxx + kplusGy*kplusGy*GGTyy + kplusGz*kplusGz*GGTzz + 2*(kplusGx*kplusGy*GGTxy + kplusGx*kplusGz*GGTxz + kplusGy*kplusGz*GGTyz )); Lc.data.d[j] = -kplusG2*c.data.d[j]; } } #ifdef DFT_PROFILING timerOff(31); // turn off L timer #endif // DFT_PROFILING } /* * The inverse of the Laplacian on vectors: the is obviously modulo * G=0 where there are infinities. For planewaves, we have -1/|G|^2. */ void apply_invL(const PW_ComplexColumn &c, PW_ComplexColumn &invLc) { #ifdef DFT_PROFILING timerOn(32); // turn on invL timer #endif // DFT_PROFILING int Nx,Ny,Nz,Nx2,Ny2,Nz2,NyNz; int i,j,k,index; real G2,GGTxx,GGTxy,GGTxz,GGTyy,GGTyz,GGTzz; BasisSpec *spec; Lattice *lattice; if (c.basis == 0) die("invL(vector) called with v.basis==0\n"); if (c.length != c.basis_spec->NxNyNz) die("invL(vector) called with vector.n != FFT box size\n"); if ((c.basis_spec->Nx%2)!=0 || (c.basis_spec->Ny%2)!=0 || (c.basis_spec->Nz%2)!=0) die("invL(vector) called with basis->Nx,Ny,or Nz not a multiple of 2\n"); spec=c.basis_spec; lattice = spec->lattice; Nx = spec->Nx; Nx2 = Nx/2; Ny = spec->Ny; Ny2 = Ny/2; Nz = spec->Nz; Nz2 = Nz/2; NyNz = Ny*Nz; GGTxx = lattice->GGT.m[0][0]; GGTyy = lattice->GGT.m[1][1]; GGTzz = lattice->GGT.m[2][2]; GGTxy = lattice->GGT.m[0][1]; GGTxz = lattice->GGT.m[0][2]; GGTyz = lattice->GGT.m[1][2]; for (i=-Nx2; i < Nx2; i++) for (j=-Ny2; j < Ny2; j++) for (k=-Nz2; k < Nz2; k++) { /* G = 0 case */ if (i==0 && j==0 && k==0) invLc.data.d[0] = 0.0; else { index = 0; if (k < 0) index += k+Nz; else index += k; if (j < 0) index += Nz*(j+Ny); else index += Nz*j; if (i < 0) index += NyNz*(i+Nx); else index += NyNz*i; G2 = i*i*GGTxx + j*j*GGTyy + k*k*GGTzz + 2*(i*j*GGTxy + i*k*GGTxz + j*k*GGTyz); invLc.data.d[index] = -c.data.d[index]/G2; } } #ifdef DFT_PROFILING timerOff(32); // turn off invL timer #endif // DFT_PROFILING return; }