!*****************************************************************************************************! ! Copyright 2008-2020 The ALaDyn Collaboration ! !*****************************************************************************************************! !*****************************************************************************************************! ! This file is part of ALaDyn. ! ! ! ! ALaDyn is free software: you can redistribute it and/or modify ! ! it under the terms of the GNU General Public License as published by ! ! the Free Software Foundation, either version 3 of the License, or ! ! (at your option) any later version. ! ! ! ! ALaDyn is distributed in the hope that it will be useful, ! ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! ! GNU General Public License for more details. ! ! ! ! You should have received a copy of the GNU General Public License ! ! along with ALaDyn. If not, see <http://www.gnu.org/licenses/>. ! !*****************************************************************************************************! module legacy_fft_lib use precision_def use, intrinsic :: iso_c_binding implicit none include 'fftw3.f03' integer(dp) :: plan1, iplan1 integer(dp) :: plan2, iplan2 integer(dp) :: plan3, iplan3 real(dp), allocatable :: cw(:, :), w1(:), w1_st(:), w2(:), w3(:) real(dp), allocatable :: cfhx(:), sfhx(:) real(dp), allocatable :: cfhy(:), sfhy(:) real(dp), allocatable :: cfhz(:), sfhz(:) contains subroutine ftw_init(n1, n2, n3, ind_ft) integer, intent(in) :: n1, n2, n3, ind_ft integer :: i, nm real(dp) :: wk !!$PRAGMA C( DFFTW_PLAN_DFT_R2C_1D, DFFTW_PLAN_DFT_C2R_1D ) select case (ind_ft) case (0) nm = max(n1, n2) allocate (w1(n1 + 2), w1_st(nm + 1), cfhx(n1), sfhx(n1)) wk = acos(-1.0)/real(n1, dp) do i = 1, n1 cfhx(i) = cos(real(i - 1, dp)*wk) sfhx(i) = sin(real(i - 1, dp)*wk) end do w1 = 0.0 call dfftw_plan_dft_r2c_1d(plan1, n1, w1, w1, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan1, n1, w1, w1, fftw_estimate) allocate (w2(n2 + 2), cfhy(n2), sfhy(n2)) w2 = 0.0 call dfftw_plan_dft_r2c_1d(plan2, n2, w2, w2, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan2, n2, w2, w2, fftw_estimate) wk = acos(-1.0)/real(n2, dp) do i = 1, n2 cfhy(i) = cos(real(i - 1, dp)*wk) sfhy(i) = sin(real(i - 1, dp)*wk) end do allocate (w3(n3 + 2), cfhz(n3), sfhz(n3)) w3 = 0.0 call dfftw_plan_dft_r2c_1d(plan3, n3, w3, w3, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan3, n3, w3, w3, fftw_estimate) wk = acos(-1.0)/real(n3, dp) do i = 1, n3 cfhz(i) = cos(real(i - 1, dp)*wk) sfhz(i) = sin(real(i - 1, dp)*wk) end do case (1) allocate (w1(n1 + 2)) w1 = 0.0 call dfftw_plan_dft_r2c_1d(plan1, n1, w1, w1, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan1, n1, w1, w1, fftw_estimate) allocate (w2(n2 + 2)) w2 = 0.0 call dfftw_plan_dft_r2c_1d(plan2, n2, w2, w2, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan2, n2, w2, w2, fftw_estimate) allocate (w3(n3 + 2)) w3 = 0.0 call dfftw_plan_dft_r2c_1d(plan3, n3, w3, w3, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan3, n3, w3, w3, fftw_estimate) case (2) !for sin/cos transforms allocate (w1(2*n1 + 2)) w1 = 0.0 call dfftw_plan_dft_r2c_1d(plan1, 2*n1, w1, w1, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan1, 2*n1, w1, w1, fftw_estimate) if (n2 > 1) then allocate (w2(2*n2 + 2)) w2 = 0.0 call dfftw_plan_dft_r2c_1d(plan2, 2*n2, w2, w2, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan2, 2*n2, w2, w2, fftw_estimate) end if allocate (w3(2*n3 + 2)) w3 = 0.0 call dfftw_plan_dft_r2c_1d(plan3, 2*n3, w3, w3, fftw_estimate) call dfftw_plan_dft_c2r_1d(iplan3, 2*n3, w3, w3, fftw_estimate) end select end subroutine !---------------------- subroutine ftw_end if (allocated(w1)) deallocate (w1) if (allocated(w1_st)) deallocate (w1_st) if (allocated(w2)) deallocate (w2) if (allocated(w3)) deallocate (w3) if (allocated(cw)) deallocate (cw) end subroutine subroutine ftw1d_st(w, n1, n2, n3, is, dir) real(dp), intent(inout) :: w(:, :, :) integer, intent(in) :: n1, n2, n3, is, dir integer :: ii, ix, iy, iz, i1, i2, n1_tr, n2_tr real(dp) :: sc, wrr, wir, wri, wii !!$PRAGMA C( DFFTW_EXECUTE ) !============================= !staggered (k_x,k_y,k_z) !=================== select case (dir) case (1) if (is < 0) then sc = 1./real(n1, dp) do iz = 1, n3 do iy = 1, n2 do ix = 1, n1 w1(ix) = cfhx(ix)*w(ix, iy, iz) end do call dfftw_execute(plan1) w1_st(1:n1) = w1(1:n1) do ix = 1, n1 w1(ix) = sfhx(ix)*w(ix, iy, iz) end do call dfftw_execute(plan1) do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 w(i1, iy, iz) = sc*(w1_st(i1) + w1(i2)) w(i2, iy, iz) = sc*(w1_st(i2) - w1(i1)) end do end do end do else n1_tr = n1/2 + n1/4 do iz = 1, n3 do iy = 1, n2 w(n1_tr + 1:n1, iy, iz) = 0.0 w1(n1 + 1:n1 + 2) = 0.0 w1(1:n1) = w(1:n1, iy, iz) call dfftw_execute(iplan1) w1_st(1:n1) = w1(1:n1) w1(1:n1 + 2) = 0.0 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 w1(i1) = -w(i2, iy, iz) w1(i2) = w(i1, iy, iz) end do call dfftw_execute(iplan1) do ix = 1, n1 w(ix, iy, iz) = cfhx(ix)*w1_st(ix) + sfhx(ix)*w1(ix) end do end do end do end if case (2) allocate (cw(n1, n2)) if (is < 0) then sc = 1./real(n2, dp) do iz = 1, n3 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do ii = i1, i2 do iy = 1, n2 w2(iy) = cfhy(iy)*w(ii, iy, iz) end do call dfftw_execute(plan2) do iy = 1, n2 cw(ii, iy) = sc*w2(iy) w2(iy) = sfhy(iy)*w(ii, iy, iz) end do call dfftw_execute(plan2) do iy = 1, n2/2 cw(ii, 2*iy - 1) = cw(ii, 2*iy - 1) + sc*w2(2*iy) cw(ii, 2*iy) = cw(ii, 2*iy) - sc*w2(2*iy - 1) end do end do end do !=========== reordering as 2D fft do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do iy = 1, n2/2 wrr = cw(i1, 2*iy - 1) wri = cw(i1, 2*iy) wir = cw(i2, 2*iy - 1) wii = cw(i2, 2*iy) w(i1, iy, iz) = wrr - wii w(i2, iy, iz) = wri + wir w(i1, n2 + 1 - iy, iz) = wrr + wii w(i2, n2 + 1 - iy, iz) = wir - wri end do end do end do else n2_tr = n2/2 + n2/4 do iz = 1, n3 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do iy = 1, n2/2 cw(i1, 2*iy - 1) = 0.5*(w(i1, iy, iz) + w(i1, n2 + 1 - iy, iz)) !wrr cw(i1, 2*iy) = 0.5*(w(i2, iy, iz) - w(i2, n2 + 1 - iy, iz)) !wri cw(i2, 2*iy - 1) = 0.5*(w(i2, iy, iz) + w(i2, n2 + 1 - iy, iz)) !wir cw(i2, 2*iy) = 0.5*(w(i1, n2 + 1 - iy, iz) - w(i1, iy, iz)) !wii end do end do do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do ii = i1, i2 cw(ii, n2_tr + 1:n2) = 0.0 w2(n2 + 1:n2 + 2) = 0.0 do iy = 1, n2 w2(iy) = cw(ii, iy) end do call dfftw_execute(iplan2) do iy = 1, n2 w(ii, iy, iz) = cfhy(iy)*w2(iy) end do w2(n2 + 1:n2 + 2) = 0.0 do iy = 1, n2/2 w2(2*iy - 1) = -cw(ii, 2*iy) w2(2*iy) = cw(ii, 2*iy - 1) end do call dfftw_execute(iplan2) do iy = 1, n2 w(ii, iy, iz) = w(ii, iy, iz) + sfhy(iy)*w2(iy) end do end do end do end do end if if (allocated(cw)) deallocate (cw) case (3) allocate (cw(n1, n3)) if (is < 0) then sc = 1./real(n3, dp) do iy = 1, n2 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do ii = i1, i2 do iz = 1, n3 w3(iz) = cfhz(iz)*w(ii, iy, iz) end do call dfftw_execute(plan3) do iz = 1, n3 cw(ii, iz) = sc*w3(iz) w3(iz) = sfhz(iz)*w(ii, iy, iz) end do call dfftw_execute(plan3) do iz = 1, n3/2 cw(ii, 2*iz - 1) = cw(ii, 2*iz - 1) + sc*w3(2*iz) cw(ii, 2*iz) = cw(ii, 2*iz) - sc*w3(2*iz - 1) end do end do end do !=========== reordering as 2D fft do iz = 1, n3/2 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 wrr = cw(i1, 2*iz - 1) wri = cw(i1, 2*iz) wir = cw(i2, 2*iz - 1) wii = cw(i2, 2*iz) w(i1, iy, iz) = wrr - wii w(i2, iy, iz) = wri + wir w(i1, iy, n3 + 1 - iz) = wrr + wii w(i2, iy, n3 + 1 - iz) = wir - wri end do end do end do else n2_tr = n3/2 + n3/4 ! First reorders do iy = 1, n2 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do iz = 1, n3/2 cw(i1, 2*iz - 1) = 0.5*(w(i1, iy, iz) + w(i1, iy, n3 + 1 - iz)) !wrr cw(i1, 2*iz) = 0.5*(w(i2, iy, iz) - w(i2, iy, n3 + 1 - iz)) !wri cw(i2, 2*iz - 1) = 0.5*(w(i2, iy, iz) + w(i2, iy, n3 + 1 - iz)) !wir cw(i2, 2*iz) = 0.5*(w(i1, iy, n3 + 1 - iz) - w(i1, iy, iz)) !wii end do end do do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do ii = i1, i2 cw(ii, n2_tr + 1:n3) = 0.0 w3(n3 + 1:n3 + 2) = 0.0 do iz = 1, n3 w3(iz) = cw(ii, iz) end do call dfftw_execute(iplan3) do iz = 1, n3 w(ii, iy, iz) = cfhz(iz)*w3(iz) end do w3(n3 + 1:n3 + 2) = 0.0 do iz = 1, n3/2 w3(2*iz - 1) = -cw(ii, 2*iz) w3(2*iz) = cw(ii, 2*iz - 1) end do call dfftw_execute(iplan3) do iz = 1, n3 w(ii, iy, iz) = w(ii, iy, iz) + sfhz(iz)*w3(iz) end do end do end do end do end if if (allocated(cw)) deallocate (cw) end select end subroutine !==================== subroutine ftw1d(w, n1, n2, n3, is, dir) real(dp), intent(inout) :: w(:, :, :) integer, intent(in) :: n1, n2, n3, is, dir integer :: ix, iy, iz, i1, i2, n1_tr, n2_tr real(dp) :: sc, wrr, wir, wri, wii !!$PRAGMA C( DFFTW_EXECUTE ) select case (dir) case (1) if (is < 0) then sc = 1./real(n1, dp) do iz = 1, n3 do iy = 1, n2 w1(1:n1) = w(1:n1, iy, iz) call dfftw_execute(plan1) w(1:n1, iy, iz) = sc*w1(1:n1) end do end do else n1_tr = n1 do iz = 1, n3 do iy = 1, n2 w1(n1 + 1:n1 + 2) = 0.0 w1(1:n1_tr) = w(1:n1_tr, iy, iz) call dfftw_execute(iplan1) w(1:n1, iy, iz) = w1(1:n1) end do end do end if case (2) allocate (cw(n1, n2)) if (is < 0) then sc = 1./real(n2, dp) do iz = 1, n3 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do iy = 1, n2 w2(iy) = w(i1, iy, iz) end do call dfftw_execute(plan2) do iy = 1, n2 cw(i1, iy) = sc*w2(iy) w2(iy) = w(i2, iy, iz) end do call dfftw_execute(plan2) do iy = 1, n2 cw(i2, iy) = sc*w2(iy) end do end do !=========== reordering as 2D fft do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 w(i1:i2, 1:n2, iz) = 0. w(i1:i2, 1, iz) = cw(i1:i2, 1) do iy = 2, n2/2 wrr = cw(i1, 2*iy - 1) wri = cw(i1, 2*iy) wir = cw(i2, 2*iy - 1) wii = cw(i2, 2*iy) w(i1, iy, iz) = wrr - wii w(i2, iy, iz) = wri + wir w(i1, n2 + 2 - iy, iz) = wrr + wii w(i2, n2 + 2 - iy, iz) = wir - wri end do end do end do else n2_tr = n2/2 do iz = 1, n3 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do iy = 1, n2 cw(i1:i2, iy) = w(i1:i2, iy, iz) end do w2(1:n2 + 2) = 0.0 w2(1) = cw(i1, 1) do iy = 2, n2_tr w2(2*iy - 1) = 0.5*(cw(i1, iy) + cw(i1, n2 + 2 - iy)) w2(2*iy) = 0.5*(cw(i2, iy) - cw(i2, n2 + 2 - iy)) end do call dfftw_execute(iplan2) do iy = 1, n2 w(i1, iy, iz) = w2(iy) end do w2(1:n2 + 2) = 0.0 w2(1) = cw(i2, 1) do iy = 2, n2_tr w2(2*iy - 1) = 0.5*(cw(i2, iy) + cw(i2, n2 + 2 - iy)) w2(2*iy) = 0.5*(cw(i1, n2 + 2 - iy) - cw(i1, iy)) end do call dfftw_execute(iplan2) do iy = 1, n2 w(i2, iy, iz) = w2(iy) end do end do end do end if if (allocated(cw)) deallocate (cw) case (3) allocate (cw(n1, n3)) if (is < 0) then sc = 1./real(n3, dp) do iy = 1, n2 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 do iz = 1, n3 w3(iz) = w(i1, iy, iz) end do call dfftw_execute(plan3) do iz = 1, n3 cw(i1, iz) = sc*w3(iz) w3(iz) = w(i2, iy, iz) end do call dfftw_execute(plan3) do iz = 1, n3 cw(i2, iz) = sc*w3(iz) end do end do !=========== reordering as 2D fft do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 w(i1:i2, iy, 1) = cw(i1:i2, 1) end do do iz = 2, n3/2 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 wrr = cw(i1, 2*iz - 1) wri = cw(i1, 2*iz) wir = cw(i2, 2*iz - 1) wii = cw(i2, 2*iz) w(i1, iy, iz) = wrr - wii w(i2, iy, iz) = wri + wir w(i1, iy, n3 + 2 - iz) = wrr + wii w(i2, iy, n3 + 2 - iz) = wir - wri end do end do end do else n2_tr = n3/2 do iy = 1, n2 do iz = 1, n3 do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 cw(i1:i2, iz) = w(i1:i2, iy, iz) end do end do do ix = 1, n1/2 i2 = 2*ix i1 = i2 - 1 w3(1:n3 + 2) = 0.0 w3(1) = cw(i1, 1) do iz = 2, n2_tr w3(2*iz - 1) = 0.5*(cw(i1, iz) + cw(i1, n3 + 2 - iz)) !wrr w3(2*iz) = 0.5*(cw(i2, iz) - cw(i2, n3 + 2 - iz)) !wri end do call dfftw_execute(iplan3) do iz = 1, n3 w(i1, iy, iz) = w3(iz) end do w3(1:n3 + 2) = 0.0 w3(1) = cw(i2, 1) do iz = 2, n2_tr w3(2*iz - 1) = 0.5*(cw(i2, iz) + cw(i2, n3 + 2 - iz)) !wir w3(2*iz) = 0.5*(cw(i1, n3 + 2 - iz) - cw(i1, iz)) !wii end do call dfftw_execute(iplan3) do iz = 1, n3 w(i2, iy, iz) = w3(iz) end do end do end do end if if (allocated(cw)) deallocate (cw) end select end subroutine !================ subroutine ft_kern(w, n1, is) real(dp), intent(inout) :: w(:) integer, intent(in) :: n1, is integer :: ix, i2 real(dp) :: sc integer :: ndb !!$PRAGMA C( DFFTW_EXECUTE ) ndb = 2*n1 sc = 1. if (is < 0) then w1(1:n1) = w(1:n1) w1(n1 + 1) = 0.0 do ix = n1 + 2, ndb w1(ix) = -w1(ndb + 2 - ix) end do call dfftw_execute(plan1) do ix = 1, n1 i2 = 2*ix w(ix) = sc*w1(i2) end do else w1(1:n1) = w(1:n1) do ix = n1 + 2, ndb w1(ix) = w1(ndb + 2 - ix) end do w1(n1 + 1) = 0.5*(w1(n1) + w1(n1 + 2)) call dfftw_execute(plan1) do ix = 1, n1 i2 = 2*ix - 1 w(ix) = sc*w1(i2) end do end if end subroutine !========================== subroutine ftw1d_sc(w, n1, n2, n3, is, dir, sym) real(dp), intent(inout) :: w(:, :, :) integer, intent(in) :: n1, n2, n3, is, dir, sym integer :: ix, iy, iz, i2, n1_tr, n2_tr real(dp) :: sc integer :: ndb !!$PRAGMA C( DFFTW_EXECUTE ) select case (dir) case (1) ndb = 2*n1 if (is < 0) then !grid to Fourier space sc = 1./real(ndb, dp) if (sym == 1) then !sin do iz = 1, n3 do iy = 1, n2 w1(1:n1) = w(1:n1, iy, iz) w1(n1 + 1) = 0.0 do ix = n1 + 2, ndb w1(ix) = -w1(ndb + 2 - ix) end do call dfftw_execute(plan1) do ix = 1, n1 i2 = 2*ix w(ix, iy, iz) = sc*w1(i2) end do end do end do else do iz = 1, n3 !cos do iy = 1, n2 w1(1:n1) = w(1:n1, iy, iz) do ix = n1 + 2, ndb w1(ix) = w1(ndb + 2 - ix) end do w1(n1 + 1) = 0.5*(w1(n1) + w1(n1 + 2)) call dfftw_execute(plan1) do ix = 1, n1 i2 = 2*ix - 1 w(ix, iy, iz) = sc*w1(i2) end do end do end do end if else n1_tr = n1 if (sym == 1) then do iz = 1, n3 do iy = 1, n2 w1 = 0.0 do ix = 1, n1 i2 = 2*ix w1(i2) = w(ix, iy, iz) end do call dfftw_execute(iplan1) w(1:n1, iy, iz) = w1(1:n1) end do end do else do iz = 1, n3 do iy = 1, n2 w1 = 0.0 do ix = 1, n1 i2 = 2*ix - 1 w1(i2) = w(ix, iy, iz) end do call dfftw_execute(iplan1) w(1:n1, iy, iz) = w1(1:n1) end do end do end if end if case (2) ndb = 2*n2 allocate (cw(n1, n2)) if (is < 0) then sc = 1./real(ndb, dp) do iz = 1, n3 do ix = 1, n1 do iy = 1, n2 w2(iy) = w(ix, iy, iz) end do w2(n2 + 1) = 0.0 do iy = n2 + 2, ndb w2(iy) = -w2(ndb + 2 - iy) end do call dfftw_execute(plan2) do iy = 1, n2 cw(ix, iy) = sc*w2(2*iy) end do end do do iy = 1, n2 do ix = 1, n1 w(ix, iy, iz) = cw(ix, iy) end do end do end do else n2_tr = n2 do iz = 1, n3 do ix = 1, n1 w2 = 0.0 do iy = 1, n2 w2(2*iy) = w(ix, iy, iz) end do call dfftw_execute(iplan2) do iy = 1, n2 cw(ix, iy) = w2(iy) end do end do w(1:n1, 1:n2, iz) = cw(1:n1, 1:n2) end do end if if (allocated(cw)) deallocate (cw) case (3) ndb = 2*n3 allocate (cw(n1, n3)) if (is < 0) then sc = 1./real(ndb, dp) do iy = 1, n2 do ix = 1, n1 do iz = 1, n3 w3(iz) = w(ix, iy, iz) end do w3(n3 + 1) = 0.0 do iz = n3 + 2, ndb w3(iz) = -w3(ndb + 2 - iz) end do call dfftw_execute(plan3) do iz = 1, n3 cw(ix, iz) = sc*w3(2*iz) end do end do do iz = 1, n3 do ix = 1, n1 w(ix, iy, iz) = cw(ix, iz) end do end do end do else n2_tr = n3 do iy = 1, n2 do ix = 1, n1 w3 = 0.0 do iz = 1, n3 w3(2*iz) = w(ix, iy, iz) end do call dfftw_execute(iplan3) do iz = 1, n3 cw(ix, iz) = w3(iz) end do end do do iz = 1, n3 do ix = 1, n1 w(ix, iy, iz) = cw(ix, iz) end do end do end do end if if (allocated(cw)) deallocate (cw) end select end subroutine end module