mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
mdft.hpp
Go to the documentation of this file.
1/** \file mdft.hpp
2 * \brief The Matrix Discrete Fourier Transform interface
3 * \ingroup fft_files
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2024 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 mdft_hpp
28#define mdft_hpp
29
30#pragma GCC system_header
31#include <Eigen/Dense>
32
33#include "fft.hpp"
34#include "../../math/constants.hpp"
35
36namespace mx
37{
38namespace math
39{
40namespace fft
41{
42
43template <typename _inputT, typename _outputT, size_t _rank, int _cudaGPU = 0>
44class mdftT;
45
46/// Matrix Discrete Fourier Transforms
47/** Calculates the Discrete Fourier Transform (DFT) using matrix multiplication. This
48 * is normally much less efficient than the FFT, but for large oversampling (padding)
49 * the Matrix DFT (MDFT) will be much more space efficient and faster at the cost of
50 * "field of view".
51 *
52 * This interface is modeled after the fftT interface to fftw. Note that by default
53 * these MDFTs are normalized as in fftw, so 1/N on the forward.
54 *
55 * \tparam inputT is the input type of the transform, can be either real or complex
56 * \tparam outputT is the output type of the transform, can be either real or complex
57 *
58 * \ingroup fft
59 */
60template <typename _inputT, typename _outputT, size_t _rank>
61class mdftT<_inputT, _outputT, _rank, 0>
62{
63 typedef _inputT inputT;
64 typedef _outputT outputT;
65
66 typedef typename fftwTypeSpec<inputT, outputT>::realT realT;
67
68 typedef typename fftwTypeSpec<_inputT, _outputT>::complexT complexT;
69
70 static const size_t rank = _rank;
71
72 typedef Eigen::Array<inputT, -1, -1> eigenArrayInputT;
73 typedef Eigen::Array<outputT, -1, -1> eigenArrayOutputT;
74
75 typedef Eigen::Matrix<complexT, -1, -1> eigenMatrixT;
76
77 protected:
78 int m_dir{ MXFFT_FORWARD }; ///< Direction of this MDFT, either MXFFT_FORWARD (default) or MXFFT_BACKWARD
79
80 int m_szX{ 0 }; ///< Size of the x dimension
81 int m_szY{ 0 }; ///< Size of the y dimension
82 int m_szZ{ 0 }; ///< size of the z dimension
83
84 float m_osFac{ 1 }; ///< The oversampling factor
85
86 realT m_xOff{ 0 }; ///< The offset in the rows direction for the center of the DFT.
87 realT m_yOff{ 0 }; ///< The offset in the columns direction for the center of the DFT.
88
89 eigenMatrixT m_dftR; ///< DFT matrix for the rows
90 eigenMatrixT m_dftC; ///< DFT matrix for the columnss
91
92 public:
93 /// Default c'tor
95
96 /// Constructor for rank 1 MDFT.
97 template <size_t crank = _rank>
98 mdftT( int nx, ///< [in] the desired size of the MDFT
99 int ndir = MXFFT_FORWARD, /**< [in] [optional] direction of this MDFT, either MXFFT_FORWARD (default)
100 or MXFFT_BACKWARD */
101 realT xOff = 0, /**< [in] [optional] the x offset of the center of the transformed array. Default 0.*/
102 realT osFac = 1.0, /**< [in] [optional] the oversampling factor. Default 1. */
103 typename std::enable_if<crank == 1>::type * = 0 ) = delete;
104
105 /// Constructor for rank 2 MDFT.
106 template <size_t crank = _rank>
107 mdftT( int nx, ///< [in] the desired x size of the MDFT
108 int ny, ///< [in] the desired y size of the MDFT
109 int ndir = MXFFT_FORWARD, /**< [in] [optional] direction of this MDFT, either MXFFT_FORWARD (default)
110 or MXFFT_BACKWARD */
111 realT xOff = 0, /**< [in] [optional] the x offset of the center of the transformed array. Default 0.*/
112 realT yOff = 0, /**< [in] [optional] the y offset of the center of the transformed array Default 0.*/
113 realT osFac = 1.0, /**< [in] [optional] the oversampling factor. Default 1. */
114 typename std::enable_if<crank == 2>::type * = 0 );
115
116 /// Constructor for rank 3 MDFT.
117 template <size_t crank = _rank>
118 mdftT( int nx, ///< [in] the desired x size of the MDFT
119 int ny, ///< [in] the desired y size of the MDFT
120 int nz, ///< [in] the desired z size of the MDFT
121 int ndir = MXFFT_FORWARD, /**< [in] [optional] direction of this MDFT, either MXFFT_FORWARD (default)
122 or MXFFT_BACKWARD */
123 realT xOff = 0, /**< [in] [optional] the x offset of the center of the transformed array. Default 0.*/
124 realT yOff = 0, /**< [in] [optional] the y offset of the center of the transformed array Default 0.*/
125 realT zOff = 0, /**< [in] [optional] the z offset of the center of the transformed array Default 0.*/
126 realT osFac = 1.0, /**< [in] [optional] the oversampling factor. Default 1. */
127 typename std::enable_if<crank == 3>::type * = 0 ) = delete;
128
129 /// Planning routine for rank 2 transforms.
130 template <size_t crank = _rank>
131 void plan( int nx, ///< [in] the desired x size of the MDFT
132 int ny, ///< [in] the desired y size of the MDFT
133 int ndir = MXFFT_FORWARD, /**< [in] [optional] direction of this MDFT, either MXFFT_FORWARD (default)
134 or MXFFT_BACKWARD */
135 realT xOff = 0, /**< [in] [optional] the x offset of the center of the transformed array. Default 0.*/
136 realT yOff = 0, /**< [in] [optional] the y offset of the center of the transformed array Default 0.*/
137 realT osFac = 1.0, /**< [in] [optional] the oversampling factor. Default 1. */
138 typename std::enable_if<crank == 2>::type * = 0 );
139
140 /// Conduct the DFT
141 void operator()( eigenArrayOutputT &out, /**< [out] the output of the DFT, must be pre-allocated */
142 const eigenArrayInputT &in /**< [in] the input to the DFT */ ) const;
143};
144
145template <typename inputT, typename outputT, size_t rank>
146mdftT<inputT, outputT, rank, 0>::mdftT()
147{
148}
149
150template <typename inputT, typename outputT, size_t rank>
151template <size_t crank>
152mdftT<inputT, outputT, rank, 0>::mdftT(
153 int nx, int ny, int ndir, realT xoff, realT yoff, realT osFac, typename std::enable_if<crank == 2>::type * )
154{
155 plan( nx, ny, ndir, xoff, yoff, osFac );
156}
157
158template <typename inputT, typename outputT, size_t rank>
159template <size_t crank>
160void mdftT<inputT, outputT, rank, 0>::plan(
161 int nx, int ny, int ndir, realT xOff, realT yOff, realT osFac, typename std::enable_if<crank == 2>::type * )
162{
163 m_szX = nx;
164 m_szY = ny;
165 m_dir = ndir;
166 m_xOff = xOff;
167 m_yOff = yOff;
168 m_osFac = osFac;
169
170 if( m_szX != m_szY )
171 {
172 throw std::invalid_argument( "MDFT of non-square size is not implemented. nx must equal ny." );
173 }
174
175 // These should depend on szX too.
176 m_dftR.resize( m_szX, m_szX );
177 m_dftC.resize( m_szX, m_szX );
178
179 // There is probably an osNx and an osNy?
180 int osN = ceil( m_szX * m_osFac );
181
182 if( m_dir == MXFFT_FORWARD )
183 {
184 realT norm = 1.0 / ( m_szX * m_szY );
185 for( int cc = 0; cc < m_szY; ++cc )
186 {
187 for( int rr = 0; rr < m_szX; ++rr )
188 {
189 realT x = static_cast<realT>( rr - m_xOff ) * static_cast<realT>( cc );
190
191 m_dftR( rr, cc ) = norm * exp( complexT( { 0, -2 * pi<realT>() * x / ( osN ) } ) );
192
193 x = static_cast<realT>( rr ) * static_cast<realT>( cc - m_yOff );
194
195 m_dftC( rr, cc ) = norm * exp( complexT( { 0, -2 * pi<realT>() * x / ( osN ) } ) );
196 }
197 }
198 }
199 else
200 {
201 realT norm = 1.0;
202
203 for( int rr = 0; rr < m_szX; ++rr )
204 {
205 for( int cc = 0; cc < m_szY; ++cc )
206 {
207 realT x = static_cast<realT>( rr - m_xOff ) * static_cast<realT>( cc );
208
209 m_dftR( cc, rr ) = norm * exp( complexT( { 0, +2 * pi<realT>() * x / ( osN ) } ) );
210
211 x = static_cast<realT>( rr ) * static_cast<realT>( cc - m_yOff );
212
213 m_dftC( cc, rr ) = norm * exp( complexT( { 0, +2 * pi<realT>() * x / ( osN ) } ) );
214 }
215 }
216 }
217}
218
219template <typename inputT, typename outputT, size_t rank>
220void mdftT<inputT, outputT, rank, 0>::operator()( eigenArrayOutputT &out, const eigenArrayInputT &in ) const
221{
222 out = ( m_dftR * in.matrix() * m_dftC ).array();
223}
224
225} // namespace fft
226} // namespace math
227} // namespace mx
228
229#endif // mdft_hpp
mdftT(int nx, int ny, int nz, int ndir=MXFFT_FORWARD, realT xOff=0, realT yOff=0, realT zOff=0, realT osFac=1.0, typename std::enable_if< crank==3 >::type *=0)=delete
Constructor for rank 3 MDFT.
mdftT(int nx, int ndir=MXFFT_FORWARD, realT xOff=0, realT osFac=1.0, typename std::enable_if< crank==1 >::type *=0)=delete
Constructor for rank 1 MDFT.
mdftT(int nx, int ny, int ndir=MXFFT_FORWARD, realT xOff=0, realT yOff=0, realT osFac=1.0, typename std::enable_if< crank==2 >::type *=0)
Constructor for rank 2 MDFT.
eigenMatrixT m_dftC
DFT matrix for the columnss.
Definition mdft.hpp:90
void operator()(eigenArrayOutputT &out, const eigenArrayInputT &in) const
Conduct the DFT.
eigenMatrixT m_dftR
DFT matrix for the rows.
Definition mdft.hpp:89
void plan(int nx, int ny, int ndir=MXFFT_FORWARD, realT xOff=0, realT yOff=0, realT osFac=1.0, typename std::enable_if< crank==2 >::type *=0)
Planning routine for rank 2 transforms.
The fast Fourier transform interface.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
The mxlib c++ namespace.
Definition mxError.hpp:106
std::complex< realT > complexT
The complex data type.
_realT realT
The real data type (_realT is actually defined in specializations).