src/FFT/SCSL_FFT.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 #ifndef IPPL_FFT_SCSL_FFT_H
00012 #define IPPL_FFT_SCSL_FFT_H
00013 
00014 // include files
00015 #include "Utility/PAssert.h"
00016 #include "Utility/IpplInfo.h"
00017 
00018 
00019 /**************************************************************************
00020  * SCSL_FFT.h:  Prototypes for accessing Fortran 1D FFT routines from the
00021  * SGI/Cray Scientific Library, and definitions for templated class SCSL,
00022  * which acts as an FFT engine for the FFT class, providing storage for
00023  * trigonometric information and performing the 1D FFTs as needed.
00024  **************************************************************************/
00025 
00026 
00027 // For platforms that do Fortran symbols in all caps.
00028 #if defined(IPPL_T3E)
00029 
00030 #define sgiccfft_ SGICCFFT
00031 #define sgiscfft_ SGISCFFT
00032 #define sgicsfft_ SGICSFFT
00033 
00034 #endif
00035 
00036 // SCSL Fortran wrapper function prototypes
00037 // These functions are defined in file SCSL_FFT.F, and they just turn
00038 // around and call the native library routines.
00039 
00040 #if defined(IPPL_T3E)
00041 
00042 // Cray T3E has only "real" routines, which are automatically double precision
00043 extern "C" {
00044   // double-precision CC FFT
00045   void sgiccfft_(int& isign, int& n, double& scale, double& x, double& y,
00046                  double& table, double& work, int& isys);
00047   // double-precision RC FFT
00048   void sgiscfft_(int& isign, int& n, double& scale, double& x, double& y,
00049                  double& table, double& work, int& isys);
00050   // double-precision CR FFT
00051   void sgicsfft_(int& isign, int& n, double& scale, double& x, double& y,
00052                  double& table, double& work, int& isys);
00053 }
00054 
00055 #else
00056 
00057 // SGI offers separate single- and double-precision routines
00058 extern "C" {
00059   // double-precision CC FFT
00060   void sgizzfft_(int& isign, int& n, double& scale, double& x, double& y,
00061                  double& table, double& work, int& isys);
00062   // double-precision RC FFT
00063   void sgidzfft_(int& isign, int& n, double& scale, double& x, double& y,
00064                  double& table, double& work, int& isys);
00065   // double-precision CR FFT
00066   void sgizdfft_(int& isign, int& n, double& scale, double& x, double& y,
00067                  double& table, double& work, int& isys);
00068   // single-precision CC FFT
00069   void sgiccfft_(int& isign, int& n, float& scale, float& x, float& y,
00070                  float& table, float& work, int& isys);
00071   // single-precision RC FFT
00072   void sgiscfft_(int& isign, int& n, float& scale, float& x, float& y,
00073                  float& table, float& work, int& isys);
00074   // single-precision CR FFT
00075   void sgicsfft_(int& isign, int& n, float& scale, float& x, float& y,
00076                  float& table, float& work, int& isys);
00077 }
00078 
00079 #endif // defined(IPPL_T3E)
00080 
00081 
00082 // SCSL_wrap provides static functions that wrap the Fortran functions
00083 // in a common interface.  We specialize this class on precision type.
00084 template <class T>
00085 class SCSL_wrap {};
00086 
00087 // Specialization for float
00088 template <>
00089 class SCSL_wrap<float> {
00090 
00091 public:
00092   // interface functions used by class SCSL
00093 
00094   // complex-to-complex FFT
00095   static void ccfft(int isign, int n, float scale, float* x, float* y,
00096                     float* table, float* work, int isys) {
00097     sgiccfft_(isign, n, scale, *x, *y, *table, *work, isys);
00098   }
00099   // real-to-complex FFT
00100   static void rcfft(int isign, int n, float scale, float* x, float* y,
00101                     float* table, float* work, int isys) {
00102     sgiscfft_(isign, n, scale, *x, *y, *table, *work, isys);
00103   }
00104   // complex-to-real FFT
00105   static void crfft(int isign, int n, float scale, float* x, float* y,
00106                     float* table, float* work, int isys) {
00107     sgicsfft_(isign, n, scale, *x, *y, *table, *work, isys);
00108   }
00109 
00110 };
00111 
00112 
00113 // Specialization for double
00114 
00115 #if defined(IPPL_T3E)
00116 
00117 // Cray T3E uses single-precision function names for double-precision FFTs
00118 template <>
00119 class SCSL_wrap<double> {
00120 
00121 public:
00122   // interface functions used by class SCSL
00123 
00124   // complex-to-complex FFT
00125   static void ccfft(int isign, int n, double scale, double* x, double* y,
00126                     double* table, double* work, int isys) {
00127     sgiccfft_(isign, n, scale, *x, *y, *table, *work, isys);
00128   }
00129   // real-to-complex FFT
00130   static void rcfft(int isign, int n, double scale, double* x, double* y,
00131                     double* table, double* work, int isys) {
00132     sgiscfft_(isign, n, scale, *x, *y, *table, *work, isys);
00133   }
00134   // complex-to-real FFT
00135   static void crfft(int isign, int n, double scale, double* x, double* y,
00136                     double* table, double* work, int isys) {
00137     sgicsfft_(isign, n, scale, *x, *y, *table, *work, isys);
00138   }
00139 
00140 };
00141 
00142 #else
00143 
00144 // SGI has special FFT routines for double-precision
00145 template <>
00146 class SCSL_wrap<double> {
00147 
00148 public:
00149   // interface functions used by class SCSL
00150 
00151   // complex-to-complex FFT
00152   static void ccfft(int isign, int n, double scale, double* x, double* y,
00153                     double* table, double* work, int isys) {
00154     sgizzfft_(isign, n, scale, *x, *y, *table, *work, isys);
00155   }
00156   // real-to-complex FFT
00157   static void rcfft(int isign, int n, double scale, double* x, double* y,
00158                     double* table, double* work, int isys) {
00159     sgidzfft_(isign, n, scale, *x, *y, *table, *work, isys);
00160   }
00161   // complex-to-real FFT
00162   static void crfft(int isign, int n, double scale, double* x, double* y,
00163                     double* table, double* work, int isys) {
00164     sgizdfft_(isign, n, scale, *x, *y, *table, *work, isys);
00165   }
00166 
00167 };
00168 
00169 #endif  // defined(IPPL_T3E)
00170 
00171 
00172 // Definition of FFT engine class SCSL
00173 template <class T>
00174 class SCSL {
00175 
00176 public:
00177 
00178   // definition of complex type
00179 #ifdef IPPL_HAS_TEMPLATED_COMPLEX
00180   typedef complex<T> Complex_t;
00181 #else
00182   typedef complex Complex_t;
00183 #endif
00184 
00185   // Trivial constructor.  Do the real work in setup function.
00186   SCSL(void) {}
00187 
00188   // destructor
00189   ~SCSL(void);
00190 
00191   // setup internal storage and prepare to do FFTs
00192   void setup(unsigned numTransformDims, const int* transformTypes,
00193              const int* axisLengths);
00194 
00195   // invoke FFT on complex data for given dimension and direction
00196   void callFFT(unsigned transformDim, int direction, Complex_t* data);
00197 
00198   // invoke FFT on real data for given dimension and direction
00199   void callFFT(unsigned transformDim, int direction, T* data);
00200 
00201 private:
00202 
00203   unsigned numTransformDims_m;  // number of dimensions to transform
00204   int* transformType_m;         // type of transform for each dimension
00205   int* axisLength_m;            // length along each dimension
00206   T** table_m;                  // tables of trigonometric factors
00207   T** work_m;                   // workspace arrays
00208 
00209 };
00210 
00211 
00212 // Inline member function definitions
00213 
00214 // destructor
00215 template <class T>
00216 inline
00217 SCSL<T>::~SCSL(void) {
00218   // delete storage
00219   for (unsigned d=0; d<numTransformDims_m; ++d) {
00220     delete [] table_m[d];
00221     delete [] work_m[d];
00222   }
00223   delete [] table_m;
00224   delete [] work_m;
00225   delete [] transformType_m;
00226   delete [] axisLength_m;
00227 }
00228 
00229 // setup internal storage and prepare for doing FFTs
00230 template <class T>
00231 inline void
00232 SCSL<T>::setup(unsigned numTransformDims, const int* transformTypes,
00233                const int* axisLengths) {
00234 
00235   // store transform types and lengths for each transform dim
00236   numTransformDims_m = numTransformDims;
00237   transformType_m = new int[numTransformDims_m];
00238   axisLength_m = new int[numTransformDims_m];
00239   unsigned d;
00240   for (d=0; d<numTransformDims_m; ++d) {
00241     transformType_m[d] = transformTypes[d];
00242     axisLength_m[d] = axisLengths[d];
00243   }
00244 
00245   // allocate trig table and workspace arrays and initialize table
00246   // table and work array sizes vary for the Cray T3E and the SGI Origin 2000
00247   table_m = new T*[numTransformDims_m];
00248   work_m = new T*[numTransformDims_m];
00249   T dummy = T();
00250   for (d=0; d<numTransformDims_m; ++d) {
00251     switch (transformType_m[d]) {
00252     case 0:  // CC FFT
00253 #if defined(IPPL_T3E)
00254       table_m[d] = new T[2 * axisLength_m[d]];
00255       work_m[d] = new T[4 * axisLength_m[d]];
00256 #else
00257       table_m[d] = new T[2 * axisLength_m[d] + 30];
00258       work_m[d] = new T[2 * axisLength_m[d]];
00259 #endif
00260       // this call initializes table
00261       SCSL_wrap<T>::ccfft(0, axisLength_m[d], dummy, &dummy, &dummy,
00262                           table_m[d], &dummy, 0);
00263       break;
00264     case 1:  // RC FFT
00265 #if defined(IPPL_T3E)
00266       table_m[d] = new T[2 * axisLength_m[d]];
00267       work_m[d] = new T[2 * (axisLength_m[d] + 2)]; // extend length by two
00268 #else
00269       table_m[d] = new T[axisLength_m[d] + 15];
00270       work_m[d] = new T[axisLength_m[d] + 2];  // extend length by two reals
00271 #endif
00272       // this call initializes table
00273       SCSL_wrap<T>::rcfft(0, axisLength_m[d], dummy, &dummy, &dummy,
00274                           table_m[d], &dummy, 0);
00275       break;
00276     case 2:  // Sine transform
00277       ERRORMSG("No sine transforms available in SCSL!!" << endl);
00278       break;
00279     default:
00280       ERRORMSG("Unknown transform type requested!!" << endl);
00281       break;
00282     }
00283   }
00284 
00285   return;
00286 }
00287 
00288 // invoke FFT on complex data for given dimension and direction
00289 template <class T>
00290 inline void
00291 SCSL<T>::callFFT(unsigned transformDim, int direction,
00292                  SCSL<T>::Complex_t* data) {
00293 
00294   // check transform dimension and direction arguments
00295   PAssert(transformDim<numTransformDims_m);
00296   PAssert(direction==+1 || direction==-1);
00297 
00298   // cast complex number pointer to T* for calling Fortran routines
00299   T* rdata = reinterpret_cast<T*>(data);
00300 
00301   // branch on type of transform for this dimension
00302   switch (transformType_m[transformDim]) {
00303   case 0:  // CC FFT
00304     SCSL_wrap<T>::ccfft(direction, axisLength_m[transformDim], 1.0, rdata,
00305                         rdata, table_m[transformDim], work_m[transformDim], 0);
00306     break;
00307   case 1:  // RC FFT
00308     if (direction == +1) {  // real-to-complex
00309       SCSL_wrap<T>::rcfft(+1, axisLength_m[transformDim], 1.0, rdata, rdata,
00310                           table_m[transformDim], work_m[transformDim], 0);
00311     }
00312     else {                  // complex-to-real
00313       SCSL_wrap<T>::crfft(-1, axisLength_m[transformDim], 1.0, rdata, rdata,
00314                           table_m[transformDim], work_m[transformDim], 0);
00315     }
00316     break;
00317   case 2:  // Sine transform
00318     ERRORMSG("No sine transforms available in SCSL!!" << endl);
00319     break;
00320   default:
00321     ERRORMSG("Unknown transform type requested!!" << endl);
00322     break;
00323   }
00324 
00325   return;
00326 }
00327 
00328 
00329 // invoke FFT on real data for given dimension and direction
00330 template <class T>
00331 inline void
00332 SCSL<T>::callFFT(unsigned transformDim, int direction, T* data) {
00333 
00334   // check transform dimension argument
00335   PAssert(transformDim<numTransformDims_m);
00336   // branch on transform type for this dimension
00337   switch (transformType_m[transformDim]) {
00338   case 0:  // CC FFT
00339     ERRORMSG("complex-to-complex FFT uses complex data!!" << endl);
00340     break;
00341   case 1:  // RC FFT
00342     ERRORMSG("real-to-complex FFT uses complex data!!" << endl);
00343     break;
00344   case 2:  // Sine transform
00345     ERRORMSG("No sine transforms available in SCSL!!" << endl);
00346     break;
00347   default:
00348     ERRORMSG("Unknown transform type requested!!" << endl);
00349     break;
00350   }
00351 
00352   return;
00353 }
00354 
00355 
00356 #endif // IPPL_FFT_SCSL_FFT_H
00357 
00358 /***************************************************************************
00359  * $RCSfile: SCSL_FFT.h,v $   $Author: adelmann $
00360  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:25 $
00361  * IPPL_VERSION_ID: $Id: SCSL_FFT.h,v 1.1.1.1 2003/01/23 07:40:25 adelmann Exp $ 
00362  ***************************************************************************/
00363 

Generated on Mon Jan 16 13:23:42 2006 for IPPL by  doxygen 1.4.6