Xmipp  v3.23.11-Nereus
xmipp_fft.cpp
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 #include "bilib/dft.h"
27 
28 #include "xmipp_fft.h"
29 #include "args.h"
30 #include "histogram.h"
31 
32 /* Format conversions ------------------------------------------------------ */
34 void Whole2Half(const MultidimArray<std::complex<double> > &in,
35  MultidimArray<std::complex<double> > &out)
36 {
37  if (in.getDim() == 1)
38  {
39  // 1D
40  int ldim = (int)(XSIZE(in) / 2) + 1;
41  out.resize(ldim);
42  for (int j = 0; j < ldim; j++)
43  out(j) = in(j);
44  }
45  else if (in.getDim() == 2)
46  {
47  // 2D
48  // This assumes squared images...
49  int ldim = (int)(YSIZE(in) / 2) + 1;
50 
51  out.initZeros(ldim, XSIZE(in));
52  // Fill first column only half
53  for (int j = 0; j < ldim; j++)
54  dAij(out, 0, j) = dAij(in, 0, j);
55  // Fill rest
56  for (int i = 1; i < ldim; i++)
57  for (size_t j = 0; j < XSIZE(in); j++)
58  dAij(out, i, j) = dAij(in, i, j);
59  }
60  else
61  REPORT_ERROR(ERR_MULTIDIM_DIM,"ERROR: Whole2Half only implemented for 1D and 2D multidimArrays");
62 
63 }
64 
66 void Half2Whole(const MultidimArray<std::complex<double> > &in,
67  MultidimArray<std::complex<double> > &out, size_t oridim)
68 {
69  if (in.getDim() == 1)
70  {
71  // 1D
72  out.resizeNoCopy(oridim);
73  for (size_t j = 0; j < XSIZE(in); j++)
75  for (size_t j = XSIZE(in); j < oridim; j++)
76  DIRECT_A1D_ELEM(out,j) = conj(DIRECT_A1D_ELEM(in,oridim - j));
77  }
78  else if (in.getDim() == 2)
79  {
80  // 2D
81  out.resizeNoCopy(oridim, XSIZE(in));
82 
83  // Old part
84  for (size_t i = 0; i < YSIZE(in); i++)
85  for (size_t j = 0; j < XSIZE(in); j++)
86  dAij(out, i, j) = dAij(in, i, j);
87 
88  // Complete first column of old part
89  for (size_t j = YSIZE(in); j < XSIZE(in); j++)
90  dAij(out, 0, j) = conj(dAij(in, 0, XSIZE(in) - j));
91 
92  // New part
93  for (size_t i = YSIZE(in); i < oridim; i++)
94  {
95  dAij(out, i, 0) = conj(dAij(in, oridim - i, 0));
96  for (size_t j = 1; j < XSIZE(in); j++)
97  dAij(out, i, j) = conj(dAij(in, oridim - i, XSIZE(in) - j));
98  }
99  }
100 }
101 
103 void Complex2RealImag(const MultidimArray< std::complex< double > > & in,
106 {
107  real.resizeNoCopy(in);
108  imag.resizeNoCopy(in);
111 }
112 
115  const MultidimArray< double > & imag,
116  MultidimArray< std::complex< double > > & out)
117 {
118  out.resizeNoCopy(real);
120  MULTIDIM_ARRAY(out), MULTIDIM_SIZE(real));
121 }
122 
125  MultidimArray< std::complex<double> > &out)
126 {
127  if ( in.getDim() == 1 )
128  {
129  // 1D
130  int N = XSIZE(in);
131  MultidimArray<double> re(in), tmp(N), im(N), cas(N);
132  out.resizeNoCopy(N);
133 
134  GetCaS(MULTIDIM_ARRAY(cas), N);
136  MULTIDIM_ARRAY(tmp), MULTIDIM_ARRAY(cas), N);
138  MULTIDIM_ARRAY(out), N);
139  }
140  else
141  {
142  // 2D and 3D
143  int Status;
144  MultidimArray<double> re(in), im;
145  im.resizeNoCopy(in);
146  out.resizeNoCopy(in);
148  MULTIDIM_ARRAY(im), XSIZE(in), YSIZE(in), ZSIZE(in), &Status);
149  RealImag2Complex(re,im,out);
150  }
151 
152 }
153 
155 void InverseFourierTransform(const MultidimArray< std::complex<double> > &in,
157 {
158  if ( in.getDim() == 1 )
159  {
160  // 1D
161  int N = XSIZE(in);
162  MultidimArray<double> tmp(N), im(N), cas(N);
163  out.resizeNoCopy(N);
164 
165  GetCaS(MULTIDIM_ARRAY(cas), N);
167  MULTIDIM_ARRAY(im), N);
169  MULTIDIM_ARRAY(tmp), MULTIDIM_ARRAY(cas), N);
170  }
171  else
172  {
173  // 2D and 3D
174  int Status;
176  out.resizeNoCopy(in);
177  im.resizeNoCopy(in);
178  Complex2RealImag(in, out, im);
180  MULTIDIM_ARRAY(im),
181  XSIZE(in), YSIZE(in), ZSIZE(in), &Status);
182  }
183 }
184 
185 
188  MultidimArray< std::complex<double> > &out)
189 {
190 
192  FourierTransform(in, aux);
193  Whole2Half(aux, out);
194 }
195 
197 void InverseFourierTransformHalf(const MultidimArray< std::complex<double> > &in,
198  MultidimArray<double> &out, int oridim)
199 {
200 
202  Half2Whole(in, aux, oridim);
203  InverseFourierTransform(aux, out);
204  out.setXmippOrigin();
205 }
206 
207 /* Complex Fourier Transform ------------------------------------------------------ */
208 
210 void FourierTransform(const MultidimArray<std::complex<double> > &in,
211  MultidimArray< std::complex<double> > &out)
212 {
213  // Only implemented for 1D transforms
214  in.checkDimension(1);
215 
216  int N = XSIZE(in);
217  MultidimArray<double> re(N), tmpre(N), tmpim(N), im(N), cas(N);
218  out.resizeNoCopy(N);
219 
220  GetCaS(MULTIDIM_ARRAY(cas), N);
222  MULTIDIM_ARRAY(im), N);
224  MULTIDIM_ARRAY(tmpre), MULTIDIM_ARRAY(tmpim),
225  MULTIDIM_ARRAY(cas), N);
227  MULTIDIM_ARRAY(out), N);
228 }
229 
231 void InverseFourierTransform(const MultidimArray< std::complex<double> > &in,
232  MultidimArray<std::complex<double> > &out)
233 {
234  // Only implemented for 1D transforms
235  in.checkDimension(1);
236 
237  int N = XSIZE(in);
238  MultidimArray<double> tmpre(N), tmpim(N), re(N), im(N), cas(N);
239  out.resizeNoCopy(N);
240 
241  GetCaS(MULTIDIM_ARRAY(cas), N);
243  MULTIDIM_ARRAY(im), N);
245  MULTIDIM_ARRAY(tmpre), MULTIDIM_ARRAY(tmpim),
246  MULTIDIM_ARRAY(cas), N);
248  MULTIDIM_ARRAY(out), N);
249 }
250 
252 void FourierTransformHalf(const MultidimArray<std::complex<double> > &in,
253  MultidimArray< std::complex<double> > &out)
254 {
255  // Only implemented for 1D transforms
256  in.checkDimension(1);
257 
259  FourierTransform(in, aux);
260  Whole2Half(aux, out);
261 }
262 
264 void InverseFourierTransformHalf(const MultidimArray< std::complex<double> > &in,
265  MultidimArray<std::complex<double> > &out, int orixdim)
266 {
267  // Only implemented for 1D transforms
268  in.checkDimension(1);
269 
271  Half2Whole(in, aux, orixdim);
272  InverseFourierTransform(aux, out);
273  out.setXmippOrigin();
274 }
275 
277 {
278  if (v.getDim() == 2)
279  {
280  //Just separe the even and odd dimensions case
281  if (XSIZE(v) % 2 == 0 && YSIZE(v) % 2 == 0)
282  {
283  int xsize = XSIZE(v);
284  int xhalf = xsize / 2;
285  int yhalf = YSIZE(v) / 2;
286  double * posA = MULTIDIM_ARRAY(v);
287  double * posB = posA + xhalf;
288  double * posC = posA + xsize * yhalf;
289  double * posD = posC + xhalf;
290  double * buffer=new double[xhalf];
291  size_t bytes = xhalf * sizeof(double);
292 
293  for (int i = 0; i < yhalf; ++i,
294  posA += xsize, posB += xsize, posC += xsize, posD += xsize)
295  {
296  SWAP_ARRAY(posA, posD, bytes);
297  SWAP_ARRAY(posB, posC, bytes);
298  }
299  delete []buffer;
300  }
301  else
302  {
303  //todo: implementation for the odd case needed
304  CenterFFT(v, true);
305  }
306  }
307  else
308  std::cerr <<"bad dim: " << v.getDim() << std::endl;
309 }
310 /* FFT shifts ------------------------------------------------------------ */
311 void ShiftFFT(MultidimArray< std::complex< double > > & v,
312  double xshift)
313 {
314  v.checkDimension(1);
315  double dotp, a, b, c, d, ac, bd, ab_cd;
316  double xxshift = xshift / (double)XSIZE(v);
318  {
319  dotp = -2 * PI * ((double)(i) * xxshift);
320  a = cos(dotp);
321  b = sin(dotp);
322  c = DIRECT_A1D_ELEM(v,i).real();
323  d = DIRECT_A1D_ELEM(v,i).imag();
324  ac = a * c;
325  bd = b * d;
326  ab_cd = (a + b) * (c + d); // (ab_cd-ac-bd = ad+bc : but needs 4 multiplications)
327  DIRECT_A1D_ELEM(v,i) = std::complex<double>(ac - bd, ab_cd - ac - bd);
328  }
329 }
330 
331 void ShiftFFT(MultidimArray< std::complex< double > > & v,
332  double xshift, double yshift)
333 {
334  v.checkDimension(2);
335  double dotp, a, b, c, d, ac, bd, ab_cd;
336  double xxshift = xshift / (double)XSIZE(v);
337  double yyshift = yshift / (double)YSIZE(v);
339  {
340  dotp = -2 * PI * ((double)(j) * xxshift + (double)(i) * yyshift);
341  a = cos(dotp);
342  b = sin(dotp);
343  c = DIRECT_A2D_ELEM(v,i,j).real();
344  d = DIRECT_A2D_ELEM(v,i,j).imag();
345  ac = a * c;
346  bd = b * d;
347  ab_cd = (a + b) * (c + d);
348  DIRECT_A2D_ELEM(v,i,j) = std::complex<double>(ac - bd, ab_cd - ac - bd);
349  }
350 }
351 
352 void ShiftFFT(MultidimArray< std::complex< double > > & v,
353  double xshift, double yshift, double zshift)
354 {
355  v.checkDimension(3);
356  double dotp, a, b, c, d, ac, bd, ab_cd;
357  double xxshift = -2 * PI * xshift / (double)XSIZE(v);
358  double yyshift = -2 * PI * yshift / (double)YSIZE(v);
359  double zzshift = -2 * PI * zshift / (double)ZSIZE(v);
360  for (size_t k=0; k<ZSIZE(v); ++k)
361  {
362  double zdot=(double)(k) * zzshift;
363  for (size_t i=0; i<YSIZE(v); ++i)
364  {
365  double zydot=zdot+(double)(i) * yyshift;
366  for (size_t j=0; j<XSIZE(v); ++j)
367  {
368  double *ptrv_kij=(double *)&DIRECT_A3D_ELEM(v,k,i,j);
369  dotp = (double)(j) * xxshift + zydot;
370  //sincos(dotp,&b,&a);
371  b = sin(dotp);
372  a = cos(dotp);
373  c = *ptrv_kij;
374  d = *(ptrv_kij+1);
375  ac = a * c;
376  bd = b * d;
377  ab_cd = (a + b) * (c + d);
378  *ptrv_kij = ac - bd;
379  *(ptrv_kij+1) = ab_cd - ac - bd;
380  }
381  }
382  }
383 }
384 
385 /* Position origin at center ----------------------------------------------- */
386 void CenterOriginFFT(MultidimArray< std::complex< double > > & v, bool forward)
387 {
388  if ( v.getDim() == 1 )
389  {
390  // 1D
391  double xshift = -(double)(int)(XSIZE(v) / 2);
392  if (forward)
393  {
394  ShiftFFT(v, xshift);
395  CenterFFT(v, forward);
396  }
397  else
398  {
399  CenterFFT(v, forward);
400  ShiftFFT(v, -xshift);
401  }
402  }
403  else if ( v.getDim() == 2)
404  {
405  // 2D
406 
407  double xshift = -(double)(int)(XSIZE(v) / 2);
408  double yshift = -(double)(int)(YSIZE(v) / 2);
409  if (forward)
410  {
411  ShiftFFT(v, xshift, yshift);
412  CenterFFT(v, forward);
413  }
414  else
415  {
416  CenterFFT(v, forward);
417  ShiftFFT(v, -xshift, -yshift);
418  }
419  }
420  else if ( v.getDim() == 3)
421  {
422  // 3D
423  double xshift = -(double)(int)(XSIZE(v) / 2);
424  double yshift = -(double)(int)(YSIZE(v) / 2);
425  double zshift = -(double)(int)(ZSIZE(v) / 2);
426  if (forward)
427  {
428  ShiftFFT(v, xshift, yshift, zshift);
429  CenterFFT(v, forward);
430  }
431  else
432  {
433  CenterFFT(v, forward);
434  ShiftFFT(v, -xshift, -yshift, -zshift);
435  }
436  }
437  else
438  REPORT_ERROR(ERR_MULTIDIM_DIM,"CenterOriginFFT ERROR: only valis for 1D or 2D or 3D");
439 }
440 
441 /* Xmipp image -> Xmipp PSD ------------------------------------------------ */
442 template<typename T>
443 void xmipp2PSD(const MultidimArray<T> &input, MultidimArray<T> &output,
444  bool takeLog)
445 {
446  output = input;
447  CenterFFT(output, true);
448  if (takeLog) {
449  auto min_val = std::numeric_limits<T>::max();
451  {
452  auto pixval=A2D_ELEM(output,i,j);
453  if (pixval > 0 && pixval < min_val)
454  min_val = pixval;
455  }
456  min_val = 10 * log10(min_val);
458  {
459  auto pixval=A2D_ELEM(output,i,j);
460  if (pixval > 0)
461  A2D_ELEM(output,i,j) = 10 * log10(pixval);
462  else
463  A2D_ELEM(output,i,j) = min_val;
464  }
465  }
466  reject_outliers(output);
467 }
468 template void xmipp2PSD<float>(const MultidimArray<float> &, MultidimArray<float>&, bool);
469 template void xmipp2PSD<double>(const MultidimArray<double> &, MultidimArray<double>&, bool);
470 
471 /* Xmipp image -> Xmipp CTF ------------------------------------------------ */
473 {
474  output = input;
475  CenterFFT(output, true);
476 
477  // Prepare PSD part
478  double min_val = output(0, XSIZE(output) - 1);
479  double max_val = min_val;
480  bool first = true;
481  int Xdim = XSIZE(output);
482  int Ydim = YSIZE(output);
484  {
485  if ((i < Ydim / 2 && j >= Xdim / 2) || (i >= Ydim / 2 && j < Xdim / 2))
486  {
487  if (output(i, j) > XMIPP_EQUAL_ACCURACY &&
488  (output(i, j) < min_val || first))
489  min_val = output(i, j);
490  if (output(i, j) > XMIPP_EQUAL_ACCURACY &&
491  (output(i, j) > max_val || first))
492  {
493  max_val = output(i, j);
494  first = false;
495  }
496  }
497  }
498  MultidimArray<double> left(YSIZE(output), XSIZE(output));
499  min_val = 10 * log10(min_val);
501  {
502  if ((i < Ydim / 2 && j >= Xdim / 2) || (i >= Ydim / 2 && j < Xdim / 2))
503  {
504  if (output(i, j) > XMIPP_EQUAL_ACCURACY)
505  left(i, j) = 10 * log10(output(i, j));
506  else
507  left(i, j) = min_val;
508  }
509  }
510  reject_outliers(left);
511 
512  // Join both parts
514  if ((i < Ydim / 2 && j >= Xdim / 2) || (i >= Ydim / 2 && j < Xdim / 2))
515  output(i, j) = left(i, j);
516  else
517  output(i, j) = ABS(output(i, j));
518 }
void FourierTransformHalf(const MultidimArray< double > &in, MultidimArray< std::complex< double > > &out)
Definition: xmipp_fft.cpp:187
#define YSIZE(v)
template void xmipp2PSD< float >(const MultidimArray< float > &, MultidimArray< float > &, bool)
#define A2D_ELEM(v, i, j)
alglib::complex conj(const alglib::complex &z)
Definition: ap.cpp:4988
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(m)
doublereal * c
#define MULTIDIM_SIZE(v)
void ShiftFFT(MultidimArray< std::complex< double > > &v, double xshift)
Definition: xmipp_fft.cpp:311
void resizeNoCopy(const MultidimArray< T1 > &v)
#define dAij(M, i, j)
int InvDftRealImaginaryToRealImaginary(double Re2Re[], double Im2Im[], double *TmpRe, double *TmpIm, double CaS[], long SignalLength)
HBITMAP buffer
Definition: svm-toy.cpp:37
#define DIRECT_A2D_ELEM(v, i, j)
void centerFFT2(MultidimArray< double > &v)
Definition: xmipp_fft.cpp:276
#define MULTIDIM_ARRAY(v)
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
int DftRealToRealImaginary(double R2Re[], double ImOut[], double *Tmp, double CaS[], long SignalLength)
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(v)
int InvDftRealImaginaryToReal(double Re2R[], double ImIn[], double *Tmp, double CaS[], long SignalLength)
int VolumeInvDftRealImaginaryToReal(double *Re2Re, double *ImIn, long Nx, long Ny, long Nz, int *Status)
#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
doublereal * d
#define FOR_ALL_ELEMENTS_IN_ARRAY2D(m)
int GetCaS(double CaS[], long SignalLength)
void CenterFFT(MultidimArray< T > &v, bool forward)
Definition: xmipp_fft.h:291
glob_log first
void Half2Whole(const MultidimArray< std::complex< double > > &in, MultidimArray< std::complex< double > > &out, size_t oridim)
Definition: xmipp_fft.cpp:66
#define DIRECT_A1D_ELEM(v, i)
int VolumeDftRealToRealImaginary(double *Re2Re, double *ImOut, long Nx, long Ny, long Nz, int *Status)
doublereal * b
void xmipp2PSD(const MultidimArray< T > &input, MultidimArray< T > &output, bool takeLog)
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
int in
void reject_outliers(T &v, double percentil_out=0.25)
Definition: histogram.h:605
void xmipp2CTF(const MultidimArray< double > &input, MultidimArray< double > &output)
Definition: xmipp_fft.cpp:472
#define XMIPP_EQUAL_ACCURACY
Definition: xmipp_macros.h:119
#define XSIZE(v)
void max(Image< double > &op1, const Image< double > &op2)
#define ABS(x)
Definition: xmipp_macros.h:142
#define ZSIZE(v)
void log10(Image< double > &op)
void FourierTransform(const MultidimArray< double > &in, MultidimArray< std::complex< double > > &out)
Definition: xmipp_fft.cpp:124
#define DIRECT_A3D_ELEM(v, k, i, j)
#define j
#define SWAP_ARRAY(a, b, n)
Definition: xmipp_fft.h:278
int DftRealImaginaryToRealImaginary(double Re2Re[], double Im2Im[], double *TmpRe, double *TmpIm, double CaS[], long SignalLength)
Incorrect MultidimArray dimensions.
Definition: xmipp_error.h:173
#define PI
Definition: tools.h:43
void Complex2RealImag(const MultidimArray< std::complex< double > > &in, MultidimArray< double > &real, MultidimArray< double > &imag)
Definition: xmipp_fft.cpp:103
doublereal * a
void InverseFourierTransformHalf(const MultidimArray< std::complex< double > > &in, MultidimArray< double > &out, int oridim)
Definition: xmipp_fft.cpp:197
template void xmipp2PSD< double >(const MultidimArray< double > &, MultidimArray< double > &, bool)
void CenterOriginFFT(MultidimArray< std::complex< double > > &v, bool forward)
Definition: xmipp_fft.cpp:386