cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: FFTW 3.3.5: Reversing array dimensions cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: cannam@127:
cannam@127:

cannam@127: Next: , Previous: , Up: Calling FFTW from Modern Fortran   [Contents][Index]

cannam@127:
cannam@127:
cannam@127: cannam@127:

7.2 Reversing array dimensions

cannam@127: cannam@127: cannam@127: cannam@127:

A minor annoyance in calling FFTW from Fortran is that FFTW’s array cannam@127: dimensions are defined in the C convention (row-major order), while cannam@127: Fortran’s array dimensions are the opposite convention (column-major cannam@127: order). See Multi-dimensional Array Format. This is just a cannam@127: bookkeeping difference, with no effect on performance. The only cannam@127: consequence of this is that, whenever you create an FFTW plan for a cannam@127: multi-dimensional transform, you must always reverse the cannam@127: ordering of the dimensions. cannam@127:

cannam@127:

For example, consider the three-dimensional (L × M × N) arrays: cannam@127:

cannam@127:
cannam@127:
  complex(C_DOUBLE_COMPLEX), dimension(L,M,N) :: in, out
cannam@127: 
cannam@127: cannam@127:

To plan a DFT for these arrays using fftw_plan_dft_3d, you could do: cannam@127:

cannam@127: cannam@127:
cannam@127:
  plan = fftw_plan_dft_3d(N,M,L, in,out, FFTW_FORWARD,FFTW_ESTIMATE)
cannam@127: 
cannam@127: cannam@127:

That is, from FFTW’s perspective this is a N × M × L array. cannam@127: No data transposition need occur, as this is only cannam@127: notation. Similarly, to use the more generic routine cannam@127: fftw_plan_dft with the same arrays, you could do: cannam@127:

cannam@127:
cannam@127:
  integer(C_INT), dimension(3) :: n = [N,M,L]
cannam@127:   plan = fftw_plan_dft_3d(3, n, in,out, FFTW_FORWARD,FFTW_ESTIMATE)
cannam@127: 
cannam@127: cannam@127:

Note, by the way, that this is different from the legacy Fortran cannam@127: interface (see Fortran-interface routines), which automatically cannam@127: reverses the order of the array dimension for you. Here, you are cannam@127: calling the C interface directly, so there is no “translation” layer. cannam@127:

cannam@127: cannam@127:

An important thing to keep in mind is the implication of this for cannam@127: multidimensional real-to-complex transforms (see Multi-Dimensional DFTs of Real Data). In C, a multidimensional real-to-complex DFT cannam@127: chops the last dimension roughly in half (N × M × L real input cannam@127: goes to N × M × L/2+1 complex output). In Fortran, because cannam@127: the array dimension notation is reversed, the first dimension of cannam@127: the complex data is chopped roughly in half. For example consider the cannam@127: ‘r2c’ transform of L × M × N real input in Fortran: cannam@127:

cannam@127: cannam@127: cannam@127:
cannam@127:
  type(C_PTR) :: plan
cannam@127:   real(C_DOUBLE), dimension(L,M,N) :: in
cannam@127:   complex(C_DOUBLE_COMPLEX), dimension(L/2+1,M,N) :: out
cannam@127:   plan = fftw_plan_dft_r2c_3d(N,M,L, in,out, FFTW_ESTIMATE)
cannam@127:   ...
cannam@127:   call fftw_execute_dft_r2c(plan, in, out)
cannam@127: 
cannam@127: cannam@127: cannam@127: cannam@127:

Alternatively, for an in-place r2c transform, as described in the C cannam@127: documentation we must pad the first dimension of the cannam@127: real input with an extra two entries (which are ignored by FFTW) so as cannam@127: to leave enough space for the complex output. The input is cannam@127: allocated as a 2[L/2+1] × M × N array, even though only cannam@127: L × M × N of it is actually used. In this example, we will cannam@127: allocate the array as a pointer type, using ‘fftw_alloc’ to cannam@127: ensure aligned memory for maximum performance (see Allocating aligned memory in Fortran); this also makes it easy to reference the cannam@127: same memory as both a real array and a complex array. cannam@127:

cannam@127: cannam@127: cannam@127:
cannam@127:
  real(C_DOUBLE), pointer :: in(:,:,:)
cannam@127:   complex(C_DOUBLE_COMPLEX), pointer :: out(:,:,:)
cannam@127:   type(C_PTR) :: plan, data
cannam@127:   data = fftw_alloc_complex(int((L/2+1) * M * N, C_SIZE_T))
cannam@127:   call c_f_pointer(data, in, [2*(L/2+1),M,N])
cannam@127:   call c_f_pointer(data, out, [L/2+1,M,N])
cannam@127:   plan = fftw_plan_dft_r2c_3d(N,M,L, in,out, FFTW_ESTIMATE)
cannam@127:   ...
cannam@127:   call fftw_execute_dft_r2c(plan, in, out)
cannam@127:   ...
cannam@127:   call fftw_destroy_plan(plan)
cannam@127:   call fftw_free(data)
cannam@127: 
cannam@127: cannam@127:
cannam@127:
cannam@127:

cannam@127: Next: , Previous: , Up: Calling FFTW from Modern Fortran   [Contents][Index]

cannam@127:
cannam@127: cannam@127: cannam@127: cannam@127: cannam@127: