BALL  1.4.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
FFT1D.h
Go to the documentation of this file.
1 // -*- Mode: C++; tab-width: 2; -*-
2 // vi: set ts=2:
3 //
4 
5 #ifndef BALL_MATHS_TFFT1D_H
6 #define BALL_MATHS_TFFT1D_H
7 
8 #ifndef BALL_COMMON_EXCEPTION_H
9 # include <BALL/COMMON/exception.h>
10 #endif
11 
12 #ifndef BALL_DATATYPE_REGULARDATA1D_H
14 #endif
15 
16 #include <cmath>
17 #include <complex>
18 #include <fftw3.h>
19 
20 #include <BALL/MATHS/fftwCommon.h>
21 
22 namespace BALL
23 {
26 
27 
35  template <typename ComplexTraits>
36  class TFFT1D
37  : public TRegularData1D<std::complex<typename ComplexTraits::ComplexPrecision> >
38  {
39  public:
40 
41  typedef std::complex<typename ComplexTraits::ComplexPrecision> Complex;
43 
45 
46 
49 
51  TFFT1D();
52 
54  TFFT1D(const TFFT1D &data);
55 
65  // AR: ldn is not any longer the binary logarithm but the absolute number of grid points
66  TFFT1D(Size ldn, double stepPhys = 1., double origin = 0., bool inFourierSpace = false);
67 
69  virtual ~TFFT1D();
70 
72 
76 
78  const TFFT1D& operator = (const TFFT1D& fft1d);
79 
82  virtual void clear();
83 
86  virtual void destroy();
87 
89 
93 
96  bool operator == (const TFFT1D& fft1d) const;
98 
99  // @name Accessors
100 
103  void doFFT();
104 
107  void doiFFT();
108 
113  bool translate(double trans_origin);
114 
120  bool setPhysStepWidth(double new_width);
121 
124  double getPhysStepWidth() const;
125 
128  double getFourierStepWidth() const;
129 
132  double getPhysSpaceMin() const;
133 
136  double getPhysSpaceMax() const;
137 
140  double getFourierSpaceMin() const;
141 
144  double getFourierSpaceMax() const;
145 
151  Size getMaxIndex() const;
152 
157 
160  double getGridCoordinates(Position position) const;
161 
168  Complex getData(const double pos) const;
169 
177  Complex getInterpolatedValue(const double pos) const;
178 
185  void setData(double pos, Complex val);
186 
192  Complex& operator [] (const double pos);
193 
199  const Complex& operator [] (const double pos) const;
200 
205  Complex& operator[](const Position& pos)
206  {
208  }
209 
214  const Complex& operator[](const Position& pos) const
215  {
217  }
218 
220  {
221  numPhysToFourier_ = num;
222  }
223 
225  {
226  numFourierToPhys_ = num;
227  }
228 
232  bool isInFourierSpace() const;
233 
239  Complex phase(const double pos) const;
240 
241  protected:
242 
247  double origin_;
248  double stepPhys_;
249  double stepFourier_;
250  double minPhys_;
251  double maxPhys_;
252  double minFourier_;
253  double maxFourier_;
254 
255  typename ComplexTraits::FftwPlan planForward_;
256  typename ComplexTraits::FftwPlan planBackward_;
257 
258  // AR: to control plan calculation with new fftw3
261  };
263 
267 
268  // AR:
271 // const TRegularData1D<Complex>& operator << (TRegularData1D<Complex>& to, const TFFT1D& from)
272  //; ?????
273 
278 // const RegularData1D& operator << (RegularData1D& to, const TFFT1D& from)
279 //; ???????
280 
281 
282 
283  template <typename ComplexTraits>
285  : TRegularData1D<Complex>(0, 0, 1.), // AR: old case: This is necessary because FFTW_COMPLEX has no default constructor
286  length_(0),
287  inFourierSpace_(false),
288  dataAdress_(0),
289  planCalculated_(false)
290  {
291  }
292 
293 
294  template <typename ComplexTraits>
296  {
297  if (ComplexVector::size() == fft1d.size() &&
298  origin_ == fft1d.origin_ &&
299  stepPhys_ == fft1d.stepPhys_ &&
300  stepFourier_ == fft1d.stepFourier_ &&
301  minPhys_ == fft1d.minPhys_ &&
302  maxPhys_ == fft1d.maxPhys_ &&
303  minFourier_ == fft1d.minFourier_ &&
304  maxFourier_ == fft1d.maxFourier_ &&
305  inFourierSpace_ == fft1d.inFourierSpace_ &&
306  numPhysToFourier_ == fft1d.numPhysToFourier_ &&
307  numFourierToPhys_ == fft1d.numFourierToPhys_ &&
308  planCalculated_ == fft1d.planCalculated_)
309  {
310  double min = inFourierSpace_ ? minFourier_ : minPhys_;
311  double max = inFourierSpace_ ? maxFourier_ : maxPhys_;
312  double step = inFourierSpace_ ? stepFourier_ : stepPhys_;
313 
314  for (double pos=min; pos<=max; pos+=step)
315  {
316  if (getData(pos) != fft1d.getData(pos))
317  {
318  return false;
319  }
320  }
321 
322  return true;
323  }
324 
325  return false;
326  }
327 
328  template <typename ComplexTraits>
329  bool TFFT1D<ComplexTraits>::translate(double trans_origin)
330  {
331  Position internalOrigin = (int) rint(trans_origin/stepPhys_);
332  if (internalOrigin <= length_)
333  {
334  origin_ = trans_origin;
335 
336  minPhys_ = ((-1.)*origin_);
337  maxPhys_ = (((length_-1)*stepPhys_)-origin_);
338  minFourier_ = ((-1.)*(length_/2.-1)*stepFourier_);
339  maxFourier_ = ((length_/2.)*stepFourier_);
340 
341  return true;
342  }
343  else
344  {
345  return false;
346  }
347  }
348 
349  template <typename ComplexTraits>
351  {
352  if (new_width < 0)
353  {
354  return false;
355  }
356  else
357  {
358  stepPhys_ = new_width;
359  stepFourier_ = 2.*M_PI/(stepPhys_*length_);
360 
361  minPhys_ = ((-1.)*origin_);
362  maxPhys_ = (((length_-1)*stepPhys_)-origin_);
363  minFourier_ = ((-1.)*(length_/2.-1)*stepFourier_);
364  maxFourier_ = ((length_/2.)*stepFourier_);
365 
366  return true;
367  }
368  }
369 
370  template <typename ComplexTraits>
372  {
373  return stepPhys_;
374  }
375 
376  template <typename ComplexTraits>
378  {
379  return stepFourier_;
380  }
381 
382  template <typename ComplexTraits>
384  {
385  return minPhys_;
386  }
387 
388  template <typename ComplexTraits>
390  {
391  return maxPhys_;
392  }
393 
394  template <typename ComplexTraits>
396  {
397  return minFourier_;
398  }
399 
400  template <typename ComplexTraits>
402  {
403  return maxFourier_;
404  }
405 
406  template <typename ComplexTraits>
408  {
409  return (length_ - 1);
410  }
411 
412  template <typename ComplexTraits>
414  {
415  return numFourierToPhys_;
416  }
417 
418  // AR: new
419  template <typename ComplexTraits>
421  {
422  if (!inFourierSpace_)
423  {
424  if (position >= ComplexVector::size())
425  {
426  throw Exception::OutOfGrid(__FILE__, __LINE__);
427  }
428 
429  double r;
430 
431  r = -origin_ + (float)position * stepPhys_;
432 
433  return r;
434  }
435  else
436  {
437  if (position >= ComplexVector::size())
438  {
439  throw Exception::OutOfGrid(__FILE__, __LINE__);
440  }
441 
442  double r;
443  Index x;
444 
445  x = position;
446 
447  if (x>=length_/2.)
448  {
449  x-=length_;
450  }
451 
452  r = (float)x * stepFourier_;
453 
454  return r;
455  }
456  }
457 
458  template <typename ComplexTraits>
460  {
461  Complex result;
462  double normalization=1.;
463 
464  if (!inFourierSpace_)
465  {
466  result = (*this)[pos];//Complex((*this)[pos].real(), (*this)[pos].imag());
467  normalization=1./pow((double)length_,(int)numFourierToPhys_);
468  }
469  else
470  {
471  result = (*this)[pos]*phase(pos);//Complex((*this)[pos].real(),(*this)[pos].imag()) * phase(pos);
472  //Log.error() << pos << " " << phase(pos).real() << std::endl;
473  normalization=1./(sqrt(2.*M_PI))/pow((double)length_,(int)numFourierToPhys_);
474  }
475 
476  result *= normalization;
477 
478  return result;
479  }
480 
481  template <typename ComplexTraits>
483  {
484  Complex result;
485 
486  double min = inFourierSpace_ ? minFourier_ : minPhys_;
487  double max = inFourierSpace_ ? maxFourier_ : maxPhys_;
488  double step = inFourierSpace_ ? stepFourier_ : stepPhys_;
489 
490  if ((pos < min) || (pos > max))
491  {
492  throw Exception::OutOfGrid(__FILE__, __LINE__);
493  }
494 
495  double h = pos - min;
496  double mod = fmod(h,step);
497 
498  if (mod ==0) // we are on the grid
499  {
500  return getData(pos);
501  }
502 
503  double before = floor(h/step)*step+ min;
504  double after = ceil(h/step)*step+ min;
505 
506  double t = (pos - before)/step;
507 
508  result = getData(before)*(typename ComplexTraits::ComplexPrecision)(1.-t);
509  result += getData(after)*(typename ComplexTraits::ComplexPrecision)t;
510 
511  return result;
512  }
513 
514  template <typename ComplexTraits>
516  {
517  Complex dummy;
518  if (!inFourierSpace_)
519  {
520  dummy = Complex(val.real()*((typename ComplexTraits::ComplexPrecision)pow((typename ComplexTraits::ComplexPrecision)(length_),(int)numFourierToPhys_)),
521  val.imag()*((typename ComplexTraits::ComplexPrecision)pow((typename ComplexTraits::ComplexPrecision)(length_),(int)numFourierToPhys_)));
522 
523  (*this)[pos]=dummy;
524  }
525  else
526  {
527  val*=phase(pos)*(typename ComplexTraits::ComplexPrecision)((sqrt(2*M_PI)/stepPhys_))
528  *(typename ComplexTraits::ComplexPrecision)pow((typename ComplexTraits::ComplexPrecision)length_,(int)numFourierToPhys_);
529 
530  dummy = val;
531 
532  (*this)[pos]=dummy;
533  }
534  }
535 
536  template <typename ComplexTraits>
538  {
539  Index internalPos;
540 
541  if (!inFourierSpace_)
542  {
543  internalPos = (Index) rint((pos+origin_)/stepPhys_);
544  }
545  else
546  {
547  internalPos = (Index) rint(pos/stepFourier_);
548 
549  if (internalPos < 0)
550  {
551  internalPos+=length_;
552  }
553  }
554 
555  if ((internalPos < 0) || (internalPos>=(Index) length_))
556  {
557  throw Exception::OutOfGrid(__FILE__, __LINE__);
558  }
559 
560  return operator [] ((Position)internalPos);
561  }
562 
563  template <typename ComplexTraits>
565  {
566  Index internalPos;
567 
568  if (!inFourierSpace_)
569  {
570  internalPos = (Index) rint((pos+origin_)/stepPhys_);
571  }
572  else
573  {
574  internalPos = (Index) rint(pos/stepFourier_);
575 
576  if (internalPos < 0)
577  {
578  internalPos+=length_;
579  }
580  }
581 
582  if ((internalPos < 0) || (internalPos>=(Index) length_))
583  {
584  throw Exception::OutOfGrid(__FILE__, __LINE__);
585  }
586 
587  return operator [] ((Position)internalPos);
588  }
589 
590  template <typename ComplexTraits>
592  {
593  double phase = 2.*M_PI*(rint(pos/stepFourier_))
594  *(rint(origin_/stepPhys_))
595  /length_;
596  Complex result = Complex(cos(phase), sin(phase));
597 
598  return result;
599  }
600 
601  template <typename ComplexTraits>
603  {
604  return inFourierSpace_;
605  }
606 /*
607  const TRegularData1D<Complex >& operator << (TRegularData1D<Complex >& to, const TFFT1D<ComplexTraits>& from)
608  {
609  // first decide if the TFFT1D data is in Fourier space.
610  if (!from.isInFourierSpace())
611  {
612  // create a new grid
613  Size lengthX = from.getMaxIndex()+1;
614 
615  TRegularData1D<Complex > newGrid(TRegularData1D<Complex >::IndexType(lengthX), from.getPhysSpaceMin(), from.getPhysSpaceMax());
616 
617  // and fill it
618  double normalization=1./(pow((float)(lengthX),from.getNumberOfInverseTransforms()));
619 
620  for (Position i = 0; i < from.size(); i++)
621  {
622  newGrid[i] = from[i]*(ComplexTraits::ComplexPrecision)normalization;
623  }
624 
625  to = newGrid;
626 
627  return to;
628  }
629  else
630  {
631  // we are in Fourier space
632 
633  // create a new grid
634  Size lengthX = from.getMaxIndex()+1;
635  //float stepPhysX = from.getPhysStepWidthX();
636  float stepFourierX = from.getFourierStepWidth();
637 
638 
639  TRegularData1D<Complex > newGrid(TRegularData1D<Complex >::IndexType(lengthX),
640  from.getFourierSpaceMin(),
641  from.getFourierSpaceMax());
642 
643  // and fill it
644  // AR: old double normalization=1./(sqrt(2.*M_PI))*(stepPhysX*stepPhysY*stepPhysZ)/(pow((float)(lengthX*lengthY*lengthZ),from.getNumberOfInverseTransforms()));
645  double normalization=1./sqrt(2.*M_PI)/(pow((float)(lengthX),from.getNumberOfInverseTransforms()));
646 
647 
648  Index x;
649  float r;
650 
651  for (Position i = 0; i < from.size(); i++)
652  {
653  x = i;
654 
655  if (x>lengthX/2.)
656  {
657  x-=lengthX;
658  }
659 
660  r = (float)x * stepFourierX;
661 
662  newGrid[i] = from[i]*(ComplexTraits::ComplexPrecision)normalization*from.phase(r);
663  }
664 
665  to = newGrid;
666 
667  return to;
668  }
669  }
670  */
671 
672  template <typename ComplexTraits>
673  const RegularData1D& operator << (RegularData1D& to, const TFFT1D<ComplexTraits>& from)
674  {
675  // first decide if the FFT1D data is in Fourier space.
676  if (!from.isInFourierSpace())
677  {
678  // create a new grid
679  Size lengthX = from.getMaxIndex()+1;
680 
681  RegularData1D newGrid(lengthX);
682  newGrid.setOrigin(from.getPhysSpaceMin());
683  newGrid.setDimension(from.getPhysSpaceMax()-from.getPhysSpaceMin());
684 
685  // and fill it
686  double normalization = 1./(pow((float)(lengthX),from.getNumberOfInverseTransforms()));
687 
688  for (Position i = 0; i < from.size(); i++)
689  {
690  newGrid[i] = from[i].real()*normalization;
691  }
692 
693  to = newGrid;
694 
695  return to;
696  }
697  else
698  {
699  // we are in Fourier space
700 
701  // create a new grid
702  Size lengthX = from.getMaxIndex()+1;
703  //float stepPhysX = from.getPhysStepWidth();
704  float stepFourierX = from.getFourierStepWidth();
705 
706  RegularData1D newGrid(lengthX);
707  newGrid.setOrigin(from.getFourierSpaceMin());
708  newGrid.setDimension(from.getFourierSpaceMax()-from.getFourierSpaceMin());
709 
710  // and fill it
711  // AR: old version double normalization=1./(sqrt(2.*M_PI))*(stepPhysX*stepPhysY*stepPhysZ)/(pow((float)(lengthX*lengthY*lengthZ),from.getNumberOfInverseTransforms()));
712  double normalization=1./sqrt(2.*M_PI)/(pow((float)(lengthX),from.getNumberOfInverseTransforms()));
713 
714  Index x;
715  signed int xp;
716  float r;
717 
718  for (Position i = 0; i < from.size(); i++)
719  {
720  x = i;
721 
722  xp = x;
723 
724  if (xp>=lengthX/2.)
725  {
726  xp-=(int)lengthX;
727  }
728 
729  if (x>=lengthX/2.)
730  {
731  x-=(int)(lengthX/2.);
732  }
733  else
734  {
735  x+=(int)(lengthX/2.);
736  }
737 
738 
739  r = ((float)xp * stepFourierX);
740 
741  newGrid[i] = (from[i]*(typename ComplexTraits::ComplexPrecision)normalization*from.phase(r)).real();
742  }
743 
744  to = newGrid;
745 
746  return to;
747  }
748  }
749 }
750 #endif // BALL_MATHS_TFFT1D_H