Octopus
nfft.F90
Go to the documentation of this file.
1!! Copyright (C) 2011 U. De Giovannini
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19
20#include "global.h"
21
22module nfft_oct_m
24 use debug_oct_m
25 use global_oct_m
26 use, intrinsic :: iso_c_binding
30 use parser_oct_m
32 implicit none
33
34 private
35
36 public :: &
37 nfft_t, &
39 nfft_init, &
40 nfft_end, &
48
49 ! global constants
50 integer, public, parameter :: &
51 nfft_real = 0, &
52 nfft_complex = 1
53
54 !NFFT flags
55 integer, public, parameter :: &
56 NFFT_PRE_PHI_HUT = 0, &
57 nfft_fg_psi = 2, &
58 nfft_pre_lin_psi = 4, &
59 nfft_pre_fg_psi = 8, &
60 nfft_pre_psi = 16, &
61 nfft_pre_full_psi = 32, &
62 nfft_malloc_x = 64, &
63 nfft_malloc_f_hat = 128, &
64 nfft_malloc_f = 256, &
66 nfft_fftw_init = 1024
67
68
69 type nfft_t
70 private
71
72 integer :: N(3)
73 integer :: M(3)
74 integer :: dim
75 integer :: fftN(3)
76 real(real64), public :: norm
77
78 ! Guru options
79 logical, public :: set_defaults = .false.
80 logical, public :: guru
81 integer, public :: precompute
82 integer, public :: mm
83 real(real64), public :: sigma
84
85 type(c_ptr) :: plan
86
87 end type nfft_t
88
89
90contains
91
92
93
94 ! ---------------------------------------------------------
95 ! GURU options
96 subroutine nfft_guru_options(nfft, namespace)
97 type(nfft_t), intent(inout) :: nfft
98 type(namespace_t), intent(in) :: namespace
99
100 push_sub(nfft_guru_options)
101
102 !%Variable NFFTGuruInterface
103 !%Type logical
104 !%Default false
105 !%Section Mesh::FFTs
106 !%Description
107 !% Perform NFFT with guru interface. This permits the fine tuning of several critical parameters.
108 !%End
109 call parse_variable(namespace, 'NFFTGuruInterface', .false., nfft%guru)
110
111
112 !%Variable NFFTCutoff
113 !%Type integer
114 !%Default 6
115 !%Section Mesh::FFTs
116 !%Description
117 !% Cut-off parameter of the window function.
118 !% See NFFT manual for details.
119 !%End
120 call parse_variable(namespace, 'NFFTCutoff', 6, nfft%mm)
121
122
123 !%Variable NFFTOversampling
124 !%Type float
125 !%Default 2
126 !%Section Mesh::FFTs
127 !%Description
128 !% NFFT oversampling factor (sigma). This will rule the size of the FFT under the hood.
129 !%End
130 call parse_variable(namespace, 'NFFTOversampling', m_two, nfft%sigma)
131
132 !%Variable NFFTPrecompute
133 !%Type integer
134 !%Default NFFT_PRE_PSI
135 !%Section Mesh::FFTs
136 !%Description
137 !% NFFT precomputation strategy.
138 !%Option NFFT_PRE_LIN_PSI 4
139 !% This method implements a linear interpolation from a lookup table.
140 !%Option NFFT_PRE_PSI 16
141 !% This method uses a medium amount of memory to store d*(2*m+1)*M real numbers and requires at most
142 !% 2(2m + 1)d extra multiplications for each node.
143 !% This is the default option.
144 !%Option NFFT_PRE_FULL_PSI 32
145 !% Is the fastest method but requires a large amount of memory as it requires to store (2*m+1)^d*M
146 !% real numbers. No extra operations are needed during matrix vector multiplication.
147 !%End
148 call parse_variable(namespace, 'NFFTPrecompute', nfft_pre_psi, nfft%precompute)
149 if (.not. varinfo_valid_option('NFFTPrecompute', nfft%precompute)) call messages_input_error(namespace, 'NFFTPrecompute')
150! call messages_print_var_option("NFFTPrecompute", nfft%precompute, namespace=namespace)
151
152! if (.not. varinfo_valid_option('NFFTPrecompute', nfft%precompute, is_flag=.true.)) then
153! call messages_input_error('NFFTPrecompute')
154! end if
155
156
157 pop_sub(nfft_guru_options)
158 end subroutine nfft_guru_options
159
160
161
162 ! ---------------------------------------------------------
163 subroutine nfft_init(nfft, nfft_options, N, dim, M, optimize)
164 type(nfft_t), intent(inout) :: nfft
165 type(nfft_t), intent(in) :: nfft_options
166 integer, intent(inout) :: n(3)
167 integer, intent(inout) :: m(3)
168 integer, intent(in) :: dim
169 logical, optional, intent(in) :: optimize
170
171 integer :: ii, my_n(3)
172 logical :: optimize_
173 integer :: nfft_flags
176 push_sub(nfft_init)
177
179
180 nfft%dim = dim
181 nfft%M(:) = m(:)
182 nfft%N(:) = n(:)
183
184 if (.not. nfft%set_defaults) then
185 nfft%guru = nfft_options%guru
186 nfft%mm = nfft_options%mm
187 nfft%sigma = nfft_options%sigma
188 nfft%precompute = nfft_options%precompute
189 end if
190
191 ! set unused dimensions to 1
192 nfft%M(dim+1:3) = 1
193
194 my_n = 0
195 do ii = 1, dim
196 my_n(ii) = n(ii)*int(nfft%sigma)
197 if (optimize_ .or. (.not. nfft%guru)) call loct_fft_optimize(my_n(ii), 1) ! ask for an odd number
198 end do
199
200 nfft%fftN(1:dim) = my_n(1:dim)
201
202 if (nfft%guru) then ! Guru interface
203 nfft_flags = nfft_pre_phi_hut + nfft_malloc_x +nfft_malloc_f_hat +&
205
206 nfft_flags = nfft_flags + nfft%precompute
207
208 call oct_nfft_init_guru(nfft%plan, dim, n, m(1)*m(2)*m(3), my_n, nfft%mm, &
209 nfft_flags, fftw_measure + fftw_destroy_input)
210
211 else ! Default interfaces
212
213 select case (dim)
214 case (3)
215 call oct_nfft_init_3d(nfft%plan, n(1), n(2),n(3), m(1)*m(2)*m(3))
216 case (2)
217 call oct_nfft_init_2d(nfft%plan, n(1), n(2), m(1)*m(2))
218 case (1)
219 call oct_nfft_init_1d(nfft%plan,n(1),m(1))
220 end select
221
222 end if
223
224
225 pop_sub(nfft_init)
226 end subroutine nfft_init
227
228 ! ---------------------------------------------------------
229 subroutine nfft_write_info(nfft)
230 type(nfft_t), intent(inout) :: nfft
231
232 integer :: idir
233! integer :: mm
234
235 push_sub(nfft_write_info)
236
237 call messages_write("Info: NFFT parameters")
238 call messages_new_line()
239 call messages_write(" Fourier coefficients N = ")
240 do idir = 1, nfft%dim
241 call messages_write(nfft%N(idir))
242 if (idir < nfft%dim) call messages_write(" x ")
243 end do
244 call messages_new_line()
245
246 call messages_write(" Spatial nodes M = ")
247
248! mm = nfft%M(1)*nfft%M(2)*nfft%M(3)
249!
250! call messages_write(mm)
251! call messages_new_line()
252 do idir = 1, nfft%dim
253 call messages_write(nfft%M(idir))
254 if (idir < nfft%dim) call messages_write(" x ")
255 end do
257
258
259 call messages_write(" Oversampling factor sigma = ")
260 call messages_write(nfft%sigma)
261 call messages_new_line()
262
263 call messages_write(" FFT grid size n = ")
264 do idir = 1, nfft%dim
265 call messages_write(nfft%fftN(idir))
266 if (idir < nfft%dim) call messages_write(" x ")
267 end do
268 call messages_new_line()
269
270 call messages_write(" Real space cutoff m = ")
271 call messages_write(nfft%mm)
272 call messages_new_line()
273
274 call messages_write(" Pre-computation strategy = ")
275 select case (nfft%precompute)
276 case (nfft_pre_lin_psi)
277 call messages_write(" NFFT_PRE_LIN_PSI")
278 case (nfft_pre_psi)
279 call messages_write(" NFFT_PRE_PSI")
280 case (nfft_pre_full_psi)
281 call messages_write(" NFFT_PRE_FULL_PSI")
282 end select
283
284 call messages_info()
285
286
287 pop_sub(nfft_write_info)
288 end subroutine nfft_write_info
289
290
291 ! ---------------------------------------------------------
292 subroutine nfft_end(nfft)
293 type(nfft_t), intent(inout) :: nfft
294
295 push_sub(nfft_end)
296
297 call oct_nfft_finalize(nfft%plan)
298
299 pop_sub(nfft_end)
300 end subroutine nfft_end
301
302 ! ---------------------------------------------------------
303 ! This routine is intend to copy the configuration parameters
304 ! rather the whole structure.
305 ! ---------------------------------------------------------
306 subroutine nfft_copy_info(in, out)
307 type(nfft_t), intent(in) :: in
308 type(nfft_t), intent(out) :: out
309
310
311 push_sub(nfft_copy_info)
312
313 out%N = in%N
314 out%M = in%M
315 out%dim = in%dim
316 out%fftN = in%fftN
317 out%norm = in%norm
318
319 out%guru = in%guru
320 out%precompute = in%precompute
321 out%mm = in%mm
322 out%sigma = in%sigma
323
324
325 pop_sub(nfft_copy_info)
326 end subroutine nfft_copy_info
327
328
329 !----------------------------------------------------------
330 ! Precompute the plan according to the position the grid nodes in real space
331 ! x axis is X1, y axis is X2, z axis is X3
332 ! NOTE: We only allow different spacing for each direction x,y,z
333 ! the NFFT interface however is more general
334 ! ---------------------------------------------------------
335 subroutine nfft_precompute(nfft, X1, X2, X3)
336 type(nfft_t), intent(inout) :: nfft
337 real(real64), intent(in) :: x1(:)
338 real(real64), optional, intent(in) :: x2(:)
339 real(real64), optional, intent(in) :: x3(:)
340
341
342
343 real(real64) :: x1_(1:nfft%m(1)), x2_(1:nfft%m(2)), x3_(1:nfft%m(3))
344 real(real64) :: length, cc, eps, dx1(1:nfft%m(1)-1), dx2(1:nfft%m(2)-1), dx3(1:nfft%m(3)-1)
345
346 integer :: ii
347
348 push_sub(nfft_precompute)
349
350! eps = 1.000001 ! the sample nodes must be in [0.5,0.5)
351 eps = m_one+m_epsilon ! the sample nodes must be in [0.5,0.5)
352
353 select case (nfft%dim)
354 case (3)
355 length = (maxval(x1)-minval(x1))*eps
356 cc = (minval(x1)+maxval(x1))/m_two
357 x1_ =(x1-cc)/length
358 length = (maxval(x2)-minval(x2))*eps
359 cc = (minval(x2)+maxval(x2))/m_two
360 x2_ =(x2-cc)/length
361 length = (maxval(x3)-minval(x3))*eps
362 cc = (minval(x3)+maxval(x3))/m_two
363 x3_ =(x3-cc)/length
364 call oct_nfft_precompute_one_psi_3d(nfft%plan, nfft%M, x1_, x2_, x3_)
365
366 ! Set the normalization factor
367 do ii = 1, nfft%M(1)-1
368 dx1(ii)= abs(x1_(ii+1)-x1_(ii))
369 end do
370 do ii = 1, nfft%M(2)-1
371 dx2(ii)= abs(x2_(ii+1)-x2_(ii))
372 end do
373 do ii = 1, nfft%M(3)-1
374 dx3(ii)= abs(x3_(ii+1)-x3_(ii))
375 end do
376 nfft%norm = m_one/(minval(dx1(:)) * minval(dx2(:)) * minval(dx3(:)))
377
378 case (2)
379 length = (maxval(x1)-minval(x1))*eps
380 cc = (minval(x1)+maxval(x1))/m_two
381 x1_ =(x1-cc)/length
382 length = (maxval(x2)-minval(x2))*eps
383 cc = (minval(x2)+maxval(x2))/m_two
384 x2_ =(x2-cc)/length
385 call oct_nfft_precompute_one_psi_2d(nfft%plan, nfft%M, x1_, x2_)
386
387 ! Set the normalization factor
388 do ii = 1, nfft%M(1)-1
389 dx1(ii)= abs(x1_(ii+1)-x1_(ii))
390 end do
391 do ii = 1, nfft%M(2)-1
392 dx2(ii)= abs(x2_(ii+1)-x2_(ii))
393 end do
394 nfft%norm = m_one/(minval(dx1(:)) * minval(dx2(:)))
395
396
397 case (1)
398 length = (maxval(x1)-minval(x1))*eps
399 cc = (minval(x1)+maxval(x1))/m_two
400 x1_ =(x1-cc)/length
401 call oct_nfft_precompute_one_psi_1d(nfft%plan,nfft%M(1),x1_)
402
403 ! Set the normalization factor
404 do ii = 1, nfft%M(1)-1
405 dx1(ii)= abs(x1_(ii+1)-x1_(ii))
406 end do
407 nfft%norm = m_one/(minval(dx1(:)))
408
409 end select
410
411 ! check the plan
412 call oct_nfft_check(nfft%plan)
413
414
415 write(message(1), '(a)') "Info: NFFT plan precomputed."
416 call messages_info(1)
417
418
419 pop_sub(nfft_precompute)
420 end subroutine nfft_precompute
421
422#include "undef.F90"
423#include "real.F90"
424#include "nfft_inc.F90"
425
426#include "undef.F90"
427#include "complex.F90"
428#include "nfft_inc.F90"
429
430end module nfft_oct_m
431
432!! Local Variables:
433!! mode: f90
434!! coding: utf-8
435!! End:
subroutine optimize()
real(real64), parameter, public m_two
Definition: global.F90:189
real(real64), parameter, public m_epsilon
Definition: global.F90:203
real(real64), parameter, public m_one
Definition: global.F90:188
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
subroutine, public messages_new_line()
Definition: messages.F90:1146
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
integer, parameter, public nfft_pre_lin_psi
Definition: nfft.F90:148
integer, parameter, public nfft_complex
Definition: nfft.F90:143
subroutine, public nfft_write_info(nfft)
Definition: nfft.F90:323
subroutine, public znfft_forward(nfft, in, out)
Definition: nfft.F90:721
integer, parameter, public nfft_fftw_init
Definition: nfft.F90:148
subroutine, public nfft_end(nfft)
Definition: nfft.F90:386
integer, parameter, public nfft_pre_fg_psi
Definition: nfft.F90:148
integer, parameter, public nfft_fg_psi
Definition: nfft.F90:148
subroutine, public nfft_init(nfft, nfft_options, N, dim, M, optimize)
Definition: nfft.F90:257
subroutine, public nfft_copy_info(in, out)
Definition: nfft.F90:400
integer, parameter, public nfft_malloc_x
Definition: nfft.F90:148
integer, parameter, public nfft_malloc_f_hat
Definition: nfft.F90:148
subroutine, public dnfft_forward(nfft, in, out)
Definition: nfft.F90:584
integer, parameter, public nfft_malloc_f
Definition: nfft.F90:148
subroutine, public dnfft_backward(nfft, in, out)
Definition: nfft.F90:615
integer, parameter, public nfft_pre_full_psi
Definition: nfft.F90:148
integer, parameter, public nfft_fft_out_of_place
Definition: nfft.F90:148
subroutine, public znfft_backward(nfft, in, out)
Definition: nfft.F90:752
subroutine, public nfft_precompute(nfft, X1, X2, X3)
Definition: nfft.F90:429
integer, parameter, public nfft_pre_psi
Definition: nfft.F90:148
subroutine, public nfft_guru_options(nfft, namespace)
Definition: nfft.F90:190
int true(void)