Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_fft_fftw3.F90
Go to the documentation of this file.
1 !**************************************************************
2 ! Copyright INRIA
3 ! Authors :
4 ! CALVI project team
5 !
6 ! This code SeLaLib (for Semi-Lagrangian-Library)
7 ! is a parallel library for simulating the plasma turbulence
8 ! in a tokamak.
9 !
10 ! This software is governed by the CeCILL-B license
11 ! under French law and abiding by the rules of distribution
12 ! of free software. You can use, modify and redistribute
13 ! the software under the terms of the CeCILL-B license as
14 ! circulated by CEA, CNRS and INRIA at the following URL
15 ! "http://www.cecill.info".
16 !**************************************************************
66 
67 module sll_m_fft
68 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
69 #include "sll_working_precision.h"
70 #include "sll_assert.h"
71 #include "sll_memory.h"
72 #include "sll_errors.h"
73 #include "sll_fftw.h"
74 
75  use sll_m_fftw3
76  use, intrinsic :: iso_c_binding, only: &
77  c_f_pointer, &
78  c_loc
79 
80  implicit none
81 
82  public :: &
83  sll_t_fft, &
118 
119  private
120 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
121 
124 
125  fftw_plan, private :: fftw
126  logical :: normalized
127  sll_int32 :: direction
128  sll_int32 :: problem_rank
129  sll_int32, allocatable :: problem_shape(:)
130 
131  sll_comp64, allocatable, private :: scratch(:)
132  sll_int32, private :: transform_type
133 
134  end type sll_t_fft
135 
136  ! Flags for direction (values as in fftw3.f03)
137  integer, parameter :: sll_p_fft_forward = fftw_forward
138  integer, parameter :: sll_p_fft_backward = fftw_backward
139 
140  ! Flags for initialization of the plan (values as in fftw3.f03)
141  integer(C_INT), parameter :: sll_p_fft_measure = fftw_measure
142  integer(C_INT), parameter :: sll_p_fft_patient = fftw_patient
143  integer(C_INT), parameter :: sll_p_fft_estimate = fftw_estimate
144  integer(C_INT), parameter :: sll_p_fft_exhaustive = fftw_exhaustive
145  integer(C_INT), parameter :: sll_p_fft_wisdom_only = fftw_wisdom_only ! 2097152 !< FFTW planning-rigor flag FFTW_WISDOM_ONLY (planner only initialized if wisdom is available) [value 2097152]
146 
147 ! Flags to pass when we create a new plan
148 ! We can define 31 different flags.
149 ! The value assigned to the flag can only be a power of two.
150 ! See section "How-to manipulate flags ?" for more information.
151 
152  ! Flags for the various types of transform (to make sure same type of init and execute functions are used)
153  integer, parameter :: p_fftw_c2c_1d = 0
154  integer, parameter :: p_fftw_r2r_1d = 1
155  integer, parameter :: p_fftw_r2c_1d = 2
156  integer, parameter :: p_fftw_c2r_1d = 3
157  integer, parameter :: p_fftw_c2c_2d = 4
158  integer, parameter :: p_fftw_r2r_2d = 5
159  integer, parameter :: p_fftw_r2c_2d = 6
160  integer, parameter :: p_fftw_c2r_2d = 7
161  integer, parameter :: p_fftw_c2c_3d = 8
162 
163 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
164 contains
165 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
166 
167  !-----------------------------------------------------------------------------
169  !-----------------------------------------------------------------------------
171  print *, 'The library used is FFTW'
172  end subroutine
173 
174  !-----------------------------------------------------------------------------
176  !-----------------------------------------------------------------------------
177  function sll_f_fft_allocate_aligned_complex(n) result(data)
178  sll_int32, intent(in) :: n
179  complex(C_DOUBLE_COMPLEX), pointer :: data(:)
180 
181  type(c_ptr) :: ptr_data ! C pointer needed for allocation
182 
183 #ifdef FFTW_F2003
184  ptr_data = fftw_alloc_complex(int(n, kind=c_size_t))
185  call c_f_pointer(ptr_data, data, [n])
186 #else
187  allocate (data(n))
188  sll_warning('sll_f_fft_allocate_aligned_complex', 'Aligned allocation only supported by F2003. Usual allocation.')
189 #endif
190 
192 
193  !-----------------------------------------------------------------------------
195  !-----------------------------------------------------------------------------
196  function sll_f_fft_allocate_aligned_real(n) result(data)
197  sll_int32, intent(in) :: n
198  real(c_double), pointer :: data(:)
199 
200  type(c_ptr) :: ptr_data ! C pointer needed for allocation
201 
202 #ifdef FFTW_F2003
203  ptr_data = fftw_alloc_real(int(n, kind=c_size_t))
204  call c_f_pointer(ptr_data, data, [n])
205 #else
206  allocate (data(n))
207  sll_warning('sll_f_fft_allocate_aligned_real', 'Aligned allocation only supported by F2003. Usual allocation.')
208 #endif
209 
211 
212  !-----------------------------------------------------------------------------
214  !-----------------------------------------------------------------------------
216  complex(C_DOUBLE_COMPLEX), pointer :: data(:)
217 
218 #ifdef FFTW_F2003
219  type(c_ptr) :: ptr_data ! C pointer needed for deallocation
220  ptr_data = c_loc(data(1))
221  call fftw_free(ptr_data)
222 #else
223  deallocate (data)
224  sll_warning('sll_s_fft_deallocate_aligned_complex', 'Aligned deallocation only supported by F2003. Usual deallocation.')
225 #endif
226 
228 
229  !-----------------------------------------------------------------------------
231  !-----------------------------------------------------------------------------
233  real(c_double), pointer :: data(:)
234 
235 #ifdef FFTW_F2003
236  type(c_ptr) :: ptr_data ! C pointer needed for deallocation
237  ptr_data = c_loc(data(1))
238  call fftw_free(ptr_data)
239 #else
240  deallocate (data)
241  sll_warning('sll_s_fft_deallocate_aligned_real', 'Aligned deallocation only supported by F2003. Usual deallocation.')
242 #endif
243 
244  end subroutine sll_s_fft_deallocate_aligned_real
245 
246  !-----------------------------------------------------------------------------
249  !-----------------------------------------------------------------------------
250  subroutine sll_s_fft_get_k_list_c2c_1d(plan, k_list)
251  type(sll_t_fft), intent(in) :: plan
252  sll_int32, intent(out) :: k_list(0:)
253 
254  sll_int32 :: k ! single mode
255  sll_int32 :: n ! problem size
256  n = plan%problem_shape(1)
257 
258  if (size(k_list) /= n) then
259  sll_error("sll_s_fft_get_k_list_c2c_1d", "k_list must have n elements")
260  end if
261 
262  k_list(0:n/2) = [(k, k=0, n/2)]
263  k_list(n/2 + 1:n - 1) = [(k - n, k=n/2 + 1, n - 1)]
264 
265  end subroutine sll_s_fft_get_k_list_c2c_1d
266 
267  !-----------------------------------------------------------------------------
270  !-----------------------------------------------------------------------------
271  subroutine sll_s_fft_get_k_list_r2r_1d(plan, k_list)
272  type(sll_t_fft), intent(in) :: plan
273  sll_int32, intent(out) :: k_list(0:)
274 
275  sll_int32 :: k ! single mode
276  sll_int32 :: n ! problem size
277  n = plan%problem_shape(1)
278 
279  if (size(k_list) /= n) then
280  sll_error("sll_s_fft_get_k_list_r2r_1d", "k_list must have n elements")
281  end if
282 
283  k_list(0:n/2) = [(k, k=0, n/2)]
284  k_list(n/2 + 1:n - 1) = [(n - k, k=n/2 + 1, n - 1)]
285 
286  end subroutine sll_s_fft_get_k_list_r2r_1d
287 
288  !-----------------------------------------------------------------------------
291  !-----------------------------------------------------------------------------
292  subroutine sll_s_fft_get_k_list_r2c_1d(plan, k_list)
293  type(sll_t_fft), intent(in) :: plan
294  sll_int32, intent(out) :: k_list(0:)
295 
296  sll_int32 :: k ! single mode
297  sll_int32 :: n_2 ! problem size / 2 (rounded down)
298  n_2 = plan%problem_shape(1)/2
299 
300  if (size(k_list) /= n_2 + 1) then
301  sll_error("sll_s_fft_get_k_list_r2c_1d", "k_list must have n/2+1 elements")
302  end if
303 
304  k_list(:) = [(k, k=0, n_2)]
305 
306  end subroutine sll_s_fft_get_k_list_r2c_1d
307 
308  !-----------------------------------------------------------------------------
310  !-----------------------------------------------------------------------------
311  function sll_f_fft_get_mode_r2c_1d(plan, data, k) result(ck)
312  type(sll_t_fft), intent(in) :: plan
313  sll_real64, intent(in) :: data(0:)
314  sll_int32, intent(in) :: k
315  sll_comp64 :: ck
316 
317  sll_int32 :: n ! problem size
318  n = plan%problem_shape(1)
319 
320  if (k == 0) then; ck = cmplx(data(k), 0.0_f64, kind=f64)
321  else if (k <= (n + 1)/2 - 1) then; ck = cmplx(data(k), data(n - k), kind=f64)
322  else if (k == n/2) then; ck = cmplx(data(k), 0.0_f64, kind=f64)
323  else if (k <= n - 1) then; ck = cmplx(data(n - k), -data(k), kind=f64)
324  else
325  sll_error("sll_f_fft_get_mode_r2c_1d", "k must be between 0 and n-1")
326  end if
327 
328  end function sll_f_fft_get_mode_r2c_1d
329 
330  !-----------------------------------------------------------------------------
332  !-----------------------------------------------------------------------------
333  subroutine sll_s_fft_set_mode_c2r_1d(plan, data, ck, k)
334  type(sll_t_fft), intent(in) :: plan
335  sll_real64, intent(inout) :: data(0:)
336  sll_comp64, intent(in) :: ck
337  sll_int32, intent(in) :: k
338 
339  sll_int32 :: n ! problem size
340  n = plan%problem_shape(1)
341 
342  if (k == 0) then; data(0) = real(ck) ! imaginary part ignored
343  else if (k <= (n + 1)/2 - 1) then; data(k) = real(ck); data(n - k) = aimag(ck)
344  else if (k == n/2) then; data(k) = real(ck) ! imaginary part ignored
345  else if (k <= n - 1) then; data(n - k) = real(ck); data(k) = -aimag(ck)
346  else
347  sll_error("sll_s_fft_set_mode_c2r_1d", "k must be between 0 and n-1")
348  end if
349 
350  end subroutine sll_s_fft_set_mode_c2r_1d
351 
352 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
353 !
354 ! COMPLEX to COMPLEX (1D)
355 !
356 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
357 
358  !-----------------------------------------------------------------------------
360  !-----------------------------------------------------------------------------
361  subroutine sll_s_fft_init_c2c_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
362  type(sll_t_fft) :: plan
363  sll_int32, intent(in) :: nx
364  sll_comp64, intent(inout) :: array_in(:)
365  sll_comp64, intent(inout) :: array_out(:)
366  sll_int32, intent(in) :: direction
367  logical, optional, intent(in) :: normalized
368  logical, optional, intent(in) :: aligned
372  sll_int32, optional, intent(in) :: optimization
373 
374  ! local variables
375  sll_int32 :: ierr
376  sll_int32 :: flag_fftw
377 
378  plan%transform_type = p_fftw_c2c_1d
379  plan%direction = direction
380  if (present(normalized)) then
381  plan%normalized = normalized
382  else
383  plan%normalized = .false.
384  end if
385  ! Set the information about the algorithm to compute the plan. The default is FFTW_ESTIMATE
386  if (present(optimization)) then
387  flag_fftw = optimization
388  else
389  flag_fftw = fftw_estimate
390  end if
391  if (present(aligned)) then
392  if (aligned .EQV. .false.) then
393  flag_fftw = flag_fftw + fftw_unaligned
394  end if
395  else
396  flag_fftw = flag_fftw + fftw_unaligned
397  end if
398  plan%problem_rank = 1
399  sll_allocate(plan%problem_shape(1), ierr)
400  plan%problem_shape = (/nx/)
401 
402 #ifdef FFTW_F2003
403  plan%fftw = fftw_plan_dft_1d(nx, array_in, array_out, direction, flag_fftw)
404 #else
405  call dfftw_plan_dft_1d(plan%fftw, nx, array_in, array_out, direction, flag_fftw)
406 #endif
407 
408  end subroutine sll_s_fft_init_c2c_1d
409 
410  !-----------------------------------------------------------------------------
412  !-----------------------------------------------------------------------------
413  subroutine sll_s_fft_exec_c2c_1d(plan, array_in, array_out)
414  type(sll_t_fft), intent(in) :: plan
415  sll_comp64, intent(inout) :: array_in(:)
416  sll_comp64, intent(inout) :: array_out(:)
417 
418  sll_real64 :: factor
419 
420  sll_assert(plan%transform_type == p_fftw_c2c_1d)
421 
422  call fftw_execute_dft(plan%fftw, array_in, array_out)
423 
424  if (plan%normalized .EQV. .true.) then
425  factor = 1.0_f64/real(plan%problem_shape(1), kind=f64)
426  array_out = cmplx(factor, 0.0, f64)*array_out
427  end if
428  end subroutine
429 
430 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
431 !
432 ! COMPLEX to COMPLEX (2D)
433 !
434 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
435 
436  !-----------------------------------------------------------------------------
438  !-----------------------------------------------------------------------------
439  subroutine sll_s_fft_init_c2c_2d(plan, nx, ny, array_in, array_out, direction, normalized, aligned, optimization)
440  type(sll_t_fft), intent(out) :: plan
441  sll_int32, intent(in) :: nx
442  sll_int32, intent(in) :: ny
443  sll_comp64, intent(inout) :: array_in(0:, 0:)
444  sll_comp64, intent(inout) :: array_out(0:, 0:)
445  sll_int32, intent(in) :: direction
446  logical, optional, intent(in) :: normalized
447  logical, optional, intent(in) :: aligned
448  sll_int32, optional, intent(in) :: optimization
449 
450 
451  sll_int32 :: ierr
452  sll_int32 :: flag_fftw
453 
454  plan%transform_type = p_fftw_c2c_2d
455  plan%direction = direction
456  if (present(normalized)) then
457  plan%normalized = normalized
458  else
459  plan%normalized = .false.
460  end if
461  ! Set the information about the algorithm to compute the plan. The default is FFTW_ESTIMATE
462  if (present(optimization)) then
463  flag_fftw = optimization
464  else
465  flag_fftw = fftw_estimate
466  end if
467  if (present(aligned)) then
468  if (aligned .EQV. .false.) then
469  flag_fftw = flag_fftw + fftw_unaligned
470  end if
471  else
472  flag_fftw = flag_fftw + fftw_unaligned
473  end if
474  plan%problem_rank = 2
475  sll_allocate(plan%problem_shape(2), ierr)
476  plan%problem_shape = (/nx, ny/)
477 
478  !We must switch the dimension. It's a fftw convention.
479 
480 #ifdef FFTW_F2003
481  plan%fftw = fftw_plan_dft_2d(ny, nx, array_in, array_out, direction, flag_fftw)!FFTW_ESTIMATE + FFTW_UNALIGNED)
482 #else
483  call dfftw_plan_dft_2d(plan%fftw, ny, nx, array_in, array_out, direction, flag_fftw)!FFTW_ESTIMATE + FFTW_UNALIGNED)
484 #endif
485 
486  end subroutine sll_s_fft_init_c2c_2d
487 
488  !-----------------------------------------------------------------------------
490  !-----------------------------------------------------------------------------
491  subroutine sll_s_fft_exec_c2c_2d(plan, array_in, array_out)
492  type(sll_t_fft), intent(in) :: plan
493  sll_comp64, intent(inout) :: array_in(0:, 0:)
494  sll_comp64, intent(inout) :: array_out(0:, 0:)
495 
496  sll_real64 :: factor
497 
498  call fftw_execute_dft(plan%fftw, array_in, array_out)
499 
500  if (plan%normalized .EQV. .true.) then
501  factor = 1.0_f64/real(plan%problem_shape(1)*plan%problem_shape(2), kind=f64)
502  array_out = cmplx(factor, 0.0, f64)*array_out
503  end if
504 
505  end subroutine
506 
507 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
508 !
509 ! COMPLEX to COMPLEX (3D)
510 !
511 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
512 
513  !-----------------------------------------------------------------------------
515  !-----------------------------------------------------------------------------
516  subroutine sll_s_fft_init_c2c_3d(plan, nx, ny, nz, array_in, array_out, direction, normalized, aligned, optimization)
517  type(sll_t_fft), intent(out) :: plan
518  sll_int32, intent(in) :: nx
519  sll_int32, intent(in) :: ny
520  sll_int32, intent(in) :: nz
521  sll_comp64, intent(inout) :: array_in(0:, 0:, 0:)
522  sll_comp64, intent(inout) :: array_out(0:, 0:, 0:)
523  sll_int32, intent(in) :: direction
524  logical, optional, intent(in) :: normalized
525  logical, optional, intent(in) :: aligned
526  sll_int32, optional, intent(in) :: optimization
527 
528 
529  sll_int32 :: ierr
530  sll_int32 :: flag_fftw
531 
532  plan%transform_type = p_fftw_c2c_3d
533  plan%direction = direction
534  if (present(normalized)) then
535  plan%normalized = normalized
536  else
537  plan%normalized = .false.
538  end if
539  ! Set the information about the algorithm to compute the plan. The default is FFTW_ESTIMATE
540  if (present(optimization)) then
541  flag_fftw = optimization
542  else
543  flag_fftw = fftw_estimate
544  end if
545  if (present(aligned)) then
546  if (aligned .EQV. .false.) then
547  flag_fftw = flag_fftw + fftw_unaligned
548  end if
549  else
550  flag_fftw = flag_fftw + fftw_unaligned
551  end if
552  plan%problem_rank = 3
553  sll_allocate(plan%problem_shape(3), ierr)
554  plan%problem_shape = [nx, ny, nz]
555 
556  !We must switch the dimension. It's a fftw convention.
557 
558 #ifdef FFTW_F2003
559  plan%fftw = fftw_plan_dft_3d(nz, ny, nx, array_in, array_out, direction, flag_fftw)!FFTW_ESTIMATE + FFTW_UNALIGNED)
560 #else
561  call dfftw_plan_dft_3d(plan%fftw, nz, ny, nx, array_in, array_out, direction, flag_fftw)!FFTW_ESTIMATE + FFTW_UNALIGNED)
562 #endif
563 
564  end subroutine sll_s_fft_init_c2c_3d
565 
566  !-----------------------------------------------------------------------------
568  !-----------------------------------------------------------------------------
569  subroutine sll_s_fft_exec_c2c_3d(plan, array_in, array_out)
570  type(sll_t_fft), intent(in) :: plan
571  sll_comp64, intent(inout) :: array_in(0:, 0:, 0:)
572  sll_comp64, intent(inout) :: array_out(0:, 0:, 0:)
573 
574  sll_real64 :: factor
575 
576  call fftw_execute_dft(plan%fftw, array_in, array_out)
577 
578  if (plan%normalized) then
579  factor = 1.0_f64/real(plan%problem_shape(1)*plan%problem_shape(2)*plan%problem_shape(3), kind=f64)
580  array_out = cmplx(factor, 0.0, f64)*array_out
581  end if
582 
583  end subroutine
584 
585 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
586 !
587 ! REAL to REAL (1D)
588 !
589 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
590 
591  !-----------------------------------------------------------------------------
593  !-----------------------------------------------------------------------------
594  subroutine sll_s_fft_init_r2r_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
595  type(sll_t_fft), intent(out) :: plan
596  sll_int32, intent(in) :: nx
597  sll_real64, intent(inout) :: array_in(:)
598  sll_real64, intent(inout) :: array_out(:)
599  sll_int32, intent(in) :: direction
600  logical, optional, intent(in) :: normalized
601  logical, optional, intent(in) :: aligned
602  sll_int32, optional, intent(in) :: optimization
603 
604 
605  sll_int32 :: ierr
606  sll_int32 :: flag_fftw
607 
608  plan%transform_type = p_fftw_r2r_1d
609  plan%direction = direction
610  if (present(normalized)) then
611  plan%normalized = normalized
612  else
613  plan%normalized = .false.
614  end if
615  ! Set the information about the algorithm to compute the plan. The default is FFTW_ESTIMATE
616  if (present(optimization)) then
617  flag_fftw = optimization
618  else
619  flag_fftw = fftw_estimate
620  end if
621  if (present(aligned)) then
622  if (aligned .EQV. .false.) then
623  flag_fftw = flag_fftw + fftw_unaligned
624  end if
625  else
626  flag_fftw = flag_fftw + fftw_unaligned
627  end if
628  plan%problem_rank = 1
629  sll_allocate(plan%problem_shape(1), ierr)
630  plan%problem_shape = (/nx/)
631 
632  if (direction .eq. sll_p_fft_forward) then
633 #ifdef FFTW_F2003
634  plan%fftw = fftw_plan_r2r_1d(nx, array_in, array_out, fftw_r2hc, flag_fftw)
635 #else
636  ! This would be the call to actually create a r2r plan
637  !call dfftw_plan_r2r_1d(plan%fftw,nx,array_in,array_out,FFTW_R2HC,flag_fftw)
638 
639  allocate (plan%scratch(nx/2 + 1))
640  call dfftw_plan_dft_r2c_1d(plan%fftw, nx, array_in, plan%scratch, flag_fftw)
641  sll_warning('sll_s_fft_init_r2r_1d', 'R2HC not supported without FFTW_F2003. Use implementation based on r2c/c2r transform.')
642 #endif
643  else if (direction .eq. sll_p_fft_backward) then
644 #ifdef FFTW_F2003
645  plan%fftw = fftw_plan_r2r_1d(nx, array_in, array_out, fftw_hc2r, flag_fftw)
646 #else
647  ! This would be the code to actually create an r2r plan
648  !call dfftw_plan_r2r_1d(plan%fftw,nx,array_in,array_out,FFTW_HC2R,flag_fftw)
649 
650  allocate (plan%scratch(nx/2 + 1))
651  call dfftw_plan_dft_c2r_1d(plan%fftw, nx, plan%scratch, array_out, flag_fftw)
652  sll_warning('sll_s_fft_init_r2r_1d', 'HC2R not supported without FFTW_F2003. Use implementation based on r2c/c2r transform.')
653 #endif
654  end if
655  end subroutine sll_s_fft_init_r2r_1d
656 
657  !-----------------------------------------------------------------------------
659  !-----------------------------------------------------------------------------
660  subroutine sll_s_fft_exec_r2r_1d(plan, array_in, array_out)
661  type(sll_t_fft), intent(inout) :: plan
662  sll_real64, intent(inout) :: array_in(:)
663  sll_real64, intent(inout) :: array_out(:)
664 
665  sll_real64 :: factor
666 #ifndef FFTW_F2003
667  sll_int32 :: j
668 #endif
669 
670  sll_assert(plan%transform_type == p_fftw_r2r_1d)
671 
672 #ifdef FFTW_F2003
673  call fftw_execute_r2r(plan%fftw, array_in, array_out)
674 
675  if (plan%normalized .EQV. .true.) then
676  factor = 1.0_f64/real(plan%problem_shape(1), kind=f64)
677  array_out = factor*array_out
678  end if
679 
680 #else
681 
682  if (plan%direction == sll_p_fft_forward) then
683  call sll_s_fft_exec_r2c_1d(plan, array_in, plan%scratch)
684  array_out(1) = real(plan%scratch(1), f64)
685  array_out(plan%problem_shape(1)/2 + 1) = real(plan%scratch((plan%problem_shape(1)/2 + 1)), f64)
686  do j = 1, plan%problem_shape(1)/2 - 1
687  call sll_s_fft_set_mode_c2r_1d(plan, array_out, plan%scratch(j + 1), j)
688  end do
689  elseif (plan%direction == sll_p_fft_backward) then
690  do j = 0, plan%problem_shape(1)/2
691  plan%scratch(j + 1) = sll_f_fft_get_mode_r2c_1d(plan, array_out, j)
692  end do
693  call sll_s_fft_exec_c2r_1d(plan, plan%scratch, array_out)
694  end if
695 
696 #endif
697 
698  end subroutine
699 
700 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
701 !
702 ! REAL to COMPLEX
703 !
704 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
705 
706  !-----------------------------------------------------------------------------
708  !-----------------------------------------------------------------------------
709  subroutine sll_s_fft_init_r2c_1d(plan, nx, array_in, array_out, normalized, aligned, optimization)
710  type(sll_t_fft), intent(out) :: plan
711  sll_int32, intent(in) :: nx
712  sll_real64, intent(inout) :: array_in(:)
713  sll_comp64, intent(out) :: array_out(:)
714  logical, optional, intent(in) :: normalized
715  logical, optional, intent(in) :: aligned
716  sll_int32, optional, intent(in) :: optimization
717 
718 
719  sll_int32 :: ierr
720  sll_int32 :: flag_fftw
721 
722  plan%transform_type = p_fftw_r2c_1d
723  plan%direction = 0
724  if (present(normalized)) then
725  plan%normalized = normalized
726  else
727  plan%normalized = .false.
728  end if
729  ! Set the information about the algorithm to compute the plan. The default is FFTW_ESTIMATE
730  if (present(optimization)) then
731  flag_fftw = optimization
732  else
733  flag_fftw = fftw_estimate
734  end if
735  if (present(aligned)) then
736  if (aligned .EQV. .false.) then
737  flag_fftw = flag_fftw + fftw_unaligned
738  end if
739  else
740  flag_fftw = flag_fftw + fftw_unaligned
741  end if
742  plan%problem_rank = 1
743  sll_allocate(plan%problem_shape(1), ierr)
744  plan%problem_shape = (/nx/)
745 
746 #ifdef FFTW_F2003
747  plan%fftw = fftw_plan_dft_r2c_1d(nx, array_in, array_out, flag_fftw)
748 #else
749  call dfftw_plan_dft_r2c_1d(plan%fftw, nx, array_in, array_out, flag_fftw)
750 #endif
751  end subroutine sll_s_fft_init_r2c_1d
752 
754  subroutine sll_s_fft_exec_r2c_1d(plan, array_in, array_out)
755  type(sll_t_fft), intent(in) :: plan
756  sll_real64, intent(inout) :: array_in(:)
757  sll_comp64, intent(out) :: array_out(:)
758 
759  sll_real64 :: factor
760 
761  sll_assert(plan%transform_type == p_fftw_r2c_1d)
762 
763  call fftw_execute_dft_r2c(plan%fftw, array_in, array_out)
764 
765  if (plan%normalized .EQV. .true.) then
766  factor = 1.0_f64/real(plan%problem_shape(1), kind=f64)
767  array_out = cmplx(factor, 0.0, kind=f64)*array_out
768  end if
769  end subroutine
770 
771  !-----------------------------------------------------------------------------
773  !-----------------------------------------------------------------------------
774  subroutine sll_s_fft_init_r2c_2d(plan, nx, ny, array_in, array_out, normalized, aligned, optimization)
775  type(sll_t_fft), intent(out) :: plan
776  sll_int32, intent(in) :: nx
777  sll_int32, intent(in) :: ny
778  sll_real64, intent(inout) :: array_in(:, :)
779  sll_comp64, intent(out) :: array_out(:, :)
780  logical, optional, intent(in) :: normalized
781  logical, optional, intent(in) :: aligned
782  sll_int32, optional, intent(in) :: optimization
783 
784 
785  sll_int32 :: ierr
786  sll_int32 :: flag_fftw
787 
788  plan%transform_type = p_fftw_r2c_2d
789  plan%direction = 0
790  if (present(normalized)) then
791  plan%normalized = normalized
792  else
793  plan%normalized = .false.
794  end if
795  ! Set the information about the algorithm to compute the plan. The default is FFTW_ESTIMATE
796  if (present(optimization)) then
797  flag_fftw = optimization
798  else
799  flag_fftw = fftw_estimate
800  end if
801  if (present(aligned)) then
802  if (aligned .EQV. .false.) then
803  flag_fftw = flag_fftw + fftw_unaligned
804  end if
805  else
806  flag_fftw = flag_fftw + fftw_unaligned
807  end if
808 
809  plan%problem_rank = 2
810  sll_allocate(plan%problem_shape(2), ierr)
811  plan%problem_shape = (/nx, ny/)
812 
813 #ifdef FFTW_F2003
814  plan%fftw = fftw_plan_dft_r2c_2d(ny, nx, array_in, array_out, fftw_estimate + fftw_unaligned)
815 #else
816  call dfftw_plan_dft_r2c_2d(plan%fftw, nx, ny, array_in, array_out, fftw_estimate)
817 #endif
818 
819  end subroutine sll_s_fft_init_r2c_2d
820 
821  !-----------------------------------------------------------------------------
823  !-----------------------------------------------------------------------------
824  subroutine sll_s_fft_exec_r2c_2d(plan, array_in, array_out)
825  type(sll_t_fft), intent(in) :: plan
826  sll_real64, intent(inout) :: array_in(:, :)
827  sll_comp64, intent(out) :: array_out(:, :)
828 
829  sll_int32 :: nx, ny
830  sll_real64 :: factor
831 
832  sll_assert(plan%transform_type == p_fftw_r2c_2d)
833 
834  nx = plan%problem_shape(1)
835  ny = plan%problem_shape(2)
836 
837  if ((size(array_in, dim=1) .ne. nx) .and. (size(array_in, dim=2) .ne. ny)) then
838  print *, 'Error in file sll_m_fft.F90'
839  print *, ' in subroutine fft_apply_r2c_2d'
840  print *, ' array_in size problem'
841  stop ''
842  else if (size(array_in, dim=1) .ne. nx/2 + 1 .and. size(array_in, dim=2) .ne. ny) then
843  print *, 'Error in file sll_m_fft.F90'
844  print *, ' in subroutine fft_apply_r2c_2d'
845  print *, ' array_out size problem'
846  stop ''
847  end if
848 
849  call fftw_execute_dft_r2c(plan%fftw, array_in, array_out)
850 
851  if (plan%normalized .EQV. .true.) then
852  factor = 1.0_f64/real(nx*ny, kind=f64)
853  array_out = cmplx(factor, 0.0, kind=f64)*array_out
854  end if
855  end subroutine
856 
857 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
858 !
859 ! COMPLEX to REAL
860 !
861 !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
862 
863  !-----------------------------------------------------------------------------
865  !-----------------------------------------------------------------------------
866  subroutine sll_s_fft_init_c2r_1d(plan, nx, array_in, array_out, normalized, aligned, optimization)
867  type(sll_t_fft), intent(out) :: plan
868  sll_int32, intent(in) :: nx
869  sll_comp64, intent(inout) :: array_in(:)
870  sll_real64, intent(out) :: array_out(:)
871  logical, optional, intent(in) :: normalized
872  logical, optional, intent(in) :: aligned
873  sll_int32, optional, intent(in) :: optimization
874 
875 
876  sll_int32 :: ierr
877  sll_int32 :: flag_fftw
878 
879  plan%transform_type = p_fftw_c2r_1d
880  plan%direction = 0
881  if (present(normalized)) then
882  plan%normalized = normalized
883  else
884  plan%normalized = .false.
885  end if
886  ! Set the information about the algorithm to compute the plan. The default is FFTW_ESTIMATE
887  if (present(optimization)) then
888  flag_fftw = optimization
889  else
890  flag_fftw = fftw_estimate
891  end if
892  if (present(aligned)) then
893  if (aligned .EQV. .false.) then
894  flag_fftw = flag_fftw + fftw_unaligned
895  end if
896  else
897  flag_fftw = flag_fftw + fftw_unaligned
898  end if
899  plan%problem_rank = 1
900  sll_allocate(plan%problem_shape(1), ierr)
901  plan%problem_shape = (/nx/)
902 
903 #ifdef FFTW_F2003
904  plan%fftw = fftw_plan_dft_c2r_1d(nx, array_in, array_out, flag_fftw)
905 #else
906  call dfftw_plan_dft_c2r_1d(plan%fftw, nx, array_in, array_out, flag_fftw)
907 #endif
908 
909  end subroutine sll_s_fft_init_c2r_1d
910 
911  !-----------------------------------------------------------------------------
913  !-----------------------------------------------------------------------------
914  subroutine sll_s_fft_exec_c2r_1d(plan, array_in, array_out)
915  type(sll_t_fft), intent(in) :: plan
916  sll_comp64, intent(inout) :: array_in(:)
917  sll_real64, intent(inout) :: array_out(:)
918 
919  sll_real64 :: factor
920 
921  sll_assert(plan%transform_type == p_fftw_c2r_1d)
922 
923  call fftw_execute_dft_c2r(plan%fftw, array_in, array_out)
924 
925  if (plan%normalized .EQV. .true.) then
926  factor = 1.0_f64/real(plan%problem_shape(1), kind=f64)
927  array_out = factor*array_out
928  end if
929  end subroutine
930 
931  !-----------------------------------------------------------------------------
933  !-----------------------------------------------------------------------------
934  subroutine sll_s_fft_init_c2r_2d(plan, nx, ny, array_in, array_out, normalized, aligned, optimization)
935  type(sll_t_fft), intent(out) :: plan
936  sll_int32, intent(in) :: nx
937  sll_int32, intent(in) :: ny
938  sll_comp64, intent(inout) :: array_in(:, :)
939  sll_real64, intent(out) :: array_out(:, :)
940  logical, optional, intent(in) :: normalized
941  logical, optional, intent(in) :: aligned
942  sll_int32, optional, intent(in) :: optimization
943 
944 
945  sll_int32 :: ierr
946  sll_int32 :: flag_fftw
947 
948  plan%transform_type = p_fftw_c2r_2d
949  plan%direction = 0
950  if (present(normalized)) then
951  plan%normalized = normalized
952  else
953  plan%normalized = .false.
954  end if
955  ! Set the information about the algorithm to compute the plan. The default is FFTW_ESTIMATE
956  if (present(optimization)) then
957  flag_fftw = optimization
958  else
959  flag_fftw = fftw_estimate
960  end if
961  if (present(aligned)) then
962  if (aligned .EQV. .false.) then
963  flag_fftw = flag_fftw + fftw_unaligned
964  end if
965  else
966  flag_fftw = flag_fftw + fftw_unaligned
967  end if
968 
969  plan%problem_rank = 2
970  sll_allocate(plan%problem_shape(2), ierr)
971  plan%problem_shape = (/nx, ny/)
972 #ifdef FFTW_F2003
973  plan%fftw = fftw_plan_dft_c2r_2d(ny, nx, array_in, array_out, fftw_estimate + fftw_unaligned)
974 #else
975  call dfftw_plan_dft_c2r_2d(plan%fftw, nx, ny, array_in, array_out, fftw_estimate)
976 #endif
977  end subroutine sll_s_fft_init_c2r_2d
978 
979  !-----------------------------------------------------------------------------
981  !-----------------------------------------------------------------------------
982  subroutine sll_s_fft_exec_c2r_2d(plan, array_in, array_out)
983  type(sll_t_fft), intent(in) :: plan
984  sll_comp64, intent(inout) :: array_in(1:, 1:)
985  sll_real64, intent(out) :: array_out(1:, 1:)
986 
987  sll_int32 :: nx, ny
988  sll_real64 :: factor
989 
990  sll_assert(plan%transform_type == p_fftw_c2r_2d)
991 
992  nx = plan%problem_shape(1)
993  ny = plan%problem_shape(2)
994  call fftw_execute_dft_c2r(plan%fftw, array_in(1:nx/2 + 1, 1:ny), array_out(1:nx, 1:ny))
995 
996  if (plan%normalized .EQV. .true.) then
997  factor = 1.0_f64/real(nx*ny, kind=f64)
998  array_out = factor*array_out
999  end if
1000  end subroutine
1001 !END C2R
1002 
1003  !-----------------------------------------------------------------------------
1005  !-----------------------------------------------------------------------------
1006  subroutine sll_s_fft_free(plan)
1007  type(sll_t_fft), intent(inout) :: plan
1008 
1009  call fftw_destroy_plan(plan%fftw)
1010  if (allocated(plan%problem_shape)) then
1011  deallocate (plan%problem_shape)
1012  end if
1013 
1014  end subroutine
1015 
1016 end module sll_m_fft
FFT interface for FFTW.
subroutine, public sll_s_fft_get_k_list_r2r_1d(plan, k_list)
Get a list of the k modes in an r2r FFT k_list = [0, 1, 2, ..., n/2, (n+1)/2-1, .....
subroutine, public sll_s_fft_exec_r2c_1d(plan, array_in, array_out)
Compute fast Fourier transform in real to complex mode.
subroutine, public sll_s_fft_free(plan)
Delete a plan.
integer(c_int), parameter, public sll_p_fft_wisdom_only
subroutine, public sll_s_fft_init_c2c_2d(plan, nx, ny, array_in, array_out, direction, normalized, aligned, optimization)
Create new 2d complex to complex plan.
subroutine, public sll_s_fft_init_r2c_1d(plan, nx, array_in, array_out, normalized, aligned, optimization)
Create new 1d real to complex plan for forward FFT.
subroutine, public sll_s_fft_print_defaultlib()
Function to print the FFT library behind the interface.
integer(c_int), parameter, public sll_p_fft_exhaustive
FFTW planning-rigor flag FFTW_EXHAUSTIVE (more optimization than PATIENT) NOTE: planner overwrites th...
integer, parameter p_fftw_c2c_1d
subroutine, public sll_s_fft_exec_c2c_2d(plan, array_in, array_out)
Compute fast Fourier transform in complex to complex mode.
subroutine, public sll_s_fft_deallocate_aligned_complex(data)
Function to deallocate an aligned complex array.
subroutine, public sll_s_fft_exec_c2r_1d(plan, array_in, array_out)
Compute fast Fourier transform in complex to real mode.
integer, parameter p_fftw_r2c_2d
integer(c_int), parameter, public sll_p_fft_estimate
FFTW planning-rigor flag FFTW_ESTIMATE (simple heuristic for planer) [value 64]. This is our default ...
integer, parameter, public sll_p_fft_forward
Flag to specify forward FFT (negative sign) [value -1].
subroutine, public sll_s_fft_exec_c2r_2d(plan, array_in, array_out)
Compute fast Fourier transform in complex to real mode.
subroutine, public sll_s_fft_init_c2r_1d(plan, nx, array_in, array_out, normalized, aligned, optimization)
Create new 1d complex to real plan for backward FFT.
integer(c_int), parameter, public sll_p_fft_patient
FFTW planning-rigor flag FFTW_PATIENT (more optimizaton than MEASURE) NOTE: planner overwrites the in...
subroutine, public sll_s_fft_set_mode_c2r_1d(plan, data, ck, k)
Subroutine to set a complex mode to the real representation of r2r.
integer, parameter p_fftw_c2c_3d
real(c_double) function, dimension(:), pointer, public sll_f_fft_allocate_aligned_real(n)
Function to allocate an aligned real array.
subroutine, public sll_s_fft_init_c2c_3d(plan, nx, ny, nz, array_in, array_out, direction, normalized, aligned, optimization)
Create new 3d complex to complex plan.
subroutine, public sll_s_fft_get_k_list_r2c_1d(plan, k_list)
Get a list of the k modes in an r2c FFT k_list = [0, 1, 2, ..., n/2].
integer, parameter p_fftw_c2r_1d
subroutine, public sll_s_fft_get_k_list_c2c_1d(plan, k_list)
Get a list of the k modes in a c2c FFT k_list = [0, 1, 2, ..., n/2, (n/2+1)-n, ......
subroutine, public sll_s_fft_init_c2r_2d(plan, nx, ny, array_in, array_out, normalized, aligned, optimization)
Create new 2d real to complex plan for backward FFT.
subroutine, public sll_s_fft_init_r2r_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
Create new 1d real to real plan.
subroutine, public sll_s_fft_exec_c2c_1d(plan, array_in, array_out)
Compute fast Fourier transform in complex to complex mode.
subroutine, public sll_s_fft_exec_r2c_2d(plan, array_in, array_out)
Compute fast Fourier transform in real to complex mode.
subroutine, public sll_s_fft_deallocate_aligned_real(data)
Function to deallocate an aligned real array.
integer, parameter p_fftw_r2r_1d
integer, parameter p_fftw_r2r_2d
subroutine, public sll_s_fft_exec_c2c_3d(plan, array_in, array_out)
Compute fast Fourier transform in complex to complex mode.
subroutine, public sll_s_fft_init_c2c_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
Create new 1d complex to complex plan.
subroutine, public sll_s_fft_init_r2c_2d(plan, nx, ny, array_in, array_out, normalized, aligned, optimization)
Create new 2d complex to real plan for forward FFT.
integer, parameter, public sll_p_fft_backward
Flag to specify backward FFT (positive sign) [value 1].
subroutine, public sll_s_fft_exec_r2r_1d(plan, array_in, array_out)
Compute fast Fourier transform in real to real mode.
integer, parameter p_fftw_c2r_2d
integer, parameter p_fftw_c2c_2d
complex(kind=f64) function, public sll_f_fft_get_mode_r2c_1d(plan, data, k)
Function to reconstruct a complex FFT mode from the data of a r2r transform.
integer(c_int), parameter, public sll_p_fft_measure
FFTW planning-rigor flag FFTW_MEASURE (optimized plan) NOTE: planner overwrites the input array durin...
integer, parameter p_fftw_r2c_1d
complex(c_double_complex) function, dimension(:), pointer, public sll_f_fft_allocate_aligned_complex(n)
Function to allocate an aligned complex array.
Type for FFT plan in SeLaLib.
    Report Typos and Errors