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 c_fftw_r2r_kind, &
44 fftw_r2hc, &
45 fftw_hc2r, &
46 fftw_dht, &
47 fftw_redft00, &
48 fftw_redft01, &
49 fftw_redft10, &
50 fftw_redft11, &
51 fftw_rodft00, &
52 fftw_rodft01, &
53 fftw_rodft10, &
54 fftw_rodft11, &
55 fftw_forward, &
56 fftw_backward, &
57 fftw_measure, &
58 fftw_estimate, &
59 fftw_destroy_input, &
60 fftw_unaligned
61#ifdef HAVE_FFTW3_MPI
62 public :: fftw_mpi_default_block
63#endif
64#if defined(HAVE_OPENMP) && defined(HAVE_FFTW3_THREADS)
65 public :: &
66 fftw_init_threads, &
67 fftw_plan_with_nthreads, &
68 fftw_cleanup_threads
69#endif
70
71
72#ifdef HAVE_FFTW3_MPI
73 include "fftw3-mpi.f03"
74#else
75 include "fftw3.f03"
76#endif
77end module fftw_params_oct_m
78
79module fftw_oct_m
81 use debug_oct_m
82 use global_oct_m
83 use, intrinsic :: iso_c_binding
86 implicit none
87
88 private
89
90 public :: &
95
96
97contains
98
99 ! ---------------------------------------------------------
100 subroutine fftw_prepare_plan(plan, dim, n, howmany, batch_axis, is_real, sign, flags, din_, cin_, cout_)
101 type(c_ptr), intent(inout) :: plan
102 integer, intent(in) :: dim
103 integer, intent(in) :: n(:)
104 integer(c_int), intent(in) :: howmany
105 integer, intent(in) :: batch_axis
106 logical, intent(in) :: is_real
107 integer, intent(in) :: sign
108 integer, intent(in) :: flags
109 real(real64), optional, target, intent(in) :: din_(:,:,:,:)
110 complex(real64), optional, target, intent(in) :: cin_(:,:,:,:)
111 complex(real64), optional, target, intent(in) :: cout_(:,:,:,:)
112
113 real(real64), pointer, contiguous :: rin(:,:,:,:)
114 real(real64), pointer, contiguous :: rout(:,:,:,:)
115 complex(real64), pointer, contiguous :: cin(:,:,:,:)
116 complex(real64), pointer, contiguous :: cout(:,:,:,:)
117 logical :: aligned_memory
118 integer(c_int) :: n_r(1:dim)
119 integer(c_int) :: inembed(1:dim), onembed(1:dim)
120 integer(c_int) :: istride, ostride, idist, odist
121
122 push_sub(fftw_prepare_plan)
123
124 assert(sign == fftw_forward .or. sign == fftw_backward)
125 assert(batch_axis == 1 .or. batch_axis == 4)
126
127 aligned_memory = .false.
128 if (present(din_) .or. present(cin_)) then
129 assert(present(cout_))
130 assert(present(din_) .neqv. present(cin_))
131 aligned_memory = .true.
132 if (is_real) then
133 assert(present(din_))
134 else
135 assert(present(cin_))
136 end if
137 end if
138
139 n_r(1:dim) = n(dim:1:-1)
140 inembed(1:dim) = n_r(1:dim)
141 onembed(1:dim) = n_r(1:dim)
142 ! batch-first (batch_axis == 1): the batch is the fastest-varying axis, so consecutive
143 ! transforms are interleaved one element apart (idist = 1) and the elements within a
144 ! transform are howmany apart (istride = howmany).
145 ! batch-last (batch_axis == 4): each transform is contiguous (istride = 1) and the transforms
146 ! are a whole grid apart (idist = product of the per-transform extents). Because the real and
147 ! complex grids differ in size for r2c/c2r, idist/odist are finalized per branch below, once
148 ! inembed/onembed have been halved.
149 if (batch_axis == 1) then
150 istride = howmany
151 ostride = howmany
152 idist = 1_c_int
153 odist = 1_c_int
154 else if (batch_axis == 4) then
155 istride = 1_c_int
156 ostride = 1_c_int
157 idist = 1_c_int ! set below
158 odist = 1_c_int ! set below
159 else
160 assert(.false.)
161 end if
162
163 if (is_real) then
164 if (sign == fftw_forward) then
165 if (.not. aligned_memory) then
166 safe_allocate(rin(1:howmany, 1:n(1), 1:n(2), 1:n(3)))
167 safe_allocate(cout(1:howmany, 1:n(1)/2+1, 1:n(2), 1:n(3)))
168 else
169 rin => din_
170 cout => cout_
171 end if
172
173 onembed(dim) = onembed(dim)/2 + 1
174 if (batch_axis == 4) then
175 idist = product(inembed(1:dim))
176 odist = product(onembed(1:dim))
177 end if
178 plan = fftw_plan_many_dft_r2c(dim, n_r, howmany, &
179 rin, inembed, istride, idist, &
180 cout, onembed, ostride, odist, &
181 flags)
182 assert(c_associated(plan))
183
184 if (.not. aligned_memory) then
185 safe_deallocate_p(rin)
186 safe_deallocate_p(cout)
187 else
188 nullify(rin, cout)
189 end if
190 else
191 if (.not. aligned_memory) then
192 safe_allocate(cin(1:howmany, 1:n(1)/2+1, 1:n(2), 1:n(3)))
193 safe_allocate(rout(1:howmany, 1:n(1), 1:n(2), 1:n(3)))
194 else
195 cin => cout_
196 rout => din_
197 end if
198
199 inembed(dim) = inembed(dim)/2 + 1
200 if (batch_axis == 4) then
201 idist = product(inembed(1:dim))
202 odist = product(onembed(1:dim))
203 end if
204 plan = fftw_plan_many_dft_c2r(dim, n_r, howmany, &
205 cin, inembed, istride, idist, &
206 rout, onembed, ostride, odist, &
207 flags)
208 assert(c_associated(plan))
209
210 if (.not. aligned_memory) then
211 safe_deallocate_p(cin)
212 safe_deallocate_p(rout)
213 else
214 nullify(cin,rout)
215 end if
216 end if
217 else
218 if (.not. aligned_memory) then
219 safe_allocate(cin(1:howmany, 1:n(1), 1:n(2), 1:n(3)))
220 safe_allocate(cout(1:howmany, 1:n(1), 1:n(2), 1:n(3)))
221 else
222 if (sign == fftw_forward) then
223 cin => cin_
224 cout => cout_
225 else
226 cout => cin_
227 cin => cout_
228 end if
229 end if
230
231 if (batch_axis == 4) then
232 idist = product(inembed(1:dim))
233 odist = product(onembed(1:dim))
234 end if
235 plan = fftw_plan_many_dft(dim, n_r, howmany, &
236 cin, inembed, istride, idist, &
237 cout, onembed, ostride, odist, &
238 sign, flags)
239 assert(c_associated(plan))
240
241 if (.not. aligned_memory) then
242 safe_deallocate_p(cin)
243 safe_deallocate_p(cout)
244 else
245 nullify(cin, cout)
246 end if
247 end if
248
249 pop_sub(fftw_prepare_plan)
250 end subroutine fftw_prepare_plan
251
252 ! ---------------------------------------------------------
253 subroutine fftw_get_dims(rs_n, is_real, fs_n)
254 integer, intent(in) :: rs_n(:)
255 logical, intent(in) :: is_real
256 integer, intent(out) :: fs_n(:)
257
258 push_sub(fftw_get_dims)
259
260 fs_n = rs_n
261 if (is_real) fs_n(1) = rs_n(1)/2 + 1
262
263 pop_sub(fftw_get_dims)
264 end subroutine fftw_get_dims
265
266 ! ---------------------------------------------------------
270 subroutine fftw_alloc_memory(rs_dims, is_real, fs_dims, drs_data, zrs_data, fs_data)
271 integer, intent(in) :: rs_dims(4)
272 logical, intent(in) :: is_real
273 integer, intent(in) :: fs_dims(4)
274 real(real64), pointer, intent(inout) :: drs_data(:,:,:,:)
275 complex(real64), pointer, intent(inout) :: zrs_data(:,:,:,:)
276 complex(real64), pointer, intent(inout) :: fs_data(:,:,:,:)
277
278 type(c_ptr) :: address
279
280 push_sub(fftw_alloc_memory)
281
282 if (is_real) then
283 address = fftw_alloc_real(int(product(rs_dims), c_size_t))
284 call c_f_pointer(address, drs_data, rs_dims)
285 else
286 address = fftw_alloc_complex(int(product(rs_dims), c_size_t))
287 call c_f_pointer(address, zrs_data, rs_dims)
288 end if
289
290 address = fftw_alloc_complex(int(product(fs_dims), c_size_t))
291 call c_f_pointer(address, fs_data, fs_dims)
292
293 pop_sub(fftw_alloc_memory)
294 end subroutine fftw_alloc_memory
295
296 ! ---------------------------------------------------------
297 subroutine fftw_free_memory(is_real, drs_data, zrs_data, fs_data)
298 logical, intent(in) :: is_real
299 real(real64), pointer, intent(inout) :: drs_data(:,:,:,:)
300 complex(real64), pointer, intent(inout) :: zrs_data(:,:,:,:)
301 complex(real64), pointer, intent(inout) :: fs_data(:,:,:,:)
302
303 push_sub(fftw_free_memory)
304
305 if (is_real) then
306 if (associated(drs_data)) then
307 call fftw_free(c_loc(drs_data))
308 nullify(drs_data)
309 end if
310 else
311 if (associated(zrs_data)) then
312 call fftw_free(c_loc(zrs_data))
313 nullify(zrs_data)
314 end if
315 end if
316 if (associated(fs_data)) then
317 call fftw_free(c_loc(fs_data))
318 nullify(fs_data)
319 end if
320
321 pop_sub(fftw_free_memory)
322 end subroutine fftw_free_memory
323
324end module fftw_oct_m
325
326!! Local Variables:
327!! mode: f90
328!! coding: utf-8
329!! End:
subroutine, public fftw_free_memory(is_real, drs_data, zrs_data, fs_data)
Definition: fftw.F90:380
subroutine, public fftw_prepare_plan(plan, dim, n, howmany, batch_axis, is_real, sign, flags, din_, cin_, cout_)
Definition: fftw.F90:183
subroutine, public fftw_get_dims(rs_n, is_real, fs_n)
Definition: fftw.F90:336
subroutine, public fftw_alloc_memory(rs_dims, is_real, fs_dims, drs_data, zrs_data, fs_data)
Allocate the FFTW work buffers. The rank-4 dimension arrays (which already carry the batch axis at th...
Definition: fftw.F90:353
int true(void)