/* 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. */ /* * ft.c: Sohrab Ismail-Beigi 7/18/96, 4/7/97 * * A set of routines to do discrete Fourier transforms on 1D and 3D boxes. * * * The routines now use the FFTW package from the MIT LCS written by * Steven G. Johnson and Matteo Frigo. * * void FFT3D() -- Uses FFTW */ /* $Id: ft.cpp,v 1.8.2.3 2003/05/29 18:54:25 ivan Exp $ */ #include "header.h" /* * Include the FFTW header and also define two routines which allow us * to make usable duplicates of plans for in-place transforms. * Courtesy of Steven G. Johnson. */ #include "fftw.h" /* * This is a 3D FFT which uses the FFTW package. * * The transform performed is: * * if (sign == -1) * data(kx,ky,kz) <- sum_(x,y,z) { exp(-i*k.r))*data(x,y,z) } / (nx*ny*nz) * * if (sign == 1) * data(x,y,z) <- sum_(kx,ky,kz) { exp(i*k.r))*data(kx,ky,kz) } * * nx, ny, nz: size of FFT box * * FFTW routines do not divide by (nx*ny*nz) in the sign==-1 case, so * I do it by hand. * * The plus_- and minus_plan's are static so that we do the setup only once * and on all future calls on FFT boxes of the same size we use those * plans. * * NOTE: setupFFT3D() must be called before using FFT3D(). * */ /* Plans used by FFT3D...they are created by setupFFT3D() */ static int plan_nx,plan_ny,plan_nz; static fftwnd_plan plus_plan,minus_plan; static int FFTWsetupwasdone = 0; void setupFFT3D(int nx,int ny,int nz) { plan_nx = nx; plan_ny = ny; plan_nz = nz; dft_log("----- setupFFT3D() -----\nSetting up the FFTW subsystem\n"); dft_log("Box size: %d x %d x %d\n", nx, ny, nz); dft_log_flush(); plus_plan = fftw3d_create_plan(nx,ny,nz, FFTW_BACKWARD, FFTW_MEASURE|FFTW_IN_PLACE| FFTW_THREADSAFE|FFTW_USE_WISDOM); minus_plan = fftw3d_create_plan(nx,ny,nz, FFTW_FORWARD, FFTW_MEASURE|FFTW_IN_PLACE| FFTW_THREADSAFE|FFTW_USE_WISDOM); if (!plus_plan || !minus_plan) die("\nCan't create plans for FFTW in setupFFT3D()\n\n"); FFTWsetupwasdone = 1; dft_log_flush(); dft_log("FFTW setup done\n"); dft_log_flush(); } void FFT3D(int nx,int ny,int nz,complex *data,int sign) { #ifdef DFT_PROFILING timerOn(40); // FFT3D timer counterIncr(16); #endif if (!FFTWsetupwasdone) die("\n\nFFTW setup was not called! Call setupFFT3D() first!\n\n"); if (nx != plan_nx || ny != plan_ny || nz != plan_nz) die("\n\nFFT3D() called with sizes different from the static plans!\n\n"); if (sign == 1) { fftwnd(plus_plan,1,(FFTW_COMPLEX *)data,1,0,NULL,0,0); } else if (sign == -1) { fftwnd(minus_plan,1,(FFTW_COMPLEX *)data,1,0,NULL,0,0); const int nxyz = nx*ny*nz; const real scale = (real)1.0/(real)(nx*ny*nz); int i; for (i=0; i < nxyz; i++) { data[i].x *= scale; data[i].y *= scale; } } #ifdef DFT_PROFILING timerOff(40); // FFT3D timer #endif }