Octopus
fftw.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2011 M. Oliveira
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
23 use, intrinsic :: iso_c_binding
24 implicit none
25
26 private
27
28 ! make public some needed symbols from the FFTW library
29 public :: &
30 fftw_cleanup, &
31 fftw_execute_dft, &
32 fftw_execute_dft_c2r, &
33 fftw_execute_dft_r2c, &
34 fftw_execute_r2r, &
35 fftw_destroy_plan, &
36 fftw_alloc_real, &
37 fftw_alloc_complex, &
38 fftw_free, &
39 fftw_plan_many_dft, &
40 fftw_plan_many_dft_r2c, &
41 fftw_plan_many_dft_c2r, &
42 fftw_plan_r2r_1d, &
43 fftwf_cleanup, &
44 fftwf_execute_dft, &
45 fftwf_execute_dft_c2r, &
46 fftwf_execute_dft_r2c, &
47 fftwf_destroy_plan, &
48 fftwf_alloc_real, &
49 fftwf_alloc_complex, &
50 fftwf_free, &
51 fftwf_plan_many_dft, &
52 fftwf_plan_many_dft_r2c, &
53 fftwf_plan_many_dft_c2r, &
54 c_fftw_r2r_kind, &
55 fftw_r2hc, &
56 fftw_hc2r, &
57 fftw_dht, &
58 fftw_redft00, &
59 fftw_redft01, &
60 fftw_redft10, &
61 fftw_redft11, &
62 fftw_rodft00, &
63 fftw_rodft01, &
64 fftw_rodft10, &
65 fftw_rodft11, &
66 fftw_forward, &
67 fftw_backward, &
68 fftw_measure, &
69 fftw_estimate, &
70 fftw_destroy_input, &
71 fftw_unaligned
72#ifdef HAVE_FFTW3_MPI
73 public :: fftw_mpi_default_block
74#endif
75#if defined(HAVE_OPENMP) && defined(HAVE_FFTW3_THREADS)
76 public :: &
77 fftw_init_threads, &
78 fftw_plan_with_nthreads, &
79 fftw_cleanup_threads
80#endif
81
82
83#ifdef HAVE_FFTW3_MPI
84 include "fftw3-mpi.f03"
85#else
86 include "fftw3.f03"
87#endif
88end module fftw_params_oct_m
89
90module fftw_oct_m
92 use debug_oct_m
93 use global_oct_m
94#ifndef NDEBUG
95 use, intrinsic :: ieee_exceptions
96#endif
97 use, intrinsic :: iso_c_binding
100 implicit none
101
102 private
103
104 public :: &
112
113
114contains
115
116 ! ---------------------------------------------------------
117 subroutine fftw_prepare_plan(plan, dim, n, howmany, is_real, sign, flags_, din_, cin_, cout_)
118 type(c_ptr), intent(inout) :: plan
119 integer, intent(in) :: dim
120 integer, contiguous, intent(in) :: n(:)
121 integer(c_int), intent(in) :: howmany
122 logical, intent(in) :: is_real
123 integer, intent(in) :: sign
124 integer, intent(in) :: flags_
125 real(real64), contiguous, optional, target, intent(in) :: din_(:,:,:,:)
126 complex(real64), contiguous, optional, target, intent(in) :: cin_(:,:,:,:)
127 complex(real64), contiguous, optional, target, intent(in) :: cout_(:,:,:,:)
128
129 real(real64), pointer, contiguous :: rin(:,:,:,:)
130 real(real64), pointer, contiguous :: rout(:,:,:,:)
131 complex(real64), pointer, contiguous :: cin(:,:,:,:)
132 complex(real64), pointer, contiguous :: cout(:,:,:,:)
133 logical :: aligned_memory
134 integer(c_int) :: n_r(1:dim)
135 integer(c_int) :: inembed(1:dim), onembed(1:dim)
136 integer(c_int) :: istride, ostride, idist, odist, flags
137#ifndef NDEBUG
138 logical :: halting_mode(size(ieee_all))
139#endif
140
141 push_sub(fftw_prepare_plan)
142
143 assert(sign == fftw_forward .or. sign == fftw_backward)
144
145#ifndef NDEBUG
146 ! The oneMKL FFTW wrappers raise spurious floating-point exceptions while
147 ! committing a DFTI descriptor, so suspend trapping for builds that enable it
148 call ieee_get_halting_mode(ieee_all, halting_mode)
149 call ieee_set_halting_mode(ieee_all, .false.)
150#endif
151
152 aligned_memory = .false.
153 ! at the calling site, one of these is always passed, but present is only true
154 ! if the corresponding pointer is associated
155 if (present(din_) .or. present(cin_)) then
156 assert(present(cout_))
157 assert(present(din_) .neqv. present(cin_))
158 aligned_memory = .true.
159 if (is_real) then
160 assert(present(din_))
161 else
162 assert(present(cin_))
163 end if
164 flags = flags_
165 else
166 flags = flags_ + fftw_unaligned
167 end if
168
169 n_r(1:dim) = n(dim:1:-1)
170 inembed(1:dim) = n_r(1:dim)
171 onembed(1:dim) = n_r(1:dim)
172 ! batch-last: each transform is contiguous (istride = 1) and the transforms are a whole grid
173 ! apart (idist = product of the per-transform extents). Because the real and complex grids
174 ! differ in size for r2c/c2r, idist/odist are finalized per branch below, once inembed/onembed
175 ! have been halved.
176 istride = 1_c_int
177 ostride = 1_c_int
178 idist = 1_c_int ! set below
179 odist = 1_c_int ! set below
180
181 if (is_real) then
182 if (sign == fftw_forward) then
183 if (.not. aligned_memory) then
184 safe_allocate(rin(1:n(1), 1:n(2), 1:n(3), 1:howmany))
185 safe_allocate(cout(1:n(1)/2+1, 1:n(2), 1:n(3), 1:howmany))
186 else
187 rin => din_
188 cout => cout_
189 end if
190
191 onembed(dim) = onembed(dim)/2 + 1
192 idist = product(inembed(1:dim))
193 odist = product(onembed(1:dim))
194 plan = fftw_plan_many_dft_r2c(dim, n_r, howmany, &
195 rin, inembed, istride, idist, &
196 cout, onembed, ostride, odist, &
197 flags)
198 assert(c_associated(plan))
200 if (.not. aligned_memory) then
201 safe_deallocate_p(rin)
202 safe_deallocate_p(cout)
203 else
204 nullify(rin, cout)
205 end if
206 else
207 if (.not. aligned_memory) then
208 safe_allocate(cin(1:n(1)/2+1, 1:n(2), 1:n(3), 1:howmany))
209 safe_allocate(rout(1:n(1), 1:n(2), 1:n(3), 1:howmany))
210 else
211 cin => cout_
212 rout => din_
213 end if
214
215 inembed(dim) = inembed(dim)/2 + 1
216 idist = product(inembed(1:dim))
217 odist = product(onembed(1:dim))
218 plan = fftw_plan_many_dft_c2r(dim, n_r, howmany, &
219 cin, inembed, istride, idist, &
220 rout, onembed, ostride, odist, &
221 flags)
222 assert(c_associated(plan))
223
224 if (.not. aligned_memory) then
225 safe_deallocate_p(cin)
226 safe_deallocate_p(rout)
227 else
228 nullify(cin,rout)
229 end if
230 end if
231 else
232 if (.not. aligned_memory) then
233 safe_allocate(cin(1:n(1), 1:n(2), 1:n(3), 1:howmany))
234 safe_allocate(cout(1:n(1), 1:n(2), 1:n(3), 1:howmany))
235 else
236 if (sign == fftw_forward) then
237 cin => cin_
238 cout => cout_
239 else
240 cout => cin_
241 cin => cout_
242 end if
243 end if
244
245 idist = product(inembed(1:dim))
246 odist = product(onembed(1:dim))
247 plan = fftw_plan_many_dft(dim, n_r, howmany, &
248 cin, inembed, istride, idist, &
249 cout, onembed, ostride, odist, &
250 sign, flags)
251 assert(c_associated(plan))
252
253 if (.not. aligned_memory) then
254 safe_deallocate_p(cin)
255 safe_deallocate_p(cout)
256 else
257 nullify(cin, cout)
258 end if
259 end if
260
261#ifndef NDEBUG
262 call ieee_set_halting_mode(ieee_all, halting_mode)
263#endif
264
265 pop_sub(fftw_prepare_plan)
266 end subroutine fftw_prepare_plan
267
268 ! ---------------------------------------------------------
269 subroutine fftw_get_dims(rs_n, is_real, fs_n)
270 integer, contiguous, intent(in) :: rs_n(:)
271 logical, intent(in) :: is_real
272 integer, contiguous, intent(out) :: fs_n(:)
273
274 push_sub(fftw_get_dims)
275
276 fs_n = rs_n
277 if (is_real) fs_n(1) = rs_n(1)/2 + 1
278
279 pop_sub(fftw_get_dims)
280 end subroutine fftw_get_dims
281
282 ! ---------------------------------------------------------
284 subroutine fftw_alloc_memory(rs_dims, is_real, fs_dims, drs_data, zrs_data, fs_data)
285 integer, intent(in) :: rs_dims(4)
286 logical, intent(in) :: is_real
287 integer, intent(in) :: fs_dims(4)
288 real(real64), pointer, intent(inout) :: drs_data(:,:,:,:)
289 complex(real64), pointer, intent(inout) :: zrs_data(:,:,:,:)
290 complex(real64), pointer, intent(inout) :: fs_data(:,:,:,:)
291
292 type(c_ptr) :: address
293
294 push_sub(fftw_alloc_memory)
295
296 if (is_real) then
297 address = fftw_alloc_real(int(product(rs_dims), c_size_t))
298 call c_f_pointer(address, drs_data, rs_dims)
299 else
300 address = fftw_alloc_complex(int(product(rs_dims), c_size_t))
301 call c_f_pointer(address, zrs_data, rs_dims)
302 end if
303
304 address = fftw_alloc_complex(int(product(fs_dims), c_size_t))
305 call c_f_pointer(address, fs_data, fs_dims)
306
307 pop_sub(fftw_alloc_memory)
308 end subroutine fftw_alloc_memory
309
310 ! ---------------------------------------------------------
311 subroutine fftw_free_memory(is_real, drs_data, zrs_data, fs_data)
312 logical, intent(in) :: is_real
313 real(real64), pointer, intent(inout) :: drs_data(:,:,:,:)
314 complex(real64), pointer, intent(inout) :: zrs_data(:,:,:,:)
315 complex(real64), pointer, intent(inout) :: fs_data(:,:,:,:)
316
317 push_sub(fftw_free_memory)
318
319 if (is_real) then
320 if (associated(drs_data)) then
321 call fftw_free(c_loc(drs_data))
322 nullify(drs_data)
323 end if
324 else
325 if (associated(zrs_data)) then
326 call fftw_free(c_loc(zrs_data))
327 nullify(zrs_data)
328 end if
329 end if
330 if (associated(fs_data)) then
331 call fftw_free(c_loc(fs_data))
332 nullify(fs_data)
333 end if
334
335 pop_sub(fftw_free_memory)
336 end subroutine fftw_free_memory
337
338 ! ---------------------------------------------------------
342 subroutine fftw_prepare_plan_single(plan, dim, n, howmany, is_real, sign, flags, sin_, cin_, cout_)
343 type(c_ptr), intent(inout) :: plan
344 integer, intent(in) :: dim
345 integer, contiguous, intent(in) :: n(:)
346 integer(c_int), intent(in) :: howmany
347 logical, intent(in) :: is_real
348 integer, intent(in) :: sign
349 integer, intent(in) :: flags
350 real(real32), contiguous, optional, target, intent(in) :: sin_(:,:,:,:)
351 complex(real32), contiguous, optional, target, intent(in) :: cin_(:,:,:,:)
352 complex(real32), contiguous, optional, target, intent(in) :: cout_(:,:,:,:)
353
354 real(real32), pointer, contiguous :: rin(:,:,:,:), rout(:,:,:,:)
355 complex(real32), pointer, contiguous :: cin(:,:,:,:), cout(:,:,:,:)
356 integer(c_int) :: n_r(1:dim)
357 integer(c_int) :: inembed(1:dim), onembed(1:dim)
358 integer(c_int) :: istride, ostride, idist, odist
359#ifndef NDEBUG
360 logical :: halting_mode(size(ieee_all))
361#endif
362
364
365 assert(sign == fftw_forward .or. sign == fftw_backward)
367#ifndef NDEBUG
368 ! See fftw_prepare_plan
369 call ieee_get_halting_mode(ieee_all, halting_mode)
370 call ieee_set_halting_mode(ieee_all, .false.)
371#endif
372
373 n_r(1:dim) = n(dim:1:-1)
374 inembed(1:dim) = n_r(1:dim)
375 onembed(1:dim) = n_r(1:dim)
376 istride = 1_c_int
377 ostride = 1_c_int
378
379 if (is_real) then
380 if (sign == fftw_forward) then
381 rin => sin_
382 cout => cout_
383 onembed(dim) = onembed(dim)/2 + 1
384 idist = product(inembed(1:dim))
385 odist = product(onembed(1:dim))
386 plan = fftwf_plan_many_dft_r2c(dim, n_r, howmany, &
387 rin, inembed, istride, idist, cout, onembed, ostride, odist, flags)
388 else
389 cin => cout_
390 rout => sin_
391 inembed(dim) = inembed(dim)/2 + 1
392 idist = product(inembed(1:dim))
393 odist = product(onembed(1:dim))
394 plan = fftwf_plan_many_dft_c2r(dim, n_r, howmany, &
395 cin, inembed, istride, idist, rout, onembed, ostride, odist, flags)
396 end if
397 else
398 if (sign == fftw_forward) then
399 cin => cin_
400 cout => cout_
401 else
402 cout => cin_
403 cin => cout_
404 end if
405 idist = product(inembed(1:dim))
406 odist = product(onembed(1:dim))
407 plan = fftwf_plan_many_dft(dim, n_r, howmany, &
408 cin, inembed, istride, idist, cout, onembed, ostride, odist, sign, flags)
409 end if
410 assert(c_associated(plan))
411
412#ifndef NDEBUG
413 call ieee_set_halting_mode(ieee_all, halting_mode)
414#endif
415
417 end subroutine fftw_prepare_plan_single
418
419 ! ---------------------------------------------------------
420 subroutine fftw_alloc_memory_single(rs_dims, is_real, fs_dims, srs_data, crs_data, cfs_data)
421 integer, intent(in) :: rs_dims(4)
422 logical, intent(in) :: is_real
423 integer, intent(in) :: fs_dims(4)
424 real(real32), pointer, intent(inout) :: srs_data(:,:,:,:)
425 complex(real32), pointer, intent(inout) :: crs_data(:,:,:,:)
426 complex(real32), pointer, intent(inout) :: cfs_data(:,:,:,:)
427
428 type(c_ptr) :: address
429
431
432 if (is_real) then
433 address = fftwf_alloc_real(int(product(rs_dims), c_size_t))
434 call c_f_pointer(address, srs_data, rs_dims)
435 else
436 address = fftwf_alloc_complex(int(product(rs_dims), c_size_t))
437 call c_f_pointer(address, crs_data, rs_dims)
438 end if
439
440 address = fftwf_alloc_complex(int(product(fs_dims), c_size_t))
441 call c_f_pointer(address, cfs_data, fs_dims)
442
444 end subroutine fftw_alloc_memory_single
445
446 ! ---------------------------------------------------------
447 subroutine fftw_free_memory_single(is_real, srs_data, crs_data, cfs_data)
448 logical, intent(in) :: is_real
449 real(real32), pointer, intent(inout) :: srs_data(:,:,:,:)
450 complex(real32), pointer, intent(inout) :: crs_data(:,:,:,:)
451 complex(real32), pointer, intent(inout) :: cfs_data(:,:,:,:)
452
454
455 if (is_real) then
456 if (associated(srs_data)) then
457 call fftwf_free(c_loc(srs_data))
458 nullify(srs_data)
459 end if
460 else
461 if (associated(crs_data)) then
462 call fftwf_free(c_loc(crs_data))
463 nullify(crs_data)
464 end if
465 end if
466 if (associated(cfs_data)) then
467 call fftwf_free(c_loc(cfs_data))
468 nullify(cfs_data)
469 end if
470
472 end subroutine fftw_free_memory_single
473
474end module fftw_oct_m
475
476!! Local Variables:
477!! mode: f90
478!! coding: utf-8
479!! End:
subroutine, public fftw_free_memory(is_real, drs_data, zrs_data, fs_data)
Definition: fftw.F90:394
subroutine, public fftw_get_dims(rs_n, is_real, fs_n)
Definition: fftw.F90:352
subroutine, public fftw_prepare_plan_single(plan, dim, n, howmany, is_real, sign, flags, sin_, cin_, cout_)
Single-precision counterpart of fftw_prepare_plan. Only the aligned-memory path is supported (the sin...
Definition: fftw.F90:425
subroutine, public fftw_alloc_memory_single(rs_dims, is_real, fs_dims, srs_data, crs_data, cfs_data)
Definition: fftw.F90:503
subroutine, public fftw_free_memory_single(is_real, srs_data, crs_data, cfs_data)
Definition: fftw.F90:530
subroutine, public fftw_prepare_plan(plan, dim, n, howmany, is_real, sign, flags_, din_, cin_, cout_)
Definition: fftw.F90:200
subroutine, public fftw_alloc_memory(rs_dims, is_real, fs_dims, drs_data, zrs_data, fs_data)
Allocate the FFTW work buffers from the rank-4 (batch-last) dimension arrays (see fft_pack).
Definition: fftw.F90:367
int true(void)