BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
FourierTransform.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Base/Math/FourierTransform.cpp
6 //! @brief Implements class FourierTransform.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2015
11 //! @authors Scientific Computing Group at MLZ Garching
12 //
13 // ************************************************************************************************
14 
16 #include "Base/Util/Assert.h"
17 #include <algorithm>
18 #include <cmath>
19 
21 
23 {
24  clear();
25 }
26 
28 {
29  // rows (h) and columns (w) of the input 'source'
30  h_src = 0;
31  w_src = 0;
32 
33  delete[] in_src;
34  in_src = nullptr;
35 
36  if (out_fftw)
37  fftw_free((fftw_complex*)out_fftw);
38  out_fftw = nullptr;
39 
40  if (p_forw_src != nullptr)
41  fftw_destroy_plan(p_forw_src);
42 
43  fftw_cleanup();
44 }
45 
46 /* ************************************************************************* */
47 // Fourier Transform in 2D
48 /* ************************************************************************* */
49 void FourierTransform::fft(const double2d_t& source, double2d_t& result)
50 {
51  // rows (h) and columns (w) of the input 'source'
52  int h_src = static_cast<int>(source.size());
53  int w_src = static_cast<int>((!source.empty() ? source[0].size() : 0));
54 
55  // initialization
56  init(h_src, w_src);
57 
58  // Compute the forward FT
59  fftw_forward_FT(source);
60 
61  double* ptr = ws.out_fftw;
62  result.clear();
63 
64  const size_t nh = ws.h_fftw;
65 
66  // Resize the array for holding the FT output to correct dimensions
67  result.resize(nh, std::vector<double>(static_cast<size_t>(ws.w_fftw)));
68 
69  // Storing FT output
70  for (size_t i = 0; i < nh; i++) {
71  size_t k = nh - i;
72  if (i == 0)
73  k -= nh;
74  for (size_t j = 0; j < static_cast<size_t>(ws.w_fftw / 2 + 1); j++) {
75  result[i][j] = *ptr;
76  size_t l = static_cast<size_t>(ws.w_fftw) - j;
77  if (j != 0)
78  result[k][l] = result[i][j];
79  ptr += 2; // Only interested in the magnitudes of the complex Fourier coefficients
80  }
81  }
82 }
83 
84 /* ************************************************************************* */
85 // Fourier Transform 2D shift - center array around zero frequency
86 /* ************************************************************************* */
88 {
89  // Centering FT around zero frequency
90  size_t row_shift;
91  if (result.size() % 2 == 0)
92  row_shift = result.size() / 2;
93  else
94  row_shift = result.size() / 2 + 1;
95 
96  size_t col_shift;
97  if (result[0].size() % 2 == 0)
98  col_shift = result[0].size() / 2;
99  else
100  col_shift = result[0].size() / 2 + 1;
101 
102  // First, shifting the rows
103  std::rotate(result.begin(), result.begin() + static_cast<int>(row_shift), result.end());
104 
105  // Second, shifting the cols
106  for (size_t i = 0; i < static_cast<size_t>(ws.h_fftw); i++)
107  std::rotate(result[i].begin(), result[i].begin() + static_cast<int>(col_shift),
108  result[i].end());
109 }
110 
111 /* ************************************************************************* */
112 // Fourier Transform in 1D
113 /* ************************************************************************* */
114 void FourierTransform::fft(const double1d_t& source, double1d_t& result)
115 {
116  // we simply create 2d arrays with length of first dimension equal to 1, and call 2d FT
117  double2d_t source2d;
118  source2d.push_back(source);
119 
120  double2d_t result2d;
121  fft(source2d, result2d);
122 
123  ASSERT(result2d.size() == 1);
124  result = result2d[0];
125 }
126 
127 /* ************************************************************************* */
128 // Fourier Transform 1D shift - center around zero frequency
129 /* ************************************************************************* */
131 {
132  // Centering FT around zero frequency
133  size_t col_shift;
134  if (result.size() % 2 == 0)
135  col_shift = result.size() / 2;
136  else
137  col_shift = result.size() / 2 + 1;
138 
139  std::rotate(result.begin(), result.begin() + static_cast<int>(col_shift), result.end());
140 }
141 
142 /* ************************************************************************************ */
143 // initialise input and output arrays in workspace for fast Fourier transformation (fftw)
144 /* ************************************************************************************ */
145 void FourierTransform::init(int h_src, int w_src)
146 {
147  ASSERT(h_src);
148  ASSERT(w_src);
149 
150  ws.clear();
151  ws.h_src = h_src;
152  ws.w_src = w_src;
153 
154  ws.h_fftw = h_src;
155  ws.w_fftw = w_src;
156 
157  ws.in_src = new double[static_cast<size_t>(ws.h_fftw * ws.w_fftw)];
158  ws.out_fftw = static_cast<double*>(
159  fftw_malloc(sizeof(fftw_complex) * static_cast<size_t>(ws.h_fftw * (ws.w_fftw / 2 + 1))));
160 
161  // Initialization of the plans
162  ws.p_forw_src = fftw_plan_dft_r2c_2d(ws.h_fftw, ws.w_fftw, ws.in_src,
163  (fftw_complex*)ws.out_fftw, FFTW_ESTIMATE);
164  // ws.p_forw_src = fftw_plan_dft_r2c_2d(ws.h_fftw, ws.w_fftw, ws.in_src,
165  // static_cast<double*>(ws.out_src), FFTW_ESTIMATE);
166 
168 }
169 
170 /* ************************************************************************* */
171 // initialise input and output arrays for fast Fourier transformation
172 /* ************************************************************************* */
173 
175 {
176  ASSERT(ws.h_fftw > 0);
177  ASSERT(ws.w_fftw > 0);
178 
179  double *ptr, *ptr_end;
180 
181  // Initializing the content of ws.in_src to zero for all elements
182  for (ptr = ws.in_src, ptr_end = ws.in_src + ws.h_fftw * ws.w_fftw; ptr != ptr_end; ++ptr)
183  *ptr = 0.0;
184 
185  // Building the input signal for fftw algorithm
186  for (size_t row = 0; row < static_cast<size_t>(ws.h_src); ++row)
187  for (size_t col = 0; col < static_cast<size_t>(ws.w_src); ++col)
188  ws.in_src[(static_cast<int>(row) % ws.h_fftw) * ws.w_fftw
189  + (static_cast<int>(col) % ws.w_fftw)] += src[row][col];
190 
191  // Computing the FFT with fftw plan
192  fftw_execute(ws.p_forw_src);
193 
194  for (ptr = ws.out_fftw, ptr_end = ws.out_fftw + 2 * ws.h_fftw * (ws.w_fftw / 2 + 1);
195  ptr != ptr_end; ++ptr) {
196  double re_out = *ptr;
197  double im_out = *(++ptr);
198 
199  // magnitude
200  *(ptr - 1) = sqrt(re_out * re_out + im_out * im_out);
201  // phase
202  *ptr = atan2(im_out, re_out);
203  }
204 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:45
Defines class Math::FourierTransform.
double * out_fftw
result of Fourier transformation of source
int h_src
Here, h = height (# rows), w = width (# columns)
void fftshift(double1d_t &result) const
Shift low frequency to the center of 1D FT array.
Workspace ws
input and output data for fftw3
std::vector< double > double1d_t
definition of 1D vector of double
void fft(const double1d_t &source, double1d_t &result)
FT in 1D.
void fftw_forward_FT(const double2d_t &src)
compute FT of source using Fast Fourier transformation from fftw
void init(int h_src, int w_src)
prepare arrays for 2D Fourier Transformation (FT) of the given vector
std::vector< double1d_t > double2d_t
definition of 2D vector of double