iup-stack/fftw/doc/modern-fortran.texi

726 lines
30 KiB
Plaintext
Raw Normal View History

2023-02-20 16:44:45 +00:00
@node Calling FFTW from Modern Fortran, Calling FFTW from Legacy Fortran, Distributed-memory FFTW with MPI, Top
@chapter Calling FFTW from Modern Fortran
@cindex Fortran interface
Fortran 2003 standardized ways for Fortran code to call C libraries,
and this allows us to support a direct translation of the FFTW C API
into Fortran. Compared to the legacy Fortran 77 interface
(@pxref{Calling FFTW from Legacy Fortran}), this direct interface
offers many advantages, especially compile-time type-checking and
aligned memory allocation. As of this writing, support for these C
interoperability features seems widespread, having been implemented in
nearly all major Fortran compilers (e.g. GNU, Intel, IBM,
Oracle/Solaris, Portland Group, NAG).
@cindex portability
This chapter documents that interface. For the most part, since this
interface allows Fortran to call the C interface directly, the usage
is identical to C translated to Fortran syntax. However, there are a
few subtle points such as memory allocation, wisdom, and data types
that deserve closer attention.
@menu
* Overview of Fortran interface::
* Reversing array dimensions::
* FFTW Fortran type reference::
* Plan execution in Fortran::
* Allocating aligned memory in Fortran::
* Accessing the wisdom API from Fortran::
* Defining an FFTW module::
@end menu
@c -------------------------------------------------------
@node Overview of Fortran interface, Reversing array dimensions, Calling FFTW from Modern Fortran, Calling FFTW from Modern Fortran
@section Overview of Fortran interface
FFTW provides a file @code{fftw3.f03} that defines Fortran 2003
interfaces for all of its C routines, except for the MPI routines
described elsewhere, which can be found in the same directory as
@code{fftw3.h} (the C header file). In any Fortran subroutine where
you want to use FFTW functions, you should begin with:
@cindex iso_c_binding
@example
use, intrinsic :: iso_c_binding
include 'fftw3.f03'
@end example
This includes the interface definitions and the standard
@code{iso_c_binding} module (which defines the equivalents of C
types). You can also put the FFTW functions into a module if you
prefer (@pxref{Defining an FFTW module}).
At this point, you can now call anything in the FFTW C interface
directly, almost exactly as in C other than minor changes in syntax.
For example:
@findex fftw_plan_dft_2d
@findex fftw_execute_dft
@findex fftw_destroy_plan
@example
type(C_PTR) :: plan
complex(C_DOUBLE_COMPLEX), dimension(1024,1000) :: in, out
plan = fftw_plan_dft_2d(1000,1024, in,out, FFTW_FORWARD,FFTW_ESTIMATE)
...
call fftw_execute_dft(plan, in, out)
...
call fftw_destroy_plan(plan)
@end example
A few important things to keep in mind are:
@itemize @bullet
@item
@tindex fftw_complex
@ctindex C_PTR
@ctindex C_INT
@ctindex C_DOUBLE
@ctindex C_DOUBLE_COMPLEX
FFTW plans are @code{type(C_PTR)}. Other C types are mapped in the
obvious way via the @code{iso_c_binding} standard: @code{int} turns
into @code{integer(C_INT)}, @code{fftw_complex} turns into
@code{complex(C_DOUBLE_COMPLEX)}, @code{double} turns into
@code{real(C_DOUBLE)}, and so on. @xref{FFTW Fortran type reference}.
@item
Functions in C become functions in Fortran if they have a return value,
and subroutines in Fortran otherwise.
@item
The ordering of the Fortran array dimensions must be @emph{reversed}
when they are passed to the FFTW plan creation, thanks to differences
in array indexing conventions (@pxref{Multi-dimensional Array
Format}). This is @emph{unlike} the legacy Fortran interface
(@pxref{Fortran-interface routines}), which reversed the dimensions
for you. @xref{Reversing array dimensions}.
@item
@cindex alignment
@cindex SIMD
Using ordinary Fortran array declarations like this works, but may
yield suboptimal performance because the data may not be not aligned
to exploit SIMD instructions on modern proessors (@pxref{SIMD
alignment and fftw_malloc}). Better performance will often be obtained
by allocating with @samp{fftw_alloc}. @xref{Allocating aligned memory
in Fortran}.
@item
@findex fftw_execute
Similar to the legacy Fortran interface (@pxref{FFTW Execution in
Fortran}), we currently recommend @emph{not} using @code{fftw_execute}
but rather using the more specialized functions like
@code{fftw_execute_dft} (@pxref{New-array Execute Functions}).
However, you should execute the plan on the @code{same arrays} as the
ones for which you created the plan, unless you are especially
careful. @xref{Plan execution in Fortran}. To prevent
you from using @code{fftw_execute} by mistake, the @code{fftw3.f03}
file does not provide an @code{fftw_execute} interface declaration.
@item
@cindex flags
Multiple planner flags are combined with @code{ior} (equivalent to @samp{|} in C). e.g. @code{FFTW_MEASURE | FFTW_DESTROY_INPUT} becomes @code{ior(FFTW_MEASURE, FFTW_DESTROY_INPUT)}. (You can also use @samp{+} as long as you don't try to include a given flag more than once.)
@end itemize
@menu
* Extended and quadruple precision in Fortran::
@end menu
@node Extended and quadruple precision in Fortran, , Overview of Fortran interface, Overview of Fortran interface
@subsection Extended and quadruple precision in Fortran
@cindex precision
If FFTW is compiled in @code{long double} (extended) precision
(@pxref{Installation and Customization}), you may be able to call the
resulting @code{fftwl_} routines (@pxref{Precision}) from Fortran if
your compiler supports the @code{C_LONG_DOUBLE_COMPLEX} type code.
Because some Fortran compilers do not support
@code{C_LONG_DOUBLE_COMPLEX}, the @code{fftwl_} declarations are
segregated into a separate interface file @code{fftw3l.f03}, which you
should include @emph{in addition} to @code{fftw3.f03} (which declares
precision-independent @samp{FFTW_} constants):
@cindex iso_c_binding
@example
use, intrinsic :: iso_c_binding
include 'fftw3.f03'
include 'fftw3l.f03'
@end example
We also support using the nonstandard @code{__float128}
quadruple-precision type provided by recent versions of @code{gcc} on
32- and 64-bit x86 hardware (@pxref{Installation and Customization}),
using the corresponding @code{real(16)} and @code{complex(16)} types
supported by @code{gfortran}. The quadruple-precision @samp{fftwq_}
functions (@pxref{Precision}) are declared in a @code{fftw3q.f03}
interface file, which should be included in addition to
@code{fftw3.f03}, as above. You should also link with
@code{-lfftw3q -lquadmath -lm} as in C.
@c -------------------------------------------------------
@node Reversing array dimensions, FFTW Fortran type reference, Overview of Fortran interface, Calling FFTW from Modern Fortran
@section Reversing array dimensions
@cindex row-major
@cindex column-major
A minor annoyance in calling FFTW from Fortran is that FFTW's array
dimensions are defined in the C convention (row-major order), while
Fortran's array dimensions are the opposite convention (column-major
order). @xref{Multi-dimensional Array Format}. This is just a
bookkeeping difference, with no effect on performance. The only
consequence of this is that, whenever you create an FFTW plan for a
multi-dimensional transform, you must always @emph{reverse the
ordering of the dimensions}.
For example, consider the three-dimensional (@threedims{L,M,N}) arrays:
@example
complex(C_DOUBLE_COMPLEX), dimension(L,M,N) :: in, out
@end example
To plan a DFT for these arrays using @code{fftw_plan_dft_3d}, you could do:
@findex fftw_plan_dft_3d
@example
plan = fftw_plan_dft_3d(N,M,L, in,out, FFTW_FORWARD,FFTW_ESTIMATE)
@end example
That is, from FFTW's perspective this is a @threedims{N,M,L} array.
@emph{No data transposition need occur}, as this is @emph{only
notation}. Similarly, to use the more generic routine
@code{fftw_plan_dft} with the same arrays, you could do:
@example
integer(C_INT), dimension(3) :: n = [N,M,L]
plan = fftw_plan_dft_3d(3, n, in,out, FFTW_FORWARD,FFTW_ESTIMATE)
@end example
Note, by the way, that this is different from the legacy Fortran
interface (@pxref{Fortran-interface routines}), which automatically
reverses the order of the array dimension for you. Here, you are
calling the C interface directly, so there is no ``translation'' layer.
@cindex r2c/c2r multi-dimensional array format
An important thing to keep in mind is the implication of this for
multidimensional real-to-complex transforms (@pxref{Multi-Dimensional
DFTs of Real Data}). In C, a multidimensional real-to-complex DFT
chops the last dimension roughly in half (@threedims{N,M,L} real input
goes to @threedims{N,M,L/2+1} complex output). In Fortran, because
the array dimension notation is reversed, the @emph{first} dimension of
the complex data is chopped roughly in half. For example consider the
@samp{r2c} transform of @threedims{L,M,N} real input in Fortran:
@findex fftw_plan_dft_r2c_3d
@findex fftw_execute_dft_r2c
@example
type(C_PTR) :: plan
real(C_DOUBLE), dimension(L,M,N) :: in
complex(C_DOUBLE_COMPLEX), dimension(L/2+1,M,N) :: out
plan = fftw_plan_dft_r2c_3d(N,M,L, in,out, FFTW_ESTIMATE)
...
call fftw_execute_dft_r2c(plan, in, out)
@end example
@cindex in-place
@cindex padding
Alternatively, for an in-place r2c transform, as described in the C
documentation we must @emph{pad} the @emph{first} dimension of the
real input with an extra two entries (which are ignored by FFTW) so as
to leave enough space for the complex output. The input is
@emph{allocated} as a @threedims{2[L/2+1],M,N} array, even though only
@threedims{L,M,N} of it is actually used. In this example, we will
allocate the array as a pointer type, using @samp{fftw_alloc} to
ensure aligned memory for maximum performance (@pxref{Allocating
aligned memory in Fortran}); this also makes it easy to reference the
same memory as both a real array and a complex array.
@findex fftw_alloc_complex
@findex c_f_pointer
@example
real(C_DOUBLE), pointer :: in(:,:,:)
complex(C_DOUBLE_COMPLEX), pointer :: out(:,:,:)
type(C_PTR) :: plan, data
data = fftw_alloc_complex(int((L/2+1) * M * N, C_SIZE_T))
call c_f_pointer(data, in, [2*(L/2+1),M,N])
call c_f_pointer(data, out, [L/2+1,M,N])
plan = fftw_plan_dft_r2c_3d(N,M,L, in,out, FFTW_ESTIMATE)
...
call fftw_execute_dft_r2c(plan, in, out)
...
call fftw_destroy_plan(plan)
call fftw_free(data)
@end example
@c -------------------------------------------------------
@node FFTW Fortran type reference, Plan execution in Fortran, Reversing array dimensions, Calling FFTW from Modern Fortran
@section FFTW Fortran type reference
The following are the most important type correspondences between the
C interface and Fortran:
@itemize @bullet
@item
@tindex fftw_plan
Plans (@code{fftw_plan} and variants) are @code{type(C_PTR)} (i.e. an
opaque pointer).
@item
@tindex fftw_complex
@cindex precision
@ctindex C_DOUBLE
@ctindex C_FLOAT
@ctindex C_LONG_DOUBLE
@ctindex C_DOUBLE_COMPLEX
@ctindex C_FLOAT_COMPLEX
@ctindex C_LONG_DOUBLE_COMPLEX
The C floating-point types @code{double}, @code{float}, and @code{long
double} correspond to @code{real(C_DOUBLE)}, @code{real(C_FLOAT)}, and
@code{real(C_LONG_DOUBLE)}, respectively. The C complex types
@code{fftw_complex}, @code{fftwf_complex}, and @code{fftwl_complex}
correspond in Fortran to @code{complex(C_DOUBLE_COMPLEX)},
@code{complex(C_FLOAT_COMPLEX)}, and
@code{complex(C_LONG_DOUBLE_COMPLEX)}, respectively.
Just as in C
(@pxref{Precision}), the FFTW subroutines and types are prefixed with
@samp{fftw_}, @code{fftwf_}, and @code{fftwl_} for the different precisions, and link to different libraries (@code{-lfftw3}, @code{-lfftw3f}, and @code{-lfftw3l} on Unix), but use the @emph{same} include file @code{fftw3.f03} and the @emph{same} constants (all of which begin with @samp{FFTW_}). The exception is @code{long double} precision, for which you should @emph{also} include @code{fftw3l.f03} (@pxref{Extended and quadruple precision in Fortran}).
@item
@tindex ptrdiff_t
@ctindex C_INT
@ctindex C_INTPTR_T
@ctindex C_SIZE_T
@findex fftw_malloc
The C integer types @code{int} and @code{unsigned} (used for planner
flags) become @code{integer(C_INT)}. The C integer type @code{ptrdiff_t} (e.g. in the @ref{64-bit Guru Interface}) becomes @code{integer(C_INTPTR_T)}, and @code{size_t} (in @code{fftw_malloc} etc.) becomes @code{integer(C_SIZE_T)}.
@item
@tindex fftw_r2r_kind
@ctindex C_FFTW_R2R_KIND
The @code{fftw_r2r_kind} type (@pxref{Real-to-Real Transform Kinds})
becomes @code{integer(C_FFTW_R2R_KIND)}. The various constant values
of the C enumerated type (@code{FFTW_R2HC} etc.) become simply integer
constants of the same names in Fortran.
@item
@ctindex FFTW_DESTROY_INPUT
@cindex in-place
@findex fftw_flops
Numeric array pointer arguments (e.g. @code{double *})
become @code{dimension(*), intent(out)} arrays of the same type, or
@code{dimension(*), intent(in)} if they are pointers to constant data
(e.g. @code{const int *}). There are a few exceptions where numeric
pointers refer to scalar outputs (e.g. for @code{fftw_flops}), in which
case they are @code{intent(out)} scalar arguments in Fortran too.
For the new-array execute functions (@pxref{New-array Execute Functions}),
the input arrays are declared @code{dimension(*), intent(inout)}, since
they can be modified in the case of in-place or @code{FFTW_DESTROY_INPUT}
transforms.
@item
@findex fftw_alloc_real
@findex c_f_pointer
Pointer @emph{return} values (e.g @code{double *}) become
@code{type(C_PTR)}. (If they are pointers to arrays, as for
@code{fftw_alloc_real}, you can convert them back to Fortran array
pointers with the standard intrinsic function @code{c_f_pointer}.)
@item
@cindex guru interface
@tindex fftw_iodim
@tindex fftw_iodim64
@cindex 64-bit architecture
The @code{fftw_iodim} type in the guru interface (@pxref{Guru vector
and transform sizes}) becomes @code{type(fftw_iodim)} in Fortran, a
derived data type (the Fortran analogue of C's @code{struct}) with
three @code{integer(C_INT)} components: @code{n}, @code{is}, and
@code{os}, with the same meanings as in C. The @code{fftw_iodim64} type in the 64-bit guru interface (@pxref{64-bit Guru Interface}) is the same, except that its components are of type @code{integer(C_INTPTR_T)}.
@item
@ctindex C_FUNPTR
Using the wisdom import/export functions from Fortran is a bit tricky,
and is discussed in @ref{Accessing the wisdom API from Fortran}. In
brief, the @code{FILE *} arguments map to @code{type(C_PTR)}, @code{const char *} to @code{character(C_CHAR), dimension(*), intent(in)} (null-terminated!), and the generic read-char/write-char functions map to @code{type(C_FUNPTR)}.
@end itemize
@cindex portability
You may be wondering if you need to search-and-replace
@code{real(kind(0.0d0))} (or whatever your favorite Fortran spelling
of ``double precision'' is) with @code{real(C_DOUBLE)} everywhere in
your program, and similarly for @code{complex} and @code{integer}
types. The answer is no; you can still use your existing types. As
long as these types match their C counterparts, things should work
without a hitch. The worst that can happen, e.g. in the (unlikely)
event of a system where @code{real(kind(0.0d0))} is different from
@code{real(C_DOUBLE)}, is that the compiler will give you a
type-mismatch error. That is, if you don't use the
@code{iso_c_binding} kinds you need to accept at least the theoretical
possibility of having to change your code in response to compiler
errors on some future machine, but you don't need to worry about
silently compiling incorrect code that yields runtime errors.
@c -------------------------------------------------------
@node Plan execution in Fortran, Allocating aligned memory in Fortran, FFTW Fortran type reference, Calling FFTW from Modern Fortran
@section Plan execution in Fortran
In C, in order to use a plan, one normally calls @code{fftw_execute},
which executes the plan to perform the transform on the input/output
arrays passed when the plan was created (@pxref{Using Plans}). The
corresponding subroutine call in modern Fortran is:
@example
call fftw_execute(plan)
@end example
@findex fftw_execute
However, we have had reports that this causes problems with some
recent optimizing Fortran compilers. The problem is, because the
input/output arrays are not passed as explicit arguments to
@code{fftw_execute}, the semantics of Fortran (unlike C) allow the
compiler to assume that the input/output arrays are not changed by
@code{fftw_execute}. As a consequence, certain compilers end up
repositioning the call to @code{fftw_execute}, assuming incorrectly
that it does nothing to the arrays.
There are various workarounds to this, but the safest and simplest
thing is to not use @code{fftw_execute} in Fortran. Instead, use the
functions described in @ref{New-array Execute Functions}, which take
the input/output arrays as explicit arguments. For example, if the
plan is for a complex-data DFT and was created for the arrays
@code{in} and @code{out}, you would do:
@example
call fftw_execute_dft(plan, in, out)
@end example
@findex fftw_execute_dft
There are a few things to be careful of, however:
@itemize @bullet
@item
@findex fftw_execute_dft_r2c
@findex fftw_execute_dft_c2r
@findex fftw_execute_r2r
You must use the correct type of execute function, matching the way
the plan was created. Complex DFT plans should use
@code{fftw_execute_dft}, Real-input (r2c) DFT plans should use use
@code{fftw_execute_dft_r2c}, and real-output (c2r) DFT plans should
use @code{fftw_execute_dft_c2r}. The various r2r plans should use
@code{fftw_execute_r2r}. Fortunately, if you use the wrong one you
will get a compile-time type-mismatch error (unlike legacy Fortran).
@item
You should normally pass the same input/output arrays that were used when
creating the plan. This is always safe.
@item
@emph{If} you pass @emph{different} input/output arrays compared to
those used when creating the plan, you must abide by all the
restrictions of the new-array execute functions (@pxref{New-array
Execute Functions}). The most tricky of these is the
requirement that the new arrays have the same alignment as the
original arrays; the best (and possibly only) way to guarantee this
is to use the @samp{fftw_alloc} functions to allocate your arrays (@pxref{Allocating aligned memory in Fortran}). Alternatively, you can
use the @code{FFTW_UNALIGNED} flag when creating the
plan, in which case the plan does not depend on the alignment, but
this may sacrifice substantial performance on architectures (like x86)
with SIMD instructions (@pxref{SIMD alignment and fftw_malloc}).
@ctindex FFTW_UNALIGNED
@end itemize
@c -------------------------------------------------------
@node Allocating aligned memory in Fortran, Accessing the wisdom API from Fortran, Plan execution in Fortran, Calling FFTW from Modern Fortran
@section Allocating aligned memory in Fortran
@cindex alignment
@findex fftw_alloc_real
@findex fftw_alloc_complex
In order to obtain maximum performance in FFTW, you should store your
data in arrays that have been specially aligned in memory (@pxref{SIMD
alignment and fftw_malloc}). Enforcing alignment also permits you to
safely use the new-array execute functions (@pxref{New-array Execute
Functions}) to apply a given plan to more than one pair of in/out
arrays. Unfortunately, standard Fortran arrays do @emph{not} provide
any alignment guarantees. The @emph{only} way to allocate aligned
memory in standard Fortran is to allocate it with an external C
function, like the @code{fftw_alloc_real} and
@code{fftw_alloc_complex} functions. Fortunately, Fortran 2003 provides
a simple way to associate such allocated memory with a standard Fortran
array pointer that you can then use normally.
We therefore recommend allocating all your input/output arrays using
the following technique:
@enumerate
@item
Declare a @code{pointer}, @code{arr}, to your array of the desired type
and dimensions. For example, @code{real(C_DOUBLE), pointer :: a(:,:)}
for a 2d real array, or @code{complex(C_DOUBLE_COMPLEX), pointer ::
a(:,:,:)} for a 3d complex array.
@item
The number of elements to allocate must be an
@code{integer(C_SIZE_T)}. You can either declare a variable of this
type, e.g. @code{integer(C_SIZE_T) :: sz}, to store the number of
elements to allocate, or you can use the @code{int(..., C_SIZE_T)}
intrinsic function. e.g. set @code{sz = L * M * N} or use
@code{int(L * M * N, C_SIZE_T)} for an @threedims{L,M,N} array.
@item
Declare a @code{type(C_PTR) :: p} to hold the return value from
FFTW's allocation routine. Set @code{p = fftw_alloc_real(sz)} for a real array, or @code{p = fftw_alloc_complex(sz)} for a complex array.
@item
@findex c_f_pointer
Associate your pointer @code{arr} with the allocated memory @code{p}
using the standard @code{c_f_pointer} subroutine: @code{call
c_f_pointer(p, arr, [...dimensions...])}, where
@code{[...dimensions...])} are an array of the dimensions of the array
(in the usual Fortran order). e.g. @code{call c_f_pointer(p, arr,
[L,M,N])} for an @threedims{L,M,N} array. (Alternatively, you can
omit the dimensions argument if you specified the shape explicitly
when declaring @code{arr}.) You can now use @code{arr} as a usual
multidimensional array.
@item
When you are done using the array, deallocate the memory by @code{call
fftw_free(p)} on @code{p}.
@end enumerate
For example, here is how we would allocate an @twodims{L,M} 2d real array:
@example
real(C_DOUBLE), pointer :: arr(:,:)
type(C_PTR) :: p
p = fftw_alloc_real(int(L * M, C_SIZE_T))
call c_f_pointer(p, arr, [L,M])
@emph{...use arr and arr(i,j) as usual...}
call fftw_free(p)
@end example
and here is an @threedims{L,M,N} 3d complex array:
@example
complex(C_DOUBLE_COMPLEX), pointer :: arr(:,:,:)
type(C_PTR) :: p
p = fftw_alloc_complex(int(L * M * N, C_SIZE_T))
call c_f_pointer(p, arr, [L,M,N])
@emph{...use arr and arr(i,j,k) as usual...}
call fftw_free(p)
@end example
See @ref{Reversing array dimensions} for an example allocating a
single array and associating both real and complex array pointers with
it, for in-place real-to-complex transforms.
@c -------------------------------------------------------
@node Accessing the wisdom API from Fortran, Defining an FFTW module, Allocating aligned memory in Fortran, Calling FFTW from Modern Fortran
@section Accessing the wisdom API from Fortran
@cindex wisdom
@cindex saving plans to disk
As explained in @ref{Words of Wisdom-Saving Plans}, FFTW provides a
``wisdom'' API for saving plans to disk so that they can be recreated
quickly. The C API for exporting (@pxref{Wisdom Export}) and
importing (@pxref{Wisdom Import}) wisdom is somewhat tricky to use
from Fortran, however, because of differences in file I/O and string
types between C and Fortran.
@menu
* Wisdom File Export/Import from Fortran::
* Wisdom String Export/Import from Fortran::
* Wisdom Generic Export/Import from Fortran::
@end menu
@c =========>
@node Wisdom File Export/Import from Fortran, Wisdom String Export/Import from Fortran, Accessing the wisdom API from Fortran, Accessing the wisdom API from Fortran
@subsection Wisdom File Export/Import from Fortran
@findex fftw_import wisdom_from_filename
@findex fftw_export_wisdom_to_filename
The easiest way to export and import wisdom is to do so using
@code{fftw_export_wisdom_to_filename} and
@code{fftw_wisdom_from_filename}. The only trick is that these
require you to pass a C string, which is an array of type
@code{CHARACTER(C_CHAR)} that is terminated by @code{C_NULL_CHAR}.
You can call them like this:
@example
integer(C_INT) :: ret
ret = fftw_export_wisdom_to_filename(C_CHAR_'my_wisdom.dat' // C_NULL_CHAR)
if (ret .eq. 0) stop 'error exporting wisdom to file'
ret = fftw_import_wisdom_from_filename(C_CHAR_'my_wisdom.dat' // C_NULL_CHAR)
if (ret .eq. 0) stop 'error importing wisdom from file'
@end example
Note that prepending @samp{C_CHAR_} is needed to specify that the
literal string is of kind @code{C_CHAR}, and we null-terminate the
string by appending @samp{// C_NULL_CHAR}. These functions return an
@code{integer(C_INT)} (@code{ret}) which is @code{0} if an error
occurred during export/import and nonzero otherwise.
It is also possible to use the lower-level routines
@code{fftw_export_wisdom_to_file} and
@code{fftw_import_wisdom_from_file}, which accept parameters of the C
type @code{FILE*}, expressed in Fortran as @code{type(C_PTR)}.
However, you are then responsible for creating the @code{FILE*}
yourself. You can do this by using @code{iso_c_binding} to define
Fortran intefaces for the C library functions @code{fopen} and
@code{fclose}, which is a bit strange in Fortran but workable.
@c =========>
@node Wisdom String Export/Import from Fortran, Wisdom Generic Export/Import from Fortran, Wisdom File Export/Import from Fortran, Accessing the wisdom API from Fortran
@subsection Wisdom String Export/Import from Fortran
@findex fftw_export_wisdom_to_string
Dealing with FFTW's C string export/import is a bit more painful. In
particular, the @code{fftw_export_wisdom_to_string} function requires
you to deal with a dynamically allocated C string. To get its length,
you must define an interface to the C @code{strlen} function, and to
deallocate it you must define an interface to C @code{free}:
@example
use, intrinsic :: iso_c_binding
interface
integer(C_INT) function strlen(s) bind(C, name='strlen')
import
type(C_PTR), value :: s
end function strlen
subroutine free(p) bind(C, name='free')
import
type(C_PTR), value :: p
end subroutine free
end interface
@end example
Given these definitions, you can then export wisdom to a Fortran
character array:
@example
character(C_CHAR), pointer :: s(:)
integer(C_SIZE_T) :: slen
type(C_PTR) :: p
p = fftw_export_wisdom_to_string()
if (.not. c_associated(p)) stop 'error exporting wisdom'
slen = strlen(p)
call c_f_pointer(p, s, [slen+1])
...
call free(p)
@end example
@findex c_associated
@findex c_f_pointer
Note that @code{slen} is the length of the C string, but the length of
the array is @code{slen+1} because it includes the terminating null
character. (You can omit the @samp{+1} if you don't want Fortran to
know about the null character.) The standard @code{c_associated} function
checks whether @code{p} is a null pointer, which is returned by
@code{fftw_export_wisdom_to_string} if there was an error.
@findex fftw_import_wisdom_from_string
To import wisdom from a string, use
@code{fftw_import_wisdom_from_string} as usual; note that the argument
of this function must be a @code{character(C_CHAR)} that is terminated
by the @code{C_NULL_CHAR} character, like the @code{s} array above.
@c =========>
@node Wisdom Generic Export/Import from Fortran, , Wisdom String Export/Import from Fortran, Accessing the wisdom API from Fortran
@subsection Wisdom Generic Export/Import from Fortran
The most generic wisdom export/import functions allow you to provide
an arbitrary callback function to read/write one character at a time
in any way you want. However, your callback function must be written
in a special way, using the @code{bind(C)} attribute to be passed to a
C interface.
@findex fftw_export_wisdom
In particular, to call the generic wisdom export function
@code{fftw_export_wisdom}, you would write a callback subroutine of the form:
@example
subroutine my_write_char(c, p) bind(C)
use, intrinsic :: iso_c_binding
character(C_CHAR), value :: c
type(C_PTR), value :: p
@emph{...write c...}
end subroutine my_write_char
@end example
Given such a subroutine (along with the corresponding interface definition), you could then export wisdom using:
@findex c_funloc
@example
call fftw_export_wisdom(c_funloc(my_write_char), p)
@end example
@findex c_loc
@findex c_f_pointer
The standard @code{c_funloc} intrinsic converts a Fortran
@code{bind(C)} subroutine into a C function pointer. The parameter
@code{p} is a @code{type(C_PTR)} to any arbitrary data that you want
to pass to @code{my_write_char} (or @code{C_NULL_PTR} if none). (Note
that you can get a C pointer to Fortran data using the intrinsic
@code{c_loc}, and convert it back to a Fortran pointer in
@code{my_write_char} using @code{c_f_pointer}.)
Similarly, to use the generic @code{fftw_import_wisdom}, you would
define a callback function of the form:
@findex fftw_import_wisdom
@example
integer(C_INT) function my_read_char(p) bind(C)
use, intrinsic :: iso_c_binding
type(C_PTR), value :: p
character :: c
@emph{...read a character c...}
my_read_char = ichar(c, C_INT)
end function my_read_char
....
integer(C_INT) :: ret
ret = fftw_import_wisdom(c_funloc(my_read_char), p)
if (ret .eq. 0) stop 'error importing wisdom'
@end example
Your function can return @code{-1} if the end of the input is reached.
Again, @code{p} is an arbitrary @code{type(C_PTR} that is passed
through to your function. @code{fftw_import_wisdom} returns @code{0}
if an error occurred and nonzero otherwise.
@c -------------------------------------------------------
@node Defining an FFTW module, , Accessing the wisdom API from Fortran, Calling FFTW from Modern Fortran
@section Defining an FFTW module
Rather than using the @code{include} statement to include the
@code{fftw3.f03} interface file in any subroutine where you want to
use FFTW, you might prefer to define an FFTW Fortran module. FFTW
does not install itself as a module, primarily because
@code{fftw3.f03} can be shared between different Fortran compilers while
modules (in general) cannot. However, it is trivial to define your
own FFTW module if you want. Just create a file containing:
@example
module FFTW3
use, intrinsic :: iso_c_binding
include 'fftw3.f03'
end module
@end example
Compile this file into a module as usual for your compiler (e.g. with
@code{gfortran -c} you will get a file @code{fftw3.mod}). Now,
instead of @code{include 'fftw3.f03'}, whenever you want to use FFTW
routines you can just do:
@example
use FFTW3
@end example
as usual for Fortran modules. (You still need to link to the FFTW
library, of course.)