/*
This file is part of the Snoopy code.
Snoopy code 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 3 of the License, or
(at your option) any later version.
Snoopy code 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 Snoopy code. If not, see .
*/
#include "common.h"
#include "debug.h"
double fft_timer;
#ifdef MPI_SUPPORT
#ifndef FFTW3_MPI_SUPPORT
// That's a long MPI if def...
#include "transpose.h"
fftw_plan r2c_2d, c2r_2d, r2c_1d, c2r_1d;
/* GFFT (Like Geo's FFT as you might have guessed...) is an FFT wrapper for FFTW>=3.2
It takes care of the MPI part of the FFT while FFTW deals with the FFT themselves
GFFT can handle threaded FFTS (just ask...).
One concludes It's FAAAARRRR better than FFTW 2.1.5
*/
// This is an inplace real 2 complex transform
// Assumes wrin has the logical dimensions [NY/PROC, NX, NZ] of real positions
// physical dimensions [NY/NPROC, NX, NZ+2];
void gfft_r2c_t(double *wrin) {
int i;
double complex *win = (double complex *) wrin;
fft_timer = fft_timer - get_c_time();
//start transforming in 2D wrin
fftw_execute_dft_r2c(r2c_2d, wrin, win);
// The logical dimensions of win are [NY_COMPLEX/NPROC, NX_COMPLEX, NZ_COMPLEX]
// transpose it
transpose_complex_YX(win, win);
// We now have an array with logical dimensions[NX_COMPLEX/NPROC, NY_COMPLEX, NZ_COMPLEX]
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for(i=0 ; i < NX_COMPLEX/NPROC ; i++)
fftw_execute_dft(r2c_1d, &win[i*NY_COMPLEX*NZ_COMPLEX],&win[i*NY_COMPLEX*NZ_COMPLEX]);
fft_timer = fft_timer + get_c_time();
// done...
return;
}
void gfft_c2r_t(double complex *win) {
int i;
double *wrin = (double *) win;
fft_timer = fft_timer - get_c_time();
// We now have an array with logical dimensions[NX_COMPLEX/NPROC, NY_COMPLEX, NZ_COMPLEX]
#ifdef _OPENMP
#pragma omp parallel for private(i) schedule(static)
#endif
for(i=0 ; i < NX_COMPLEX/NPROC ; i++)
fftw_execute_dft(c2r_1d, &win[i*NY_COMPLEX*NZ_COMPLEX],&win[i*NY_COMPLEX*NZ_COMPLEX]);
// The logical dimensions of win are [NX_COMPLEX/NPROC, NY_COMPLEX, NZ_COMPLEX]
// transpose it
transpose_complex_XY(win, win);
// The final 2D transform
fftw_execute_dft_c2r(c2r_2d, win, wrin);
// and we're done !
fft_timer = fft_timer + get_c_time();
return;
}
// In place double transpose transforms
// Not Fast, but convenient...!
void gfft_r2c(double *wrin) {
fft_timer = fft_timer - get_c_time();
transpose_real(NX, NY, NZ+2, NPROC, wrin, wrin);
gfft_r2c_t(wrin);
fft_timer = fft_timer + get_c_time();
return;
}
void gfft_c2r(double complex *win) {
double *wrin = (double *) win;
fft_timer = fft_timer - get_c_time();
gfft_c2r_t(win);
transpose_real(NY,NX,NZ+2,NPROC,wrin,wrin);
fft_timer = fft_timer + get_c_time();
return;
}
void init_gfft() {
// This will init the plans needed by gfft
// Transform of NY/NPROC arrays of (logical) size [NX, NZ]
// The physical size is [NX, NZ+2]
// We use in-place transforms
int i;
double complex *wi1;
double *wir1;
const int n_size2D[2] = {NX, NZ};
const int n_size1D[1] = {NY_COMPLEX};
DEBUG_START_FUNC;
wi1 = (double complex *) fftw_malloc( sizeof(double complex) * NTOTAL_COMPLEX);
if (wi1 == NULL) ERROR_HANDLER( ERROR_CRITICAL, "No memory for wi1 allocation");
wir1 = (double *) wi1;
for(i = 0 ; i < NTOTAL_COMPLEX; i++) {
wi1[i]=1.0;
}
#ifdef _OPENMP
fftw_plan_with_nthreads( nthreads );
#endif
r2c_2d = fftw_plan_many_dft_r2c(2, n_size2D, NY / NPROC, wir1, NULL, 1, (NZ+2)*NX,
wi1, NULL, 1, (NZ+2)*NX/2, FFT_PLANNING);
if (r2c_2d == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW R2C_2D plan creation failed");
c2r_2d = fftw_plan_many_dft_c2r(2, n_size2D, NY / NPROC, wi1, NULL, 1, (NZ+2)*NX/2,
wir1, NULL, 1, (NZ+2)*NX , FFT_PLANNING);
if (c2r_2d == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW C2R_2D plan creation failed");
// 1D transforms: This are actually c2c transforms, but are used for global 3D transforms.
// We will transform forward and backward an array of logical size [NX/NPROC, NY, (NZ+2)/2] along the 2nd dimension
// We will do NZ_COMPLEX transforms along Y. Will need a loop on NX/NPROC
// We use &w1[NZ_COMPLEX] so that alignement check is done properly (see SIMD in fftw Documentation)
#ifdef _OPENMP
fftw_plan_with_nthreads( 1 );
#endif
r2c_1d = fftw_plan_many_dft(1, n_size1D, NZ_COMPLEX, &wi1[NZ_COMPLEX], NULL, NZ_COMPLEX, 1,
&wi1[NZ_COMPLEX], NULL, NZ_COMPLEX, 1, FFTW_FORWARD, FFT_PLANNING);
if (r2c_1d == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW R2C_1D plan creation failed");
c2r_1d = fftw_plan_many_dft(1, n_size1D, NZ_COMPLEX, &wi1[NZ_COMPLEX], NULL, NZ_COMPLEX, 1,
&wi1[NZ_COMPLEX], NULL, NZ_COMPLEX, 1, FFTW_BACKWARD, FFT_PLANNING);
if (c2r_1d == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW C2R_1D plan creation failed");
// init transpose routines
init_transpose();
// Let's see which method is faster (with our without threads)
fftw_free(wi1);
fft_timer=0.0;
DEBUG_END_FUNC;
return;
}
void finish_gfft() {
DEBUG_START_FUNC;
fftw_destroy_plan(r2c_2d);
fftw_destroy_plan(c2r_2d);
fftw_destroy_plan(c2r_1d);
fftw_destroy_plan(r2c_1d);
finish_transpose();
DEBUG_END_FUNC;
return;
}
#else
#include
fftw_plan r2cfft_mpi_t, r2cfft_mpi, c2rfft_mpi, c2rfft_mpi_t;
void gfft_r2c_t(double *wrin) {
double complex *win = (double complex *) wrin;
fft_timer = fft_timer - get_c_time();
fftw_execute_dft_r2c(r2cfft_mpi_t, wrin, win);
fft_timer = fft_timer + get_c_time();
return;
}
void gfft_c2r_t(double complex *win){
double *wrin = (double *) win;
fft_timer = fft_timer - get_c_time();
fftw_execute_dft_c2r(c2rfft_mpi_t, win, wrin);
fft_timer = fft_timer + get_c_time();
return;
}
void gfft_r2c(double *wrin) {
double complex *win = (double complex *) wrin;
fft_timer = fft_timer - get_c_time();
fftw_execute_dft_r2c(r2cfft_mpi, wrin, win);
fft_timer = fft_timer + get_c_time();
return;
}
void gfft_c2r(double complex *win){
double *wrin = (double *) win;
fft_timer = fft_timer - get_c_time();
fftw_execute_dft_c2r(c2rfft_mpi, win, wrin);
fft_timer = fft_timer + get_c_time();
return;
}
void init_gfft() {
DEBUG_START_FUNC;
#ifdef _OPENMP
fftw_plan_with_nthreads( nthreads );
#endif
r2cfft_mpi_t = fftw_mpi_plan_dft_r2c_3d( NY, NX, NZ, wr1, w1, MPI_COMM_WORLD, FFT_PLANNING | FFTW_MPI_TRANSPOSED_OUT);
if (r2cfft_mpi_t == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW R2C_T plan creation failed");
r2cfft_mpi = fftw_mpi_plan_dft_r2c_3d( NX, NY, NZ, wr1, w1, MPI_COMM_WORLD, FFT_PLANNING);
if (r2cfft_mpi == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW R2C plan creation failed");
c2rfft_mpi_t = fftw_mpi_plan_dft_c2r_3d( NY, NX, NZ, w1, wr1, MPI_COMM_WORLD, FFT_PLANNING | FFTW_MPI_TRANSPOSED_IN);
if (c2rfft_mpi_t == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW C2R_T plan creation failed");
c2rfft_mpi = fftw_mpi_plan_dft_c2r_3d( NX, NY, NZ, w1, wr1, MPI_COMM_WORLD, FFT_PLANNING);
if (c2rfft_mpi == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW C2R plan creation failed");
// init transpose routines (These are used by remap routines)
init_transpose();
fft_timer=0.0;
DEBUG_END_FUNC;
return;
}
void finish_gfft() {
DEBUG_START_FUNC;
fftw_destroy_plan(r2cfft_mpi_t);
fftw_destroy_plan(r2cfft_mpi);
fftw_destroy_plan(c2rfft_mpi_t);
fftw_destroy_plan(c2rfft_mpi);
finish_transpose();
DEBUG_END_FUNC;
return;
}
#endif
/**********************************************************************
***********************************************************************
********* N O M P I R O U T I N E S ******************
***********************************************************************
***********************************************************************/
// These routines are essentially wrappers for fftw3 routines
#else
// Here, we assume we don't have MPI
fftw_plan r2cfft, c2rfft;
void gfft_r2c_t(double *wrin) {
double complex *win = (double complex *) wrin;
fft_timer = fft_timer - get_c_time();
fftw_execute_dft_r2c(r2cfft, wrin, win);
fft_timer = fft_timer + get_c_time();
return;
}
void gfft_c2r_t(double complex *win){
double *wrin = (double *) win;
fft_timer = fft_timer - get_c_time();
fftw_execute_dft_c2r(c2rfft, win, wrin);
fft_timer = fft_timer + get_c_time();
return;
}
void gfft_r2c(double *wrin) {
double complex *win = (double complex *) wrin;
fft_timer = fft_timer - get_c_time();
fftw_execute_dft_r2c(r2cfft, wrin, win);
fft_timer = fft_timer + get_c_time();
return;
}
void gfft_c2r(double complex *win){
double *wrin = (double *) win;
fft_timer = fft_timer - get_c_time();
fftw_execute_dft_c2r(c2rfft, win, wrin);
fft_timer = fft_timer + get_c_time();
return;
}
void init_gfft() {
double complex *wi1;
double *wir1;
DEBUG_START_FUNC;
wi1 = (double complex *) fftw_malloc( sizeof(double complex) * NTOTAL_COMPLEX);
if (wi1 == NULL) ERROR_HANDLER( ERROR_CRITICAL, "No memory for wi1 allocation");
wir1 = (double *) wi1;
#ifdef _OPENMP
fftw_plan_with_nthreads( nthreads );
#endif
#ifdef WITH_2D
r2cfft = fftw_plan_dft_r2c_2d( NX, NY, wr1, w1, FFT_PLANNING);
if (r2cfft == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW R2C plan creation failed");
c2rfft = fftw_plan_dft_c2r_2d( NX, NY, w1, wr1, FFT_PLANNING);
if (c2rfft == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW C2R plan creation failed");
#else
r2cfft = fftw_plan_dft_r2c_3d( NX, NY, NZ, wr1, w1, FFT_PLANNING);
if (r2cfft == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW R2C plan creation failed");
c2rfft = fftw_plan_dft_c2r_3d( NX, NY, NZ, w1, wr1, FFT_PLANNING);
if (c2rfft == NULL) ERROR_HANDLER( ERROR_CRITICAL, "FFTW C2R plan creation failed");
#endif
fftw_free(wi1);
fft_timer=0.0;
DEBUG_END_FUNC;
return;
}
void finish_gfft() {
DEBUG_START_FUNC;
fftw_destroy_plan(r2cfft);
fftw_destroy_plan(c2rfft);
DEBUG_END_FUNC;
return;
}
#endif
double read_fft_timer() {
return(fft_timer);
}