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-------------------------------------------------------------------------------
11License
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
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
106 fftRenumberRecurse
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// ************************************************************************* //
label n
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: UList.H:94
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:329
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition: UListI.H:237
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A complex number, similar to the C++ complex type.
Definition: complex.H:83
Database for solution data, solver performance and other reduced data.
Definition: data.H:58
static tmp< complexField > realTransform1D(const scalarField &field)
Transform real-value data.
Definition: fft.C:120
static tmp< complexField > forwardTransform(const tmp< complexField > &field, const UList< int > &nn)
Definition: fft.C:243
transformDirection
Definition: fft.H:61
static tmp< complexField > reverseTransform(const tmp< complexField > &field, const UList< int > &nn)
Definition: fft.C:259
static void fftRenumber(List< complex > &data, const UList< int > &nn)
Definition: fft.C:94
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
Default transformation behaviour.
static constexpr direction nComponents
Number of components in bool is 1.
Definition: bool.H:98
A class for managing temporary objects.
Definition: tmp.H:65
void clear() const noexcept
Definition: tmpI.H:287
rDeltaTY field()
scalarField Re(const UList< complex > &cf)
Extract real component.
Definition: complexField.C:159
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:536
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
uint8_t direction
Definition: direction.H:56
scalarField Im(const UList< complex > &cf)
Extract imag component.
Definition: complexField.C:172
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
const Vector< label > N(dict.get< Vector< label > >("N"))