00001
00002
00003
00004
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
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
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
00215 void setNumberOfFFTTransforms(Size num)
00216 {
00217 numPhysToFourier_ = num;
00218 }
00219
00220
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
00256 Complex *dataAdress_;
00257 bool planCalculated_;
00258 };
00260
00263 typedef TFFT1D<BALL_FFTW_DEFAULT_TRAITS> FFT1D;
00264
00265
00268
00269
00270
00275
00276
00277
00278
00279
00280 template <typename ComplexTraits>
00281 TFFT1D<ComplexTraits>::TFFT1D()
00282 : TRegularData1D<Complex>(0, 0, 1.),
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
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];
00465 normalization=1./pow((double)length_,(int)numFourierToPhys_);
00466 }
00467 else
00468 {
00469 result = (*this)[pos]*phase(pos);
00470
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)
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 [] ((Position)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 [] ((Position)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
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 template <typename ComplexTraits>
00675 const RegularData1D& operator << (RegularData1D& to, const TFFT1D<ComplexTraits>& from)
00676 {
00677
00678 if (!from.isInFourierSpace())
00679 {
00680
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
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
00702
00703
00704 Size lengthX = from.getMaxIndex()+1;
00705
00706 float stepFourierX = from.getFourierStepWidth();
00707
00708 RegularData1D newGrid(lengthX);
00709 newGrid.setOrigin(from.getFourierSpaceMin());
00710 newGrid.setDimension(from.getFourierSpaceMax()-from.getFourierSpaceMin());
00711
00712
00713
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