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 use, intrinsic :: iso_c_binding
97 implicit none
98
99 private
100
101 public :: &
109
110
111contains
112
113 ! ---------------------------------------------------------
114 subroutine fftw_prepare_plan(plan, dim, n, howmany, is_real, sign, flags_, din_, cin_, cout_)
115 type(c_ptr), intent(inout) :: plan
116 integer, intent(in) :: dim
117 integer, contiguous, intent(in) :: n(:)
118 integer(c_int), intent(in) :: howmany
119 logical, intent(in) :: is_real
120 integer, intent(in) :: sign
121 integer, intent(in) :: flags_
122 real(real64), contiguous, optional, target, intent(in) :: din_(:,:,:,:)
123 complex(real64), contiguous, optional, target, intent(in) :: cin_(:,:,:,:)
124 complex(real64), contiguous, optional, target, intent(in) :: cout_(:,:,:,:)
125
126 real(real64), pointer, contiguous :: rin(:,:,:,:)
127 real(real64), pointer, contiguous :: rout(:,:,:,:)
128 complex(real64), pointer, contiguous :: cin(:,:,:,:)
129 complex(real64), pointer, contiguous :: cout(:,:,:,:)
130 logical :: aligned_memory
131 integer(c_int) :: n_r(1:dim)
132 integer(c_int) :: inembed(1:dim), onembed(1:dim)
133 integer(c_int) :: istride, ostride, idist, odist, flags
134
135 push_sub(fftw_prepare_plan)
136
137 assert(sign == fftw_forward .or. sign == fftw_backward)
138
139 aligned_memory = .false.
140 ! at the calling site, one of these is always passed, but present is only true
141 ! if the corresponding pointer is associated
142 if (present(din_) .or. present(cin_)) then
143 assert(present(cout_))
144 assert(present(din_) .neqv. present(cin_))
145 aligned_memory = .true.
146 if (is_real) then
147 assert(present(din_))
148 else
149 assert(present(cin_))
150 end if
151 flags = flags_
152 else
153 flags = flags_ + fftw_unaligned
154 end if
155
156 n_r(1:dim) = n(dim:1:-1)
157 inembed(1:dim) = n_r(1:dim)
158 onembed(1:dim) = n_r(1:dim)
159 ! batch-last: each transform is contiguous (istride = 1) and the transforms are a whole grid
160 ! apart (idist = product of the per-transform extents). Because the real and complex grids
161 ! differ in size for r2c/c2r, idist/odist are finalized per branch below, once inembed/onembed
162 ! have been halved.
163 istride = 1_c_int
164 ostride = 1_c_int
165 idist = 1_c_int ! set below
166 odist = 1_c_int ! set below
167
168 if (is_real) then
169 if (sign == fftw_forward) then
170 if (.not. aligned_memory) then
171 safe_allocate(rin(1:n(1), 1:n(2), 1:n(3), 1:howmany))
172 safe_allocate(cout(1:n(1)/2+1, 1:n(2), 1:n(3), 1:howmany))
173 else
174 rin => din_
175 cout => cout_
176 end if
177
178 onembed(dim) = onembed(dim)/2 + 1
179 idist = product(inembed(1:dim))
180 odist = product(onembed(1:dim))
181 plan = fftw_plan_many_dft_r2c(dim, n_r, howmany, &
182 rin, inembed, istride, idist, &
183 cout, onembed, ostride, odist, &
184 flags)
185 assert(c_associated(plan))
186
187 if (.not. aligned_memory) then
188 safe_deallocate_p(rin)
189 safe_deallocate_p(cout)
190 else
191 nullify(rin, cout)
192 end if
193 else
194 if (.not. aligned_memory) then
195 safe_allocate(cin(1:n(1)/2+1, 1:n(2), 1:n(3), 1:howmany))
196 safe_allocate(rout(1:n(1), 1:n(2), 1:n(3), 1:howmany))
197 else
198 cin => cout_
199 rout => din_
200 end if
201
202 inembed(dim) = inembed(dim)/2 + 1
203 idist = product(inembed(1:dim))
204 odist = product(onembed(1:dim))
205 plan = fftw_plan_many_dft_c2r(dim, n_r, howmany, &
206 cin, inembed, istride, idist, &
207 rout, onembed, ostride, odist, &
208 flags)
209 assert(c_associated(plan))
210
211 if (.not. aligned_memory) then
212 safe_deallocate_p(cin)
213 safe_deallocate_p(rout)
214 else
215 nullify(cin,rout)
216 end if
217 end if
218 else
219 if (.not. aligned_memory) then
220 safe_allocate(cin(1:n(1), 1:n(2), 1:n(3), 1:howmany))
221 safe_allocate(cout(1:n(1), 1:n(2), 1:n(3), 1:howmany))
222 else
223 if (sign == fftw_forward) then
224 cin => cin_
225 cout => cout_
226 else
227 cout => cin_
228 cin => cout_
229 end if
230 end if
231
232 idist = product(inembed(1:dim))
233 odist = product(onembed(1:dim))
234 plan = fftw_plan_many_dft(dim, n_r, howmany, &
235 cin, inembed, istride, idist, &
236 cout, onembed, ostride, odist, &
237 sign, flags)
238 assert(c_associated(plan))
239
240 if (.not. aligned_memory) then
241 safe_deallocate_p(cin)
242 safe_deallocate_p(cout)
243 else
244 nullify(cin, cout)
245 end if
246 end if
247
248 pop_sub(fftw_prepare_plan)
249 end subroutine fftw_prepare_plan
250
251 ! ---------------------------------------------------------
252 subroutine fftw_get_dims(rs_n, is_real, fs_n)
253 integer, contiguous, intent(in) :: rs_n(:)
254 logical, intent(in) :: is_real
255 integer, contiguous, intent(out) :: fs_n(:)
256
257 push_sub(fftw_get_dims)
258
259 fs_n = rs_n
260 if (is_real) fs_n(1) = rs_n(1)/2 + 1
261
262 pop_sub(fftw_get_dims)
263 end subroutine fftw_get_dims
264
265 ! ---------------------------------------------------------
267 subroutine fftw_alloc_memory(rs_dims, is_real, fs_dims, drs_data, zrs_data, fs_data)
268 integer, intent(in) :: rs_dims(4)
269 logical, intent(in) :: is_real
270 integer, intent(in) :: fs_dims(4)
271 real(real64), pointer, intent(inout) :: drs_data(:,:,:,:)
272 complex(real64), pointer, intent(inout) :: zrs_data(:,:,:,:)
273 complex(real64), pointer, intent(inout) :: fs_data(:,:,:,:)
274
275 type(c_ptr) :: address
276
277 push_sub(fftw_alloc_memory)
278
279 if (is_real) then
280 address = fftw_alloc_real(int(product(rs_dims), c_size_t))
281 call c_f_pointer(address, drs_data, rs_dims)
282 else
283 address = fftw_alloc_complex(int(product(rs_dims), c_size_t))
284 call c_f_pointer(address, zrs_data, rs_dims)
285 end if
286
287 address = fftw_alloc_complex(int(product(fs_dims), c_size_t))
288 call c_f_pointer(address, fs_data, fs_dims)
289
290 pop_sub(fftw_alloc_memory)
291 end subroutine fftw_alloc_memory
292
293 ! ---------------------------------------------------------
294 subroutine fftw_free_memory(is_real, drs_data, zrs_data, fs_data)
295 logical, intent(in) :: is_real
296 real(real64), pointer, intent(inout) :: drs_data(:,:,:,:)
297 complex(real64), pointer, intent(inout) :: zrs_data(:,:,:,:)
298 complex(real64), pointer, intent(inout) :: fs_data(:,:,:,:)
299
300 push_sub(fftw_free_memory)
301
302 if (is_real) then
303 if (associated(drs_data)) then
304 call fftw_free(c_loc(drs_data))
305 nullify(drs_data)
306 end if
307 else
308 if (associated(zrs_data)) then
309 call fftw_free(c_loc(zrs_data))
310 nullify(zrs_data)
311 end if
312 end if
313 if (associated(fs_data)) then
314 call fftw_free(c_loc(fs_data))
315 nullify(fs_data)
316 end if
317
318 pop_sub(fftw_free_memory)
319 end subroutine fftw_free_memory
320
321 ! ---------------------------------------------------------
325 subroutine fftw_prepare_plan_single(plan, dim, n, howmany, is_real, sign, flags, sin_, cin_, cout_)
326 type(c_ptr), intent(inout) :: plan
327 integer, intent(in) :: dim
328 integer, contiguous, intent(in) :: n(:)
329 integer(c_int), intent(in) :: howmany
330 logical, intent(in) :: is_real
331 integer, intent(in) :: sign
332 integer, intent(in) :: flags
333 real(real32), contiguous, optional, target, intent(in) :: sin_(:,:,:,:)
334 complex(real32), contiguous, optional, target, intent(in) :: cin_(:,:,:,:)
335 complex(real32), contiguous, optional, target, intent(in) :: cout_(:,:,:,:)
336
337 real(real32), pointer, contiguous :: rin(:,:,:,:), rout(:,:,:,:)
338 complex(real32), pointer, contiguous :: cin(:,:,:,:), cout(:,:,:,:)
339 integer(c_int) :: n_r(1:dim)
340 integer(c_int) :: inembed(1:dim), onembed(1:dim)
341 integer(c_int) :: istride, ostride, idist, odist
342
344
345 assert(sign == fftw_forward .or. sign == fftw_backward)
346
347 n_r(1:dim) = n(dim:1:-1)
348 inembed(1:dim) = n_r(1:dim)
349 onembed(1:dim) = n_r(1:dim)
350 istride = 1_c_int
351 ostride = 1_c_int
352
353 if (is_real) then
354 if (sign == fftw_forward) then
355 rin => sin_
356 cout => cout_
357 onembed(dim) = onembed(dim)/2 + 1
358 idist = product(inembed(1:dim))
359 odist = product(onembed(1:dim))
360 plan = fftwf_plan_many_dft_r2c(dim, n_r, howmany, &
361 rin, inembed, istride, idist, cout, onembed, ostride, odist, flags)
362 else
363 cin => cout_
364 rout => sin_
365 inembed(dim) = inembed(dim)/2 + 1
366 idist = product(inembed(1:dim))
367 odist = product(onembed(1:dim))
368 plan = fftwf_plan_many_dft_c2r(dim, n_r, howmany, &
369 cin, inembed, istride, idist, rout, onembed, ostride, odist, flags)
370 end if
371 else
372 if (sign == fftw_forward) then
373 cin => cin_
374 cout => cout_
375 else
376 cout => cin_
377 cin => cout_
378 end if
379 idist = product(inembed(1:dim))
380 odist = product(onembed(1:dim))
381 plan = fftwf_plan_many_dft(dim, n_r, howmany, &
382 cin, inembed, istride, idist, cout, onembed, ostride, odist, sign, flags)
383 end if
384 assert(c_associated(plan))
385
387 end subroutine fftw_prepare_plan_single
388
389 ! ---------------------------------------------------------
390 subroutine fftw_alloc_memory_single(rs_dims, is_real, fs_dims, srs_data, crs_data, cfs_data)
391 integer, intent(in) :: rs_dims(4)
392 logical, intent(in) :: is_real
393 integer, intent(in) :: fs_dims(4)
394 real(real32), pointer, intent(inout) :: srs_data(:,:,:,:)
395 complex(real32), pointer, intent(inout) :: crs_data(:,:,:,:)
396 complex(real32), pointer, intent(inout) :: cfs_data(:,:,:,:)
397
398 type(c_ptr) :: address
399
401
402 if (is_real) then
403 address = fftwf_alloc_real(int(product(rs_dims), c_size_t))
404 call c_f_pointer(address, srs_data, rs_dims)
405 else
406 address = fftwf_alloc_complex(int(product(rs_dims), c_size_t))
407 call c_f_pointer(address, crs_data, rs_dims)
408 end if
409
410 address = fftwf_alloc_complex(int(product(fs_dims), c_size_t))
411 call c_f_pointer(address, cfs_data, fs_dims)
412
414 end subroutine fftw_alloc_memory_single
415
416 ! ---------------------------------------------------------
417 subroutine fftw_free_memory_single(is_real, srs_data, crs_data, cfs_data)
418 logical, intent(in) :: is_real
419 real(real32), pointer, intent(inout) :: srs_data(:,:,:,:)
420 complex(real32), pointer, intent(inout) :: crs_data(:,:,:,:)
421 complex(real32), pointer, intent(inout) :: cfs_data(:,:,:,:)
422
424
425 if (is_real) then
426 if (associated(srs_data)) then
427 call fftwf_free(c_loc(srs_data))
428 nullify(srs_data)
429 end if
430 else
431 if (associated(crs_data)) then
432 call fftwf_free(c_loc(crs_data))
433 nullify(crs_data)
434 end if
435 end if
436 if (associated(cfs_data)) then
437 call fftwf_free(c_loc(cfs_data))
438 nullify(cfs_data)
439 end if
440
442 end subroutine fftw_free_memory_single
443
444end module fftw_oct_m
445
446!! Local Variables:
447!! mode: f90
448!! coding: utf-8
449!! End:
subroutine, public fftw_free_memory(is_real, drs_data, zrs_data, fs_data)
Definition: fftw.F90:377
subroutine, public fftw_get_dims(rs_n, is_real, fs_n)
Definition: fftw.F90:335
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:408
subroutine, public fftw_alloc_memory_single(rs_dims, is_real, fs_dims, srs_data, crs_data, cfs_data)
Definition: fftw.F90:473
subroutine, public fftw_free_memory_single(is_real, srs_data, crs_data, cfs_data)
Definition: fftw.F90:500
subroutine, public fftw_prepare_plan(plan, dim, n, howmany, is_real, sign, flags_, din_, cin_, cout_)
Definition: fftw.F90:197
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:350
int true(void)