Go to the first, previous, next, last section, table of contents.

Quick Start for Multi-dimensional Transforms

This chapter describes the basic usage of FFTW for computing complex multi-dimensional Fourier Transforms. See section FFTW Reference, for more information.

The syntax for performing multi-dimensional transforms in FFTW is very similar to the syntax for one-dimensional transforms; the main difference is that `fftw_' gets replaced by `fftwnd_'. (fftwnd stands for "fftw in N dimensions.")

As before, include <fftw.h> at the top of your program:

#include <fftw.h>

Then, just as in one dimension, you must create a plan before computing a transform of any given size. The plan is created by fftwnd_create_plan.

fftwnd_plan fftwnd_create_plan(int rank, const int *n, 
                               fftw_direction dir, int flags);

The arguments of this function are analogous to those of fftw_create_plan. rank is the dimensionality of the array, and can be any non-negative integer. The next argument, n, is a pointer to an array of length rank containing the (positive) sizes of each dimension of the array. (Note that the array will be stored in row-major order. See section Multi-dimensional Array Format, for more information.) dir, as in the one-dimensional transform, specifies the direction of the transform, and can be FFTW_FORWARD or FFTW_BACKWARD (or, equivalently, the sign, -1 or +1 respectively, of the exponent of the transform). The last argument, flags, is a bitwise OR (`|') of options. Two possible options are FFTW_ESTIMATE (the default) and FFTW_MEASURE; just as in fftw_create_plan, these specify whether the code just estimates the optimal plan or actually performs timing measurements. Also, if you intend to perform in-place transforms, you must include the option FFTW_IN_PLACE in the flags (the default is to perform out-of-place transforms). (An in-place transform is one in which the output data overwrite the input data. It thus requires half as much memory as--and is often faster than--its opposite, an out-of-place transform.)

For two and three dimensional transforms, there are optional, alternative routines that allow you to simply pass the sizes of each dimension directly, rather than specifying a rank and an array of sizes. These are otherwise identical to fftwnd_create_plan, and are sometimes more convenient:

fftwnd_plan fftw2d_create_plan(int nx, int ny, 
                               fftw_direction dir, int flags);
fftwnd_plan fftw3d_create_plan(int nx, int ny, int nz, 
                               fftw_direction dir, int flags);

Once the plan has been created, you can use it any number of times for transforms of the same size. The subroutine that performs the transform is fftwnd:

void fftwnd(fftwnd_plan plan, int howmany,
            FFTW_COMPLEX *in, int istride, int idist,
            FFTW_COMPLEX *out, int ostride, int odist);

This means: compute howmany multi-dimensional FFTs according to the plan plan (which contains the size and rank of the transform). The first (0th) element of the input array is pointed to by in, and consists of howmany subarrays, placed at a distance idist from each other, and whose elements are istride apart and are stored in row-major order. (See section Multi-dimensional Array Format, for more detail.) In other words, the element at the i-th location in the j-th subarray will be in position in[i * istride + j * idist], where i and j are both zero-based. (Note that i here refers to the actual index into the row-major-ordered array, and not an index in any particular dimension.) If the plan was created with the FFTW_IN_PLACE option, the results are stored in the in array with the same stride, etcetera, and the last three arguments are ignored. Otherwise, the result will be stored in the out array, which consists of howmany subarrays, placed at a distance odist from each other, and whose elements are ostride apart.

Finally, don't forget to destroy the plan once you are done using it:

void fftwnd_destroy_plan(fftwnd_plan plan);

This frees all the memory and data structures associated with the plan.

Examples of Use

As a simple example, let us compute an out-of-place, forward transform of a four-dimensional array. In this case, the strides are all 1 and, since we are only computing a single transform (howmany is 1), the idist and odist parameters are ignored.

/* declare static in/out arrays */
FFTW_COMPLEX in[4][5][6][7], out[4][5][6][7];   

/* the dimensions of the array */
int n[4] = { 4, 5, 6, 7 };  

fftwnd_plan plan;

/* Create the plan (just estimate the optimal strategy): */
plan = fftwnd_create_plan(4, n, FFTW_FORWARD, 
                          FFTW_ESTIMATE);

/* ... initialize the in array ... */

/* Compute the transform, writing the result to out: */
fftwnd(plan, 1, (FFTW_COMPLEX *) in, 1, 0, (FFTW_COMPLEX *) out, 1, 0);

fftwnd_destroy_plan(plan);

Note that the type-casts were necessary in order to get an ordinary pointer to the first element. Alternatively, we could have used &in[0][0][0][0] and &out[0][0][0][0].

The previous example is probably typical of the needs of most users. However, more sophisticated uses of fftwnd are possible. For a more complicated example involving strides, consider the following: Suppose that we have a three dimensional array, but the array elements, rather than being single FFTW_COMPLEX values, are "vectors," or arrays of three FFTW_COMPLEX values. (Thus, our data form a complex vector field in three dimensions.) We will declare the (10x11x12) array as follows:

typedef COMPLEX cvector[3];
cvector vector_field[10][11][12];

Now, we will create the plan for an in-place transform (using fftw3d_create_plan instead of fftwnd_create_plan just for variety):

fftwnd_plan plan;

plan = fftw3d_create_plan(10, 11, 12, FFTW_FORWARD,
                          FFTW_ESTIMATE | FFTW_IN_PLACE);

Finally, let us transform each component of the vector field separately (i.e. three 3D transforms, and not one 4D transform), using three separate calls to fftwnd (note that the last three parameters to fftwnd are ignored since we are transforming in-place). We use an istride of 3 since each vector has three components that are stored in adjacent locations in memory.

/* transform 1st component */
fftwnd(plan, 1, &in[0][0][0][0], 3, 0, 0, 0, 0);

/* transform 2nd component */
fftwnd(plan, 1, &in[0][0][0][1], 3, 0, 0, 0, 0);  

/* transform 3rd component */
fftwnd(plan, 1, &in[0][0][0][2], 3, 0, 0, 0, 0);

Alternatively, we could use the howmany parameter to perform all three transforms with one subroutine call. Here, we use an idist of 1 since the components of the first element of the array are stored in adjacent locations. howmany is 3 since there are three arrays to transform, and the stride is unchanged:

/* transform all components at once */
fftwnd(plan, 3, &in[0][0][0][0], 3, 1, 0, 0, 0); 

Note that we used the same plan in all instances, since the dimensions of the data to transform were the same, even though other parameters were different.

What FFTWND really computes.

The Gods forbade using HTML to display mathematical formulas. Please see the TeX or Postscript version of this manual for the proper definition of the n-dimensional Fourier Transform that FFTW uses. For completeness, we include a bitmap of the TeX output below:


Go to the first, previous, next, last section, table of contents.