FFT1D.h

Go to the documentation of this file.
00001 // -*- Mode: C++; tab-width: 2; -*-
00002 // vi: set ts=2:
00003 //
00004 // $Id: FFT1D.h,v 1.19 2006/01/03 17:42:39 anhi Exp $
00005 //
00006 
00007 #ifndef BALL_MATHS_TFFT1D_H
00008 #define BALL_MATHS_TFFT1D_H
00009 
00010 #ifndef BALL_COMMON_EXCEPTION_H
00011 # include <BALL/COMMON/exception.h>
00012 #endif
00013 
00014 #ifndef BALL_DATATYPE_REGULARDATA1D_H
00015 # include <BALL/DATATYPE/regularData1D.h>
00016 #endif
00017 
00018 #include <math.h>
00019 #include <complex>
00020 #include <fftw3.h>
00021 
00022 #include <BALL/MATHS/fftwCommon.h>
00023 
00024 namespace BALL
00025 {
00028 
00029 
00037   template <typename ComplexTraits>
00038   class TFFT1D 
00039     : public TRegularData1D<std::complex<typename ComplexTraits::ComplexPrecision> >
00040   {
00041     public:
00042 
00043     typedef std::complex<typename ComplexTraits::ComplexPrecision> Complex;
00044     typedef TRegularData1D<std::complex<typename ComplexTraits::ComplexPrecision> > ComplexVector;
00045 
00046     BALL_CREATE(TFFT1D)
00047 
00048     
00051 
00053     TFFT1D();
00054 
00056     TFFT1D(const TFFT1D &data);
00057 
00067      // AR: ldn is not any longer the binary logarithm but the absolute number of grid points
00068     TFFT1D(Size ldn, double stepPhys = 1., double origin = 0., bool inFourierSpace = false);
00069     
00071     virtual ~TFFT1D();
00072     
00074 
00078 
00080     const TFFT1D& operator = (const TFFT1D& fft1d);
00081     
00084     virtual void clear();
00085     
00088     virtual void destroy();
00089 
00091 
00095 
00098     bool operator == (const TFFT1D& fft1d) const;
00100     
00101     // @name Accessors
00102     
00105     void doFFT();
00106 
00109     void doiFFT();
00110 
00115     bool translate(double trans_origin);
00116 
00122     bool setPhysStepWidth(double new_width);
00123 
00126     double getPhysStepWidth() const;
00127 
00130     double getFourierStepWidth() const;
00131 
00134     double getPhysSpaceMin() const;
00135 
00138     double getPhysSpaceMax() const;
00139 
00142     double getFourierSpaceMin() const;
00143 
00146     double getFourierSpaceMax() const;
00147       
00153     Size getMaxIndex() const;
00154 
00158     Size getNumberOfInverseTransforms() const;
00159   
00162     double getGridCoordinates(Position position) const;
00163 
00168     Complex getData(const double pos) const
00169       throw(Exception::OutOfGrid);
00170 
00176     Complex getInterpolatedValue(const double pos) const
00177       throw(Exception::OutOfGrid);
00178 
00183     void setData(double pos, Complex val)
00184       throw(Exception::OutOfGrid);
00185 
00189     Complex& operator [] (const double pos)
00190       throw(Exception::OutOfGrid);
00191 
00195     const Complex& operator [] (const double pos) const
00196       throw(Exception::OutOfGrid);
00197     
00200     Complex& operator[](const Position& pos)
00201       throw(Exception::OutOfGrid)
00202     {
00203       return TRegularData1D<Complex>::operator[](pos);
00204     }
00205       
00208     const Complex& operator[](const Position& pos) const
00209       throw(Exception::OutOfGrid)
00210     {
00211       return TRegularData1D<Complex>::operator[](pos);
00212     } 
00213     
00214     // AR:
00215     void setNumberOfFFTTransforms(Size num)
00216     {
00217       numPhysToFourier_ = num;
00218     }
00219       
00220     // AR:
00221     void setNumberOfiFFTTransforms(Size num)
00222     {
00223       numFourierToPhys_ = num;
00224     }
00225     
00229     bool isInFourierSpace() const;
00230     
00236     Complex phase(const double pos) const;
00237 
00238     protected:
00239 
00240     Size length_;
00241     bool inFourierSpace_;
00242     Size numPhysToFourier_;
00243     Size numFourierToPhys_;
00244     double origin_;
00245     double stepPhys_;
00246     double stepFourier_;
00247     double minPhys_;
00248     double maxPhys_;
00249     double minFourier_;
00250     double maxFourier_;
00251 
00252     typename ComplexTraits::FftwPlan planForward_;
00253     typename ComplexTraits::FftwPlan planBackward_;
00254     
00255     // AR: to control plan calculation with new fftw3
00256     Complex *dataAdress_;
00257     bool planCalculated_;
00258   };
00260   
00263   typedef TFFT1D<BALL_FFTW_DEFAULT_TRAITS> FFT1D;
00264   
00265   // AR:
00268 //  const TRegularData1D<Complex>& operator << (TRegularData1D<Complex>& to, const TFFT1D& from)
00269   //; ?????
00270   
00275 //  const RegularData1D& operator << (RegularData1D& to, const TFFT1D& from)
00276 //; ???????
00277 
00278 
00279 
00280   template <typename ComplexTraits>
00281   TFFT1D<ComplexTraits>::TFFT1D()
00282     : TRegularData1D<Complex>(0, 0, 1.),  // AR: old case: This is necessary because FFTW_COMPLEX has no default constructor
00283       length_(0),
00284       inFourierSpace_(false),
00285       dataAdress_(0),
00286       planCalculated_(false)
00287   {
00288   }
00289     
00290 
00291   template <typename ComplexTraits>
00292   bool TFFT1D<ComplexTraits>::operator == (const TFFT1D<ComplexTraits>& fft1d) const
00293   {
00294     if (ComplexVector::size() == fft1d.size() &&
00295         origin_ == fft1d.origin_ &&
00296         stepPhys_ == fft1d.stepPhys_ &&
00297         stepFourier_ == fft1d.stepFourier_ &&
00298         minPhys_ == fft1d.minPhys_ &&
00299         maxPhys_ == fft1d.maxPhys_ &&
00300         minFourier_ == fft1d.minFourier_ &&
00301         maxFourier_ == fft1d.maxFourier_ &&
00302         inFourierSpace_ == fft1d.inFourierSpace_ &&
00303         numPhysToFourier_ == fft1d.numPhysToFourier_ &&
00304         numFourierToPhys_ == fft1d.numFourierToPhys_ &&
00305         planCalculated_ == fft1d.planCalculated_)
00306     {
00307       double min  = inFourierSpace_ ?  minFourier_ :  minPhys_;
00308       double max  = inFourierSpace_ ?  maxFourier_ :  maxPhys_;
00309       double step = inFourierSpace_ ? stepFourier_ : stepPhys_;
00310         
00311       for (double pos=min; pos<=max; pos+=step)
00312       {
00313         if (getData(pos) != fft1d.getData(pos))
00314         {
00315           return false;
00316         }
00317       }
00318       
00319       return true;
00320     }
00321   
00322     return false;
00323   } 
00324 
00325   template <typename ComplexTraits>
00326   bool TFFT1D<ComplexTraits>::translate(double trans_origin)
00327   {
00328     Position internalOrigin = (int) rint(trans_origin/stepPhys_);
00329     if (internalOrigin <= length_)
00330     {
00331       origin_ = trans_origin;
00332 
00333       minPhys_ = ((-1.)*origin_);
00334       maxPhys_ = (((length_-1)*stepPhys_)-origin_);
00335       minFourier_ = ((-1.)*(length_/2.-1)*stepFourier_);
00336       maxFourier_ = ((length_/2.)*stepFourier_);
00337       
00338       return true;
00339     }
00340     else
00341     {
00342       return false;
00343     }
00344   }
00345 
00346   template <typename ComplexTraits>
00347   bool TFFT1D<ComplexTraits>::setPhysStepWidth(double new_width)
00348   {
00349     if (new_width < 0)
00350     {
00351       return false;
00352     }
00353     else
00354     {
00355       stepPhys_ = new_width;
00356       stepFourier_ = 2.*M_PI/(stepPhys_*length_);
00357 
00358       minPhys_ = ((-1.)*origin_);
00359       maxPhys_ = (((length_-1)*stepPhys_)-origin_);
00360       minFourier_ = ((-1.)*(length_/2.-1)*stepFourier_);
00361       maxFourier_ = ((length_/2.)*stepFourier_);
00362 
00363       return true;
00364     }
00365   }
00366 
00367   template <typename ComplexTraits> 
00368   double TFFT1D<ComplexTraits>::getPhysStepWidth() const
00369   {
00370     return stepPhys_;
00371   }
00372 
00373   template <typename ComplexTraits>
00374   double TFFT1D<ComplexTraits>::getFourierStepWidth() const
00375   {
00376     return stepFourier_;
00377   }
00378 
00379   template <typename ComplexTraits>
00380   double TFFT1D<ComplexTraits>::getPhysSpaceMin() const
00381   {
00382     return minPhys_;
00383   }
00384 
00385   template <typename ComplexTraits>
00386   double TFFT1D<ComplexTraits>::getPhysSpaceMax() const
00387   {
00388     return maxPhys_;
00389   }
00390 
00391   template <typename ComplexTraits>
00392   double TFFT1D<ComplexTraits>::getFourierSpaceMin() const
00393   {
00394     return minFourier_;
00395   }
00396 
00397   template <typename ComplexTraits>
00398   double TFFT1D<ComplexTraits>::getFourierSpaceMax() const
00399   {
00400     return maxFourier_;
00401   }
00402 
00403   template <typename ComplexTraits> 
00404   Size TFFT1D<ComplexTraits>::getMaxIndex() const
00405   {
00406     return (length_ - 1);
00407   }
00408 
00409   template <typename ComplexTraits> 
00410   Size TFFT1D<ComplexTraits>::getNumberOfInverseTransforms() const
00411   {
00412     return numFourierToPhys_;
00413   }
00414   
00415   // AR: new 
00416   template <typename ComplexTraits>
00417   double TFFT1D<ComplexTraits>::getGridCoordinates(Position position) const
00418   {
00419     if (!inFourierSpace_)
00420     {
00421       if (position >= ComplexVector::size())
00422       {
00423         throw Exception::OutOfGrid(__FILE__, __LINE__);
00424       }
00425     
00426       double r;
00427       
00428       r = -origin_ + (float)position * stepPhys_;
00429 
00430       return r;
00431     }
00432     else
00433     {
00434       if (position >= ComplexVector::size())
00435       {
00436         throw Exception::OutOfGrid(__FILE__, __LINE__);
00437       }
00438     
00439       double r;
00440       Index x;
00441   
00442       x = position;
00443 
00444       if (x>=length_/2.)
00445       {
00446         x-=length_;
00447       }
00448       
00449       r = (float)x * stepFourier_;
00450 
00451       return r;
00452     }
00453   }
00454 
00455   template <typename ComplexTraits>
00456   typename TFFT1D<ComplexTraits>::Complex TFFT1D<ComplexTraits>::getData(const double pos) const
00457     throw(Exception::OutOfGrid)
00458   {
00459     Complex result;
00460     double normalization=1.;
00461 
00462     if (!inFourierSpace_)
00463     {
00464       result = (*this)[pos];//Complex((*this)[pos].real(), (*this)[pos].imag());
00465       normalization=1./pow((double)length_,(int)numFourierToPhys_);
00466     }
00467     else
00468     {
00469       result = (*this)[pos]*phase(pos);//Complex((*this)[pos].real(),(*this)[pos].imag()) * phase(pos);
00470       //Log.error() << pos <<  " " << phase(pos).real() <<  std::endl;
00471       normalization=1./(sqrt(2.*M_PI))/pow((double)length_,(int)numFourierToPhys_);
00472     }
00473 
00474     result *= normalization;
00475     
00476     return result;
00477   }
00478 
00479   template <typename ComplexTraits>
00480   typename TFFT1D<ComplexTraits>::Complex TFFT1D<ComplexTraits>::getInterpolatedValue(const double pos) const
00481     throw(Exception::OutOfGrid)
00482   {
00483     Complex result;
00484     
00485     double min  = inFourierSpace_ ? minFourier_  :  minPhys_;
00486     double max  = inFourierSpace_ ? maxFourier_  :  maxPhys_;
00487     double step = inFourierSpace_ ? stepFourier_ : stepPhys_;
00488     
00489     if ((pos < min) || (pos > max))
00490     {
00491       throw Exception::OutOfGrid(__FILE__, __LINE__);
00492     }
00493 
00494     double h = pos - min;
00495     double mod = fmod(h,step);
00496 
00497     if (mod ==0) // we are on the grid
00498     {
00499       return getData(pos);
00500     }
00501 
00502     double before = floor(h/step)*step+ min;
00503     double after  = ceil(h/step)*step+ min;
00504       
00505     double t = (pos - before)/step;
00506 
00507     result  =  getData(before)*(typename ComplexTraits::ComplexPrecision)(1.-t);
00508     result +=  getData(after)*(typename ComplexTraits::ComplexPrecision)t; 
00509 
00510     return result;
00511   }
00512 
00513   template <typename ComplexTraits>
00514   void TFFT1D<ComplexTraits>::setData(double pos, Complex val)
00515     throw(Exception::OutOfGrid)
00516   {
00517     Complex dummy;
00518     if (!inFourierSpace_)
00519     {
00520       dummy = Complex(val.real()*((typename ComplexTraits::ComplexPrecision)pow((typename ComplexTraits::ComplexPrecision)(length_),(int)numFourierToPhys_)),
00521                        val.imag()*((typename ComplexTraits::ComplexPrecision)pow((typename ComplexTraits::ComplexPrecision)(length_),(int)numFourierToPhys_)));
00522   
00523       (*this)[pos]=dummy;
00524     }
00525     else
00526     {
00527       val*=phase(pos)*(typename ComplexTraits::ComplexPrecision)((sqrt(2*M_PI)/stepPhys_))
00528                      *(typename ComplexTraits::ComplexPrecision)pow((typename ComplexTraits::ComplexPrecision)length_,(int)numFourierToPhys_);
00529       
00530       dummy = val;
00531       
00532       (*this)[pos]=dummy;
00533     }
00534   }
00535 
00536   template <typename ComplexTraits>
00537   typename TFFT1D<ComplexTraits>::Complex& TFFT1D<ComplexTraits>::operator[](const double pos) 
00538     throw(Exception::OutOfGrid)
00539   {
00540     Index internalPos;
00541 
00542     if (!inFourierSpace_)
00543     {
00544       internalPos = (Index) rint((pos+origin_)/stepPhys_);
00545     }
00546     else
00547     {
00548       internalPos =  (Index) rint(pos/stepFourier_);
00549 
00550       if (internalPos < 0)
00551       {
00552         internalPos+=length_;
00553       }
00554     }
00555 
00556     if ((internalPos < 0) || (internalPos>=(Index) length_))
00557     {
00558       throw Exception::OutOfGrid(__FILE__, __LINE__);
00559     }
00560     
00561     return operator [] (internalPos);
00562   }
00563 
00564   template <typename ComplexTraits>
00565   const typename TFFT1D<ComplexTraits>::Complex& TFFT1D<ComplexTraits>::operator[](const double pos) const
00566     throw(Exception::OutOfGrid)
00567   {
00568     Index internalPos;
00569 
00570     if (!inFourierSpace_)
00571     {
00572       internalPos = (Index) rint((pos+origin_)/stepPhys_);
00573     }
00574     else
00575     {
00576       internalPos =  (Index) rint(pos/stepFourier_);
00577 
00578       if (internalPos < 0)
00579       {
00580         internalPos+=length_;
00581       }
00582     }
00583 
00584     if ((internalPos < 0) || (internalPos>=(Index) length_))
00585     {
00586       throw Exception::OutOfGrid(__FILE__, __LINE__);
00587     }
00588     
00589     return operator [] (internalPos);
00590   }
00591 
00592   template <typename ComplexTraits>
00593   typename TFFT1D<ComplexTraits>::Complex TFFT1D<ComplexTraits>::phase(const double pos) const
00594   {
00595     double phase = 2.*M_PI*(rint(pos/stepFourier_))
00596                          *(rint(origin_/stepPhys_))
00597                          /length_;
00598     Complex result = Complex(cos(phase), sin(phase));
00599             
00600     return result;
00601   }
00602 
00603   template <typename ComplexTraits>
00604   bool TFFT1D<ComplexTraits>::isInFourierSpace() const
00605   {
00606     return inFourierSpace_;
00607   }
00608 /*  
00609   const TRegularData1D<Complex >& operator << (TRegularData1D<Complex >& to, const TFFT1D<ComplexTraits>& from)
00610   {
00611     // first decide if the TFFT1D data is in Fourier space.
00612     if (!from.isInFourierSpace())
00613     {
00614       // create a new grid
00615       Size lengthX = from.getMaxIndex()+1;
00616       
00617       TRegularData1D<Complex > newGrid(TRegularData1D<Complex >::IndexType(lengthX), from.getPhysSpaceMin(), from.getPhysSpaceMax());
00618 
00619       // and fill it
00620       double normalization=1./(pow((float)(lengthX),from.getNumberOfInverseTransforms()));
00621       
00622       for (Position i = 0; i < from.size(); i++)
00623       {
00624         newGrid[i] = from[i]*(ComplexTraits::ComplexPrecision)normalization;
00625       }
00626 
00627       to = newGrid;
00628 
00629       return to;
00630     }
00631     else
00632     {
00633       // we are in Fourier space
00634       
00635       // create a new grid
00636       Size lengthX = from.getMaxIndex()+1;
00637       //float stepPhysX = from.getPhysStepWidthX();
00638       float stepFourierX = from.getFourierStepWidth();
00639 
00640       
00641       TRegularData1D<Complex > newGrid(TRegularData1D<Complex >::IndexType(lengthX),
00642                                       from.getFourierSpaceMin(), 
00643                                       from.getFourierSpaceMax());
00644 
00645       // and fill it
00646       // AR: old double normalization=1./(sqrt(2.*M_PI))*(stepPhysX*stepPhysY*stepPhysZ)/(pow((float)(lengthX*lengthY*lengthZ),from.getNumberOfInverseTransforms()));
00647       double normalization=1./sqrt(2.*M_PI)/(pow((float)(lengthX),from.getNumberOfInverseTransforms()));
00648       
00649       
00650       Index x;
00651       float r;
00652   
00653       for (Position i = 0; i < from.size(); i++)
00654       {
00655         x = i;
00656 
00657         if (x>lengthX/2.)
00658         {
00659           x-=lengthX;
00660         }
00661 
00662         r = (float)x * stepFourierX;
00663 
00664         newGrid[i] = from[i]*(ComplexTraits::ComplexPrecision)normalization*from.phase(r);
00665       }
00666 
00667       to = newGrid;
00668 
00669       return to;
00670     }
00671   }
00672   */
00673   
00674   template <typename ComplexTraits>
00675   const RegularData1D& operator << (RegularData1D& to, const TFFT1D<ComplexTraits>& from)
00676   {
00677     // first decide if the FFT1D data is in Fourier space.
00678     if (!from.isInFourierSpace())
00679     {
00680       // create a new grid
00681       Size lengthX = from.getMaxIndex()+1;
00682       
00683       RegularData1D newGrid(lengthX);
00684       newGrid.setOrigin(from.getPhysSpaceMin());
00685       newGrid.setDimension(from.getPhysSpaceMax()-from.getPhysSpaceMin());
00686 
00687       // and fill it
00688       double normalization = 1./(pow((float)(lengthX),from.getNumberOfInverseTransforms()));
00689       
00690       for (Position i = 0; i < from.size(); i++)
00691       {
00692         newGrid[i] = from[i].real()*normalization;
00693       }
00694 
00695       to = newGrid;
00696 
00697       return to;
00698     }
00699     else
00700     {
00701       // we are in Fourier space
00702       
00703       // create a new grid
00704       Size lengthX = from.getMaxIndex()+1;
00705       //float stepPhysX = from.getPhysStepWidth();
00706       float stepFourierX = from.getFourierStepWidth();
00707 
00708       RegularData1D newGrid(lengthX);
00709       newGrid.setOrigin(from.getFourierSpaceMin());
00710       newGrid.setDimension(from.getFourierSpaceMax()-from.getFourierSpaceMin());
00711 
00712       // and fill it
00713       // AR: old version double normalization=1./(sqrt(2.*M_PI))*(stepPhysX*stepPhysY*stepPhysZ)/(pow((float)(lengthX*lengthY*lengthZ),from.getNumberOfInverseTransforms()));
00714       double normalization=1./sqrt(2.*M_PI)/(pow((float)(lengthX),from.getNumberOfInverseTransforms()));
00715       
00716       Index x;
00717       signed int xp;
00718       float r;
00719   
00720       for (Position i = 0; i < from.size(); i++)
00721       {
00722         x =  i;
00723         
00724         xp = x;
00725 
00726         if (xp>=lengthX/2.)
00727         {
00728           xp-=(int)lengthX;
00729         }
00730 
00731         if (x>=lengthX/2.)
00732         {
00733           x-=(int)(lengthX/2.);
00734         }
00735         else
00736         {
00737           x+=(int)(lengthX/2.);
00738         }
00739 
00740 
00741         r = ((float)xp * stepFourierX);
00742 
00743         newGrid[i] = (from[i]*(typename ComplexTraits::ComplexPrecision)normalization*from.phase(r)).real();
00744       }
00745 
00746       to = newGrid;
00747 
00748       return to;
00749     }
00750   }
00751 }
00752 #endif // BALL_MATHS_TFFT1D_H