BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
FourierTransform.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Device/Instrument/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 //! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
13 //
14 // ************************************************************************** //
15 
17 #include "Base/Types/Exceptions.h"
18 #include <algorithm>
19 #include <cmath>
20 #include <iostream>
21 #include <sstream>
22 #include <stdexcept>
23 
25 
27  : h_src(0), w_src(0), h_fftw(0), w_fftw(0), in_src(0), out_fftw(0), p_forw_src(nullptr)
28 {
29 }
30 
32 {
33  clear();
34 }
35 
37 {
38  // rows (h) and columns (w) of the input 'source'
39  h_src = 0;
40  w_src = 0;
41 
42  if (in_src)
43  delete[] in_src;
44  in_src = 0;
45 
46  if (out_fftw)
47  fftw_free((fftw_complex*)out_fftw);
48  out_fftw = 0;
49 
50  if (p_forw_src != nullptr)
51  fftw_destroy_plan(p_forw_src);
52 
53  fftw_cleanup();
54 }
55 
56 /* ************************************************************************* */
57 // Fourier Transform in 2D
58 /* ************************************************************************* */
59 void FourierTransform::fft(const double2d_t& source, double2d_t& result)
60 {
61  // rows (h) and columns (w) of the input 'source'
62  int h_src = static_cast<int>(source.size());
63  int w_src = static_cast<int>((source.size() ? source[0].size() : 0));
64 
65  // initialisation
66  init(h_src, w_src);
67 
68  // Compute the forward FT
69  fftw_forward_FT(source);
70 
71  double* ptr = ws.out_fftw;
72  result.clear();
73 
74  // Resize the array for holding the FT output to correct dimensions
75  result.resize(static_cast<size_t>(ws.h_fftw),
76  std::vector<double>(static_cast<size_t>(ws.w_fftw)));
77 
78  // Storing FT output
79  for (size_t i = 0; i < static_cast<size_t>(ws.h_fftw); i++) {
80  size_t k = static_cast<size_t>(ws.h_fftw) - i;
81  if (i == 0)
82  k -= static_cast<size_t>(ws.h_fftw);
83  for (size_t j = 0; j < static_cast<size_t>(ws.w_fftw / 2 + 1); j++) {
84  result[i][j] = *ptr;
85  size_t l = static_cast<size_t>(ws.w_fftw) - j;
86  if (j != 0)
87  result[k][l] = result[i][j];
88  ptr += 2; // Only interested in the magnitudes of the complex Fourier coefficients
89  }
90  }
91 }
92 
93 /* ************************************************************************* */
94 // Fourier Transform 2D shift - center array around zero frequency
95 /* ************************************************************************* */
97 {
98  // Centering FT around zero frequency
99  size_t row_shift;
100  if (result.size() % 2 == 0)
101  row_shift = result.size() / 2;
102  else
103  row_shift = result.size() / 2 + 1;
104 
105  size_t col_shift;
106  if (result[0].size() % 2 == 0)
107  col_shift = result[0].size() / 2;
108  else
109  col_shift = result[0].size() / 2 + 1;
110 
111  // First, shifting the rows
112  std::rotate(result.begin(), result.begin() + static_cast<int>(row_shift), result.end());
113 
114  // Second, shifting the cols
115  for (size_t i = 0; i < static_cast<size_t>(ws.h_fftw); i++) {
116  std::rotate(result[i].begin(), result[i].begin() + static_cast<int>(col_shift),
117  result[i].end());
118  }
119 }
120 
121 /* ************************************************************************* */
122 // Fourier Transform in 1D
123 /* ************************************************************************* */
124 void FourierTransform::fft(const double1d_t& source, double1d_t& result)
125 {
126  // we simply create 2d arrays with length of first dimension equal to 1, and call 2d FT
127  double2d_t source2d;
128  source2d.push_back(source);
129 
130  double2d_t result2d;
131  fft(source2d, result2d);
132 
133  if (result2d.size() != 1)
134  throw Exceptions::RuntimeErrorException("FourierTransform::fft -> Panic in 1d");
135 
136  result = result2d[0];
137 }
138 
139 /* ************************************************************************* */
140 // Fourier Transform 1D shift - center around zero frequency
141 /* ************************************************************************* */
143 {
144  // Centering FT around zero frequency
145  size_t col_shift;
146  if (result.size() % 2 == 0)
147  col_shift = result.size() / 2;
148  else
149  col_shift = result.size() / 2 + 1;
150 
151  std::rotate(result.begin(), result.begin() + static_cast<int>(col_shift), result.end());
152 }
153 
154 /* ************************************************************************************ */
155 // initialise input and output arrays in workspace for fast Fourier transformation (fftw)
156 /* ************************************************************************************ */
157 void FourierTransform::init(int h_src, int w_src)
158 {
159  if (!h_src || !w_src) {
160  std::ostringstream os;
161  os << "FourierTransform::init() -> Panic! Wrong dimensions " << h_src << " " << w_src
162  << std::endl;
163  throw Exceptions::RuntimeErrorException(os.str());
164  }
165 
166  ws.clear();
167  ws.h_src = h_src;
168  ws.w_src = w_src;
169 
170  ws.h_fftw = h_src;
171  ws.w_fftw = w_src;
172 
173  ws.in_src = new double[static_cast<size_t>(ws.h_fftw * ws.w_fftw)];
174  ws.out_fftw = static_cast<double*>(
175  fftw_malloc(sizeof(fftw_complex) * static_cast<size_t>(ws.h_fftw * (ws.w_fftw / 2 + 1))));
176 
177  // Initialization of the plans
178  ws.p_forw_src = fftw_plan_dft_r2c_2d(ws.h_fftw, ws.w_fftw, ws.in_src,
179  (fftw_complex*)ws.out_fftw, FFTW_ESTIMATE);
180  // ws.p_forw_src = fftw_plan_dft_r2c_2d(ws.h_fftw, ws.w_fftw, ws.in_src,
181  // static_cast<double*>(ws.out_src), FFTW_ESTIMATE);
182 
183  if (ws.p_forw_src == nullptr)
185  "FourierTransform::init() -> Error! Can't initialise p_forw_src plan.");
186 }
187 
188 /* ************************************************************************* */
189 // initialise input and output arrays for fast Fourier transformation
190 /* ************************************************************************* */
191 
193 {
194  if (ws.h_fftw <= 0 || ws.w_fftw <= 0)
196  "FourierTransform::fftw_forward_FT() -> Panic! Initialisation is missed.");
197 
198  double *ptr, *ptr_end;
199 
200  // Initializing the content of ws.in_src to zero for all elements
201  for (ptr = ws.in_src, ptr_end = ws.in_src + ws.h_fftw * ws.w_fftw; ptr != ptr_end; ++ptr)
202  *ptr = 0.0;
203 
204  // Building the input signal for fftw algorithm
205  for (size_t row = 0; row < static_cast<size_t>(ws.h_src); ++row)
206  for (size_t col = 0; col < static_cast<size_t>(ws.w_src); ++col)
207  ws.in_src[(static_cast<int>(row) % ws.h_fftw) * ws.w_fftw
208  + (static_cast<int>(col) % ws.w_fftw)] += src[row][col];
209 
210  // Computing the FFT with fftw plan
211  fftw_execute(ws.p_forw_src);
212 
213  double re_out, im_out;
214  for (ptr = ws.out_fftw, ptr_end = ws.out_fftw + 2 * ws.h_fftw * (ws.w_fftw / 2 + 1);
215  ptr != ptr_end; ++ptr) {
216  re_out = *ptr;
217  im_out = *(++ptr);
218 
219  // magnitude
220  *(ptr - 1) = sqrt(re_out * re_out + im_out * im_out);
221  // phase
222  *ptr = atan2(im_out, re_out);
223  }
224 }
Defines many exception classes in namespace Exceptionss.
Defines class MathFunctions::FourierTransform.
double * out_fftw
result of Fourier transformation of source
int h_src
Here, h = height (# rows), w = width (# columns)
Workspace ws
input and output data for fftw3
void fftw_forward_FT(const double2d_t &source)
compute FT of source using Fast Fourier transformation from fftw
void fft(const double1d_t &source, double1d_t &result)
FT in 1D.
std::vector< double > double1d_t
definition of 1D vector of double
void fftshift(double1d_t &result)
Shift low frequency to the center of 1D FT array.
std::vector< double1d_t > double2d_t
definition of 2D vector of double
void init(int h_src, int w_src)
prepare arrays for 2D Fourier Transformation (FT) of the given vector