kspaceFirstOrder3D-OMP  1.2
The C++ implementation of the k-wave toolbox for the time-domain simulation of acoustic wave fields in 3D
FftwComplexMatrix.cpp
Go to the documentation of this file.
1 /**
2  * @file FftwComplexMatrix.cpp
3  *
4  * @author Jiri Jaros \n
5  * Faculty of Information Technology \n
6  * Brno University of Technology \n
7  * jarosjir@fit.vutbr.cz
8  *
9  * @brief The implementation file containing the class that implements 3D FFT using the FFTW interface.
10  *
11  * @version kspaceFirstOrder3D 2.16
12  *
13  * @date 09 August 2011, 13:10 (created) \n
14  * 04 September 2017, 11:02 (revised)
15  *
16  * @copyright Copyright (C) 2017 Jiri Jaros and Bradley Treeby.
17  *
18  * This file is part of the C++ extension of the [k-Wave Toolbox](http://www.k-wave.org).
19  *
20  * This file is part of the k-Wave. k-Wave is free software: you can redistribute it and/or modify it under the terms
21  * of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the
22  * License, or (at your option) any later version.
23  *
24  * k-Wave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
25  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
26  * more details.
27  *
28  * You should have received a copy of the GNU Lesser General Public License along with k-Wave.
29  * If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).
30  */
31 
32 #include <stdexcept>
33 
36 
37 #include <Parameters/Parameters.h>
38 #include <Logger/Logger.h>
39 
40 
41 
42 //--------------------------------------------------------------------------------------------------------------------//
43 //---------------------------------------------------- Constants -----------------------------------------------------//
44 //--------------------------------------------------------------------------------------------------------------------//
45 
46 const std::string FftwComplexMatrix::kFftWisdomFileExtension = "FFTW_Wisdom";
47 //--------------------------------------------------------------------------------------------------------------------//
48 //------------------------------------------------- Public methods ---------------------------------------------------//
49 //--------------------------------------------------------------------------------------------------------------------//
50 
51 /**
52  * Constructor.
53  */
55  : ComplexMatrix(dimensionSizes),
56  mR2CFftPlan3D(nullptr), mC2RFftPlan3D(nullptr),
57  mR2CFftPlan1DX(nullptr), mR2CFftPlan1DY(nullptr), mR2CFftPlan1DZ(nullptr),
58  mC2RFftPlan1DX(nullptr), mC2RFftPlan1DY(nullptr), mC2RFftPlan1DZ(nullptr)
59 {
60 }// end of FftwComplexMatrix
61 //----------------------------------------------------------------------------------------------------------------------
62 
63 /**
64  * Destructor.
65  */
67 {
68  // free 3D plans
69  if (mR2CFftPlan3D) fftwf_destroy_plan(mR2CFftPlan3D);
70  if (mC2RFftPlan3D) fftwf_destroy_plan(mC2RFftPlan3D);
71 
72  //free 1D plans.
73  if (mR2CFftPlan1DX) fftwf_destroy_plan(mR2CFftPlan1DX);
74  if (mR2CFftPlan1DY) fftwf_destroy_plan(mR2CFftPlan1DY);
75  if (mR2CFftPlan1DZ) fftwf_destroy_plan(mR2CFftPlan1DZ);
76 
77  if (mC2RFftPlan1DX) fftwf_destroy_plan(mC2RFftPlan1DX);
78  if (mC2RFftPlan1DY) fftwf_destroy_plan(mC2RFftPlan1DY);
79  if (mC2RFftPlan1DZ) fftwf_destroy_plan(mC2RFftPlan1DZ);
80 
81  mR2CFftPlan3D = nullptr;
82  mC2RFftPlan3D = nullptr;
83 
84  mR2CFftPlan1DX = nullptr;
85  mR2CFftPlan1DY = nullptr;
86  mR2CFftPlan1DZ = nullptr;
87 
88  mC2RFftPlan1DX = nullptr;
89  mC2RFftPlan1DY = nullptr;
90  mC2RFftPlan1DZ = nullptr;
91 
92  // Memory will be freed by ~ComplexMatrix
93  //freeMemory();
94 
95 }// end of ~FftwComplexMatrix
96 //----------------------------------------------------------------------------------------------------------------------
97 
98 /**
99  * Create an FFTW plan for 3D Real-to-Complex.
100  */
102 {
103  mR2CFftPlan3D = fftwf_plan_dft_r2c_3d(inMatrix.getDimensionSizes().nz,
104  inMatrix.getDimensionSizes().ny,
105  inMatrix.getDimensionSizes().nx,
106  inMatrix.getData(),
107  reinterpret_cast<fftwf_complex*>(mData),
109 
110  if (!mR2CFftPlan3D)
111  {
112  throw std::runtime_error(kErrFmtCreateR2CFftPlan3D);
113  }
114 }// end of createR2CFftPlan3D
115 //----------------------------------------------------------------------------------------------------------------------
116 
117 /**
118  * Create an FFTW plan for 3D Complex-to-Real.
119  */
121 {
122  mC2RFftPlan3D = fftwf_plan_dft_c2r_3d(outMatrix.getDimensionSizes().nz,
123  outMatrix.getDimensionSizes().ny,
124  outMatrix.getDimensionSizes().nx,
125  reinterpret_cast<fftwf_complex*>(mData),
126  outMatrix.getData(),
128 
129  if (!mC2RFftPlan3D)
130  {
131  throw std::runtime_error(kErrFmtCreateC2RFftPlan3D);
132  }
133 }//end of createC2RFftPlan3D
134 //----------------------------------------------------------------------------------------------------------------------
135 
136 /**
137  * Create an FFTW plan for 1D Real-to-Complex in the x dimension.
138  */
140 {
141  // the FFTW uses here 32b interface although it is internally 64b, it doesn't mind since the size of 1
142  // domain will never be bigger than 2^31 - however it it not a clear solution :)
143  const int nx = static_cast<int> (inMatrix.getDimensionSizes().nx);
144  const int ny = static_cast<int> (inMatrix.getDimensionSizes().ny);
145  const int nz = static_cast<int> (inMatrix.getDimensionSizes().nz);
146  const int nxR = ((nx / 2) + 1);
147 
148  // 1D FFT definition - over the x axis
149  const int rank = 1;
150  fftw_iodim dims[1];
151 
152  dims[0].is = 1;
153  dims[0].n = nx;
154  dims[0].os = 1;
155 
156  // GNU Compiler + FFTW does it all at once
157  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
158  // How FFTs we need to perform - Z * Y
159  const int howManyRank = 2;
160  fftw_iodim howManyDims[2];
161 
162  // z dim
163  howManyDims[0].is = nx * ny;
164  howManyDims[0].n = nz;
165  howManyDims[0].os = nxR * ny;
166 
167  // y dim
168  howManyDims[1].is = nx;
169  howManyDims[1].n = ny;
170  howManyDims[1].os = nxR;
171  #endif
172 
173  // Intel Compiler + MKL does it slab by slab
174  #if (defined(__INTEL_COMPILER))
175  const int howManyRank = 1;
176  fftw_iodim howManyDims[1];
177 
178  // y dim
179  howManyDims[0].is = nx;
180  howManyDims[0].n = ny;
181  howManyDims[0].os = nxR;
182  #endif
183 
184  mR2CFftPlan1DX = fftwf_plan_guru_dft_r2c(rank, // 1D FFT rank
185  dims, // 1D FFT dimensions of x
186  howManyRank, // how many in y and z
187  howManyDims, // Dims and strides in y and z
188  inMatrix.getData(), // input data
189  reinterpret_cast<fftwf_complex*>(mData), // output data
190  kFftMeasureFlag); // flags
191 
192  if (!mR2CFftPlan1DX)
193  {
194  throw std::runtime_error(kErrFmtCreateR2CFftPlan1DX);
195  }
196 }// end of createR2CFftPlan1DX
197 //----------------------------------------------------------------------------------------------------------------------
198 
199 
200 /**
201  * Create an FFTW plan for 1D Real-to-Complex in the y dimension.
202  */
204 {
205  // the FFTW uses here 32b interface although it is internally 64b, it doesn't mind
206  // since the size of 1 domain will never be bigger than 2^31 - however it it not a clear solution :)
207  const int nx = static_cast<int>(inMatrix.getDimensionSizes().nx);
208  const int ny = static_cast<int>(inMatrix.getDimensionSizes().ny);
209  const int nz = static_cast<int>(inMatrix.getDimensionSizes().nz);
210  const int nyR = ((ny / 2) + 1);
211 
212  // 1D FFT definition - over the ny axis
213  const int rank = 1;
214  fftw_iodim dims[1];
215 
216  dims[0].is = nx;
217  dims[0].n = ny;
218  dims[0].os = nx;
219 
220  // GNU Compiler + FFTW does it all at once
221  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
222  // How FFTs we need to perform - Z * X
223  const int howManyRank = 2;
224  fftw_iodim howManyDims[2];
225 
226  // z dim
227  howManyDims[0].is = nx * ny;
228  howManyDims[0].n = nz;
229  howManyDims[0].os = nx * nyR ;
230 
231  // x dim
232  howManyDims[1].is = 1;
233  howManyDims[1].n = nx;
234  howManyDims[1].os = 1;
235  #endif
236 
237  // Intel Compiler + MKL does it slab by slab
238  #if (defined(__INTEL_COMPILER))
239  const int howManyRank = 1;
240  fftw_iodim howManyDims[1];
241 
242  // x dim
243  howManyDims[0].is = 1;
244  howManyDims[0].n = nx;
245  howManyDims[0].os = 1;
246  #endif
247 
248  mR2CFftPlan1DY = fftwf_plan_guru_dft_r2c(rank, // 1D FFT rank
249  dims, // 1D FFT dimensions of y
250  howManyRank, // how many in x and z
251  howManyDims, // Dims and strides in x and z
252  inMatrix.getData(), // input data
253  reinterpret_cast<fftwf_complex*>(mData), // output data
254  kFftMeasureFlag); // flags
255 
256  if (!mR2CFftPlan1DY)
257  {
258  throw std::runtime_error(kErrFmtCreateR2CFftPlan1DY);
259  }
260 }// end of createR2CFftPlan1DY
261 //----------------------------------------------------------------------------------------------------------------------
262 
263 /**
264  * Create an FFTW plan for 1D Real-to-Complex in the z dimension.
265  */
267 {
268  // the FFTW uses here 32b interface although it is internally 64b, it doesn't mind
269  // since the size of 1 domain will never be bigger than 2^31 - however it it not a clear solution :)
270  const int nx = static_cast<int> (inMatrix.getDimensionSizes().nx);
271  const int ny = static_cast<int> (inMatrix.getDimensionSizes().ny);
272  const int nz = static_cast<int> (inMatrix.getDimensionSizes().nz);
273 
274  // 1D FFT definition - over the ny axis
275  const int rank = 1;
276  fftw_iodim dims[1];
277 
278  dims[0].is = nx * ny;
279  dims[0].n = nz;
280  dims[0].os = nx * ny;
281 
282  // GNU Compiler + FFTW
283  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
284  // How FFTs we need to perform - Y * X
285  const int howManyRank = 2;
286  fftw_iodim howManyDims[2];
287 
288  // y dim
289  howManyDims[0].is = nx;
290  howManyDims[0].n = ny;
291  howManyDims[0].os = nx;
292 
293  // x dim
294  howManyDims[1].is = 1;
295  howManyDims[1].n = nx;
296  howManyDims[1].os = 1;
297  #endif
298 
299  // Intel Compiler + MKL does it slab by slab
300  #if (defined(__INTEL_COMPILER))
301  const int howManyRank = 1;
302  fftw_iodim howManyDims[1];
303 
304  // x dim
305  howManyDims[0].is = 1;
306  howManyDims[0].n = nx;
307  howManyDims[0].os = 1;
308  #endif
309 
310  mR2CFftPlan1DZ = fftwf_plan_guru_dft_r2c(rank, // 1D FFT rank
311  dims, // 1D FFT dimensions of z
312  howManyRank, // how many in x and y
313  howManyDims, // Dims and strides in x and y
314  inMatrix.getData(), // input data
315  reinterpret_cast<fftwf_complex*>(mData), // output data
316  kFftMeasureFlag); // flags
317 
318  if (!mR2CFftPlan1DZ)
319  {
320  throw std::runtime_error(kErrFmtCreateR2CFftPlan1DZ);
321  }
322 }// end of createR2CFftPlan1DZ
323 //----------------------------------------------------------------------------------------------------------------------
324 
325 /**
326  * Create FFTW plan for Complex-to-Real in the x dimension.
327  */
329 {
330  // the FFTW uses here 32b interface although it is internally 64b, it doesn't mind
331  // since the size of 1 domain will never be bigger than 2^31 - however it it not a clear solution :)
332  const int nx = static_cast<int> (outMatrix.getDimensionSizes().nx);
333  const int ny = static_cast<int> (outMatrix.getDimensionSizes().ny);
334  const int nz = static_cast<int> (outMatrix.getDimensionSizes().nz);
335  const int nxR = ((nx / 2) + 1);
336 
337  // 1D FFT definition - over the x axis
338  const int rank = 1;
339  fftw_iodim dims[1];
340 
341  dims[0].is = 1;
342  dims[0].n = nx;
343  dims[0].os = 1;
344 
345  // GNU Compiler + FFTW
346  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
347  // How FFTs we need to perform - Z * Y
348  const int howManyRank = 2;
349  fftw_iodim howManyDims[2];
350 
351  // z dim
352  howManyDims[0].is = nxR * ny;
353  howManyDims[0].n = nz;
354  howManyDims[0].os = nx * ny;
355 
356  // y dim
357  howManyDims[1].is = nxR;
358  howManyDims[1].n = ny;
359  howManyDims[1].os = nx;
360  #endif
361 
362  // Intel Compiler + MKL does it slab by slab
363  #if (defined(__INTEL_COMPILER))
364  const int howManyRank = 1;
365  fftw_iodim howManyDims[1];
366 
367  // y dim
368  howManyDims[0].is = nxR;
369  howManyDims[0].n = ny;
370  howManyDims[0].os = nx;
371  #endif
372 
373  mC2RFftPlan1DX = fftwf_plan_guru_dft_c2r(rank, // 1D FFT rank
374  dims, // 1D FFT dimensions of x
375  howManyRank, // how many in y and z
376  howManyDims, // Dims and strides in y and z
377  reinterpret_cast<fftwf_complex*>(mData), // input data
378  outMatrix.getData(), // output data
379  kFftMeasureFlag); // flags
380 
381  if (!mC2RFftPlan1DX)
382  {
383  throw std::runtime_error(kErrFmtCreateC2RFftPlan1DX);
384  }
385 }// end of createC2RFftPlan1DX
386 //----------------------------------------------------------------------------------------------------------------------
387 
388  /**
389  * Create FFTW plan for Complex-to-Real in the y dimension.
390  */
392 {
393  // the FFTW uses here 32b interface although it is internally 64b, it doesn't mind
394  // since the size of 1 domain will never be bigger than 2^31 - however it it not a clear solution :)
395  const int nx = static_cast<int> (outMatrix.getDimensionSizes().nx);
396  const int ny = static_cast<int> (outMatrix.getDimensionSizes().ny);
397  const int nz = static_cast<int> (outMatrix.getDimensionSizes().nz);
398  const int nyR = ((ny / 2) + 1);
399 
400  // 1D FFT definition - over the y axis
401  const int rank = 1;
402 
403  fftw_iodim dims[1];
404  dims[0].is = nx;
405  dims[0].n = ny;
406  dims[0].os = nx;
407 
408  // GNU Compiler + FFTW
409  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
410  // How FFTs we need to perform - Z * X
411  const int howManyRank = 2;
412  fftw_iodim howManyDims[2];
413 
414  // z dim
415  howManyDims[0].is = nx * nyR;
416  howManyDims[0].n = nz;
417  howManyDims[0].os = nx * ny;
418 
419  // x dim
420  howManyDims[1].is = 1;
421  howManyDims[1].n = nx;
422  howManyDims[1].os = 1;
423  #endif
424 
425  // Intel Compiler + MKL does it slab by slab
426  #if (defined(__INTEL_COMPILER))
427  const int howManyRank = 1;
428  fftw_iodim howManyDims[1];
429 
430  // x dim
431  howManyDims[0].is = 1;
432  howManyDims[0].n = nx;
433  howManyDims[0].os = 1;
434  #endif
435 
436  mC2RFftPlan1DY = fftwf_plan_guru_dft_c2r(rank, // 1D FFT rank
437  dims, // 1D FFT dimensions of y
438  howManyRank, // how many in x and z
439  howManyDims, // Dims and strides in x and z
440  reinterpret_cast<fftwf_complex*>(mData), // input data
441  outMatrix.getData(), // output data
442  kFftMeasureFlag); // flags
443 
444  if (!mC2RFftPlan1DY)
445  {
446  throw std::runtime_error(kErrFmtCreateC2RFftPlan1DY);
447  }
448 }// end of createC2RFftPlan1DY
449 //----------------------------------------------------------------------------------------------------------------------
450 
451 /**
452  * Create FFTW plan for Complex-to-Real in the z dimension.
453  */
455 {
456  // the FFTW uses here 32b interface although it is internally 64b, it doesn't mind
457  // since the size of 1 domain will never be bigger than 2^31 - however it it not a clear solution :)
458  const int nx = static_cast<int> (outMatrix.getDimensionSizes().nx);
459  const int ny = static_cast<int> (outMatrix.getDimensionSizes().ny);
460  const int nz = static_cast<int> (outMatrix.getDimensionSizes().nz);
461 
462  // 1D FFT definition - over the z axis
463  const int rank = 1;
464  fftw_iodim dims[1];
465 
466  dims[0].is = nx * ny;
467  dims[0].n = nz;
468  dims[0].os = nx * ny;
469 
470  // GNU Compiler + FFTW
471  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
472  // How FFTs we need to perform - Y * X
473  const int howManyRank = 2;
474  fftw_iodim howManyDims[2];
475 
476  // y dim
477  howManyDims[0].is = nx;
478  howManyDims[0].n = ny;
479  howManyDims[0].os = nx;
480 
481  // x dim
482  howManyDims[1].is = 1;
483  howManyDims[1].n = nx;
484  howManyDims[1].os = 1;
485  #endif
486 
487  // Intel Compiler + MKL does it slab by slab
488  #if (defined(__INTEL_COMPILER))
489  const int howManyRank = 1;
490  fftw_iodim howManyDims[1];
491 
492  // x dim
493  howManyDims[0].is = 1;
494  howManyDims[0].n = nx;
495  howManyDims[0].os = 1;
496  #endif
497 
498  mC2RFftPlan1DZ = fftwf_plan_guru_dft_c2r(rank, // 1D FFT rank
499  dims, // 1D FFT dimensions of z
500  howManyRank, // how many in x and y
501  howManyDims, // Dims and strides in x and y
502  reinterpret_cast<fftwf_complex*>(mData), // input data
503  outMatrix.getData(), // output data
504  kFftMeasureFlag); // flags
505 
506  if (!mC2RFftPlan1DZ)
507  {
508  throw std::runtime_error(kErrFmtCreateC2RFftPlan1DX);
509  }
510 }// end of createC2RFftPlan1DZ
511 //----------------------------------------------------------------------------------------------------------------------
512 
513 /**
514  * Computer forward out-of place 3D Real-to-Complex FFT.
515  */
517 {
518  if (mR2CFftPlan3D)
519  {
520  fftwf_execute_dft_r2c(mR2CFftPlan3D, inMatrix.getData(), reinterpret_cast<fftwf_complex*>(mData));
521  }
522  else //error
523  {
524  throw std::runtime_error(kErrFmtExecuteR2CFftPlan3D);
525  }
526 }// end of computeR2CFft3D
527 //----------------------------------------------------------------------------------------------------------------------
528 
529 /**
530  * Compute inverse out-of-place 3D Complex to Real FFT.
531  */
533 {
534  if (mC2RFftPlan3D)
535  {
536  fftwf_execute_dft_c2r(mC2RFftPlan3D, reinterpret_cast<fftwf_complex*>(mData), outMatrix.getData());
537  }
538  else // error
539  {
540  throw std::runtime_error(kErrFmtExecuteC2RFftPlan3D);
541  }
542 }// end of computeC2RFft3D
543 //----------------------------------------------------------------------------------------------------------------------
544 
545 /**
546  * Compute 1D out-of-place Real-to-Complex FFT in the x dimension.
547  */
549 {
550  if (mR2CFftPlan1DX)
551  {
552  // GNU Compiler + FFTW
553  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
554  fftwf_execute_dft_r2c(mR2CFftPlan1DX,
555  inMatrix.getData(),
556  reinterpret_cast<fftwf_complex*>(mData));
557  #endif
558 
559  // Intel Compiler + MKL
560  #if (defined(__INTEL_COMPILER))
562  for (size_t slab_id = 0; slab_id < dims.nz; slab_id++)
563  {
564  fftwf_execute_dft_r2c(mR2CFftPlan1DX,
565  &inMatrix.getData()[slab_id * dims.nx * dims.ny],
566  (fftwf_complex *) &mData[slab_id * 2 * (dims.nx / 2 + 1) * dims.ny]);
567  }
568  #endif
569  }
570  else //error
571  {
572  throw std::runtime_error(kErrFmtExecuteR2CFftPlan1DX);
573  }
574 }// end of computeR2CFft1DX
575 //----------------------------------------------------------------------------------------------------------------------
576 
577 /**
578  * Compute 1D out-of-place Real-to-Complex FFT in the Y dimension.
579  */
581 {
582  if (mR2CFftPlan1DY)
583  {
584  // GNU Compiler + FFTW
585  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
586  fftwf_execute_dft_r2c(mR2CFftPlan1DY,
587  inMatrix.getData(),
588  reinterpret_cast<fftwf_complex*>(mData));
589  #endif
590 
591  // Intel Compiler + MKL
592  #if (defined(__INTEL_COMPILER))
594  for (size_t slab_id = 0; slab_id < dims.nz; slab_id++)
595  {
596  fftwf_execute_dft_r2c(mR2CFftPlan1DY,
597  &inMatrix.getData()[slab_id * dims.nx * dims.ny],
598  (fftwf_complex *) &mData[slab_id * dims.nx * 2 * (dims.ny / 2 + 1)]);
599  }
600  #endif
601  }
602  else //error
603  {
604  throw std::runtime_error(kErrFmtExecuteR2CFftPlan1DY);
605  }
606 }// end of computeR2CFft1DY
607 //----------------------------------------------------------------------------------------------------------------------
608 
609 /**
610  * Compute 1D out-of-place Real-to-Complex FFT in the z dimension.
611  */
613 {
614  if (mR2CFftPlan1DZ)
615  {
616  // GNU Compiler + FFTW
617  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
618  fftwf_execute_dft_r2c(mR2CFftPlan1DZ,
619  inMatrix.getData(),
620  reinterpret_cast<fftwf_complex*>(mData));
621  #endif
622 
623  // Intel Compiler + MKL
624  #if (defined(__INTEL_COMPILER))
626  for (size_t slab_id = 0; slab_id < dims.ny; slab_id++)
627  {
628  fftwf_execute_dft_r2c(mR2CFftPlan1DZ,
629  &inMatrix.getData()[slab_id * dims.nx],
630  (fftwf_complex *) &mData[slab_id * 2 * dims.nx]);
631  }
632  #endif
633  }
634  else //error
635  {
636  throw std::runtime_error(kErrFmtExecuteR2CFftPlan1DZ);
637  }
638 }// end of computeR2CFft1DZ
639 //----------------------------------------------------------------------------------------------------------------------
640 
641 /**
642  * Compute 1D out-of-place Complex-to-Real FFT in the x dimension.
643  */
645 {
646  if (mC2RFftPlan1DX)
647  {
648  // GNU Compiler + FFTW
649  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
650  fftwf_execute_dft_c2r(mC2RFftPlan1DX,
651  reinterpret_cast<fftwf_complex*>(mData),
652  outMatrix.getData());
653  #endif
654 
655  // Intel Compiler + MKL
656  #if (defined(__INTEL_COMPILER))
658  for (size_t slab_id = 0; slab_id < dims.nz; slab_id++)
659  {
660  fftwf_execute_dft_c2r(mC2RFftPlan1DX,
661  (fftwf_complex *) &mData[slab_id * 2 * (dims.nx / 2 + 1) * dims.ny],
662  &outMatrix.getData()[slab_id * dims.nx * dims.ny]);
663  }
664  #endif
665  }
666  else //error
667  {
668  throw std::runtime_error(kErrFmtExecuteC2RFftPlan1DX);
669  }
670 }// end of computeR2CFft1DX
671 //----------------------------------------------------------------------------------------------------------------------
672 
673 /**
674  * Compute 1D out-of-place Complex-to-Real FFT in the y dimension.
675  */
677 {
678  if (mC2RFftPlan1DY)
679  {
680  // GNU Compiler + FFTW
681  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
682  fftwf_execute_dft_c2r(mC2RFftPlan1DY,
683  reinterpret_cast<fftwf_complex*>(mData),
684  outMatrix.getData());
685  #endif
686 
687  // Intel Compiler + MKL
688  #if (defined(__INTEL_COMPILER))
690  for (size_t slab_id = 0; slab_id < dims.nz; slab_id++)
691  {
692  fftwf_execute_dft_c2r(mC2RFftPlan1DY,
693  (fftwf_complex *) &mData[slab_id * dims.nx * 2 * (dims.ny / 2 + 1)],
694  &outMatrix.getData()[slab_id * dims.nx * dims.ny]);
695  }
696  #endif
697  }
698  else //error
699  {
700  throw std::runtime_error(kErrFmtExecuteC2RFftPlan1DY);
701  }
702 }// end of computeR2CFft1DY
703 //----------------------------------------------------------------------------------------------------------------------
704 
705 /**
706  * Compute 1D out-of-place Complex-to-Real FFT in the Z dimension
707  */
709 {
710  if (mC2RFftPlan1DZ)
711  {
712  // GNU Compiler + FFTW
713  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
714  fftwf_execute_dft_c2r(mC2RFftPlan1DZ,
715  reinterpret_cast<fftwf_complex*>(mData),
716  outMatrix.getData());
717  #endif
718 
719  // Intel Compiler + MKL
720  #if (defined(__INTEL_COMPILER))
722  for (size_t slab_id = 0; slab_id < dims.ny; slab_id++)
723  {
724  fftwf_execute_dft_c2r(mC2RFftPlan1DZ,
725  (fftwf_complex *) &mData[slab_id * 2 * dims.nx ],
726  &outMatrix.getData()[slab_id * dims.nx]);
727  }
728  #endif
729  }
730  else //error
731  {
732  throw std::runtime_error(kErrFmtExecuteC2RFftPlan1DZ);
733  }
734 }// end of computeR2CFft1DZ
735 //----------------------------------------------------------------------------------------------------------------------
736 
737 /**
738  * Export wisdom to the file.
739  */
741 {
742  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
743  int success = fftwf_export_wisdom_to_filename(getWisdomFileName().c_str());
744  if (success == 0)
745  {
746  throw std::runtime_error(kErrFmtFftWisdomNotExported);
747  }
748  #endif
749 }// end of exportWisdom
750 //----------------------------------------------------------------------------------------------------------------------
751 
752 /**
753  * Import wisdom from the file.
754  */
756 {
757  #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
758  int success = fftwf_import_wisdom_from_filename(getWisdomFileName().c_str());
759  if (success == 0)
760  {
761  // print out a warning!
762  throw std::runtime_error(ErrFmtFftWisdomNotImported);
763  }
764  #endif
765 }// end of importWisdom
766 //----------------------------------------------------------------------------------------------------------------------
767 
768 /**
769  * Delete stored wisdom (delete the file).
770  */
772 {
773  std::remove(getWisdomFileName().c_str());
774 }// end of deleteStoredWisdom
775 //----------------------------------------------------------------------------------------------------------------------
776 
777 
778 //--------------------------------------------------------------------------------------------------------------------//
779 //------------------------------------------------ Protected methods -------------------------------------------------//
780 //--------------------------------------------------------------------------------------------------------------------//
781 
782 /**
783  * Allocate Memory using fftwf_malloc function to ensure correct alignment.
784  */
786 {
787  /* No memory allocated before this function*/
788  mData = (float *) fftwf_malloc(mCapacity * sizeof (float));
789 
790  if (!mData)
791  {
792  throw std::bad_alloc();
793  }
794 
795  // first touch
796  #pragma omp parallel for simd schedule(static)
797  for (size_t i = 0; i < mCapacity; i++)
798  {
799  mData[i] = 0.0f;
800  }
801 }// end of allocateMemory
802 //----------------------------------------------------------------------------------------------------------------------
803 
804  /**
805  * Free memory using fftwf_free.
806  */
808 {
809  if (mData) fftwf_free(mData);
810  mData = nullptr;
811  }// end of freeMemory
812  //---------------------------------------------------------------------------------------------------------------------
813 
814 /**
815  * Get Wisdom file name (derive it form the checkpoint filename).
816  */
818 {
819  std::string fileName = Parameters::getInstance().getCheckpointFileName();
820  fileName.erase(fileName.find_last_of("."), std::string::npos);
821 
822  fileName.append(".");
823  fileName.append(kFftWisdomFileExtension);
824 
825  return fileName;
826 }// end of getWisdomFileName
827 //----------------------------------------------------------------------------------------------------------------------
828 
829 
830 
831 //--------------------------------------------------------------------------------------------------------------------//
832 //------------------------------------------------ Private methods ---------------------------------------------------//
833 //--------------------------------------------------------------------------------------------------------------------//
The class for real matrices.
Definition: RealMatrix.h:47
void createC2RFftPlan1DY(RealMatrix &outMatrix)
Create FFTW plan for Complex-to-Real in the y dimension.
void createC2RFftPlan3D(RealMatrix &outMatrix)
Create FFTW plan for 3D Complex-to-Real.
ErrorMessage kErrFmtCreateR2CFftPlan1DZ
FFTW error message.
ErrorMessage kErrFmtExecuteC2RFftPlan1DX
FFTW error message.
ErrorMessage kErrFmtExecuteR2CFftPlan3D
FFTW error message.
size_t nz
Number of elements in the z direction.
void computeC2RFft1DX(RealMatrix &outMatrix)
Compute 1D out-of-place Complex-to-Real FFT in the x dimension.
ErrorMessage kErrFmtExecuteC2RFftPlan3D
FFTW error message.
std::string getCheckpointFileName() const
Get checkpoint file name.
Definition: Parameters.h:184
ErrorMessage kErrFmtExecuteR2CFftPlan1DX
FFTW error message.
ErrorMessage kErrFmtCreateR2CFftPlan1DX
FFTW error message.
virtual ~FftwComplexMatrix()
Destructor.
static const unsigned kFftMeasureFlag
FFTW plan flag.
ErrorMessage kErrFmtCreateC2RFftPlan3D
FFTW error message.
The header file containing the class for real matrices.
void createC2RFftPlan1DX(RealMatrix &outMatrix)
Create FFTW plan for Complex-to-Real in the x dimension.
fftwf_plan mC2RFftPlan1DY
FFTW plan for the 3D Complex-to-Real transform in the y dimension.
fftwf_plan mC2RFftPlan1DZ
FFTW plan for the 3Z Complex-to-Real transform in the z dimension.
DimensionSizes getFullDimensionSizes() const
Get full dimension sizes of the simulation (real classes).
Definition: Parameters.h:191
void computeC2RFft1DZ(RealMatrix &outMatrix)
Compute 1D out-of-place Complex-to-Real FFT in the z dimension.
fftwf_plan mR2CFftPlan1DY
FFTW plan for the 3D Real-to-Complex transform in the y dimension.
fftwf_plan mC2RFftPlan1DX
FFTW plan for the 3D Complex-to-Real transform in the x dimension.
void createR2CFftPlan1DY(RealMatrix &inMatrix)
Create an FFTW plan for 1D Real-to-Complex in the y dimension.
fftwf_plan mC2RFftPlan3D
FFTW plan for the 3D Complex-to-Real transform.
static void exportWisdom()
Export wisdom to the file.
ErrorMessage kErrFmtExecuteC2RFftPlan1DY
FFTW error message.
The header file containing the parameters of the simulation.
ErrorMessage kErrFmtFftWisdomNotExported
FFTW error message.
void computeC2RFft3D(RealMatrix &outMatrix)
Compute forward out-of-place 3D Complex-to-Real FFT.
fftwf_plan mR2CFftPlan1DX
FFTW plan for the 1D Real-to-Complex transform in the x dimension.
float * mData
Raw matrix data.
ErrorMessage kErrFmtExecuteR2CFftPlan1DY
FFTW error message.
static void deleteStoredWisdom()
Destroy wisdom in the file (delete it).
virtual void freeMemory()
Free memory of the FFTW matrix.
void computeR2CFft3D(RealMatrix &inMatrix)
Compute forward out-of-place 3D Real-to-Complex FFT.
The header file containing a class responsible for printing out info and error messages (stdout...
The class for complex matrices.
Definition: ComplexMatrix.h:51
fftwf_plan mR2CFftPlan3D
FFTW plan for the 3D Real-to-Complex transform.
ErrorMessage kErrFmtExecuteR2CFftPlan1DZ
FFTW error message.
fftwf_plan mR2CFftPlan1DZ
FFTW plan for the 3D Real-to-Complex transform in the z dimension.
ErrorMessage kErrFmtCreateC2RFftPlan1DX
FFTW error message.
Structure with 4D dimension sizes (3 in space and 1 in time).
void createC2RFftPlan1DZ(RealMatrix &outMatrix)
Create FFTW plan for Complex-to-Real in the z dimension.
size_t ny
Number of elements in the y direction.
static std::string getWisdomFileName()
void computeR2CFft1DX(RealMatrix &inMatrix)
Compute 1D out-of-place Real-to-Complex FFT in the x dimension.
virtual float * getData()
Get raw data out of the class (for direct kernel access).
void computeR2CFft1DZ(RealMatrix &inMatrix)
Compute 1D out-of-place Real-to-Complex FFT in the z dimension.
void createR2CFftPlan1DX(RealMatrix &inMatrix)
Create an FFTW plan for 1D Real-to-Complex in the x dimension.
size_t nx
Number of elements in the x direction.
ErrorMessage kErrFmtCreateR2CFftPlan3D
FFTW error message.
ErrorMessage kErrFmtExecuteC2RFftPlan1DZ
FFTW error message.
The header file containing the class that implements 3D FFT using the FFTW interface.
static Parameters & getInstance()
Get instance of the singleton class.
Definition: Parameters.cpp:84
void computeC2RFft1DY(RealMatrix &outMatrix)
Compute 1D out-of-place Complex-to-Real FFT in the y dimension.
static void importWisdom()
Import wisdom from the file.
ErrorMessage kErrFmtCreateC2RFftPlan1DY
FFTW error message.
virtual const DimensionSizes & getDimensionSizes() const
Get dimension sizes of the matrix.
void createR2CFftPlan3D(RealMatrix &inMatrix)
Create FFTW plan for 3D Real-to-Complex.
static const std::string kFftWisdomFileExtension
The file extension for FFTW wisdom.
ErrorMessage ErrFmtFftWisdomNotImported
FFTW error message.
FftwComplexMatrix()=delete
Default constructor not allowed for public.
void createR2CFftPlan1DZ(RealMatrix &inMatrix)
Create an FFTW plan for 1D Real-to-Complex in the z dimension.
virtual void allocateMemory()
Allocate memory for the FFTW matrix.
ErrorMessage kErrFmtCreateR2CFftPlan1DY
FFTW error message.
void computeR2CFft1DY(RealMatrix &inMatrix)
Compute 1D out-of-place Real-to-Complex FFT in the y dimension.
size_t mCapacity
Total number of allocated elements (in terms of floats).