2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2012 - INRIA - Serge STEER
4 * Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
6 * Copyright (C) 2012 - 2016 - Scilab Enterprises
8 * This file is hereby licensed under the terms of the GNU GPL v2.0,
9 * pursuant to article 5.3.4 of the CeCILL v.2.1.
10 * This file was originally licensed under the terms of the CeCILL v2.1,
11 * and continues to be available under such terms.
12 * For more information, see the COPYING file which you should have received
13 * along with this program.
17 #include "fftw_gw.hxx"
18 #include "function.hxx"
19 #include "fftw_common.hxx"
24 #include "localization.h"
25 #include "charEncoding.h"
29 extern void C2F(dscal)(int *n, double *da, double *dx, int *incx); /* blas routine */
30 extern void C2F(dset)(int *n, double *da, double *dx, int *incx); /* blas routine */
32 /*--------------------------------------------------------------------------*/
39 /*--------------------------------------------------------------------------*/
40 static int sci_fft_gen(const char *fname, types::Double* A, types::Double** O, int isn, guru_dim_struct gdim, int iopt);
41 /*--------------------------------------------------------------------------*/
42 types::Function::ReturnValue sci_fftw(types::typed_list &in, int _iRetCount, types::typed_list &out)
44 std::wstring name(L"fftw");
45 return fftw_common(name, in, _iRetCount, out, sci_fft_gen);
47 /*--------------------------------------------------------------------------*/
48 int sci_fft_gen(const char *fname, types::Double* A, types::Double** O, int isn, guru_dim_struct gdim, int iopt)
50 types::Double* tmp = A->clone()->getAs<types::Double>();
51 int ndimsA = tmp->getDims();
52 int *dimsA = tmp->getDimsArray();
53 double *Ar = tmp->get();
54 double *Ai = tmp->getImg();
56 /* Input array variables */
57 int isrealA = (Ai == NULL), issymA = 1, lA = 1;
59 int isrealA_save = isrealA;
61 /*FFTW specific library variable */
62 enum Scaling scale = None;
66 /* input/output address for transform variables */
67 double *ri = NULL, *ii = NULL, *ro = NULL, *io = NULL;
69 /* for MKL special cases */
80 for (i = 0; i < ndimsA; i++)
87 /* automatically selected algorithm*/
88 issymA = check_array_symmetry(Ar, Ai, gdim);
91 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
97 issymA = 1; /* user forces symmetry */
109 /*MKL does not implement the r2c nor r2r guru split methods, make A complex */
112 /* result will be real, the imaginary part of A can be allocated alone */
113 Ai = (double*)MALLOC(sizeof(double) * lA);
114 C2F(dset)(&lA, &dzero, Ai, &one);
119 /* result will be complex, set clone of A complex for inplace computation */
120 tmp->setComplex(true);
122 C2F(dset)(&lA, &dzero, Ai, &one);
128 /* Set pointers on real and imaginary part of the input */
132 scale = None; /*no scaling needed */
133 if (isn == FFTW_BACKWARD)
137 if (isrealA & !WITHMKL) /* To have type = C2C_PLAN*/
142 ///*r2r = isrealA && issymA*/
143 ///* there is no general plan able to compute r2r transform so it is tranformed into
144 //a R2c plan. The computed imaginary part will be zero*/
148 (*O)->setComplex(false);
150 Ai = (double*)MALLOC(sizeof(double) * lA);
153 C2F(dset)(&lA, &dzero, io, &one);
158 /*r2c = isrealA && ~issymA;*/
159 /* transform cannot be done in place */
160 *O = new types::Double(ndimsA, dimsA, true);
163 type = R2C_PLAN; /* fftw_plan_guru_split_dft_r2c plans for an FFTW_FORWARD transform*/
164 if (isn == FFTW_BACKWARD)
166 /*transform problem into a FORWARD fft*/
167 /*ifft(A)=conj(fft(A/N)) cas vect*/
168 /* pre traitement A must be divided by N cas vect*/
169 /* post treatment result must conjugated */
178 if (!WITHMKL && issymA) /*result is real*/
180 /*c2r = ~isrealA && issymA*/
184 type = C2R_PLAN; /*fftw_plan_guru_split_dft_c2r plans for an FFTW_BACKWARD transform*/
185 if (isn == FFTW_FORWARD)
187 /*transform problem into a BACKWARD fft : fft(A)=ifft(conj(A))*/
188 double minusone = -1.0;
189 C2F(dscal)(&lA, &minusone, ii, &one);
194 /*c2c = ~isrealA && ~issymA;*/
195 /* use inplace transform*/
197 type = C2C_PLAN; /* fftw_plan_guru_split_dft plans for an FFTW_FORWARD transform*/
198 if (isn == FFTW_BACKWARD)
200 /*transform problem into a FORWARD fft*/
201 /* ifft(A) = %i*conj(fft(%i*conj(A)/N) */
221 for (i = 0; i < gdim.rank; i++)
223 ak = ak * ((double)(gdim.dims[i].n));
229 C2F(dscal)(&lA, &ak, ri, &one);
232 C2F(dscal)(&lA, &ak, ii, &one);
236 if (!WITHMKL || gdim.howmany_rank <= 1)
239 p = GetFFTWPlan(type, &gdim, ri, ii, ro, io, getCurrentFftwFlags(), isn, (fftw_r2r_kind *)NULL, &errflag);
244 Scierror(999, _("%s: No more memory.\n"), fname);
246 else if (errflag == 2)
248 Scierror(999, _("%s: Creation of requested fftw plan failed.\n"), fname);
267 /* execute FFTW plan */
268 ExecuteFFTWPlan(type, p, ri, ii, ro, io);
272 /*FFTW MKL does not implement yet guru plan with howmany_rank>1 */
273 /* associated loops described in gdim.howmany_rank and gdim.howmany_dims */
274 /* are implemented here by a set of call with howmany_rank==1 */
275 fftw_iodim *howmany_dims = gdim.howmany_dims;
276 int howmany_rank = gdim.howmany_rank;
282 gdim.howmany_rank = 0;
283 gdim.howmany_dims = NULL;
285 p = GetFFTWPlan(type, &gdim, ri, ii, ro, io, getCurrentFftwFlags(), isn, (fftw_r2r_kind *)NULL, &errflag);
290 Scierror(999, _("%s: No more memory.\n"), fname);
292 else if (errflag == 2)
294 Scierror(999, _("%s: Creation of requested fftw plan failed.\n"), fname);
316 /* flatten nested loops: replace howmany_rank nested loops by a single one*/
317 /* Build temporary arrays used by flatened loop */
318 if ((dims1 = (int *)MALLOC(sizeof(int) * howmany_rank)) == NULL)
320 Scierror(999, _("%s: No more memory.\n"), fname);
339 dims1[0] = howmany_dims[0].n;
340 for (i = 1; i < howmany_rank; i++)
342 dims1[i] = dims1[i - 1] * howmany_dims[i].n;
344 nloop = dims1[howmany_rank - 1];
346 if ((incr1 = (int *)MALLOC(sizeof(int) * howmany_rank)) == NULL)
348 Scierror(999, _("%s: No more memory.\n"), fname);
368 for (i = 0; i < howmany_rank; i++)
370 t += (howmany_dims[i].n - 1) * howmany_dims[i].is;
373 /*loop on each "plan" */
374 i = 0; /*index on the first plan entry */
375 for (i1 = 1; i1 <= nloop; i1++)
377 /* the input and output are assumed to be complex because
378 within MKL real cases are transformed to complex ones in
379 previous steps of sci_fft_gen*/
380 ExecuteFFTWPlan(type, p, &ri[i], &ii[i], &ro[i], &io[i]);
381 i += howmany_dims[0].is;
382 /* check if a loop ends*/
383 for (i2 = howmany_rank - 2; i2 >= 0; i2--)
385 if ((i1 % dims1[i2]) == 0)
387 /*loop on dimension i2 ends, compute jump on the first plan entry index*/
388 i += howmany_dims[i2 + 1].is - incr1[i2];
393 /* free temporary arrays */
396 /* reset initial value of gdim for post treatment*/
397 gdim.howmany_rank = howmany_rank;
398 gdim.howmany_dims = howmany_dims;
406 iErr = complete_array(ro, NULL, gdim);
413 /*R2C has been used to solve an r2r problem*/
414 iErr = complete_array(ro, NULL, gdim);
418 iErr = complete_array(ro, io, gdim);
419 if (iErr != -1 && isn == FFTW_BACKWARD)
421 /*conjugate result */
423 C2F(dscal)(&lA, &ak, io, &one);
428 if (WITHMKL && isrealA_save)
430 if (isn == FFTW_FORWARD)
432 iErr = complete_array(ro, io, gdim);
436 iErr = complete_array(io, ro, gdim);
454 Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
462 (*O)->setComplex(false);