• Main Page
  • Classes
  • Files
  • File List
  • File Members

fftsrc/ath_fft.c

Go to the documentation of this file.
00001 /*============================================================================*/
00002 /*! \file ath_fft.c
00003  *  \brief Simple wrappers for 2D and 3D FFT functions. 
00004  *
00005  * PURPOSE:  Simple wrappers for 2D and 3D FFT functions.  These exist to
00006  *   hide the differences in function calls needed for single processor vs
00007  *   MPI FFT calls.  If you're concerned about performance, or want
00008  *   additional functionality, use these functions as examples to either
00009  *   write your own wrappers or to use the FFTW and/or block decomposition
00010  *   libraries directly.
00011  *
00012  * CONTAINS PUBLIC FUNCTIONS:
00013  * - ath_3d_fft_quick_plan()   - create a plan for global 3D grid
00014  * - ath_3d_fft_create_plan()  - create a more flexible plan for 3D FFT
00015  * - ath_3d_fft_malloc()       - allocate memory for 3D FFT data
00016  * - ath_3d_fft()              - perform a 3D FFT
00017  * - ath_3d_fft_free()         - free memory for 3D FFT data
00018  * - ath_3d_fft_destroy_plan() - free up memory
00019  * - ath_2d_fft_quick_plan()   - create a plan for global 2D grid (Nx3=1)
00020  * - ath_2d_fft_create_plan()  - create a more flexible plan for 2D FFT
00021  * - ath_2d_fft_malloc()       - allocate memory for 2D FFT data
00022  * - ath_2d_fft()              - perform a 2D FFT
00023  * - ath_2d_fft_free()         - free memory for 2D FFT data
00024  * - ath_2d_fft_destroy_plan() - free up memory                               */
00025 /*============================================================================*/
00026 
00027 #include <stdlib.h>
00028 #include "../defs.h"
00029 #include "../athena.h"
00030 #include "../prototypes.h"
00031 #include "../globals.h"
00032 
00033 #ifdef FFT_ENABLED
00034 
00035 #ifdef FFT_BLOCK_DECOMP
00036 /* Include Steve Plimpton's FFTW interface code */
00037 #include "fft_3d.h"
00038 #include "fft_2d.h"
00039 #else /* FFT_BLOCK_DECOMP */
00040 /* For a single processor, use FFTW directly */
00041 #include "fftw3.h"
00042 #endif /* FFT_BLOCK_DECOMP */
00043 
00044 /**************************************************************************
00045  *
00046  *  Athena 3D FFT functions
00047  *
00048  **************************************************************************/
00049 
00050 /*! \fn struct ath_3d_fft_plan *ath_3d_fft_quick_plan(DomainS *pD,
00051  *      ath_fft_data *data, ath_fft_direction dir)
00052  *  \brief Sets up an FFT plan for the entire 3D grid, using
00053  *      ath_3d_fft_create_plan()
00054  */
00055 
00056 struct ath_3d_fft_plan *ath_3d_fft_quick_plan(DomainS *pD,
00057                                 ath_fft_data *data, ath_fft_direction dir)
00058 {
00059   GridS *pGrid = (pD->Grid);
00060   /* Get size of global FFT grid */
00061   int gnx1 = pD->Nx[0];
00062   int gnx2 = pD->Nx[1];
00063   int gnx3 = pD->Nx[2];
00064 
00065   /* Get extents of local FFT grid in global coordinates */
00066   int gis = pD->Disp[0];
00067   int gie = pD->Disp[0] + pGrid->Nx[0];
00068   int gjs = pD->Disp[1];
00069   int gje = pD->Disp[1] + pGrid->Nx[1];
00070   int gks = pD->Disp[2];
00071   int gke = pD->Disp[2] + pGrid->Nx[2];
00072 
00073   /* Create the plan using a more generic function.
00074    * If the data hasn't already been allocated, it will now */
00075   return ath_3d_fft_create_plan(gnx3, gnx2, gnx1, gks, gke, gjs, gje,
00076                                    gis, gie, data, 0, dir);
00077 }
00078 
00079 /*! \fn struct ath_3d_fft_plan *ath_3d_fft_create_plan(int gnx3, int gnx2,
00080  *                              int gnx1, int gks, int gke, int gjs, int gje,
00081  *                              int gis, int gie, ath_fft_data *data, int al,
00082  *                              ath_fft_direction dir)
00083  *  \brief Sets up a 3D FFT plan
00084  *
00085  *  - gnx3, gnx2, gnx1 are the dimensions of the GLOBAL data
00086  *  - gks, gke, gjs, gje, gis, gie are the starting and ending indices of
00087  *      the LOCAL data in GLOBAL coordinates
00088  *  - data is any array of type ath_fft_data big enough to hold entire
00089  *      transform, for use in planning (contents will be trashed)
00090  *  - al != 0 means allocate data if it doesn't exist (otherwise temporary)
00091  *  - dir is either ATH_FFT_FOWARD or ATH_FFT_BACKWARD
00092  *  FFTs will be done in place (overwrite data)
00093  */
00094 
00095 struct ath_3d_fft_plan *ath_3d_fft_create_plan(int gnx3, int gnx2,
00096                                 int gnx1, int gks, int gke, int gjs, int gje,
00097                                 int gis, int gie, ath_fft_data *data, int al,
00098                                 ath_fft_direction dir)
00099 {
00100   int nbuf, tmp;
00101   struct ath_3d_fft_plan *ath_plan;
00102 
00103   if ((dir != ATH_FFT_FORWARD) && (dir != ATH_FFT_BACKWARD)) {
00104     ath_error("Invalid Athena FFT direction.\n");
00105   }
00106 
00107   /* Allocate memory for the plan */
00108   ath_plan = (struct ath_3d_fft_plan *)malloc(sizeof(struct ath_3d_fft_plan));
00109   if (ath_plan == NULL) {
00110     ath_error("Couldn't malloc for FFT plan.");
00111   }
00112   /* Set forward/backward FFT */
00113   ath_plan->dir = dir;
00114   /* Set element count (for easy malloc and memset) */
00115   ath_plan->cnt = (gke-gks+1)*(gje-gjs+1)*(gie-gis+1);
00116   ath_plan->gcnt = gnx3*gnx2*gnx1;
00117 
00118   tmp = (al==0 ? 1 : 0);
00119   if (data != NULL) tmp = 0;
00120 
00121   /* If data == NULL, then allocate something (temporarily if tmp=1) */
00122   if (data == NULL)
00123     data = (ath_fft_data *)ath_3d_fft_malloc(ath_plan);
00124   if (data == NULL)
00125     ath_error("Couln't malloc for FFT plan data.");
00126 
00127   /* Create the plan */
00128 #ifdef FFT_BLOCK_DECOMP
00129   /* Block decomp library plans don't care if forward or backward */
00130   ath_plan->plan = fft_3d_create_plan(MPI_COMM_WORLD, gnx3, gnx2, gnx1, 
00131                                         gks, gke, gjs, gje, gis, gie, 
00132                                         gks, gke, gjs, gje, gis, gie, 
00133                                         0, 0, &nbuf);
00134 #else /* FFT_BLOCK_DECOMP */
00135   if (dir == ATH_FFT_FORWARD) {
00136     ath_plan->plan = fftw_plan_dft_3d(gnx1, gnx2, gnx3, data, data,
00137                                         FFTW_FORWARD, FFTW_MEASURE);
00138   } else {
00139     ath_plan->plan = fftw_plan_dft_3d(gnx1, gnx2, gnx3, data, data,
00140                                         FFTW_BACKWARD, FFTW_MEASURE);
00141   }
00142 #endif /* FFT_BLOCK_DECOMP */
00143 
00144   if (tmp) ath_3d_fft_free(data);
00145 
00146   return ath_plan;
00147 }
00148 
00149 /*! \fn ath_fft_data *ath_3d_fft_malloc(struct ath_3d_fft_plan *ath_plan)
00150  *  \brief Easy allocation of data array needed for particular 3D plan 
00151  */
00152 
00153 ath_fft_data *ath_3d_fft_malloc(struct ath_3d_fft_plan *ath_plan)
00154 {
00155   return (ath_fft_data *)fftw_malloc(sizeof(ath_fft_data) * ath_plan->cnt);
00156 }
00157 
00158 /*! \fn void ath_3d_fft(struct ath_3d_fft_plan *ath_plan, ath_fft_data *data)
00159  *  \brief Performs a 3D FFT in place
00160  */
00161 
00162 void ath_3d_fft(struct ath_3d_fft_plan *ath_plan, ath_fft_data *data)
00163 {
00164 #ifdef FFT_BLOCK_DECOMP
00165   fft_3d(data, data, ath_plan->dir, ath_plan->plan);
00166 #else /* FFT_BLOCK_DECOMP */
00167   /* Plan already includes forward/backward */
00168   fftw_execute_dft(ath_plan->plan, data, data);
00169 #endif /* FFT_BLOCK_DECOMP */
00170 
00171   return;
00172 }
00173 
00174 /*! \fn void ath_3d_fft_free(ath_fft_data *data)
00175  *  \brief Frees memory used to hold data for 3D FFT
00176  */
00177 
00178 void ath_3d_fft_free(ath_fft_data *data)
00179 {
00180   if (data != NULL) fftw_free((void*)data);
00181 
00182   return;
00183 }
00184 
00185 /*! \fn void ath_3d_fft_destroy_plan(struct ath_3d_fft_plan *ath_plan)
00186  *  \brief Frees a 3D FFT plan
00187  */
00188 
00189 void ath_3d_fft_destroy_plan(struct ath_3d_fft_plan *ath_plan)
00190 {
00191   if (ath_plan != NULL) {
00192 #ifdef FFT_BLOCK_DECOMP
00193     fft_3d_destroy_plan(ath_plan->plan);
00194 #else /* FFT_BLOCK_DECOMP */
00195     fftw_destroy_plan(ath_plan->plan);
00196 #endif /* FFT_BLOCK_DECOMP */
00197     free(ath_plan);
00198   }
00199 
00200   return;
00201 }
00202 
00203 /**************************************************************************
00204  *
00205  *  Athena 2D FFT functions
00206  *
00207  **************************************************************************/
00208 
00209 /*! \fn struct ath_2d_fft_plan *ath_2d_fft_quick_plan(DomainS *pD,
00210  *                              ath_fft_data *data, ath_fft_direction dir)
00211  *  \brief Sets up an FFT plan for the entire 2D grid, assuming NX3=1, using
00212  *      ath_2d_fft_create_plan()
00213  */
00214 
00215 struct ath_2d_fft_plan *ath_2d_fft_quick_plan(DomainS *pD,
00216                                 ath_fft_data *data, ath_fft_direction dir)
00217 {
00218   GridS *pGrid=(pD->Grid);
00219   if (pGrid->Nx[2] != 1) {
00220     ath_error("ath_2d_fft_quick_plan only works for Nx3=1.\n");
00221   }
00222 
00223   /* Get size of global FFT grid */
00224   int gnx1 = pD->Nx[0];
00225   int gnx2 = pD->Nx[1];
00226 
00227   /* Get extents of local FFT grid in global coordinates */
00228   int gis = pD->Disp[0];
00229   int gie = pD->Disp[0] + pGrid->Nx[0];
00230   int gjs = pD->Disp[1];
00231   int gje = pD->Disp[1] + pGrid->Nx[1];
00232 
00233   /* Create the plan using a more generic function
00234    * If the data hasn't already been allocated, it will now */
00235   return ath_2d_fft_create_plan(gnx2, gnx1, gjs, gje, gis, gie, data, 0, dir);
00236 }
00237 
00238 /*! \fn struct ath_2d_fft_plan *ath_2d_fft_create_plan(int gnx2, int gnx1,
00239  *                              int gjs, int gje, int gis, int gie,
00240  *                              ath_fft_data *data, int al,
00241  *                              ath_fft_direction dir)
00242  *  \brief Sets up a 2D FFT plan
00243  *
00244  *  - gnx2, gnx1 are the dimensions of the GLOBAL data
00245  *  - gjs, gje, gis, gie are the starting and ending indices of the
00246  *      LOCAL data in GLOBAL coordinates
00247  *  - dir is either ATH_FFT_FOWARD or ATH_FFT_BACKWARD
00248  *  FFTs will be done in place (overwrite data)
00249  */
00250 
00251 struct ath_2d_fft_plan *ath_2d_fft_create_plan(int gnx2, int gnx1,
00252                                 int gjs, int gje, int gis, int gie,
00253                                 ath_fft_data *data, int al,
00254                                 ath_fft_direction dir)
00255 {
00256   int nbuf, tmp;
00257   struct ath_2d_fft_plan *ath_plan;
00258 
00259   if ((dir != ATH_FFT_FORWARD) && (dir != ATH_FFT_BACKWARD)) {
00260     ath_error("Invalid Athena FFT direction.\n");
00261   }
00262 
00263   /* Allocate memory for plan */
00264   ath_plan = (struct ath_2d_fft_plan *)malloc(sizeof(struct ath_2d_fft_plan));
00265   if (ath_plan == NULL) {
00266     ath_error("Couldn't malloc for FFT plan.");
00267   }
00268   /* Set forward/backward FFT */
00269   ath_plan->dir = dir;
00270   /* Set element count (for easy malloc and memset) */
00271   ath_plan->cnt = (gje-gjs+1)*(gie-gis+1);
00272   ath_plan->gcnt = gnx2*gnx1;
00273 
00274   tmp = (al==0 ? 1 : 0);
00275   if (data != NULL) tmp = 0;
00276 
00277   /* If data == NULL, then allocate something (temporarily if tmp=1) */
00278   if (data == NULL)
00279     data = (ath_fft_data *)ath_2d_fft_malloc(ath_plan);
00280   if (data == NULL)
00281     ath_error("Couln't malloc for FFT plan data.");
00282 
00283   /* Create the plan */
00284 #ifdef FFT_BLOCK_DECOMP
00285   /* Block decomp plans don't care if forward/backward */
00286   ath_plan->plan = fft_2d_create_plan(MPI_COMM_WORLD, gnx2, gnx1, gjs, gje,
00287                                         gis, gie, gjs, gje, gis, gie, 
00288                                         0, 0, &nbuf);
00289 #else /* FFT_BLOCK_DECOMP */
00290   if (dir == ATH_FFT_FORWARD) {
00291     ath_plan->plan = fftw_plan_dft_2d(gnx1, gnx2, data, data, FFTW_FORWARD,
00292                                         FFTW_MEASURE);
00293   } else {
00294     ath_plan->plan = fftw_plan_dft_2d(gnx1, gnx2, data, data, FFTW_BACKWARD,
00295                                         FFTW_MEASURE);
00296   }
00297 #endif /* FFT_BLOCK_DECOMP */
00298 
00299   if (tmp) ath_2d_fft_free(data);
00300 
00301   return ath_plan;
00302 }
00303 
00304 /*! \fn ath_fft_data *ath_2d_fft_malloc(struct ath_2d_fft_plan *ath_plan)
00305  *  \brief Easy allocation of data array needed for particular 2D plan
00306  */
00307 
00308 ath_fft_data *ath_2d_fft_malloc(struct ath_2d_fft_plan *ath_plan)
00309 {
00310   return (ath_fft_data *)fftw_malloc(sizeof(ath_fft_data) * ath_plan->cnt);
00311 }
00312 
00313 
00314 /*! \fn void ath_2d_fft(struct ath_2d_fft_plan *ath_plan, fftw_complex *data)
00315  *  \brief Performs a 2D FFT in place
00316  */
00317 
00318 void ath_2d_fft(struct ath_2d_fft_plan *ath_plan, fftw_complex *data)
00319 {
00320 #ifdef FFT_BLOCK_DECOMP
00321   fft_2d(data, data, ath_plan->dir, ath_plan->plan);
00322 #else /* FFT_BLOCK_DECOMP */
00323   /* Plan already includes forward/backward */
00324   fftw_execute_dft(ath_plan->plan, data, data);
00325 #endif /* FFT_BLOCK_DECOMP */
00326 
00327   return;
00328 }
00329 
00330 /*! \fn void ath_2d_fft_free(ath_fft_data *data)
00331  *  \brief Frees memory used to hold data for 2D FFT
00332  */
00333 
00334 void ath_2d_fft_free(ath_fft_data *data)
00335 {
00336   if (data != NULL) fftw_free((void*)data);
00337 
00338   return;
00339 }
00340 
00341 /*! \fn void ath_2d_fft_destroy_plan(struct ath_2d_fft_plan *ath_plan)
00342  *  \brief Frees a 2D FFT plan
00343  */
00344 
00345 void ath_2d_fft_destroy_plan(struct ath_2d_fft_plan *ath_plan)
00346 {
00347   if (ath_plan != NULL) {
00348 #ifdef FFT_BLOCK_DECOMP
00349     fft_2d_destroy_plan(ath_plan->plan);
00350 #else /* FFT_BLOCK_DECOMP */
00351     fftw_destroy_plan(ath_plan->plan);
00352 #endif /* FFT_BLOCK_DECOMP */
00353     free(ath_plan);
00354   }
00355 
00356   return;
00357 }
00358 
00359 #endif /* FFT_ENABLED */

Generated on Mon Sep 27 2010 23:03:07 for Athena by  doxygen 1.7.1