Commit 88be8bd4 authored by BLANCHARD Pierre's avatar BLANCHARD Pierre

Redesigned fftw wrapper to handle float and double (Important: Make sure float is enabled in fftw).

parent f3fb5e98
......@@ -26,14 +26,14 @@
#include <fstream>
#include <typeinfo>
#include "../../Utils/FBlas.hpp"
#include "../../Utils/FTic.hpp"
#include "../../Utils/FDft.hpp"
#include "Utils/FBlas.hpp"
#include "Utils/FTic.hpp"
#include "Utils/FDft.hpp"
#include "../../Utils/FComplex.hpp"
#include "Utils/FComplex.hpp"
#include "./FUnifTensor.hpp"
#include "FUnifTensor.hpp"
/*! Precomputation of the 316 interactions by evaluation of the matrix kernel on the uniform grid and transformation into Fourier space.
PB: Compute() does not belong to the M2LHandler like it does in the Chebyshev kernel. This allows much nicer specialization of the M2LHandler class with respect to the homogeneity of the kernel of interaction like in the ChebyshevSym kernel.*/
......@@ -67,9 +67,7 @@ static void Compute(const MatrixKernelClass *const MatrixKernel, const FReal Cel
TensorType::setNodeIdsPairs(node_ids_pairs);
// init Discrete Fourier Transformator
const int dimfft = 1; // unidim FFT since fully circulant embedding
const int steps[dimfft] = {rc};
FFft<FReal,dimfft> Dft;
Dft.buildDFT(steps);
FFftw<FReal,FComplex<FReal>,dimfft> Dft(rc);
// get first column of K via permutation
unsigned int perm[rc];
TensorType::setStoragePermutation(perm);
......@@ -178,7 +176,7 @@ class FUnifM2LHandler<FReal, ORDER,HOMOGENEOUS>
/// DFT specific
static const int dimfft = 1; // unidim FFT since fully circulant embedding
typedef FFft<FReal,dimfft> DftClass; // Fast Discrete Fourier Transformator
typedef FFftw<FReal,FComplex<FReal>,dimfft> DftClass; // Fast Discrete Fourier Transformator
DftClass Dft;
const unsigned int opt_rc; // specific to real valued kernel
......@@ -198,11 +196,8 @@ class FUnifM2LHandler<FReal, ORDER,HOMOGENEOUS>
public:
template <typename MatrixKernelClass>
FUnifM2LHandler(const MatrixKernelClass *const MatrixKernel, const unsigned int, const FReal, const int inLeafLevelSeparationCriterion = 1)
: FC(nullptr), Dft(), opt_rc(rc/2+1), LeafLevelSeparationCriterion(inLeafLevelSeparationCriterion)
: FC(nullptr), Dft(rc), opt_rc(rc/2+1), LeafLevelSeparationCriterion(inLeafLevelSeparationCriterion)
{
// init DFT
const int steps[dimfft] = {rc};
Dft.buildDFT(steps);
// initialize root node ids
TensorType::setNodeIdsDiff(node_diff);
......@@ -216,11 +211,8 @@ public:
* Copy constructor
*/
FUnifM2LHandler(const FUnifM2LHandler& other)
: FC(other.FC), Dft(), opt_rc(other.opt_rc), LeafLevelSeparationCriterion(other.LeafLevelSeparationCriterion)
: FC(other.FC), Dft(other.Dft), opt_rc(other.opt_rc), LeafLevelSeparationCriterion(other.LeafLevelSeparationCriterion)
{
// init DFT
const int steps[dimfft] = {rc};
Dft.buildDFT(steps);
// copy node_diff
memcpy(node_diff,other.node_diff,sizeof(unsigned int)*nnodes*nnodes);
}
......@@ -269,7 +261,7 @@ public:
FReal Px[rc];
FBlas::setzero(rc,Px);
// Apply forward Discrete Fourier Transform
Dft.applyIDFT(FX,Px);
Dft.applyIDFTNorm(FX,Px);
// Unapply Zero Padding
for (unsigned int j=0; j<nnodes; ++j)
x[j]+=Px[node_diff[nnodes-j-1]];
......@@ -342,7 +334,7 @@ class FUnifM2LHandler<FReal,ORDER,NON_HOMOGENEOUS>
unsigned int node_diff[nnodes*nnodes];
/// DFT specific
static const int dimfft = 1; // unidim FFT since fully circulant embedding
typedef FFft<FReal,dimfft> DftClass; // Fast Discrete Fourier Transformator
typedef FFftw<FReal,FComplex<FReal>,dimfft> DftClass; // Fast real-valued Discrete Fourier Transformator
DftClass Dft;
const unsigned int opt_rc; // specific to real valued kernel
......@@ -364,11 +356,8 @@ public:
FUnifM2LHandler(const MatrixKernelClass *const MatrixKernel, const unsigned int inTreeHeight, const FReal inRootCellWidth, const int inLeafLevelSeparationCriterion = 1)
: TreeHeight(inTreeHeight),
RootCellWidth(inRootCellWidth),
Dft(), opt_rc(rc/2+1), LeafLevelSeparationCriterion(inLeafLevelSeparationCriterion)
Dft(rc), opt_rc(rc/2+1), LeafLevelSeparationCriterion(inLeafLevelSeparationCriterion)
{
// init DFT
const int steps[dimfft] = {rc};
Dft.buildDFT(steps);
// initialize root node ids
TensorType::setNodeIdsDiff(node_diff);
......@@ -390,11 +379,8 @@ public:
: FC(other.FC),
TreeHeight(other.TreeHeight),
RootCellWidth(other.RootCellWidth),
Dft(), opt_rc(other.opt_rc), LeafLevelSeparationCriterion(other.LeafLevelSeparationCriterion)
Dft(other.Dft), opt_rc(other.opt_rc), LeafLevelSeparationCriterion(other.LeafLevelSeparationCriterion)
{
// init DFT
const int steps[dimfft] = {rc};
Dft.buildDFT(steps);
// copy node_diff
memcpy(node_diff,other.node_diff,sizeof(unsigned int)*nnodes*nnodes);
}
......@@ -455,7 +441,7 @@ public:
FReal Px[rc];
FBlas::setzero(rc,Px);
// Apply forward Discrete Fourier Transform
Dft.applyIDFT(FX,Px);
Dft.applyIDFTNorm(FX,Px);
// Unapply Zero Padding
for (unsigned int j=0; j<nnodes; ++j)
x[j]+=Px[node_diff[nnodes-j-1]];
......
......@@ -26,14 +26,14 @@
#include <fstream>
#include <typeinfo>
#include "../../Utils/FBlas.hpp"
#include "../../Utils/FTic.hpp"
#include "../../Utils/FDft.hpp"
#include "Utils/FBlas.hpp"
#include "Utils/FTic.hpp"
#include "Utils/FDft.hpp"
#include "../../Utils/FComplex.hpp"
#include "Utils/FComplex.hpp"
#include "./FUnifTensor.hpp"
#include "FUnifTensor.hpp"
/*! Precomputation of the 316 interactions by evaluation of the matrix kernel on the uniform grid and transformation into Fourier space. These interactions can be tensorial (of size ncmp) and are computed blockwise
......@@ -83,9 +83,7 @@ static void Compute(const MatrixKernelClass *const MatrixKernel,
// init Discrete Fourier Transformator
const int dimfft = 1; // unidim FFT since fully circulant embedding
const int steps[dimfft] = {rc};
FFft<FReal,dimfft> Dft;
Dft.buildDFT(steps);
FFftw<FReal,FComplex<FReal>,dimfft> Dft(rc);
// get first column of K via permutation
unsigned int perm[rc];
......@@ -208,7 +206,7 @@ class FUnifTensorialM2LHandler<FReal, ORDER,MatrixKernelClass,HOMOGENEOUS>
/// DFT specific
static const int dimfft = 1; // unidim FFT since fully circulant embedding
typedef FFft<FReal,dimfft> DftClass; // Fast Discrete Fourier Transformator
typedef FFftw<FReal,FComplex<FReal>,dimfft> DftClass; // Fast Discrete Fourier Transformator
DftClass Dft;
const unsigned int opt_rc; // specific to real valued kernel
......@@ -228,11 +226,8 @@ class FUnifTensorialM2LHandler<FReal, ORDER,MatrixKernelClass,HOMOGENEOUS>
public:
FUnifTensorialM2LHandler(const MatrixKernelClass *const MatrixKernel, const unsigned int, const FReal, const FReal inCellWidthExtension, const int inLeafLevelSeparationCriterion = 1)
: CellWidthExtension(inCellWidthExtension),
Dft(), opt_rc(rc/2+1), LeafLevelSeparationCriterion(inLeafLevelSeparationCriterion)
Dft(rc), opt_rc(rc/2+1), LeafLevelSeparationCriterion(inLeafLevelSeparationCriterion)
{
// init DFT
const int steps[dimfft] = {rc};
Dft.buildDFT(steps);
// allocate FC
FC = new FComplex<FReal>*[ncmp];
......@@ -252,12 +247,8 @@ public:
FUnifTensorialM2LHandler(const FUnifTensorialM2LHandler& other)
: FC(other.FC),
CellWidthExtension(other.CellWidthExtension),
Dft(), opt_rc(other.opt_rc), LeafLevelSeparationCriterion(other.LeafLevelSeparationCriterion)
{
// init DFT
const int steps[dimfft] = {rc};
Dft.buildDFT(steps);
Dft(other.Dft), opt_rc(other.opt_rc), LeafLevelSeparationCriterion(other.LeafLevelSeparationCriterion)
{
// copy node_diff
memcpy(node_diff,other.node_diff,sizeof(unsigned int)*nnodes*nnodes);
}
......@@ -311,7 +302,7 @@ public:
FReal Px[rc];
FBlas::setzero(rc,Px);
// Apply forward Discrete Fourier Transform
Dft.applyIDFT(FX,Px);
Dft.applyIDFTNorm(FX,Px);
// Unapply Zero Padding
for (unsigned int j=0; j<nnodes; ++j)
x[j]+=Px[node_diff[nnodes-j-1]];
......@@ -403,7 +394,7 @@ class FUnifTensorialM2LHandler<FReal,ORDER,MatrixKernelClass,NON_HOMOGENEOUS>
/// DFT specific
static const int dimfft = 1; // unidim FFT since fully circulant embedding
typedef FFft<FReal,dimfft> DftClass; // Fast Discrete Fourier Transformator
typedef FFftw<FReal,FComplex<FReal>,dimfft> DftClass; // Fast Discrete Fourier Transformator
DftClass Dft;
const unsigned int opt_rc; // specific to real valued kernel
......@@ -425,11 +416,8 @@ public:
: TreeHeight(inTreeHeight),
RootCellWidth(inRootCellWidth),
CellWidthExtension(inCellWidthExtension),
Dft(), opt_rc(rc/2+1), LeafLevelSeparationCriterion(inLeafLevelSeparationCriterion)
Dft(rc), opt_rc(rc/2+1), LeafLevelSeparationCriterion(inLeafLevelSeparationCriterion)
{
// init DFT
const int steps[dimfft] = {rc};
Dft.buildDFT(steps);
// allocate FC
FC = new FComplex<FReal>**[TreeHeight];
......@@ -454,12 +442,8 @@ public:
TreeHeight(other.TreeHeight),
RootCellWidth(other.RootCellWidth),
CellWidthExtension(other.CellWidthExtension),
Dft(), opt_rc(other.opt_rc), LeafLevelSeparationCriterion(other.LeafLevelSeparationCriterion)
Dft(other.Dft), opt_rc(other.opt_rc), LeafLevelSeparationCriterion(other.LeafLevelSeparationCriterion)
{
// init DFT
const int steps[dimfft] = {rc};
Dft.buildDFT(steps);
// copy node_diff
memcpy(node_diff,other.node_diff,sizeof(unsigned int)*nnodes*nnodes);
}
......@@ -517,7 +501,7 @@ public:
FReal Px[rc];
FBlas::setzero(rc,Px);
// Apply forward Discrete Fourier Transform
Dft.applyIDFT(FX,Px);
Dft.applyIDFTNorm(FX,Px);
// Unapply Zero Padding
for (unsigned int j=0; j<nnodes; ++j)
x[j]+=Px[node_diff[nnodes-j-1]];
......
This diff is collapsed.
......@@ -50,7 +50,7 @@
#include "Core/FFmmAlgorithm.hpp"
#include "Core/FFmmAlgorithmThread.hpp"
#include "../../Src/Utils/FParameterNames.hpp"
#include "Utils/FParameterNames.hpp"
/**
* This program runs the FMM Algorithm with the Uniform kernel and compares the results with a direct computation.
......
// ===================================================================================
// Ce LOGICIEL "ScalFmm" est couvert par le copyright Inria 20xx-2012.
// Inria détient tous les droits de propriété sur le LOGICIEL, et souhaite que
// la communauté scientifique l'utilise afin de le tester et de l'évaluer.
// Inria donne gracieusement le droit d'utiliser ce LOGICIEL. Toute utilisation
// dans un but lucratif ou à des fins commerciales est interdite sauf autorisation
// expresse et préalable d'Inria.
// Toute utilisation hors des limites précisées ci-dessus et réalisée sans l'accord
// expresse préalable d'Inria constituerait donc le délit de contrefaçon.
// Le LOGICIEL étant un produit en cours de développement, Inria ne saurait assurer
// aucune responsabilité et notamment en aucune manière et en aucun cas, être tenu
// de répondre d'éventuels dommages directs ou indirects subits par l'utilisateur.
// Tout utilisateur du LOGICIEL s'engage à communiquer à Inria ses remarques
// relatives à l'usage du LOGICIEL
// ===================================================================================
// ==== CMAKE =====
// @FUSE_FFT
// ================
#include <iostream>
#include <stdlib.h>
#include <fftw3.h>
#include "Utils/FGlobal.hpp"
#include "Utils/FComplex.hpp"
#include "Utils/FTic.hpp"
#include "Utils/FParameterNames.hpp"
#include "Utils/FDft.hpp"
int main(int argc, char** argv)
{
FHelpDescribeAndExit(argc, argv, "Test the FFT wrapper.");
typedef float FReal;
const FReal FRandMax = FReal(RAND_MAX);
FTic time;
//////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
// dimension
static const int dim = 3;
// size (pick a power of 2 for better performance of the FFT algorithm)
const int size = 50;
int total_size = 1;
for(int d = 0; d<dim;++d) total_size *= size;
// input/output types
typedef FReal FftR2CInputType;
typedef FComplex<FReal> FftR2COutputType;
typedef FComplex<FReal> FftC2CInputType;
typedef FComplex<FReal> FftC2COutputType;
// fftw arrays
FftR2CInputType* FftR2CInput = new FftR2CInputType[total_size];
FftR2CInputType* FftR2CInvOut = new FftR2CInputType[total_size];
FftR2COutputType* FftR2COutput = new FftR2COutputType[total_size];
FftC2CInputType* FftC2CInput = new FftC2CInputType[total_size];
FftC2CInputType* FftC2CInvOut = new FftC2CInputType[total_size];
FftC2COutputType* FftC2COutput = new FftC2COutputType[total_size];
// fftw wrappers
typedef FFftw<FReal ,FComplex<FReal>,dim> FftwR2CClass;
typedef FFftw<FComplex<FReal>,FComplex<FReal>,dim> FftwC2CClass;
std::cout<< "Init FFTW wrappers: ";
time.tic();
FftwR2CClass FftwR2C(size);
FftwC2CClass FftwC2C(size);
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
//////////////////////////////////////////////////////////////////////////////
// EXECUTION
// generate random physical data and set output to zero
for( int s=0; s<total_size; ++s){
FftR2CInput[s] = FftR2CInputType(FReal(rand())/FRandMax);
FftR2CInvOut[s] = FftR2CInputType(0.);
FftR2COutput[s] = FftR2COutputType(0.,0.);
FftC2CInput[s] = FftC2CInputType(FReal(rand())/FRandMax,FReal(rand())/FRandMax);
FftC2CInvOut[s] = FftC2CInputType(0.,0.);
FftC2COutput[s] = FftC2COutputType(0.,0.);
}
// // display data in physical space
// std::cout<< "Physical data (R2C): "<<std::endl;
// for( int s=0; s<total_size; ++s)
// std::cout<< FftR2CInput[s] << ", ";
// std::cout<<std::endl;
//
// std::cout<< "Physical data (C2C): "<<std::endl;
// for( int s=0; s<total_size; ++s)
// std::cout<< FftC2CInput[s] << ", ";
// std::cout<<std::endl;
// perform fft
std::cout<< "Perform Forward FFT: ";
time.tic();
FftwR2C.applyDFT(FftR2CInput,FftR2COutput);
FftwC2C.applyDFT(FftC2CInput,FftC2COutput);
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
// // display transform in Fourier space
// // beware the real data FFT stores only N/2+1 complex output values
// std::cout<< "Transformed data (R2C): "<<std::endl;
// for( int s=0; s<total_size; ++s)
// std::cout<< FftR2COutput[s] << ", ";
// std::cout<<std::endl;
//
// std::cout<< "Transformed data (C2C): "<<std::endl;
// for( int s=0; s<total_size; ++s)
// std::cout<< FftC2COutput[s] << ", ";
// std::cout<<std::endl;
// perform ifft of transformed data (in order to get physical values back)
std::cout<< "Perform Normalized Backward FFT: ";
time.tic();
FftwR2C.applyIDFTNorm(FftR2COutput,FftR2CInvOut);
FftwC2C.applyIDFTNorm(FftC2COutput,FftC2CInvOut);
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
// // display data in physical space
// std::cout<< "Physical data from 1/N*IFFT(FFT(Physical data)) (R2C) : "<<std::endl;
// for( int s=0; s<total_size; ++s)
// std::cout<< FftR2CInvOut[s] << ", ";
// std::cout<<std::endl;
//
// std::cout<< "Physical data from 1/N*IFFT(FFT(Physical data)) (C2C) : "<<std::endl;
// for( int s=0; s<total_size; ++s)
// std::cout<< FftC2CInvOut[s] << ", ";
// std::cout<<std::endl;
//////////////////////////////////////////////////////////////////////////////
// VALIDATION
bool isWorking = true;
FReal threshold = (sizeof(FReal)==8 ? FReal(1.e-12) : FReal(1.e-6));
FReal* FftC2CInvOutReal = new FReal[total_size]; FReal* FftC2CInputReal = new FReal[total_size];
FReal* FftC2CInvOutImag = new FReal[total_size]; FReal* FftC2CInputImag = new FReal[total_size];
for( int s=0; s<total_size; ++s){
FftC2CInvOutReal[s] = FftC2CInvOut[s].getReal(); FftC2CInputReal[s] = FftC2CInput[s].getReal();
FftC2CInvOutImag[s] = FftC2CInvOut[s].getImag(); FftC2CInputImag[s] = FftC2CInput[s].getImag();
}
if(FMath::FAccurater<FReal>(FftR2CInput, FftR2CInvOut, total_size).getRelativeInfNorm() > threshold) isWorking=false;
if(FMath::FAccurater<FReal>(FftR2CInput, FftR2CInvOut, total_size).getRelativeL2Norm() > threshold) isWorking=false;
if(FMath::FAccurater<FReal>(FftC2CInputReal, FftC2CInvOutReal, total_size).getRelativeInfNorm() > threshold) isWorking=false;
if(FMath::FAccurater<FReal>(FftC2CInputImag, FftC2CInvOutImag, total_size).getRelativeInfNorm() > threshold) isWorking=false;
if(FMath::FAccurater<FReal>(FftC2CInputReal, FftC2CInvOutReal, total_size).getRelativeL2Norm() > threshold) isWorking=false;
if(FMath::FAccurater<FReal>(FftC2CInputImag, FftC2CInvOutImag, total_size).getRelativeL2Norm() > threshold) isWorking=false;
if(isWorking) std::cout << "FFT Wrapper is working (errors < threshold = " << threshold << ")." << std::endl;
else std::cout << "FFT Wrapper is NOT working (errors > threshold = " << threshold << ")." << std::endl;
//free memory
delete[] FftR2CInput;
delete[] FftR2CInvOut;
delete[] FftR2COutput;
delete[] FftC2CInput;
delete[] FftC2CInvOut;
delete[] FftC2COutput;
delete[] FftC2CInvOutReal;
delete[] FftC2CInputReal;
delete[] FftC2CInvOutImag;
delete[] FftC2CInputImag;
}// end test
// ===================================================================================
// Ce LOGICIEL "ScalFmm" est couvert par le copyright Inria 20xx-2012.
// Inria détient tous les droits de propriété sur le LOGICIEL, et souhaite que
// la communauté scientifique l'utilise afin de le tester et de l'évaluer.
// Inria donne gracieusement le droit d'utiliser ce LOGICIEL. Toute utilisation
// dans un but lucratif ou à des fins commerciales est interdite sauf autorisation
// expresse et préalable d'Inria.
// Toute utilisation hors des limites précisées ci-dessus et réalisée sans l'accord
// expresse préalable d'Inria constituerait donc le délit de contrefaçon.
// Le LOGICIEL étant un produit en cours de développement, Inria ne saurait assurer
// aucune responsabilité et notamment en aucune manière et en aucun cas, être tenu
// de répondre d'éventuels dommages directs ou indirects subits par l'utilisateur.
// Tout utilisateur du LOGICIEL s'engage à communiquer à Inria ses remarques
// relatives à l'usage du LOGICIEL
// ===================================================================================
// ==== CMAKE =====
// @FUSE_FFT
// ================
#include <iostream>
#include <stdlib.h>
#include <fftw3.h>
#include "../../Src/Utils/FGlobal.hpp"
#include "../../Src/Utils/FComplex.hpp"
#include "../../Src/Utils/FTic.hpp"
#include "../../Src/Utils/FParameterNames.hpp"
//#include "../../Src/Utils/FDft.hpp"
int main(int argc, char** argv)
{
FHelpDescribeAndExit(argc, argv, "Test the FFTw (only the code is interesting).");
typedef double FReal;
const FReal FRandMax = FReal(RAND_MAX);
FTic time;
//////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
// size (pick a power of 2 for better performance of the FFT algorithm)
unsigned int nsteps_ = 500;
// fftw arrays
FReal* fftR_;
FComplex<FReal>* fftC_;
fftR_ = (FReal*) fftw_malloc(sizeof(FReal) * nsteps_);
fftC_ = (FComplex<FReal>*) fftw_malloc(sizeof(FComplex<FReal>) * nsteps_);
// fftw plans
// use routine defined in file:
// /PATH/TO/mkl/interfaces/fftw3xf/wrappers/fftw_plan_dft_c2r_1d.c
fftw_plan plan_c2r_; // backward FFT plan
fftw_plan plan_r2c_; // forward FFT plan
std::cout<< "Init FFTW plans: ";
time.tic();
plan_c2r_ =
fftw_plan_dft_c2r_1d(nsteps_,
reinterpret_cast<fftw_complex*>(fftC_),
fftR_,
FFTW_MEASURE);
plan_r2c_ =
fftw_plan_dft_r2c_1d(nsteps_,
fftR_,
reinterpret_cast<fftw_complex*>(fftC_),
FFTW_MEASURE);
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
// alternative choice of plan type
// plan_c2r_ =
// fftw_plan_dft_1d(nsteps_, fftC_, fftR_, FFTW_BACKWARD, FFTW_MEASURE);
// plan_r2c_ =
// fftw_plan_dft_1d(nsteps_, fftR_, fftC_, FFTW_FORWARD, FFTW_MEASURE);
//////////////////////////////////////////////////////////////////////////////
// EXECUTION
// generate random physical data
for(unsigned int s=0; s<nsteps_; ++s)
fftR_[s] = FReal(rand())/FRandMax;
// // display data in physical space
// std::cout<< "Physical data: "<<std::endl;
// for(unsigned int s=0; s<nsteps_; ++s)
// std::cout<< fftR_[s] << ", ";
// std::cout<<std::endl;
// perform fft
std::cout<< "Perform Forward FFT: ";
time.tic();
fftw_execute( plan_r2c_ );
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
// // display transform in Fourier space
// // beware the real data FFT stores only N/2+1 complex output values
// std::cout<< "Transformed data : "<<std::endl;
// for(unsigned int s=0; s<nsteps_; ++s)
// std::cout<< fftC_[s] << ", ";
// std::cout<<std::endl;
// for(unsigned int s=0; s<nsteps_/2+1; ++s){
// fftC_[nsteps_-s]=FComplex<FReal>(fftC_[s].getReal(),-fftC_[s].getImag());
// }
//
// std::cout<< "Full Transformed data : "<<std::endl;
// for(unsigned int s=0; s<nsteps_; ++s)
// std::cout<< fftC_[s] << ", ";
// std::cout<<std::endl;
// perform ifft of tranformed data (in order to get physical values back)
std::cout<< "Perform Backward FFT: ";
time.tic();
fftw_execute( plan_c2r_ );
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
// // display data in physical space
// std::cout<< "Physical data (from 1/N*IFFT(FFT(Physical data))): "<<std::endl;
// for(unsigned int s=0; s<nsteps_; ++s)
// std::cout<< fftR_[s]/nsteps_ << ", ";
// std::cout<<std::endl;
//////////////////////////////////////////////////////////////////////////////
// VALIDATION
// TODO
//free memory
fftw_destroy_plan(plan_r2c_);
fftw_destroy_plan(plan_c2r_);
fftw_free(fftR_);
fftw_free(fftC_);
}// end test
// ===================================================================================
// Ce LOGICIEL "ScalFmm" est couvert par le copyright Inria 20xx-2012.
// Inria détient tous les droits de propriété sur le LOGICIEL, et souhaite que
// la communauté scientifique l'utilise afin de le tester et de l'évaluer.
// Inria donne gracieusement le droit d'utiliser ce LOGICIEL. Toute utilisation
// dans un but lucratif ou à des fins commerciales est interdite sauf autorisation
// expresse et préalable d'Inria.
// Toute utilisation hors des limites précisées ci-dessus et réalisée sans l'accord
// expresse préalable d'Inria constituerait donc le délit de contrefaçon.
// Le LOGICIEL étant un produit en cours de développement, Inria ne saurait assurer
// aucune responsabilité et notamment en aucune manière et en aucun cas, être tenu
// de répondre d'éventuels dommages directs ou indirects subits par l'utilisateur.
// Tout utilisateur du LOGICIEL s'engage à communiquer à Inria ses remarques
// relatives à l'usage du LOGICIEL
// ===================================================================================
// ==== CMAKE =====
// @FUSE_FFT
// ================
#include <iostream>
#include <stdlib.h>
#include <fftw3.h>
#include "../../Src/Utils/FGlobal.hpp"
#include "../../Src/Utils/FComplex.hpp"
#include "../../Src/Utils/FTic.hpp"
#include "../../Src/Utils/FParameterNames.hpp"
//#include "../../Src/Utils/FDft.hpp"
int main(int argc, char** argv)
{
FHelpDescribeAndExit(argc, argv, "Test the FFT in multi dimensions (only the code is interesting).");
typedef double FReal;
const FReal FRandMax = FReal(RAND_MAX);
FTic time;
//////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
// size (pick a power of 2 for better performance of the FFT algorithm)
const int dim=2;
const int pow_nsteps_=8;
int steps_[dim];
int nsteps_=1;
for(int d=0; d<dim; ++d) {
steps_[d]=FMath::pow(2,pow_nsteps_);
nsteps_*=steps_[d];
}
//////////////////////////////////////////////////////////////////////////////
// Multidimensionnal FFT PLANS
std::cout<< "Test "<< dim <<"D FFT."<<std::endl;
// fftw arrays
FReal* fftR_;
FComplex<FReal>* fftC_;
fftR_ = (FReal*) fftw_malloc(sizeof(FReal) * nsteps_ );
fftC_ = (FComplex<FReal>*) fftw_malloc(sizeof(FComplex<FReal>) * nsteps_ );
// fftw plans
// use routine defined in file:
// /PATH/TO/mkl/interfaces/fftw3xf/wrappers/fftw_plan_dft_c2r_1d.c
fftw_plan plan_c2r_; // backward FFT plan
fftw_plan plan_r2c_; // forward FFT plan
std::cout<< "Init FFTW plans: ";
time.tic();
plan_c2r_ =
fftw_plan_dft_c2r(dim, steps_,
reinterpret_cast<fftw_complex*>(fftC_),
fftR_,
FFTW_MEASURE);
plan_r2c_ =
fftw_plan_dft_r2c(dim, steps_,
fftR_,
reinterpret_cast<fftw_complex*>(fftC_),
FFTW_MEASURE);
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
//////////////////////////////////////////////////////////////////////////////
// EXECUTION
// generate random physical data
for(int s=0; s<nsteps_; ++s)
fftR_[s] = FReal(rand())/FRandMax;
// // display data in physical space
// std::cout<< "Physical data: "<<std::endl;
// for( int r=0; r<steps_[0]; ++r) {
// for( int s=0; s<steps_[1]; ++s)
// std::cout<< fftR_[r*steps_[1]+s] << ", ";
// std::cout<<std::endl;
// }
// std::cout<<std::endl;
// perform fft
std::cout<< "Perform Forward FFT: ";
time.tic();
fftw_execute( plan_r2c_ );
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
// // display transform in Fourier space
// // beware the real data FFT stores only N/2+1 complex output values
// std::cout<< "Transformed data : "<<std::endl;
// for( int r=0; r<steps_[0]/2+1; ++r) {
// for( int s=0; s<steps_[1]/2+1; ++s)
// std::cout<< fftC_[r*(steps_[1]/2+1)+s] << ", ";
// std::cout<<std::endl;
// }
// std::cout<<std::endl;
//// for( int s=0; s<steps_[1]/2+1; ++s){
//// fftC_[nsteps_-s]=FComplex<FReal>(fftC_[s].getReal(),-fftC_[s].getImag());
//// }
// std::cout<< "Full Transformed data : "<<std::endl;
// for( int r=0; r<steps_[0]; ++r){
// for( int s=0; s<steps_[1]; ++s)
// std::cout<< fftC_[r*steps_[1]+s] << ", ";
// std::cout<<std::endl;
// }
// std::cout<<std::endl;
// perform ifft of tranformed data (in order to get physical values back)
std::cout<< "Perform Backward FFT: ";
time.tic();
fftw_execute( plan_c2r_ );
std::cout << "took " << time.tacAndElapsed() << "sec." << std::endl;
// // display data in physical space
// std::cout<< "Physical data (from 1/N*IFFT(FFT(Physical data))): "<<std::endl;
// for( int r=0; r<steps_[0]; ++r) {
// for( int s=0; s<steps_[1]; ++s)
// std::cout<< fftR_[r*steps_[1]+s]/(nsteps_) << ", ";
// std::cout<<std::endl;
// }
// std::cout<<std::endl;
//free memory
fftw_destroy_plan(plan_r2c_);
fftw_destroy_plan(plan_c2r_);
fftw_free(fftR_);
fftw_free(fftC_);
}// end test
......@@ -28,15 +28,15 @@
#include <stdlib.h>
#include <time.h>