Chris@10
|
1 @node Calling FFTW from Legacy Fortran, Upgrading from FFTW version 2, Calling FFTW from Modern Fortran, Top
|
Chris@10
|
2 @chapter Calling FFTW from Legacy Fortran
|
Chris@10
|
3 @cindex Fortran interface
|
Chris@10
|
4
|
Chris@10
|
5 This chapter describes the interface to FFTW callable by Fortran code
|
Chris@10
|
6 in older compilers not supporting the Fortran 2003 C interoperability
|
Chris@10
|
7 features (@pxref{Calling FFTW from Modern Fortran}). This interface
|
Chris@10
|
8 has the major disadvantage that it is not type-checked, so if you
|
Chris@10
|
9 mistake the argument types or ordering then your program will not have
|
Chris@10
|
10 any compiler errors, and will likely crash at runtime. So, greater
|
Chris@10
|
11 care is needed. Also, technically interfacing older Fortran versions
|
Chris@10
|
12 to C is nonstandard, but in practice we have found that the techniques
|
Chris@10
|
13 used in this chapter have worked with all known Fortran compilers for
|
Chris@10
|
14 many years.
|
Chris@10
|
15
|
Chris@10
|
16 The legacy Fortran interface differs from the C interface only in the
|
Chris@10
|
17 prefix (@samp{dfftw_} instead of @samp{fftw_} in double precision) and
|
Chris@10
|
18 a few other minor details. This Fortran interface is included in the
|
Chris@10
|
19 FFTW libraries by default, unless a Fortran compiler isn't found on
|
Chris@10
|
20 your system or @code{--disable-fortran} is included in the
|
Chris@10
|
21 @code{configure} flags. We assume here that the reader is already
|
Chris@10
|
22 familiar with the usage of FFTW in C, as described elsewhere in this
|
Chris@10
|
23 manual.
|
Chris@10
|
24
|
Chris@10
|
25 The MPI parallel interface to FFTW is @emph{not} currently available
|
Chris@10
|
26 to legacy Fortran.
|
Chris@10
|
27
|
Chris@10
|
28 @menu
|
Chris@10
|
29 * Fortran-interface routines::
|
Chris@10
|
30 * FFTW Constants in Fortran::
|
Chris@10
|
31 * FFTW Execution in Fortran::
|
Chris@10
|
32 * Fortran Examples::
|
Chris@10
|
33 * Wisdom of Fortran?::
|
Chris@10
|
34 @end menu
|
Chris@10
|
35
|
Chris@10
|
36 @c -------------------------------------------------------
|
Chris@10
|
37 @node Fortran-interface routines, FFTW Constants in Fortran, Calling FFTW from Legacy Fortran, Calling FFTW from Legacy Fortran
|
Chris@10
|
38 @section Fortran-interface routines
|
Chris@10
|
39
|
Chris@10
|
40 Nearly all of the FFTW functions have Fortran-callable equivalents.
|
Chris@10
|
41 The name of the legacy Fortran routine is the same as that of the
|
Chris@10
|
42 corresponding C routine, but with the @samp{fftw_} prefix replaced by
|
Chris@10
|
43 @samp{dfftw_}.@footnote{Technically, Fortran 77 identifiers are not
|
Chris@10
|
44 allowed to have more than 6 characters, nor may they contain
|
Chris@10
|
45 underscores. Any compiler that enforces this limitation doesn't
|
Chris@10
|
46 deserve to link to FFTW.} The single and long-double precision
|
Chris@10
|
47 versions use @samp{sfftw_} and @samp{lfftw_}, respectively, instead of
|
Chris@10
|
48 @samp{fftwf_} and @samp{fftwl_}; quadruple precision (@code{real*16})
|
Chris@10
|
49 is available on some systems as @samp{fftwq_} (@pxref{Precision}).
|
Chris@10
|
50 (Note that @code{long double} on x86 hardware is usually at most
|
Chris@10
|
51 80-bit extended precision, @emph{not} quadruple precision.)
|
Chris@10
|
52
|
Chris@10
|
53 For the most part, all of the arguments to the functions are the same,
|
Chris@10
|
54 with the following exceptions:
|
Chris@10
|
55
|
Chris@10
|
56 @itemize @bullet
|
Chris@10
|
57
|
Chris@10
|
58 @item
|
Chris@10
|
59 @code{plan} variables (what would be of type @code{fftw_plan} in C),
|
Chris@10
|
60 must be declared as a type that is at least as big as a pointer
|
Chris@10
|
61 (address) on your machine. We recommend using @code{integer*8} everywhere,
|
Chris@10
|
62 since this should always be big enough.
|
Chris@10
|
63 @cindex portability
|
Chris@10
|
64
|
Chris@10
|
65 @item
|
Chris@10
|
66 Any function that returns a value (e.g. @code{fftw_plan_dft}) is
|
Chris@10
|
67 converted into a @emph{subroutine}. The return value is converted into
|
Chris@10
|
68 an additional @emph{first} parameter of this subroutine.@footnote{The
|
Chris@10
|
69 reason for this is that some Fortran implementations seem to have
|
Chris@10
|
70 trouble with C function return values, and vice versa.}
|
Chris@10
|
71
|
Chris@10
|
72 @item
|
Chris@10
|
73 @cindex column-major
|
Chris@10
|
74 The Fortran routines expect multi-dimensional arrays to be in
|
Chris@10
|
75 @emph{column-major} order, which is the ordinary format of Fortran
|
Chris@10
|
76 arrays (@pxref{Multi-dimensional Array Format}). They do this
|
Chris@10
|
77 transparently and costlessly simply by reversing the order of the
|
Chris@10
|
78 dimensions passed to FFTW, but this has one important consequence for
|
Chris@10
|
79 multi-dimensional real-complex transforms, discussed below.
|
Chris@10
|
80
|
Chris@10
|
81 @item
|
Chris@10
|
82 Wisdom import and export is somewhat more tricky because one cannot
|
Chris@10
|
83 easily pass files or strings between C and Fortran; see @ref{Wisdom of
|
Chris@10
|
84 Fortran?}.
|
Chris@10
|
85
|
Chris@10
|
86 @item
|
Chris@10
|
87 Legacy Fortran cannot use the @code{fftw_malloc} dynamic-allocation routine.
|
Chris@10
|
88 If you want to exploit the SIMD FFTW (@pxref{SIMD alignment and fftw_malloc}), you'll
|
Chris@10
|
89 need to figure out some other way to ensure that your arrays are at
|
Chris@10
|
90 least 16-byte aligned.
|
Chris@10
|
91
|
Chris@10
|
92 @item
|
Chris@10
|
93 @tindex fftw_iodim
|
Chris@10
|
94 @cindex guru interface
|
Chris@10
|
95 Since Fortran 77 does not have data structures, the @code{fftw_iodim}
|
Chris@10
|
96 structure from the guru interface (@pxref{Guru vector and transform
|
Chris@10
|
97 sizes}) must be split into separate arguments. In particular, any
|
Chris@10
|
98 @code{fftw_iodim} array arguments in the C guru interface become three
|
Chris@10
|
99 integer array arguments (@code{n}, @code{is}, and @code{os}) in the
|
Chris@10
|
100 Fortran guru interface, all of whose lengths should be equal to the
|
Chris@10
|
101 corresponding @code{rank} argument.
|
Chris@10
|
102
|
Chris@10
|
103 @item
|
Chris@10
|
104 The guru planner interface in Fortran does @emph{not} do any automatic
|
Chris@10
|
105 translation between column-major and row-major; you are responsible
|
Chris@10
|
106 for setting the strides etcetera to correspond to your Fortran arrays.
|
Chris@10
|
107 However, as a slight bug that we are preserving for backwards
|
Chris@10
|
108 compatibility, the @samp{plan_guru_r2r} in Fortran @emph{does} reverse the
|
Chris@10
|
109 order of its @code{kind} array parameter, so the @code{kind} array
|
Chris@10
|
110 of that routine should be in the reverse of the order of the iodim
|
Chris@10
|
111 arrays (see above).
|
Chris@10
|
112
|
Chris@10
|
113 @end itemize
|
Chris@10
|
114
|
Chris@10
|
115 In general, you should take care to use Fortran data types that
|
Chris@10
|
116 correspond to (i.e. are the same size as) the C types used by FFTW.
|
Chris@10
|
117 In practice, this correspondence is usually straightforward
|
Chris@10
|
118 (i.e. @code{integer} corresponds to @code{int}, @code{real}
|
Chris@10
|
119 corresponds to @code{float}, etcetera). The native Fortran
|
Chris@10
|
120 double/single-precision complex type should be compatible with
|
Chris@10
|
121 @code{fftw_complex}/@code{fftwf_complex}. Such simple correspondences
|
Chris@10
|
122 are assumed in the examples below.
|
Chris@10
|
123 @cindex portability
|
Chris@10
|
124
|
Chris@10
|
125 @c -------------------------------------------------------
|
Chris@10
|
126 @node FFTW Constants in Fortran, FFTW Execution in Fortran, Fortran-interface routines, Calling FFTW from Legacy Fortran
|
Chris@10
|
127 @section FFTW Constants in Fortran
|
Chris@10
|
128
|
Chris@10
|
129 When creating plans in FFTW, a number of constants are used to specify
|
Chris@10
|
130 options, such as @code{FFTW_MEASURE} or @code{FFTW_ESTIMATE}. The
|
Chris@10
|
131 same constants must be used with the wrapper routines, but of course the
|
Chris@10
|
132 C header files where the constants are defined can't be incorporated
|
Chris@10
|
133 directly into Fortran code.
|
Chris@10
|
134
|
Chris@10
|
135 Instead, we have placed Fortran equivalents of the FFTW constant
|
Chris@10
|
136 definitions in the file @code{fftw3.f}, which can be found in the same
|
Chris@10
|
137 directory as @code{fftw3.h}. If your Fortran compiler supports a
|
Chris@10
|
138 preprocessor of some sort, you should be able to @code{include} or
|
Chris@10
|
139 @code{#include} this file; otherwise, you can paste it directly into
|
Chris@10
|
140 your code.
|
Chris@10
|
141
|
Chris@10
|
142 @cindex flags
|
Chris@10
|
143 In C, you combine different flags (like @code{FFTW_PRESERVE_INPUT} and
|
Chris@10
|
144 @code{FFTW_MEASURE}) using the @samp{@code{|}} operator; in Fortran
|
Chris@10
|
145 you should just use @samp{@code{+}}. (Take care not to add in the
|
Chris@10
|
146 same flag more than once, though. Alternatively, you can use the
|
Chris@10
|
147 @code{ior} intrinsic function standardized in Fortran 95.)
|
Chris@10
|
148
|
Chris@10
|
149 @c -------------------------------------------------------
|
Chris@10
|
150 @node FFTW Execution in Fortran, Fortran Examples, FFTW Constants in Fortran, Calling FFTW from Legacy Fortran
|
Chris@10
|
151 @section FFTW Execution in Fortran
|
Chris@10
|
152
|
Chris@10
|
153 In C, in order to use a plan, one normally calls @code{fftw_execute},
|
Chris@10
|
154 which executes the plan to perform the transform on the input/output
|
Chris@10
|
155 arrays passed when the plan was created (@pxref{Using Plans}). The
|
Chris@10
|
156 corresponding subroutine call in legacy Fortran is:
|
Chris@10
|
157 @example
|
Chris@10
|
158 call dfftw_execute(plan)
|
Chris@10
|
159 @end example
|
Chris@10
|
160 @findex dfftw_execute
|
Chris@10
|
161
|
Chris@10
|
162 However, we have had reports that this causes problems with some
|
Chris@10
|
163 recent optimizing Fortran compilers. The problem is, because the
|
Chris@10
|
164 input/output arrays are not passed as explicit arguments to
|
Chris@10
|
165 @code{dfftw_execute}, the semantics of Fortran (unlike C) allow the
|
Chris@10
|
166 compiler to assume that the input/output arrays are not changed by
|
Chris@10
|
167 @code{dfftw_execute}. As a consequence, certain compilers end up
|
Chris@10
|
168 optimizing out or repositioning the call to @code{dfftw_execute},
|
Chris@10
|
169 assuming incorrectly that it does nothing.
|
Chris@10
|
170
|
Chris@10
|
171 There are various workarounds to this, but the safest and simplest
|
Chris@10
|
172 thing is to not use @code{dfftw_execute} in Fortran. Instead, use the
|
Chris@10
|
173 functions described in @ref{New-array Execute Functions}, which take
|
Chris@10
|
174 the input/output arrays as explicit arguments. For example, if the
|
Chris@10
|
175 plan is for a complex-data DFT and was created for the arrays
|
Chris@10
|
176 @code{in} and @code{out}, you would do:
|
Chris@10
|
177 @example
|
Chris@10
|
178 call dfftw_execute_dft(plan, in, out)
|
Chris@10
|
179 @end example
|
Chris@10
|
180 @findex dfftw_execute_dft
|
Chris@10
|
181
|
Chris@10
|
182 There are a few things to be careful of, however:
|
Chris@10
|
183
|
Chris@10
|
184 @itemize @bullet
|
Chris@10
|
185
|
Chris@10
|
186 @item
|
Chris@10
|
187 You must use the correct type of execute function, matching the way
|
Chris@10
|
188 the plan was created. Complex DFT plans should use
|
Chris@10
|
189 @code{dfftw_execute_dft}, Real-input (r2c) DFT plans should use use
|
Chris@10
|
190 @code{dfftw_execute_dft_r2c}, and real-output (c2r) DFT plans should
|
Chris@10
|
191 use @code{dfftw_execute_dft_c2r}. The various r2r plans should use
|
Chris@10
|
192 @code{dfftw_execute_r2r}.
|
Chris@10
|
193
|
Chris@10
|
194 @item
|
Chris@10
|
195 You should normally pass the same input/output arrays that were used when
|
Chris@10
|
196 creating the plan. This is always safe.
|
Chris@10
|
197
|
Chris@10
|
198 @item
|
Chris@10
|
199 @emph{If} you pass @emph{different} input/output arrays compared to
|
Chris@10
|
200 those used when creating the plan, you must abide by all the
|
Chris@10
|
201 restrictions of the new-array execute functions (@pxref{New-array
|
Chris@10
|
202 Execute Functions}). The most difficult of these, in Fortran, is the
|
Chris@10
|
203 requirement that the new arrays have the same alignment as the
|
Chris@10
|
204 original arrays, because there seems to be no way in legacy Fortran to obtain
|
Chris@10
|
205 guaranteed-aligned arrays (analogous to @code{fftw_malloc} in C). You
|
Chris@10
|
206 can, of course, use the @code{FFTW_UNALIGNED} flag when creating the
|
Chris@10
|
207 plan, in which case the plan does not depend on the alignment, but
|
Chris@10
|
208 this may sacrifice substantial performance on architectures (like x86)
|
Chris@10
|
209 with SIMD instructions (@pxref{SIMD alignment and fftw_malloc}).
|
Chris@10
|
210 @ctindex FFTW_UNALIGNED
|
Chris@10
|
211
|
Chris@10
|
212 @end itemize
|
Chris@10
|
213
|
Chris@10
|
214 @c -------------------------------------------------------
|
Chris@10
|
215 @node Fortran Examples, Wisdom of Fortran?, FFTW Execution in Fortran, Calling FFTW from Legacy Fortran
|
Chris@10
|
216 @section Fortran Examples
|
Chris@10
|
217
|
Chris@10
|
218 In C, you might have something like the following to transform a
|
Chris@10
|
219 one-dimensional complex array:
|
Chris@10
|
220
|
Chris@10
|
221 @example
|
Chris@10
|
222 fftw_complex in[N], out[N];
|
Chris@10
|
223 fftw_plan plan;
|
Chris@10
|
224
|
Chris@10
|
225 plan = fftw_plan_dft_1d(N,in,out,FFTW_FORWARD,FFTW_ESTIMATE);
|
Chris@10
|
226 fftw_execute(plan);
|
Chris@10
|
227 fftw_destroy_plan(plan);
|
Chris@10
|
228 @end example
|
Chris@10
|
229
|
Chris@10
|
230 In Fortran, you would use the following to accomplish the same thing:
|
Chris@10
|
231
|
Chris@10
|
232 @example
|
Chris@10
|
233 double complex in, out
|
Chris@10
|
234 dimension in(N), out(N)
|
Chris@10
|
235 integer*8 plan
|
Chris@10
|
236
|
Chris@10
|
237 call dfftw_plan_dft_1d(plan,N,in,out,FFTW_FORWARD,FFTW_ESTIMATE)
|
Chris@10
|
238 call dfftw_execute_dft(plan, in, out)
|
Chris@10
|
239 call dfftw_destroy_plan(plan)
|
Chris@10
|
240 @end example
|
Chris@10
|
241 @findex dfftw_plan_dft_1d
|
Chris@10
|
242 @findex dfftw_execute_dft
|
Chris@10
|
243 @findex dfftw_destroy_plan
|
Chris@10
|
244
|
Chris@10
|
245 Notice how all routines are called as Fortran subroutines, and the
|
Chris@10
|
246 plan is returned via the first argument to @code{dfftw_plan_dft_1d}.
|
Chris@10
|
247 Notice also that we changed @code{fftw_execute} to
|
Chris@10
|
248 @code{dfftw_execute_dft} (@pxref{FFTW Execution in Fortran}). To do
|
Chris@10
|
249 the same thing, but using 8 threads in parallel (@pxref{Multi-threaded
|
Chris@10
|
250 FFTW}), you would simply prefix these calls with:
|
Chris@10
|
251
|
Chris@10
|
252 @example
|
Chris@10
|
253 integer iret
|
Chris@10
|
254 call dfftw_init_threads(iret)
|
Chris@10
|
255 call dfftw_plan_with_nthreads(8)
|
Chris@10
|
256 @end example
|
Chris@10
|
257 @findex dfftw_init_threads
|
Chris@10
|
258 @findex dfftw_plan_with_nthreads
|
Chris@10
|
259
|
Chris@10
|
260 (You might want to check the value of @code{iret}: if it is zero, it
|
Chris@10
|
261 indicates an unlikely error during thread initialization.)
|
Chris@10
|
262
|
Chris@10
|
263 To transform a three-dimensional array in-place with C, you might do:
|
Chris@10
|
264
|
Chris@10
|
265 @example
|
Chris@10
|
266 fftw_complex arr[L][M][N];
|
Chris@10
|
267 fftw_plan plan;
|
Chris@10
|
268
|
Chris@10
|
269 plan = fftw_plan_dft_3d(L,M,N, arr,arr,
|
Chris@10
|
270 FFTW_FORWARD, FFTW_ESTIMATE);
|
Chris@10
|
271 fftw_execute(plan);
|
Chris@10
|
272 fftw_destroy_plan(plan);
|
Chris@10
|
273 @end example
|
Chris@10
|
274
|
Chris@10
|
275 In Fortran, you would use this instead:
|
Chris@10
|
276
|
Chris@10
|
277 @example
|
Chris@10
|
278 double complex arr
|
Chris@10
|
279 dimension arr(L,M,N)
|
Chris@10
|
280 integer*8 plan
|
Chris@10
|
281
|
Chris@10
|
282 call dfftw_plan_dft_3d(plan, L,M,N, arr,arr,
|
Chris@10
|
283 & FFTW_FORWARD, FFTW_ESTIMATE)
|
Chris@10
|
284 call dfftw_execute_dft(plan, arr, arr)
|
Chris@10
|
285 call dfftw_destroy_plan(plan)
|
Chris@10
|
286 @end example
|
Chris@10
|
287 @findex dfftw_plan_dft_3d
|
Chris@10
|
288
|
Chris@10
|
289 Note that we pass the array dimensions in the ``natural'' order in both C
|
Chris@10
|
290 and Fortran.
|
Chris@10
|
291
|
Chris@10
|
292 To transform a one-dimensional real array in Fortran, you might do:
|
Chris@10
|
293
|
Chris@10
|
294 @example
|
Chris@10
|
295 double precision in
|
Chris@10
|
296 dimension in(N)
|
Chris@10
|
297 double complex out
|
Chris@10
|
298 dimension out(N/2 + 1)
|
Chris@10
|
299 integer*8 plan
|
Chris@10
|
300
|
Chris@10
|
301 call dfftw_plan_dft_r2c_1d(plan,N,in,out,FFTW_ESTIMATE)
|
Chris@10
|
302 call dfftw_execute_dft_r2c(plan, in, out)
|
Chris@10
|
303 call dfftw_destroy_plan(plan)
|
Chris@10
|
304 @end example
|
Chris@10
|
305 @findex dfftw_plan_dft_r2c_1d
|
Chris@10
|
306 @findex dfftw_execute_dft_r2c
|
Chris@10
|
307
|
Chris@10
|
308 To transform a two-dimensional real array, out of place, you might use
|
Chris@10
|
309 the following:
|
Chris@10
|
310
|
Chris@10
|
311 @example
|
Chris@10
|
312 double precision in
|
Chris@10
|
313 dimension in(M,N)
|
Chris@10
|
314 double complex out
|
Chris@10
|
315 dimension out(M/2 + 1, N)
|
Chris@10
|
316 integer*8 plan
|
Chris@10
|
317
|
Chris@10
|
318 call dfftw_plan_dft_r2c_2d(plan,M,N,in,out,FFTW_ESTIMATE)
|
Chris@10
|
319 call dfftw_execute_dft_r2c(plan, in, out)
|
Chris@10
|
320 call dfftw_destroy_plan(plan)
|
Chris@10
|
321 @end example
|
Chris@10
|
322 @findex dfftw_plan_dft_r2c_2d
|
Chris@10
|
323
|
Chris@10
|
324 @strong{Important:} Notice that it is the @emph{first} dimension of the
|
Chris@10
|
325 complex output array that is cut in half in Fortran, rather than the
|
Chris@10
|
326 last dimension as in C. This is a consequence of the interface routines
|
Chris@10
|
327 reversing the order of the array dimensions passed to FFTW so that the
|
Chris@10
|
328 Fortran program can use its ordinary column-major order.
|
Chris@10
|
329 @cindex column-major
|
Chris@10
|
330 @cindex r2c/c2r multi-dimensional array format
|
Chris@10
|
331
|
Chris@10
|
332 @c -------------------------------------------------------
|
Chris@10
|
333 @node Wisdom of Fortran?, , Fortran Examples, Calling FFTW from Legacy Fortran
|
Chris@10
|
334 @section Wisdom of Fortran?
|
Chris@10
|
335
|
Chris@10
|
336 In this section, we discuss how one can import/export FFTW wisdom
|
Chris@10
|
337 (saved plans) to/from a Fortran program; we assume that the reader is
|
Chris@10
|
338 already familiar with wisdom, as described in @ref{Words of
|
Chris@10
|
339 Wisdom-Saving Plans}.
|
Chris@10
|
340
|
Chris@10
|
341 @cindex portability
|
Chris@10
|
342 The basic problem is that is difficult to (portably) pass files and
|
Chris@10
|
343 strings between Fortran and C, so we cannot provide a direct Fortran
|
Chris@10
|
344 equivalent to the @code{fftw_export_wisdom_to_file}, etcetera,
|
Chris@10
|
345 functions. Fortran interfaces @emph{are} provided for the functions
|
Chris@10
|
346 that do not take file/string arguments, however:
|
Chris@10
|
347 @code{dfftw_import_system_wisdom}, @code{dfftw_import_wisdom},
|
Chris@10
|
348 @code{dfftw_export_wisdom}, and @code{dfftw_forget_wisdom}.
|
Chris@10
|
349 @findex dfftw_import_system_wisdom
|
Chris@10
|
350 @findex dfftw_import_wisdom
|
Chris@10
|
351 @findex dfftw_export_wisdom
|
Chris@10
|
352 @findex dfftw_forget_wisdom
|
Chris@10
|
353
|
Chris@10
|
354
|
Chris@10
|
355 So, for example, to import the system-wide wisdom, you would do:
|
Chris@10
|
356
|
Chris@10
|
357 @example
|
Chris@10
|
358 integer isuccess
|
Chris@10
|
359 call dfftw_import_system_wisdom(isuccess)
|
Chris@10
|
360 @end example
|
Chris@10
|
361
|
Chris@10
|
362 As usual, the C return value is turned into a first parameter;
|
Chris@10
|
363 @code{isuccess} is non-zero on success and zero on failure (e.g. if
|
Chris@10
|
364 there is no system wisdom installed).
|
Chris@10
|
365
|
Chris@10
|
366 If you want to import/export wisdom from/to an arbitrary file or
|
Chris@10
|
367 elsewhere, you can employ the generic @code{dfftw_import_wisdom} and
|
Chris@10
|
368 @code{dfftw_export_wisdom} functions, for which you must supply a
|
Chris@10
|
369 subroutine to read/write one character at a time. The FFTW package
|
Chris@10
|
370 contains an example file @code{doc/f77_wisdom.f} demonstrating how to
|
Chris@10
|
371 implement @code{import_wisdom_from_file} and
|
Chris@10
|
372 @code{export_wisdom_to_file} subroutines in this way. (These routines
|
Chris@10
|
373 cannot be compiled into the FFTW library itself, lest all FFTW-using
|
Chris@10
|
374 programs be required to link with the Fortran I/O library.)
|