Xmipp  v3.23.11-Nereus
xmipp_fft.h
Go to the documentation of this file.
1 /***************************************************************************
2 *
3 * Authors: Carlos Oscar S. Sorzano (coss@cnb.csic.es)
4 *
5 * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 * 02111-1307 USA
21 *
22 * All comments concerning this program package may be sent to the
23 * e-mail address 'xmipp@cnb.csic.es'
24 ***************************************************************************/
25 
26 #ifndef CORE_FFT_H
27 #define CORE_FFT_H
28 
29 #include <complex>
30 
31 #include "multidim_array.h"
32 #include "xmipp_funcs.h"
33 
46 #define FFT_IDX2DIGFREQ(idx, size, freq) \
47  freq = (size<=1)? 0:(( (((int)idx) <= (((int)(size)) >> 1)) ? ((int)(idx)) : -((int)(size)) + ((int)(idx))) / \
48  (double)(size));
49 
50 #define FFT_IDX2DIGFREQ_DOUBLE(idx, size, freq) \
51  freq = (size<=1)? 0:(( (((double)idx) <= (((double)(size)) / 2.0)) ? ((double)(idx)) : -((double)(size)) + ((double)(idx))) / \
52  (double)(size));
53 
54 #define FFT_IDX2DIGFREQ_FAST(idx, size, size_2, isize, freq) \
55  freq = ( ((idx) <= (size_2)) ? (idx) : -(size) + (idx) ) * (isize);
56 
61 #define DIGFREQ2FFT_IDX(freq, size, idx) { \
62  (idx) = (int) (round((size) * (freq))); if ((idx) < 0) (idx) += (int) \
63  (size); }
64 
70 #define DIGFREQ2FFT_IDX_DOUBLE(freq, size, idx) { \
71  (idx) = ((size) * (freq)); if ((idx) < 0) (idx) += (size); }
72 
79 template <typename T>
80 void FFT_idx2digfreq(T& v, const Matrix1D< int >& idx, Matrix1D< double >& freq)
81 {
82  if (VEC_XSIZE(idx) < 1 || VEC_XSIZE(idx) > 3)
83  REPORT_ERROR(ERR_MATRIX_SIZE, "FFT_idx2digfreq: Index is not of the correct size");
84 
85  freq.resizeNoCopy(VEC_XSIZE(idx));
86 
87  switch (VEC_XSIZE(idx))
88  {
89  case 3:
90  FFT_IDX2DIGFREQ(VEC_ELEM(idx,2), ZSIZE(v), VEC_ELEM(freq,2));
91  case 2:
92  FFT_IDX2DIGFREQ(VEC_ELEM(idx,1), YSIZE(v), VEC_ELEM(freq,1));
93  case 1:
94  FFT_IDX2DIGFREQ(VEC_ELEM(idx,0), XSIZE(v), VEC_ELEM(freq,0));
95  }
96 }
97 
105 template <typename T>
107 {
108  if (VEC_XSIZE(freq) < 1 || VEC_XSIZE(freq) > 3)
109  REPORT_ERROR(ERR_MATRIX_SIZE, "digfreq2FFT_idx: freq is not of the correct size");
110 
111  idx.resizeNoCopy(VEC_XSIZE(freq));
112 
113  int size[3];
114  v.getSize(size);
115 
117  DIGFREQ2FFT_IDX(VEC_ELEM(freq,i), size[i], VEC_ELEM(idx,i));
118 }
119 
125 inline void digfreq2contfreq(const Matrix1D< double >& digfreq,
126  Matrix1D< double >& contfreq,
127  double pixel_size)
128 {
129  contfreq.resizeNoCopy(digfreq);
131  VEC_ELEM(contfreq,i) = VEC_ELEM(digfreq,i) / pixel_size;
132 }
133 
139 inline void contfreq2digfreq(const Matrix1D< double >& contfreq,
140  Matrix1D< double >& digfreq,
141  double pixel_size)
142 {
143  digfreq.resizeNoCopy(contfreq);
145  VEC_ELEM(digfreq,i) = VEC_ELEM(contfreq,i) * pixel_size;
146 }
148 
154 void Whole2Half(const MultidimArray< std::complex < double > > & in,
155  MultidimArray< std::complex < double > > & out);
156 
159 void Half2Whole(const MultidimArray< std::complex < double > > & in,
160  MultidimArray< std::complex< double > > & out,
161  size_t oridim);
162 
165 void Complex2RealImag(const MultidimArray< std::complex < double > > & in,
167  MultidimArray< double > & imag);
168 
171 void RealImag2Complex(const MultidimArray< double > & real,
172  const MultidimArray< double > & imag,
173  MultidimArray< std::complex < double > > & out);
175 
252  MultidimArray< std::complex< double > > & out);
253 
256 void InverseFourierTransform(const MultidimArray< std::complex< double > > & in,
258 
262  MultidimArray< std::complex< double > > & out);
263 
266 void InverseFourierTransformHalf(const MultidimArray< std::complex< double > > & in,
268  int oridim);
270 
274 
278 #define SWAP_ARRAY(a, b, n) memcpy(buffer, a, n); memcpy(a, b, n); memcpy(b, buffer, n);
279 
284 
285 
290 template <typename T>
291 void CenterFFT(MultidimArray< T >& v, bool forward)
292 {
293  bool firstTime=true; // First time executing inner loops.
294 
295  // Check dimension is between 1 and 3 inclusive.
296  if ( v.getDim() > 0 && v.getDim() <= 3)
297  {
298  // Shift in the X direction
299  size_t l=0;
300 
301  // Shift in the X direction
302  if (((l = XSIZE(v)) > 1) && (YSIZE(v) == 1) && (ZSIZE(v) == 1))
303  {
304  size_t firstHalfSize=0;
305  size_t secondHalfSize=0;
306  MultidimArray< T > aux;
307 
308  if (forward)
309  {
310  firstHalfSize = (l + 1) / 2;
311  secondHalfSize = l - firstHalfSize;
312  aux.resizeNoCopy( firstHalfSize);
313 
314  for (size_t k = 0; k < ZSIZE(v); k++)
315  {
316  for (size_t i = 0; i < YSIZE(v); i++)
317  {
318  memcpy( &dAi(aux, 0), &dAkij(v, k, i, 0), sizeof(T)*firstHalfSize);
319  memcpy( &dAkij(v, k, i, 0), &dAkij(v, k, i, firstHalfSize), sizeof(T)*secondHalfSize);
320  memcpy( &dAkij(v, k, i, secondHalfSize), &dAi(aux, 0), sizeof(T)*firstHalfSize);
321  }
322  }
323  }
324  else
325  {
326  secondHalfSize = (l + 1) / 2;
327  firstHalfSize = l - secondHalfSize;
328  aux.resizeNoCopy( secondHalfSize);
329 
330  for (size_t k = 0; k < ZSIZE(v); k++)
331  {
332  for (size_t i = 0; i < YSIZE(v); i++)
333  {
334  memcpy( &dAi(aux, 0), &dAkij(v, k, i, firstHalfSize), sizeof(T)*secondHalfSize);
335  memcpy( &dAkij(v, k, i, secondHalfSize), &dAkij(v, k, i, 0), sizeof(T)*firstHalfSize);
336  memcpy( &dAkij(v, k, i, 0), &dAi(aux, 0), sizeof(T)*secondHalfSize);
337  }
338  }
339  }
340  }
341  else
342  {
343  // 3D
344  MultidimArray< T > aux;
345  size_t l=0;
346  long int shift;
347 
348  int i=0; // Loop counter.
349  int halfRows=0; // Half rows of the matrix.
350  int rowSize=0; // Size in bytes of the row.
351 
352  // Size in bytes of first and second half row.
353  int firstHalfRowSize=0, secondHalfRowSize=0;
354 
355  // # elements in first and second half row.
356  int nElemsFirstHalf_X=0, nElemsSecondHalf_X=0;
357 
358  MultidimArray< T > tempVector; // Temporary vector.
359 
360  bool isOdd=false; // Odd # rows in matrix.
361  MultidimArray< T > savedRow; // Temporary vector in odd matrix.
362 
363  // Execute FFT in 2 dimensions before 3D.
364  if (forward)
365  {
366  for (size_t k=0; k<ZSIZE(v); k++)
367  {
368  // Pointers to upper and lower half matrix.
369  T *upperHalfPtr, *lowerHalfSrcPtr, *lowerHalfDestPtr;
370 
371  // This is computed first time only.
372  if (firstTime)
373  {
374  firstTime = false;
375 
376  // Compute # elements in each half vector in X-dimension.
377  nElemsFirstHalf_X = (XSIZE(v) + 1) / 2;
378  nElemsSecondHalf_X = XSIZE(v) - nElemsFirstHalf_X;
379 
380  // Compute X dimension size in bytes.
381  rowSize = XSIZE(v)*sizeof(T);
382 
383  // Allocate temporary vector.
384  firstHalfRowSize = nElemsFirstHalf_X*sizeof(T);
385  secondHalfRowSize = rowSize - firstHalfRowSize;
386  tempVector.resizeNoCopy( XSIZE(v));
387 
388  // Compute # iterations.
389  halfRows = YSIZE(v) / 2;
390 
391  // If even # rows then save row located in the middle of the matrix.
392  if ((YSIZE(v) % 2) != 0)
393  {
394  isOdd = true;
395  savedRow.resizeNoCopy( XSIZE(v));
396  }
397  }
398 
399  // Initialize pointers to upper and lower matrix rows.
400  upperHalfPtr = &dAkij(v, k, 0, 0);
401  lowerHalfSrcPtr = upperHalfPtr + (halfRows*XSIZE(v));
402  lowerHalfDestPtr = lowerHalfSrcPtr;
403 
404  // If even # rows then save row located in the middle of the matrix.
405  if (isOdd)
406  {
407  memcpy( &dAi(savedRow,0), lowerHalfSrcPtr, rowSize);
408 
409  // Source and destination rows are not the same in odd matrix.
410  lowerHalfSrcPtr = lowerHalfSrcPtr + XSIZE(v);
411  }
412 
413  // Half of the rows must be exchanged.
414  for (i=0; i<halfRows ;i++)
415  {
416  memcpy( &dAi(tempVector,0), upperHalfPtr, rowSize);
417  memcpy( upperHalfPtr, lowerHalfSrcPtr + nElemsFirstHalf_X, secondHalfRowSize);
418  memcpy( upperHalfPtr + nElemsSecondHalf_X, lowerHalfSrcPtr, firstHalfRowSize);
419  memcpy( lowerHalfDestPtr, &dAi(tempVector, nElemsFirstHalf_X), secondHalfRowSize);
420  memcpy( lowerHalfDestPtr + nElemsSecondHalf_X, &dAi(tempVector,0), firstHalfRowSize);
421 
422  upperHalfPtr = upperHalfPtr + XSIZE(v);
423  lowerHalfSrcPtr = lowerHalfSrcPtr + XSIZE(v);
424  lowerHalfDestPtr = lowerHalfDestPtr + XSIZE(v);
425  }
426 
427  // If # rows is odd then restore last row.
428  if (isOdd)
429  {
430  memcpy( lowerHalfDestPtr + nElemsSecondHalf_X, &dAi(savedRow,0), firstHalfRowSize);
431  memcpy( lowerHalfDestPtr, &dAi(savedRow, nElemsFirstHalf_X), secondHalfRowSize);
432  }
433  }
434  }
435  else
436  {
437  for (size_t k = 0; k<ZSIZE(v); k++)
438  {
439  // Pointers to upper and lower half matrix.
440  T *upperHalfSrcPtr, *upperHalfDestPtr, *lowerHalfPtr;
441 
442  // This is computed first time only.
443  if (firstTime)
444  {
445  firstTime = false;
446 
447  // Compute # elements in each half vector in X-dimension.
448  nElemsSecondHalf_X = (XSIZE(v) + 1) / 2;
449  nElemsFirstHalf_X = XSIZE(v) - nElemsSecondHalf_X;
450 
451  // Allocate temporary vector.
452  rowSize = XSIZE(v)*sizeof(T);
453  firstHalfRowSize = nElemsFirstHalf_X*sizeof(T);
454  secondHalfRowSize = rowSize - firstHalfRowSize;
455  tempVector.resizeNoCopy(rowSize);
456 
457  // Compute # iterations.
458  halfRows = YSIZE(v) / 2;
459 
460  // If odd # rows then save last row.
461  if ((YSIZE(v) % 2) != 0)
462  {
463  isOdd = true;
464  savedRow.resizeNoCopy(XSIZE(v));
465  }
466  }
467 
468  // Initialize pointers to quadrants.
469  upperHalfSrcPtr = &dAkij(v, k, halfRows-1, 0);
470  lowerHalfPtr = &dAkij(v, k, YSIZE(v)-1, 0);
471  upperHalfDestPtr = upperHalfSrcPtr;
472 
473  // If odd # rows then save last row.
474  if (isOdd)
475  {
476  // Source and destination rows are not the same in odd matrix.
477  upperHalfDestPtr = upperHalfDestPtr + XSIZE(v);
478 
479  memcpy( &dAi(savedRow,0), upperHalfDestPtr, rowSize);
480  }
481 
482  // Half of the rows must be exchanged.
483  for (i=0; i<halfRows ;i++)
484  {
485  memcpy( &dAi(tempVector, 0), upperHalfSrcPtr, rowSize);
486  memcpy( upperHalfDestPtr, lowerHalfPtr + nElemsFirstHalf_X, secondHalfRowSize);
487  memcpy( upperHalfDestPtr + nElemsSecondHalf_X, lowerHalfPtr, firstHalfRowSize);
488  memcpy( lowerHalfPtr, &dAi(tempVector, nElemsFirstHalf_X), secondHalfRowSize);
489  memcpy( lowerHalfPtr + nElemsSecondHalf_X, &dAi(tempVector,0), firstHalfRowSize);
490 
491  upperHalfSrcPtr = upperHalfSrcPtr - XSIZE(v);
492  lowerHalfPtr = lowerHalfPtr - XSIZE(v);
493  upperHalfDestPtr = upperHalfDestPtr - XSIZE(v);
494  }
495 
496  // If # rows is odd then restore row at medium position.
497  if (isOdd)
498  {
499  memcpy( upperHalfDestPtr + nElemsSecondHalf_X, &dAi(savedRow, 0), firstHalfRowSize);
500  memcpy( upperHalfDestPtr, &dAi(savedRow, nElemsFirstHalf_X), secondHalfRowSize);
501  }
502  }
503  }
504 
505  // Shift in the Z direction
506  if ((l = ZSIZE(v)) > 1)
507  {
508  aux.resizeNoCopy(l);
509  shift = (long int)(l / 2);
510 
511  if (!forward)
512  shift = -shift;
513  size_t lmax=(l/4)*4;
514  for (size_t i = 0; i < YSIZE(v); i++)
515  {
516  for (size_t j = 0; j < XSIZE(v); j++)
517  {
518  // Shift the input in an auxiliary vector
519  for (size_t k = 0; k < l; k++)
520  {
521  size_t kp = k + shift;
522  if (-shift > (long int)k)
523  kp += l;
524  else if (kp >= l)
525  kp -= l;
526 
527  dAi(aux,kp) = dAkij(v, k, i, j);
528  }
529 
530  // Copy the vector
531  const T* ptrAux=&dAi(aux,0);
532  for (size_t k = 0; k < lmax; k+=4,ptrAux+=4)
533  {
534  dAkij(v, k, i, j) = *ptrAux;
535  dAkij(v, k+1, i, j) = *(ptrAux+1);
536  dAkij(v, k+2, i, j) = *(ptrAux+2);
537  dAkij(v, k+3, i, j) = *(ptrAux+3);
538  }
539  for (size_t k = lmax; k < l; ++k, ++ptrAux)
540  {
541  dAkij(v, k, i, j) = *ptrAux;
542  }
543  }
544  }
545  }
546  }
547  }
548  else
549  {
550  REPORT_ERROR(ERR_MULTIDIM_DIM,"CenterFFT ERROR: Dimension should be 1, 2 or 3");
551  }
552 }
553 
559 void ShiftFFT(MultidimArray< std::complex< double > > & v, double xshift);
560 
566 void ShiftFFT(MultidimArray< std::complex< double > > & v, double xshift, double yshift);
567 
573 void ShiftFFT(MultidimArray< std::complex< double > > & v,
574  double xshift,
575  double yshift,
576  double zshift);
577 
582 void CenterOriginFFT(MultidimArray< std::complex< double > > & v, bool forward);
583 
584 
587 template<typename T>
588 void xmipp2PSD(const MultidimArray<T> &input, MultidimArray<T> &output,
589  bool takeLog=true);
590 
593 void xmipp2CTF(const MultidimArray<double> &input, MultidimArray<double> &output);
595 
596 #endif
void FourierTransformHalf(const MultidimArray< double > &in, MultidimArray< std::complex< double > > &out)
Definition: xmipp_fft.cpp:187
#define dAi(v, i)
#define YSIZE(v)
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
Problem with matrix size.
Definition: xmipp_error.h:152
void digfreq2FFT_idx(T &v, const Matrix1D< double > &freq, Matrix1D< int > &idx)
Definition: xmipp_fft.h:106
#define VEC_XSIZE(m)
Definition: matrix1d.h:77
void ShiftFFT(MultidimArray< std::complex< double > > &v, double xshift)
Definition: xmipp_fft.cpp:311
void resizeNoCopy(const MultidimArray< T1 > &v)
#define FFT_IDX2DIGFREQ(idx, size, freq)
Definition: xmipp_fft.h:46
void centerFFT2(MultidimArray< double > &v)
Definition: xmipp_fft.cpp:276
void Whole2Half(const MultidimArray< std::complex< double > > &in, MultidimArray< std::complex< double > > &out)
Definition: xmipp_fft.cpp:34
void InverseFourierTransform(const MultidimArray< std::complex< double > > &in, MultidimArray< double > &out)
Definition: xmipp_fft.cpp:155
#define DIGFREQ2FFT_IDX(freq, size, idx)
Definition: xmipp_fft.h:61
void FFT_idx2digfreq(T &v, const Matrix1D< int > &idx, Matrix1D< double > &freq)
Definition: xmipp_fft.h:80
#define i
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
void CenterFFT(MultidimArray< T > &v, bool forward)
Definition: xmipp_fft.h:291
void Half2Whole(const MultidimArray< std::complex< double > > &in, MultidimArray< std::complex< double > > &out, size_t oridim)
Definition: xmipp_fft.cpp:66
#define FOR_ALL_ELEMENTS_IN_MATRIX1D(v)
Definition: matrix1d.h:72
void xmipp2PSD(const MultidimArray< T > &input, MultidimArray< T > &output, bool takeLog=true)
Definition: xmipp_fft.cpp:443
void RealImag2Complex(const MultidimArray< double > &real, const MultidimArray< double > &imag, MultidimArray< std::complex< double > > &out)
Definition: xmipp_fft.cpp:114
void contfreq2digfreq(const Matrix1D< double > &contfreq, Matrix1D< double > &digfreq, double pixel_size)
Definition: xmipp_fft.h:139
int in
void xmipp2CTF(const MultidimArray< double > &input, MultidimArray< double > &output)
Definition: xmipp_fft.cpp:472
#define XSIZE(v)
#define dAkij(V, k, i, j)
#define ZSIZE(v)
void FourierTransform(const MultidimArray< double > &in, MultidimArray< std::complex< double > > &out)
Definition: xmipp_fft.cpp:124
#define j
void resizeNoCopy(int Xdim)
Definition: matrix1d.h:458
Incorrect MultidimArray dimensions.
Definition: xmipp_error.h:173
void Complex2RealImag(const MultidimArray< std::complex< double > > &in, MultidimArray< double > &real, MultidimArray< double > &imag)
Definition: xmipp_fft.cpp:103
void InverseFourierTransformHalf(const MultidimArray< std::complex< double > > &in, MultidimArray< double > &out, int oridim)
Definition: xmipp_fft.cpp:197
void digfreq2contfreq(const Matrix1D< double > &digfreq, Matrix1D< double > &contfreq, double pixel_size)
Definition: xmipp_fft.h:125
void CenterOriginFFT(MultidimArray< std::complex< double > > &v, bool forward)
Definition: xmipp_fft.cpp:386