mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
fft.hpp
Go to the documentation of this file.
1/** \file fft.hpp
2 * \brief The fast Fourier transform interface
3 * \ingroup fft_files
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2015-2020 Jared R. Males (jaredmales@gmail.com)
10//
11// This file is part of mxlib.
12//
13// mxlib is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// mxlib is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25//***********************************************************************//
26
27#ifndef fft_hpp
28#define fft_hpp
29
30#include <fftw3.h>
31
32#include <complex>
33
34#include "fftwTemplates.hpp"
35#include "../../meta/trueFalseT.hpp"
36
37namespace mx
38{
39namespace math
40{
41namespace fft
42{
43
44#define MXFFT_FORWARD ( FFTW_FORWARD )
45#define MXFFT_BACKWARD ( FFTW_BACKWARD )
46
47template <typename _inputT, typename _outputT, size_t _rank, int _cudaGPU = 0>
48class fftT;
49
50template <int rank>
51std::vector<int> fftwDimVec( int szX, int szY, int szZ );
52
53/// Fast Fourier Transforms using the FFTW library interface
54/** The fftwTemplates type resolution system is used to allow the compiler
55 * to access the right plan and types for the transforms based on inputT and outputT.
56 *
57 * Calls the FFTW plan functions are protected by '\#pragma omp critical' directives
58 * unless MX_FFTW_NOOMP is define prior to the first inclusion of this file.
59 *
60 * \todo add execute interface with fftw like signature
61 * \todo add plan interface where user passes in pointers (to avoid allocations)
62 *
63 * \tparam inputT is the input type of the transform, can be either real or complex
64 * \tparam outputT is the output type of the transform, can be either real or complex
65 *
66 * \ingroup fft
67 */
68template <typename _inputT, typename _outputT, size_t _rank>
69class fftT<_inputT, _outputT, _rank, 0>
70{
71 typedef _inputT inputT;
72 typedef _outputT outputT;
73
74 typedef typename fftwTypeSpec<inputT, outputT>::complexT complexT;
75
76 static const size_t rank = _rank;
77
78 typedef typename fftwTypeSpec<inputT, outputT>::realT realT;
79
80 typedef typename fftwPlanSpec<realT>::planT planT;
81
82 protected:
83 int m_dir{ MXFFT_FORWARD }; ///< Direction of this FFT, either MXFFT_FORWARD (default) or MXFFT_BACKWARD
84
85 int m_szX{ 0 }; ///< Size of the x dimension
86 int m_szY{ 0 }; ///< Size of the y dimension
87 int m_szZ{ 0 }; ///< size of the z dimension
88
89 planT m_plan{ nullptr }; ///< The FFTW plan object. This is a pointer, allocated by FFTW library calls.
90
91 public:
92 /// Default c'tor
94
95 /// Constructor for rank 1 FFT.
96 template <int crank = _rank>
97 fftT( int nx, ///< [in] the desired size of the FFT
98 int ndir = MXFFT_FORWARD, ///< [in] [optional] direction of this FFT, either MXFFT_FORWARD (default) or
99 ///< MXFFT_BACKWARD
100 bool inPlace = false, /**< [in] [optional] whether or not this is an in-place transform.
101 Default is false, out-of-place.*/
102 typename std::enable_if<crank == 1>::type * = 0 );
103
104 /// Constructor for rank 2 FFT.
105 template <int crank = _rank>
106 fftT( int nx, ///< [in] the desired x size of the FFT
107 int ny, ///< [in] the desired y size of the FFT
108 int ndir = MXFFT_FORWARD, ///< [in] [optional] direction of this FFT, either MXFFT_FORWARD (default) or
109 ///< MXFFT_BACKWARD
110 bool inPlace = false, /**< [in] [optional] whether or not this is an in-place transform.
111 Default is false, out-of-place. */
112 typename std::enable_if<crank == 2>::type * = 0 );
113
114 /// Constructor for rank 3 FFT.
115 template <int crank = _rank>
116 fftT( int nx, ///< [in] the desired x size of the FFT
117 int ny, ///< [in] the desired y size of the FFT
118 int nz, ///< [in] the desired z size of the FFT
119 int ndir = MXFFT_FORWARD, ///< [in] [optional] direction of this FFT, either MXFFT_FORWARD (default) or
120 ///< MXFFT_BACKWARD
121 bool inPlace =
122 false, ///< [in] [optional] whether or not this is an in-place transform. Default is false, out-of-place.
123 typename std::enable_if<crank == 3>::type * = 0 );
124
125 /// Destructor
127
128 /// Destroy (de-allocate) the plan
130
131 /// Get the direction of this FFT
132 /** The direction is either MXFFT_FORWARD or MXFFT_BACKWARD.
133 *
134 * \returns the current value of m_dir.
135 */
136 int dir();
137
138 /// Call the FFTW planning routine for an out-of-place transform.
140
141 /// Call the FFTW planning routine for an in-place transform.
143
144 /// Planning routine for rank 1 transforms.
145 template <int crank = _rank>
146 void plan(
147 int nx, ///< [in] the desired size of the FFT
148 int ndir =
149 MXFFT_FORWARD, ///< [in] [optional] direction of this FFT, either MXFFT_FORWARD (default) or MXFFT_BACKWARD
150 bool inPlace =
151 false, ///< [in] [optional] whether or not this is an in-place transform. Default is false, out-of-place.
152 typename std::enable_if<crank == 1>::type * = 0 );
153
154 /// Planning routine for rank 2 transforms.
155 template <int crank = _rank>
156 void plan(
157 int nx, ///< [in] the desired x size of the FFT
158 int ny, ///< [in] the desired y size of the FFT
159 int ndir =
160 MXFFT_FORWARD, ///< [in] [optional] direction of this FFT, either MXFFT_FORWARD (default) or MXFFT_BACKWARD
161 bool inPlace =
162 false, ///< [in] [optional] whether or not this is an in-place transform. Default is false, out-of-place.
163 typename std::enable_if<crank == 2>::type * = 0 );
164
165 /// Planning routine for rank 3 transforms.
166 template <int crank = _rank>
167 void plan(
168 int nx, ///< [in] the desired x size of the FFT
169 int ny, ///< [in] the desired y size of the FFT
170 int nz, ///< [in] the desired z size of the FFT
171 int ndir =
172 MXFFT_FORWARD, ///< [in] [optional] direction of this FFT, either MXFFT_FORWARD (default) or MXFFT_BACKWARD
173 bool inPlace =
174 false, ///< [in] [optional] whether or not this is an in-place transform. Default is false, out-of-place.
175 typename std::enable_if<crank == 3>::type * = 0 );
176
177 /// Conduct the FFT
178 void operator()( outputT *out, ///< [out] the output of the FFT, must be pre-allocated
179 inputT *in ///< [in] the input to the FFT
180 ) const;
181};
182
183template <typename inputT, typename outputT, size_t rank>
184fftT<inputT, outputT, rank, 0>::fftT()
185{
186}
187
188template <typename inputT, typename outputT, size_t rank>
189template <int crank>
190fftT<inputT, outputT, rank, 0>::fftT( int nx, int ndir, bool inPlace, typename std::enable_if<crank == 1>::type * )
191{
192 m_dir = ndir;
193
194 plan( nx, ndir, inPlace );
195}
196
197template <typename inputT, typename outputT, size_t rank>
198template <int crank>
199fftT<inputT, outputT, rank, 0>::fftT(
200 int nx, int ny, int ndir, bool inPlace, typename std::enable_if<crank == 2>::type * )
201{
202 m_dir = ndir;
203
204 plan( nx, ny, ndir, inPlace );
205}
206
207template <typename inputT, typename outputT, size_t rank>
208template <int crank>
209fftT<inputT, outputT, rank, 0>::fftT(
210 int nx, int ny, int nz, int ndir, bool inPlace, typename std::enable_if<crank == 3>::type * )
211{
212 m_dir = ndir;
213
214 plan( nx, ny, nz, ndir, inPlace );
215}
216
217template <typename inputT, typename outputT, size_t rank>
218fftT<inputT, outputT, rank, 0>::~fftT()
219{
220 destroyPlan();
221}
222
223template <typename inputT, typename outputT, size_t rank>
224void fftT<inputT, outputT, rank, 0>::destroyPlan()
225{
226 if( m_plan )
227 fftw_destroy_plan<realT>( m_plan );
228
229 m_plan = 0;
230
231 m_szX = 0;
232 m_szY = 0;
233}
234
235template <typename inputT, typename outputT, size_t rank>
236int fftT<inputT, outputT, rank, 0>::dir()
237{
238 return m_dir;
239}
240
241template <typename inputT, typename outputT, size_t rank>
242void fftT<inputT, outputT, rank, 0>::doPlan( const meta::trueFalseT<false> &inPlace )
243{
244 (void)inPlace;
245
246 inputT *forplan1;
247 outputT *forplan2;
248
249 int sz;
250
251 if( rank == 1 )
252 sz = m_szX;
253 if( rank == 2 )
254 sz = m_szX * m_szY;
255 if( rank == 3 )
256 sz = m_szX * m_szY * m_szZ;
257
260
261 int pdir = FFTW_FORWARD;
262 if( m_dir == MXFFT_BACKWARD )
264
265#ifndef MX_FFTW_NOOMP
266 #pragma omp critical
267#endif
268 { // scope for pragma
270 fftwDimVec<rank>( m_szX, m_szY, m_szZ ), forplan1, forplan2, pdir, FFTW_MEASURE );
271 }
272
275}
276
277template <typename inputT, typename outputT, size_t rank>
278void fftT<inputT, outputT, rank, 0>::doPlan( const meta::trueFalseT<true> &inPlace )
279{
280 (void)inPlace;
281
282 complexT *forplan;
283
284 int sz;
285
286 if( rank == 1 )
287 sz = m_szX;
288 if( rank == 2 )
289 sz = m_szX * m_szY;
290 if( rank == 3 )
291 sz = m_szX * m_szY * m_szZ;
292
294
295 int pdir = FFTW_FORWARD;
296 if( m_dir == MXFFT_BACKWARD )
298
299#ifndef MX_FFTW_NOOMP
300 #pragma omp critical
301#endif
302 { // scope for pragma
303 m_plan = fftw_plan_dft<inputT, outputT>( fftwDimVec<rank>( m_szX, m_szY, m_szZ ),
304 reinterpret_cast<inputT *>( forplan ),
305 reinterpret_cast<outputT *>( forplan ),
306 pdir,
307 FFTW_MEASURE );
308 }
309
310 fftw_free<inputT>( reinterpret_cast<inputT *>( forplan ) );
311}
312
313template <typename inputT, typename outputT, size_t rank>
314template <int crank>
315void fftT<inputT, outputT, rank, 0>::plan( int nx, int ndir, bool inPlace, typename std::enable_if<crank == 1>::type * )
316{
317 if( m_szX == nx && m_dir == ndir && m_plan )
318 {
319 return;
320 }
321
322 destroyPlan();
323
324 m_dir = ndir;
325
326 m_szX = nx;
327 m_szY = 0;
328 m_szZ = 0;
329
330 if( inPlace == false )
331 {
332 doPlan( meta::trueFalseT<false>() );
333 }
334 else
335 {
336 doPlan( meta::trueFalseT<true>() );
337 }
338}
339
340template <typename inputT, typename outputT, size_t rank>
341template <int crank>
342void fftT<inputT, outputT, rank, 0>::plan(
343 int nx, int ny, int ndir, bool inPlace, typename std::enable_if<crank == 2>::type * )
344{
345 if( m_szX == nx && m_szY == ny && m_dir == ndir && m_plan )
346 {
347 return;
348 }
349
350 destroyPlan();
351
352 m_dir = ndir;
353
354 m_szX = nx;
355 m_szY = ny;
356 m_szZ = 0;
357
358 if( inPlace == false )
359 {
360 doPlan( meta::trueFalseT<false>() );
361 }
362 else
363 {
364 doPlan( meta::trueFalseT<true>() );
365 }
366}
367
368template <typename inputT, typename outputT, size_t rank>
369template <int crank>
370void fftT<inputT, outputT, rank, 0>::plan(
371 int nx, int ny, int nz, int ndir, bool inPlace, typename std::enable_if<crank == 3>::type * )
372{
373 if( m_szX == nx && m_szY == ny && m_szZ == nz && m_dir == ndir && m_plan )
374 {
375 return;
376 }
377
378 destroyPlan();
379
380 m_dir = ndir;
381
382 m_szX = nx;
383 m_szY = ny;
384 m_szZ = nz;
385
386 if( inPlace == false )
387 {
388 doPlan( meta::trueFalseT<false>() );
389 }
390 else
391 {
392 doPlan( meta::trueFalseT<true>() );
393 }
394}
395
396template <typename inputT, typename outputT, size_t rank>
397void fftT<inputT, outputT, rank, 0>::operator()( outputT *out, inputT *in ) const
398{
400}
401
402template <>
403std::vector<int> fftwDimVec<1>( int szX, int szY, int szZ );
404
405template <>
406std::vector<int> fftwDimVec<2>( int szX, int szY, int szZ );
407
408template <>
409std::vector<int> fftwDimVec<3>( int szX, int szY, int szZ );
410
411#ifdef MX_CUDA
412
413template <>
414class fft<std::complex<float>, std::complex<float>, 2, 1>
415{
416 protected:
417 int m_szX;
418 int m_szY;
419
420 cufftHandle m_plan;
421
422 public:
423 fft()
424 {
425 m_szX = 0;
426 m_szY = 0;
427 }
428
429 fft( int nx, int ny )
430 {
431 m_szX = 0;
432 m_szY = 0;
433
434 plan( nx, ny );
435 }
436
437 void plan( int nx, int ny )
438 {
439 if( m_szX == nx && m_szY == ny )
440 {
441 return;
442 }
443
444 m_szX = nx;
445 m_szY = ny;
446
447 cufftPlan2d( &m_plan, m_szX, m_szY, CUFFT_C2C );
448 }
449
450 void fwdFFT( std::complex<float> *in, std::complex<float> *out )
451 {
452 cufftExecC2C( m_plan, (cufftComplex *)in, (cufftComplex *)out, CUFFT_FORWARD );
453 }
454};
455
456#endif
457
458} // namespace fft
459} // namespace math
460} // namespace mx
461
462#endif // fft_hpp
void doPlan(const meta::trueFalseT< false > &inPlace)
Call the FFTW planning routine for an out-of-place transform.
void destroyPlan()
Destroy (de-allocate) the plan.
void operator()(outputT *out, inputT *in) const
Conduct the FFT.
fftT(int nx, int ny, int nz, int ndir=MXFFT_FORWARD, bool inPlace=false, typename std::enable_if< crank==3 >::type *=0)
Constructor for rank 3 FFT.
fftT(int nx, int ndir=MXFFT_FORWARD, bool inPlace=false, typename std::enable_if< crank==1 >::type *=0)
Constructor for rank 1 FFT.
void plan(int nx, int ny, int nz, int ndir=MXFFT_FORWARD, bool inPlace=false, typename std::enable_if< crank==3 >::type *=0)
Planning routine for rank 3 transforms.
fftT(int nx, int ny, int ndir=MXFFT_FORWARD, bool inPlace=false, typename std::enable_if< crank==2 >::type *=0)
Constructor for rank 2 FFT.
void plan(int nx, int ny, int ndir=MXFFT_FORWARD, bool inPlace=false, typename std::enable_if< crank==2 >::type *=0)
Planning routine for rank 2 transforms.
void plan(int nx, int ndir=MXFFT_FORWARD, bool inPlace=false, typename std::enable_if< crank==1 >::type *=0)
Planning routine for rank 1 transforms.
int dir()
Get the direction of this FFT.
void doPlan(const meta::trueFalseT< true > &inPlace)
Call the FFTW planning routine for an in-place transform.
Declares and defines templatized wrappers for the fftw library.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
The mxlib c++ namespace.
Definition mxError.hpp:106
fftwX_plan planT
Specializations typedef planT as fftwf_plan, fftw_plan, fftwl_plan, or fftwq_plan.
std::complex< realT > complexT
The complex data type.
_realT realT
The real data type (_realT is actually defined in specializations).
Template declaration of a trueFalseT type.