1 #ifndef DOXYGEN_SHOULD_SKIP_THIS
28 #include "sll_working_precision.h"
29 #include "sll_assert.h"
30 #include "sll_memory.h"
31 #include "sll_errors.h"
83 sll_comp64,
allocatable,
private :: t(:)
85 sll_real64,
allocatable,
private :: twiddles(:)
87 sll_real64,
allocatable,
private :: twiddles_n(:)
90 sll_int32 :: direction
91 sll_int32 :: problem_rank
92 sll_int32,
allocatable :: problem_shape(:)
93 sll_int32,
allocatable,
private :: scramble_index(:)
94 sll_int32,
private :: transform_type
98 integer,
parameter :: sll_p_fft_forward = -1
100 integer,
parameter :: sll_p_fft_backward = 1
103 integer,
parameter :: sll_p_fft_measure = -1
104 integer,
parameter :: sll_p_fft_patient = -1
105 integer,
parameter :: sll_p_fft_estimate = -1
106 integer,
parameter :: sll_p_fft_exhaustive = -1
107 integer,
parameter :: sll_p_fft_wisdom_only = -1
110 integer,
parameter :: p_fftw_c2c_1d = 0
111 integer,
parameter :: p_fftw_r2r_1d = 1
112 integer,
parameter :: p_fftw_r2c_1d = 2
113 integer,
parameter :: p_fftw_c2r_1d = 3
114 integer,
parameter :: p_fftw_c2c_2d = 4
115 integer,
parameter :: p_fftw_r2r_2d = 5
116 integer,
parameter :: p_fftw_r2c_2d = 6
117 integer,
parameter :: p_fftw_c2r_2d = 7
123 print *,
'The library used is SLLFFT'
128 sll_int32,
intent(in) :: n
129 complex(f64),
pointer :: data(:)
132 sll_warning(
'sll_f_fft_allocate_aligned_complex',
'Aligned allocation not implemented for SLLFFT. Usual allocation.')
138 sll_int32,
intent(in) :: n
139 real(f64),
pointer :: data(:)
142 sll_warning(
'sll_f_fft_allocate_aligned_real',
'Aligned allocation not implemented for SLLFFT. Usual allocation.')
150 complex(f64),
pointer :: data(:)
153 sll_warning(
'sll_s_fft_deallocate_aligned_complex',
'Aligned deallocation not implemented for SLLFFT. Usual deallocation.')
161 real(f64),
pointer :: data(:)
164 sll_warning(
'sll_s_fft_deallocate_aligned_real',
'Aligned deallocation not implemented for SLLFFT. Usual deallocation.')
173 type(sll_t_fft),
intent(in) :: plan
174 sll_int32,
intent(out) :: k_list(0:)
178 n = plan%problem_shape(1)
180 if (
size(k_list) /= n)
then
181 sll_error(
"sll_s_fft_get_k_list_c2c_1d",
"k_list must have n elements")
184 k_list(0:n/2) = [(k, k=0, n/2)]
185 k_list(n/2 + 1:n - 1) = [(k - n, k=n/2 + 1, n - 1)]
194 type(sll_t_fft),
intent(in) :: plan
195 sll_int32,
intent(out) :: k_list(0:)
199 n = plan%problem_shape(1)
201 if (
size(k_list) /= n)
then
202 sll_error(
"sll_s_fft_get_k_list_r2r_1d",
"k_list must have n elements")
205 k_list(0:n/2) = [(k, k=0, n/2)]
206 k_list(n/2 + 1:n - 1) = [(n - k, k=n/2 + 1, n - 1)]
215 type(sll_t_fft),
intent(in) :: plan
216 sll_int32,
intent(out) :: k_list(0:)
220 n_2 = plan%problem_shape(1)/2
222 if (
size(k_list) /= n_2 + 1)
then
223 sll_error(
"sll_s_fft_get_k_list_r2c_1d",
"k_list must have n/2+1 elements")
226 k_list(:) = [(k, k=0, n_2)]
234 type(sll_t_fft),
intent(in) :: plan
235 sll_real64,
intent(in) ::
data(0:)
236 sll_int32,
intent(in) :: k
240 n = plan%problem_shape(1)
242 if (k == 0) then; ck = cmplx(
data(k), 0.0_f64, kind=f64)
243 else if (k <= (n + 1)/2 - 1) then; ck = cmplx(
data(k),
data(n - k), kind=f64)
244 else if (k == n/2) then; ck = cmplx(
data(k), 0.0_f64, kind=f64)
245 else if (k <= n - 1) then; ck = cmplx(
data(n - k), -
data(k), kind=f64)
247 sll_error(
"sll_f_fft_get_mode_r2c_1d",
"k must be between 0 and n-1")
256 type(sll_t_fft),
intent(in) :: plan
257 sll_real64,
intent(inout) ::
data(0:)
258 sll_comp64,
intent(in) :: ck
259 sll_int32,
intent(in) :: k
262 n = plan%problem_shape(1)
264 if (k == 0) then;
data(0) = real(ck)
265 else if (k <= (n + 1)/2 - 1) then;
data(k) = real(ck);
data(n - k) = aimag(ck)
266 else if (k == n/2) then;
data(k) = real(ck)
267 else if (k <= n - 1) then;
data(n - k) = real(ck);
data(k) = -aimag(ck)
269 sll_error(
"sll_s_fft_set_mode_c2r_1d",
"k must be between 0 and n-1")
326 subroutine sll_s_fft_init_c2c_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
327 type(sll_t_fft),
intent(out) :: plan
328 sll_int32,
intent(in) :: nx
329 sll_comp64,
intent(inout) :: array_in(:)
330 sll_comp64,
intent(inout) :: array_out(:)
331 sll_int32,
intent(in) :: direction
332 logical,
optional,
intent(in) :: normalized
333 logical,
optional,
intent(in) :: aligned
334 sll_int32,
optional,
intent(in) :: optimization
339 sll_assert(
size(array_in) .ge. nx)
340 sll_assert(
size(array_out) .ge. nx)
341 plan%transform_type = p_fftw_c2c_1d
342 plan%direction = direction
343 if (
present(normalized))
then
344 plan%normalized = normalized
346 plan%normalized = .false.
349 plan%problem_rank = 1
350 sll_allocate(plan%problem_shape(1), ierr)
351 plan%problem_shape = (/nx/)
353 sll_allocate(plan%scramble_index(0:nx - 1), ierr)
357 plan%scramble_index(i) = i
359 sll_allocate(plan%t(1:nx/2), ierr)
360 call compute_twiddles(nx, plan%t)
361 if (direction == sll_p_fft_forward)
then
362 plan%t = conjg(plan%t)
364 call bit_reverse_complex(nx/2, plan%t)
369 type(sll_t_fft),
intent(in) :: plan
370 sll_comp64,
intent(inout) :: array_in(:)
371 sll_comp64,
intent(inout) :: array_out(:)
375 sll_assert(plan%transform_type == p_fftw_c2c_1d)
377 if (loc(array_in(1)) .ne. loc(array_out(1)))
then
381 call fft_dit_nr(array_out, plan%problem_shape(1), plan%t, plan%direction)
382 call bit_reverse_complex(plan%problem_shape(1), array_out)
384 if (plan%normalized .EQV. .true.)
then
385 factor = 1.0_f64/real(plan%problem_shape(1), kind=f64)
386 array_out = factor*array_out
395 subroutine sll_s_fft_init_c2c_2d(plan, nx, ny, array_in, array_out, direction, normalized, aligned, optimization)
396 type(sll_t_fft),
intent(out) :: plan
397 sll_int32,
intent(in) :: nx
398 sll_int32,
intent(in) :: ny
399 sll_comp64,
intent(inout) :: array_in(0:, 0:)
400 sll_comp64,
intent(inout) :: array_out(0:, 0:)
401 sll_int32,
intent(in) :: direction
402 logical,
optional,
intent(in) :: normalized
403 logical,
optional,
intent(in) :: aligned
404 sll_int32,
optional,
intent(in) :: optimization
409 sll_assert(
size(array_in, dim=1) .ge. nx)
410 sll_assert(
size(array_in, dim=2) .ge. ny)
411 sll_assert(
size(array_out, dim=1) .ge. nx)
412 sll_assert(
size(array_out, dim=2) .ge. ny)
416 plan%transform_type = p_fftw_c2c_2d
417 plan%direction = direction
418 if (
present(normalized))
then
419 plan%normalized = normalized
421 plan%normalized = .false.
424 plan%problem_rank = 2
425 sll_allocate(plan%problem_shape(2), ierr)
426 plan%problem_shape = (/nx, ny/)
428 sll_allocate(plan%t(1:nx/2 + ny/2), ierr)
430 call compute_twiddles(nx, plan%t(1:nx/2))
431 if (direction == sll_p_fft_forward)
then
432 plan%t(1:nx/2) = conjg(plan%t(1:nx/2))
434 call bit_reverse_complex(nx/2, plan%t(1:nx/2))
436 call compute_twiddles(ny, plan%t(nx/2 + 1:nx/2 + ny/2))
437 if (direction == sll_p_fft_forward)
then
438 plan%t(nx/2 + 1:nx/2 + ny/2) = conjg(plan%t(nx/2 + 1:nx/2 + ny/2))
440 call bit_reverse_complex(ny/2, plan%t(nx/2 + 1:nx/2 + ny/2))
446 type(sll_t_fft),
intent(in) :: plan
447 sll_comp64,
intent(inout) :: array_in(0:, 0:)
448 sll_comp64,
intent(inout) :: array_out(0:, 0:)
450 sll_int32 :: i, nx, ny
451 sll_int32,
dimension(2) :: fft_shape
454 sll_assert(plan%transform_type == p_fftw_c2c_2d)
456 if (loc(array_in(1, 1)) .ne. loc(array_out(1, 1)))
then
459 fft_shape(1:2) = plan%problem_shape(1:2)
464 call fft_dit_nr(array_out(0:nx - 1, i), nx, plan%t(1:nx/2), plan%direction)
465 call bit_reverse_complex(nx, array_out(0:nx - 1, i))
470 array_out(i, 0:ny - 1), &
472 plan%t(nx/2 + 1:nx/2 + ny/2), &
474 call bit_reverse_complex(ny, array_out(i, 0:ny - 1))
477 if (plan%normalized .EQV. .true.)
then
478 factor = 1.0_f64/real(nx*ny, kind=f64)
479 array_out = factor*array_out
486 subroutine sll_s_fft_init_r2r_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
487 type(sll_t_fft),
intent(out) :: plan
488 sll_int32,
intent(in) :: nx
489 sll_real64,
intent(inout) :: array_in(:)
490 sll_real64,
intent(inout) :: array_out(:)
491 sll_int32,
intent(in) :: direction
492 logical,
optional,
intent(in) :: normalized
493 logical,
optional,
intent(in) :: aligned
494 sll_int32,
optional,
intent(in) :: optimization
498 sll_assert(
size(array_in) .eq. nx)
499 sll_assert(
size(array_out) .eq. nx)
500 plan%transform_type = p_fftw_r2r_1d
501 plan%direction = direction
502 if (
present(normalized))
then
503 plan%normalized = normalized
505 plan%normalized = .false.
508 plan%problem_rank = 1
509 sll_allocate(plan%problem_shape(1), ierr)
510 plan%problem_shape = (/nx/)
512 sll_allocate(plan%scramble_index(0:nx/2), ierr)
516 plan%scramble_index(0) = 0
517 plan%scramble_index(1) = nx/2
519 plan%scramble_index(i + 1) = i
522 sll_allocate(plan%twiddles(0:nx/2 - 1), ierr)
523 sll_allocate(plan%twiddles_n(0:nx - 1), ierr)
524 call compute_twiddles_real_array(nx, plan%twiddles_n)
525 call compute_twiddles_real_array(nx/2, plan%twiddles(0:nx/2 - 1))
526 if (direction .eq. sll_p_fft_forward)
then
527 call conjg_in_pairs(nx/2, plan%twiddles)
529 call bit_reverse_in_pairs(nx/4, plan%twiddles(0:nx/2 - 1))
534 type(sll_t_fft),
intent(in) :: plan
535 sll_real64,
intent(inout) :: array_in(:)
536 sll_real64,
intent(inout) :: array_out(:)
540 sll_real64 :: tmp(plan%problem_shape(1))
542 sll_assert(plan%transform_type == p_fftw_r2r_1d)
544 nx = plan%problem_shape(1)
546 if (loc(array_in(1)) .ne. loc(array_out(1)))
then
551 if (plan%direction .EQ. sll_p_fft_backward)
then
554 array_out(2*k + 1) = tmp(k + 1)
555 array_out(2*k + 2) = tmp(nx - k + 1)
557 array_out(1) = tmp(1)
558 array_out(2) = tmp(nx/2 + 1)
561 call real_data_fft_dit(array_out, nx, plan%twiddles, plan%twiddles_n, plan%direction)
564 if (plan%direction .EQ. sll_p_fft_forward)
then
567 array_out(k + 1) = tmp(2*k + 1)
568 array_out(nx - k + 1) = tmp(2*k + 1 + 1)
570 array_out(nx/2 + 1) = tmp(2)
573 if (plan%normalized .EQV. .true.)
then
574 factor = 1.0_f64/real(plan%problem_shape(1), kind=f64)
575 array_out = factor*array_out
584 type(sll_t_fft),
intent(out) :: plan
585 sll_int32,
intent(in) :: nx
586 sll_real64,
intent(inout) :: array_in(:)
587 sll_comp64,
intent(out) :: array_out(:)
588 logical,
optional,
intent(in) :: normalized
589 logical,
optional,
intent(in) :: aligned
590 sll_int32,
optional,
intent(in) :: optimization
594 sll_assert(
size(array_in) .eq. nx)
595 sll_assert(
size(array_out) .eq. nx/2 + 1)
596 plan%transform_type = p_fftw_r2c_1d
597 plan%direction = sll_p_fft_forward
598 if (
present(normalized))
then
599 plan%normalized = normalized
601 plan%normalized = .false.
603 plan%problem_rank = 1
604 sll_allocate(plan%problem_shape(1), ierr)
605 plan%problem_shape = (/nx/)
607 sll_allocate(plan%twiddles(0:nx/2 - 1), ierr)
608 sll_allocate(plan%twiddles_n(0:nx - 1), ierr)
609 call compute_twiddles_real_array(nx, plan%twiddles_n)
610 call compute_twiddles_real_array(nx/2, plan%twiddles(0:nx/2 - 1))
611 call conjg_in_pairs(nx/2, plan%twiddles)
612 call bit_reverse_in_pairs(nx/4, plan%twiddles(0:nx/2 - 1))
617 type(sll_t_fft),
intent(in) :: plan
618 sll_real64,
intent(inout) :: array_in(0:)
619 sll_comp64,
intent(out) :: array_out(0:)
624 sll_assert(plan%transform_type == p_fftw_r2c_1d)
626 nx = plan%problem_shape(1)
628 call real_data_fft_dit(array_in, nx, plan%twiddles, plan%twiddles_n, plan%direction)
630 array_out(0) = cmplx(array_in(0), 0.0_f64, kind=f64)
632 array_out(nx/2) = cmplx(array_in(1), 0.0_f64, kind=f64)
635 array_out(i) = cmplx(array_in(2*i), array_in(2*i + 1), kind=f64)
639 if (plan%normalized .EQV. .true.)
then
640 factor = 1.0_f64/real(plan%problem_shape(1), kind=f64)
641 array_out = factor*array_out
649 type(sll_t_fft),
intent(out) :: plan
650 sll_int32,
intent(in) :: nx
651 sll_comp64,
intent(in) :: array_in(:)
652 sll_real64,
intent(out) :: array_out(:)
653 logical,
optional,
intent(in) :: normalized
654 logical,
optional,
intent(in) :: aligned
655 sll_int32,
optional,
intent(in) :: optimization
659 sll_assert(
size(array_in) .eq. nx/2 + 1)
660 sll_assert(
size(array_out) .eq. nx)
661 plan%transform_type = p_fftw_c2r_1d
662 plan%direction = sll_p_fft_backward
663 if (
present(normalized))
then
664 plan%normalized = normalized
666 plan%normalized = .false.
668 plan%problem_rank = 1
669 sll_allocate(plan%problem_shape(1), ierr)
670 plan%problem_shape = (/nx/)
672 sll_allocate(plan%twiddles(0:nx/2 - 1), ierr)
673 sll_allocate(plan%twiddles_n(0:nx - 1), ierr)
674 call compute_twiddles_real_array(nx, plan%twiddles_n)
675 call compute_twiddles_real_array(nx/2, plan%twiddles(0:nx/2 - 1))
676 call bit_reverse_in_pairs(nx/4, plan%twiddles(0:nx/2 - 1))
681 type(sll_t_fft),
intent(in) :: plan
682 sll_comp64,
intent(inout) :: array_in(0:)
683 sll_real64,
intent(inout) :: array_out(0:)
688 sll_assert(plan%transform_type == p_fftw_c2r_1d)
690 nx = plan%problem_shape(1)
693 array_out(0) = real(array_in(0), kind=f64)
695 array_out(1) = real(array_in(nx/2), kind=f64)
698 array_out(2*i) = real(array_in(i), kind=f64)
699 array_out(2*i + 1) = aimag(array_in(i))
701 call real_data_fft_dit(array_out, nx, plan%twiddles, plan%twiddles_n, plan%direction)
703 if (plan%normalized .EQV. .true.)
then
704 factor = 1.0_f64/real(plan%problem_shape(1), kind=f64)
705 array_out = factor*array_out
713 subroutine sll_s_fft_init_r2c_2d(plan, nx, ny, array_in, array_out, normalized, aligned, optimization)
714 type(sll_t_fft),
intent(out) :: plan
715 sll_int32,
intent(in) :: nx
716 sll_int32,
intent(in) :: ny
717 sll_real64,
intent(inout) :: array_in(:, :)
718 sll_comp64,
intent(out) :: array_out(:, :)
719 logical,
optional,
intent(in) :: normalized
720 logical,
optional,
intent(in) :: aligned
721 sll_int32,
optional,
intent(in) :: optimization
725 sll_assert(
size(array_in, dim=1) .eq. nx)
726 sll_assert(
size(array_in, dim=2) .eq. ny)
727 sll_assert(
size(array_out, dim=1) .eq. nx/2 + 1)
728 sll_assert(
size(array_out, dim=2) .eq. ny)
729 plan%transform_type = p_fftw_r2c_2d
730 plan%direction = sll_p_fft_forward
731 if (
present(normalized))
then
732 plan%normalized = normalized
734 plan%normalized = .false.
736 plan%problem_rank = 2
737 sll_allocate(plan%problem_shape(2), ierr)
738 plan%problem_shape = (/nx, ny/)
740 sll_allocate(plan%t(1:ny/2), ierr)
741 call compute_twiddles(ny, plan%t)
742 plan%t = conjg(plan%t)
743 call bit_reverse_complex(ny/2, plan%t)
745 sll_allocate(plan%twiddles(0:nx/2 - 1), ierr)
746 sll_allocate(plan%twiddles_n(0:nx - 1), ierr)
747 call compute_twiddles_real_array(nx, plan%twiddles_n)
748 call compute_twiddles_real_array(nx/2, plan%twiddles(0:nx/2 - 1))
749 call conjg_in_pairs(nx/2, plan%twiddles)
750 call bit_reverse_in_pairs(nx/4, plan%twiddles(0:nx/2 - 1))
755 type(sll_t_fft),
intent(in) :: plan
756 sll_real64,
intent(inout) :: array_in(0:, 0:)
757 sll_comp64,
intent(out) :: array_out(0:, 0:)
759 sll_int32 :: nx, i, ny, k
762 sll_assert(plan%transform_type == p_fftw_r2c_2d)
764 nx = plan%problem_shape(1)
765 ny = plan%problem_shape(2)
768 call real_data_fft_dit(array_in(0:nx - 1, k), nx, plan%twiddles, plan%twiddles_n, plan%direction)
769 array_out(0, k) = cmplx(array_in(0, k), 0.0_f64, kind=f64)
770 array_out(nx/2, k) = cmplx(array_in(1, k), 0.0_f64, kind=f64)
772 array_out(i, k) = cmplx(array_in(2*i, k), array_in(2*i + 1, k), kind=f64)
776 call fft_dit_nr(array_out(k, 0:ny - 1), ny, plan%t, plan%direction)
777 call bit_reverse_complex(ny, array_out(k, 0:ny - 1))
780 if (plan%normalized .EQV. .true.)
then
781 factor = 1.0_f64/real(nx*ny, kind=f64)
782 array_out = factor*array_out
789 subroutine sll_s_fft_init_c2r_2d(plan, nx, ny, array_in, array_out, normalized, aligned, optimization)
790 type(sll_t_fft),
intent(out) :: plan
791 sll_int32,
intent(in) :: nx
792 sll_int32,
intent(in) :: ny
793 sll_comp64,
intent(in) :: array_in(:, :)
794 sll_real64,
intent(out) :: array_out(:, :)
795 logical,
optional,
intent(in) :: normalized
796 logical,
optional,
intent(in) :: aligned
797 sll_int32,
optional,
intent(in) :: optimization
801 sll_assert(
size(array_in, dim=1) .eq. nx/2 + 1)
802 sll_assert(
size(array_in, dim=2) .eq. ny)
803 sll_assert(
size(array_out, dim=1) .eq. nx)
804 sll_assert(
size(array_out, dim=2) .eq. ny)
806 plan%transform_type = p_fftw_c2r_2d
807 plan%direction = sll_p_fft_backward
808 if (
present(normalized))
then
809 plan%normalized = normalized
811 plan%normalized = .false.
813 plan%problem_rank = 2
814 sll_allocate(plan%problem_shape(2), ierr)
815 plan%problem_shape = (/nx, ny/)
817 sll_allocate(plan%t(1:ny/2), ierr)
818 call compute_twiddles(ny, plan%t)
819 call bit_reverse_complex(ny/2, plan%t)
821 sll_allocate(plan%twiddles(0:nx/2 - 1), ierr)
822 sll_allocate(plan%twiddles_n(0:nx - 1), ierr)
823 call compute_twiddles_real_array(nx, plan%twiddles_n)
824 call compute_twiddles_real_array(nx/2, plan%twiddles(0:nx/2 - 1))
825 call bit_reverse_in_pairs(nx/4, plan%twiddles(0:nx/2 - 1))
830 type(sll_t_fft),
intent(in) :: plan
831 sll_comp64,
intent(inout) :: array_in(0:, 0:)
832 sll_real64,
intent(inout) :: array_out(0:, 0:)
834 sll_int32 :: nx, i, ny, k, j
837 sll_assert(plan%transform_type == p_fftw_c2r_2d)
839 nx = plan%problem_shape(1)
840 ny = plan%problem_shape(2)
843 call fft_dit_nr(array_in(j, 0:ny - 1), ny, plan%t, plan%direction)
844 call bit_reverse_complex(ny, array_in(j, 0:ny - 1))
847 array_out(0, i) = real(array_in(0, i), kind=f64)
848 array_out(1, i) = real(array_in(nx/2, i), kind=f64)
850 array_out(2*k, i) = real(array_in(k, i), kind=f64)
851 array_out(2*k + 1, i) = aimag(array_in(k, i))
853 call real_data_fft_dit(array_out(0:nx - 1, i), nx, plan%twiddles, plan%twiddles_n, plan%direction)
856 if (plan%normalized .EQV. .true.)
then
857 factor = 1.0_f64/real(nx*ny, kind=f64)
858 array_out = factor*array_out
869 type(sll_t_fft),
intent(inout) :: plan
871 if (
allocated(plan%t))
then
874 if (
allocated(plan%twiddles))
then
875 deallocate (plan%twiddles)
877 if (
allocated(plan%twiddles_n))
then
878 deallocate (plan%twiddles_n)
880 if (
allocated(plan%problem_shape))
then
881 deallocate (plan%problem_shape)
900 subroutine compute_twiddles(n, t)
901 intrinsic :: exp, real
903 sll_comp64,
dimension(1:n/2),
intent(out) :: t
906 if (n .eq. 0 .or. n .eq. 1)
then
907 print *,
"ERROR: Zero array size passed to compute_twiddle_factors()."
909 else if (
size(t) .lt. n/2)
then
910 print *,
"ERROR: compute_twiddles(), array is of insufficient size."
913 theta = 2.0_f64*
sll_p_pi/real(n, kind=f64)
921 t(k + 1) = exp((0.0_f64, 1.0_f64)*theta*cmplx(k, 0.0, kind=f64))
924 t(n/4 + 1) = (0.0_f64, 1.0_f64)
926 end subroutine compute_twiddles
932 #define CREAL0(array, i) array(2*(i))
933 #define CIMAG0(array, i) array(2*(i)+1)
935 #define CREAL1(array, i) array(2*(i)-1)
936 #define CIMAG1(array, i) array(2*(i))
940 subroutine compute_twiddles_real_array(n, t)
941 intrinsic :: cos, sin, real
943 sll_real64,
dimension(0:n - 1),
intent(out) :: t
947 theta = 2.0_f64*
sll_p_pi/real(n, kind=f64)
955 creal0(t, k) = cos(real(k, kind=f64)*theta)
956 cimag0(t, k) = sin(real(k, kind=f64)*theta)
959 creal0(t, 0) = 1.0_f64
960 cimag0(t, 0) = 0.0_f64
963 creal0(t, n/4) = 0.0_f64
964 cimag0(t, n/4) = 1.0_f64
968 creal0(t, n/8) = sqrt(2.0_f64)/2.0_f64
969 cimag0(t, n/8) = sqrt(2.0_f64)/2.0_f64
971 end subroutine compute_twiddles_real_array
981 #define MAKE_BIT_REVERSE_FUNCTION( function_name, data_type ) \
982 subroutine function_name(n, a); \
983 intrinsic ishft, iand; \
984 data_type,
dimension(:),
intent(inout) :: a; \
985 integer,
intent(in) :: n; \
996 a(j + 1) = a(i + 1); \
1000 do while (k <= j); \
1006 end subroutine function_name
1008 make_bit_reverse_function(bit_reverse_complex, sll_comp64)
1016 subroutine bit_reverse_in_pairs(num_pairs, a)
1017 intrinsic ishft, iand
1018 integer,
intent(in) :: num_pairs
1019 sll_real64,
dimension(0:2*num_pairs - 1),
intent(inout) :: a
1023 sll_real64,
dimension(1:2) :: tmp
1024 sll_assert(sll_f_is_power_of_two(int(num_pairs, i64)))
1027 #define ARRAY(i) a(2*(i):2*(i)+1)
1028 do i = 0, num_pairs - 2
1035 k = ishft(num_pairs, -1)
1042 end subroutine bit_reverse_in_pairs
1046 subroutine conjg_in_pairs(n, array)
1047 sll_real64,
dimension(:) :: array
1050 sll_assert(
size(array) .eq. n)
1053 array(i) = -array(i)
1087 subroutine fft_dit_nr(data, n, twiddles, sign)
1088 sll_comp64,
dimension(:),
intent(inout) ::
data
1089 sll_int32,
intent(in) :: sign
1090 sll_comp64,
dimension(:),
intent(in) :: twiddles
1091 sll_int32,
intent(in) :: n
1092 sll_assert(sll_f_is_power_of_two(int(n, i64)))
1093 sll_assert(
size(data) .ge. n)
1094 call fft_dit_nr_aux(
data, n, twiddles, 0, sign)
1095 end subroutine fft_dit_nr
1098 recursive subroutine fft_dit_nr_aux(dat, size, twiddles, &
1099 twiddle_index, sign)
1100 intrinsic ishft, conjg
1101 integer,
intent(in) :: size
1103 sll_comp64,
dimension(0:),
intent(inout) :: dat
1105 sll_comp64,
dimension(0:),
intent(in) :: twiddles
1106 integer,
intent(in) :: twiddle_index
1107 integer,
optional,
intent(in) :: sign
1110 integer :: t_index_new
1114 half = ishft(
size, -1)
1122 omega = twiddles(twiddle_index)
1125 tmp = dat(j + half)*omega
1126 dat(j + half) = dat(j) - tmp
1127 dat(j) = dat(j) + tmp
1132 t_index_new = ishft(twiddle_index, 1)
1133 call fft_dit_nr_aux(dat(0:half - 1), &
1138 call fft_dit_nr_aux(dat(half:2*half - 1), &
1146 end subroutine fft_dit_nr_aux
1167 recursive subroutine fft_dit_rn_aux(data, &
1172 intrinsic ishft, conjg
1173 sll_int32,
intent(in) :: data_size
1176 sll_comp64,
dimension(1:data_size),
intent(inout) ::
data
1177 sll_comp64,
dimension(1:data_size/2),
intent(in) :: twiddles
1178 integer,
intent(in) :: twiddle_stride
1179 sll_int32 :: new_stride
1180 sll_int32 :: jtwiddle
1181 integer,
intent(in) :: sign
1187 half = ishft(data_size, -1)
1189 new_stride = twiddle_stride*2
1190 call fft_dit_rn_aux(
data(1:half), half, twiddles, new_stride, sign)
1191 call fft_dit_rn_aux(
data(half + 1:data_size), half, twiddles, new_stride, sign)
1202 omega = twiddles(jtwiddle)
1203 tmp =
data(j + half)*omega
1204 data(j + half) =
data(j) - tmp
1205 data(j) =
data(j) + tmp
1206 jtwiddle = jtwiddle + twiddle_stride
1208 end subroutine fft_dit_rn_aux
1226 recursive subroutine fft_dit_nr_real_array_aux(samples, &
1231 intrinsic ishft, conjg
1233 integer,
intent(in) :: num_complex
1234 sll_real64,
dimension(0:2*num_complex - 1),
intent(inout):: samples
1239 sll_real64,
dimension(0:),
intent(in) :: twiddles
1240 integer,
intent(in) :: twiddle_index
1241 integer,
intent(in) :: sign
1246 integer :: t_index_new
1247 sll_real64 :: omega_re
1248 sll_real64 :: omega_im
1249 sll_real64 :: tmp_re
1250 sll_real64 :: tmp_im
1251 sll_assert(num_complex .le.
size(samples))
1252 half = ishft(num_complex, -1)
1265 omega_re = creal0(twiddles, twiddle_index)
1266 omega_im = cimag0(twiddles, twiddle_index)
1271 creal0(samples, j + half)*omega_re - cimag0(samples, j + half)*omega_im
1273 creal0(samples, j + half)*omega_im + cimag0(samples, j + half)*omega_re
1275 creal0(samples, j + half) = creal0(samples, j) - tmp_re
1276 cimag0(samples, j + half) = cimag0(samples, j) - tmp_im
1278 creal0(samples, j) = creal0(samples, j) + tmp_re
1279 cimag0(samples, j) = cimag0(samples, j) + tmp_im
1284 t_index_new = ishft(twiddle_index, 1)
1285 call fft_dit_nr_real_array_aux(samples(0:2*half - 1), &
1290 call fft_dit_nr_real_array_aux(samples(2*half:4*half - 1), &
1298 end subroutine fft_dit_nr_real_array_aux
1300 recursive subroutine fft_dit_rn_real_array_aux(data, &
1305 intrinsic ishft, conjg
1307 integer,
intent(in) :: num_complex
1308 sll_real64,
dimension(1:2*num_complex),
intent(inout) ::
data
1313 sll_real64,
dimension(1:num_complex),
intent(in) :: twiddles
1314 sll_int32,
intent(in) :: twiddle_stride
1315 sll_int32 :: new_stride
1316 sll_int32 :: jtwiddle
1317 integer,
intent(in) :: sign
1320 sll_real64 :: omega_re
1321 sll_real64 :: omega_im
1322 sll_real64 :: tmp_re
1323 sll_real64 :: tmp_im
1324 sll_assert(num_complex .le.
size(data))
1328 half = ishft(num_complex, -1)
1331 new_stride = twiddle_stride*2
1332 call fft_dit_rn_real_array_aux(
data(1:num_complex), &
1337 call fft_dit_rn_real_array_aux(
data(num_complex + 1:2*num_complex), &
1356 omega_re = creal1(twiddles, jtwiddle)
1357 omega_im = cimag1(twiddles, jtwiddle)
1359 tmp_re = creal1(
data, j + half)*omega_re - cimag1(
data, j + half)*omega_im
1360 tmp_im = creal1(
data, j + half)*omega_im + cimag1(
data, j + half)*omega_re
1362 creal1(
data, j + half) = creal1(
data, j) - tmp_re
1363 cimag1(
data, j + half) = cimag1(
data, j) - tmp_im
1365 creal1(
data, j) = creal1(
data, j) + tmp_re
1366 cimag1(
data, j) = cimag1(
data, j) + tmp_im
1367 jtwiddle = jtwiddle + twiddle_stride
1369 end subroutine fft_dit_rn_real_array_aux
1409 subroutine real_data_fft_dit(data, n, twiddles, twiddles_n, sign)
1410 sll_int32,
intent(in) :: n
1411 sll_real64,
dimension(0:),
intent(inout) ::
data
1412 sll_real64,
dimension(0:n/2 - 1),
intent(in) :: twiddles
1413 sll_real64,
dimension(0:n - 1),
intent(in) :: twiddles_n
1414 sll_int32,
intent(in) :: sign
1419 sll_real64 :: hn_2mi_re
1420 sll_real64 :: hn_2mi_im
1421 sll_real64 :: tmp_re
1422 sll_real64 :: tmp_im
1423 sll_real64 :: tmp2_re
1424 sll_real64 :: tmp2_im
1425 sll_real64 :: tmp3_re
1426 sll_real64 :: tmp3_im
1427 sll_real64 :: omega_re
1428 sll_real64 :: omega_im
1430 sll_assert(sll_f_is_power_of_two(int(n, i64)))
1431 sll_assert(
size(data) .ge. n)
1432 sll_assert(
size(twiddles) .eq. n/2)
1455 call fft_dit_nr_real_array_aux(
data(0:n - 1), &
1462 call bit_reverse_in_pairs(n_2,
data(0:n - 1))
1466 stop
'ERROR IN =REAL_DATA_FFT_DIT= invalid argument sign'
1487 hi_re = creal0(
data, i)
1488 hi_im = cimag0(
data, i)
1489 hn_2mi_re = creal0(
data, n_2 - i)
1490 hn_2mi_im = -cimag0(
data, n_2 - i)
1491 omega_re = creal0(twiddles_n, i)
1492 omega_im = s*cimag0(twiddles_n, i)
1494 tmp_re = 0.5_f64*(hi_re + hn_2mi_re)
1495 tmp_im = 0.5_f64*(hi_im + hn_2mi_im)
1498 tmp2_re = s*0.5_f64*(hi_im - hn_2mi_im)
1499 tmp2_im = -s*0.5_f64*(hi_re - hn_2mi_re)
1501 tmp3_re = tmp2_re*omega_re - tmp2_im*omega_im
1502 tmp3_im = tmp2_re*omega_im + tmp2_im*omega_re
1503 creal0(
data, i) = tmp_re - tmp3_re
1504 cimag0(
data, i) = tmp_im - tmp3_im
1505 creal0(
data, n_2 - i) = tmp_re + tmp3_re
1506 cimag0(
data, n_2 - i) = -tmp_im - tmp3_im
1512 data(0) = tmp_re +
data(1)
1513 data(1) = tmp_re -
data(1)
1517 data(0) = 0.5_f64*(tmp_re +
data(1))
1518 data(1) = 0.5_f64*(tmp_re -
data(1))
1520 call fft_dit_nr_real_array_aux(
data(0:n - 1), &
1527 call bit_reverse_in_pairs(n_2,
data(0:n - 1))
1530 end subroutine real_data_fft_dit
1537 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
Fortran module where set some physical and mathematical constants.
real(kind=f64), parameter, public sll_p_pi
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...
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(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.
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_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].
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.
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.
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...
complex(c_double_complex) function, dimension(:), pointer, public sll_f_fft_allocate_aligned_complex(n)
Function to allocate an aligned complex array.
Some common numerical utilities.
logical function, public sll_f_is_power_of_two(n)
Check if an integer is equal to.
Type for FFT plan in SeLaLib.