fft.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2015 OpenFOAM Foundation
9  Copyright (C) 2016-2018 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "fft.H"
30 #include <fftw3.h>
31 
32 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
33 
35 (
37  List<complex>& renumData,
38  const UList<int>& nn,
39  label nnprod,
40  label ii,
41  label l1,
42  label l2
43 )
44 {
45  if (ii == nn.size())
46  {
47  // We've worked out the renumbering scheme. Now copy
48  // the components across
49 
50  data[l1] = complex(renumData[l2].Re(), renumData[l2].Im());
51  }
52  else
53  {
54  // Do another level of folding. First work out the
55  // multiplicative value of the index
56 
57  nnprod /= nn[ii];
58  label i_1(0);
59 
60  for (label i=0; i<nn[ii]; i++)
61  {
62  // Now evaluate the indices (both from array 1 and to
63  // array 2). These get multiplied by nnprod to (cumulatively)
64  // find the real position in the list corresponding to
65  // this set of indices
66 
67  if (i < nn[ii]/2)
68  {
69  i_1 = i + nn[ii]/2;
70  }
71  else
72  {
73  i_1 = i - nn[ii]/2;
74  }
75 
76 
77  // Go to the next level of recursion
78 
79  fftRenumberRecurse
80  (
81  data,
82  renumData,
83  nn,
84  nnprod,
85  ii+1,
86  l1+i*nnprod,
87  l2+i_1*nnprod
88  );
89  }
90  }
91 }
92 
93 
95 {
96  List<complex> renumData(data);
97 
98  label nnprod(1);
99  forAll(nn, i)
100  {
101  nnprod *= nn[i];
102  }
103 
104  label ii(0), l1(0), l2(0);
105 
107  (
108  data,
109  renumData,
110  nn,
111  nnprod,
112  ii,
113  l1,
114  l2
115  );
116 }
117 
118 
121 {
122  const label n = field.size();
123  const label nBy2 = n/2;
124 
125  // Copy of input field for use by fftw
126  // - require non-const access to input and output
127  // - use double to avoid additional libfftwf for single-precision
128 
129  List<double> in(n);
130  List<double> out(n);
131 
132  for (label i=0; i < n; ++i)
133  {
134  in[i] = field[i];
135  }
136 
137  // Using real to half-complex fftw 'kind'
138  fftw_plan plan = fftw_plan_r2r_1d
139  (
140  n,
141  in.data(),
142  out.data(),
143  FFTW_R2HC,
144  FFTW_ESTIMATE
145  );
146 
147  fftw_execute(plan);
148 
149  // field[0] = DC component
150  auto tresult = tmp<complexField>::New(nBy2 + 1);
151  auto& result = tresult.ref();
152 
153  result[0].Re() = out[0];
154  result[nBy2].Re() = out[nBy2];
155  for (label i = 1; i < nBy2; ++i)
156  {
157  result[i].Re() = out[i];
158  result[i].Im() = out[n - i];
159  }
160 
161  fftw_destroy_plan(plan);
162 
163  return tresult;
164 }
165 
166 
168 (
169  const tmp<scalarField>& tfield
170 )
171 {
172  tmp<complexField> tresult = realTransform1D(tfield());
173  tfield.clear();
174  return tresult;
175 }
176 
177 
179 (
181  const UList<int>& nn,
183 )
184 {
185  // Copy field into fftw containers
186  const label N = field.size();
187 
188  fftw_complex* inPtr =
189  static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex)*N));
190  fftw_complex* outPtr =
191  static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex)*N));
192 
193  // If reverse transform : renumber before transform
194  if (dir == REVERSE_TRANSFORM)
195  {
196  fftRenumber(field, nn);
197  }
198 
199  forAll(field, i)
200  {
201  inPtr[i][0] = field[i].Re();
202  inPtr[i][1] = field[i].Im();
203  }
204 
205  // Create the plan
206  // FFTW_FORWARD = -1
207  // FFTW_BACKWARD = 1
208 
209  // 1-D plan
210  // fftw_plan plan =
211  // fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
212 
213  // Generic 1..3-D plan
214  const label rank = nn.size();
215  fftw_plan plan =
216  fftw_plan_dft(rank, nn.begin(), inPtr, outPtr, dir, FFTW_ESTIMATE);
217 
218  // Compute the FFT
219  fftw_execute(plan);
220 
221  forAll(field, i)
222  {
223  field[i].Re() = outPtr[i][0];
224  field[i].Im() = outPtr[i][1];
225  }
226 
227  fftw_destroy_plan(plan);
228 
229  fftw_free(inPtr);
230  fftw_free(outPtr);
231 
232  // If forward transform : renumber after transform
233  if (dir == FORWARD_TRANSFORM)
234  {
235  fftRenumber(field, nn);
236  }
237 }
238 
239 
240 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
241 
243 (
244  const tmp<complexField>& tfield,
245  const UList<int>& nn
246 )
247 {
248  auto tresult = tmp<complexField>::New(tfield);
249 
250  transform(tresult.ref(), nn, FORWARD_TRANSFORM);
251 
252  tfield.clear();
253 
254  return tresult;
255 }
256 
257 
259 (
260  const tmp<complexField>& tfield,
261  const UList<int>& nn
262 )
263 {
264  auto tresult = tmp<complexField>::New(tfield);
265 
266  transform(tresult.ref(), nn, REVERSE_TRANSFORM);
267 
268  tfield.clear();
269 
270  return tresult;
271 }
272 
273 
275 (
276  const tmp<complexVectorField>& tfield,
277  const UList<int>& nn
278 )
279 {
280  auto tresult = tmp<complexVectorField>::New(tfield().size());
281 
282  for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
283  {
284  tresult.ref().replace
285  (
286  cmpt,
287  forwardTransform(tfield().component(cmpt), nn)
288  );
289  }
290 
291  tfield.clear();
292 
293  return tresult;
294 }
295 
296 
298 (
299  const tmp<complexVectorField>& tfield,
300  const UList<int>& nn
301 )
302 {
303  auto tresult = tmp<complexVectorField>::New(tfield().size());
304 
305  for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
306  {
307  tresult.ref().replace
308  (
309  cmpt,
310  reverseTransform(tfield().component(cmpt), nn)
311  );
312  }
313 
314  tfield.clear();
315 
316  return tresult;
317 }
318 
319 
320 // ************************************************************************* //
Foam::roots::complex
Definition: Roots.H:57
Foam::component
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
Definition: FieldFieldFunctions.C:44
Foam::tmp::clear
void clear() const noexcept
Definition: tmpI.H:287
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:61
Foam::fft::transformDirection
transformDirection
Definition: fft.H:60
Foam::transform
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::fft::reverseTransform
static tmp< complexField > reverseTransform(const tmp< complexField > &field, const UList< int > &nn)
Definition: fft.C:259
Foam::UList::begin
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:329
Foam::Im
scalarField Im(const UList< complex > &cf)
Extract imag component.
Definition: complexField.C:172
Foam::Field< scalar >
field
rDeltaTY field()
Foam::fft::fftRenumber
static void fftRenumber(List< complex > &data, const UList< int > &nn)
Definition: fft.C:94
Foam::fft::fftRenumberRecurse
static void fftRenumberRecurse(List< complex > &data, List< complex > &renumData, const UList< int > &nn, label nnprod, label ii, label l1, label l2)
Definition: fft.C:35
Foam::fft::transform
static void transform(complexField &field, const UList< int > &nn, transformDirection fftDirection)
Transform complex-value data.
Definition: fft.C:179
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:103
Foam::Re
scalarField Re(const UList< complex > &cf)
Extract real component.
Definition: complexField.C:159
Foam::fft::forwardTransform
static tmp< complexField > forwardTransform(const tmp< complexField > &field, const UList< int > &nn)
Definition: fft.C:243
Foam::tmp::New
static tmp< T > New(Args &&... args)
Construct tmp of T with forwarding arguments.
Foam::direction
uint8_t direction
Definition: direction.H:52
Foam::UList::size
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
N
const Vector< label > N(dict.get< Vector< label >>("N"))
fft.H
Foam::data
Database for solution data, solver performance and other reduced data.
Definition: data.H:55
Foam::VectorSpace< Vector< scalar >, scalar, 3 >::nComponents
static constexpr direction nComponents
Number of components in this vector space.
Definition: VectorSpace.H:101
Foam::fft::realTransform1D
static tmp< complexField > realTransform1D(const scalarField &field)
Transform real-value data.
Definition: fft.C:120