!> author: Sam Hatfield, Fred Kucharski, Franco Molteni ! date: 01/05/2019 ! For computing direct and inverse Fourier transforms. module fourier use types, only : p use params use legendre, only : ModLegendre_t use geometry, only : ModGeometry_t implicit none private public ModFourier_t, ModFourier_initialize, ModFourier_delete !> Fourier module object ! Although the ModLegendre_t is not need it, we make it a base class ! to allow the ModSpectral to inherit that class too when the ModFourier module ! is inherited. This needs to be done since Fortran does not suppoert multiple inheritance. type, extends(ModLegendre_t) :: ModFourier_t logical :: mod_fourier_initialized = .false. real(p), allocatable, dimension(:) :: work !! Work array required by FFTPACK. Contains trigonometric functions etc. integer, allocatable, dimension(:) :: ifac !! Work array required by FFTPACK. Contains prime factors contains procedure :: initialize => ModFourier_initialize procedure :: delete => ModFourier_delete procedure :: fourier => ModFourier_fourier procedure :: fourier_inv => ModFourier_fourier_inv end type contains !> Initializes the ModFourier instance. subroutine ModFourier_initialize(this, mod_geometry) use legendre, only : ModLegendre_initialize class(ModFourier_t), intent(inout) :: this class(ModGeometry_t), intent(in), target :: mod_geometry call ModLegendre_initialize(this, mod_geometry) if (this%mod_fourier_initialized) then return end if allocate(this%work(ix)) allocate(this%ifac(15)) call rffti1(ix, this%work, this%ifac) end subroutine !> Delete the Fourier instance subroutine ModFourier_delete(this) use legendre, only : ModLegendre_delete class(ModFourier_t), intent(inout) :: this call ModLegendre_delete(this) if (this%mod_fourier_initialized) then deallocate(this%work, this%ifac) end if end subroutine !> Transforms Fourier coefficients to grid-point data. function ModFourier_fourier_inv(this, input, kcos) result(output) class(ModFourier_t), intent(in) :: this real(p), intent(in) :: input(2 * mx, il) !! Input field integer, intent(in) :: kcos !! Scale output by cos(lat) (1) or not (0) real(p) :: output(ix, il) !! Output field integer :: j, m real(p) :: fvar(ix), ch(ix) do j = 1, il fvar(1) = input(1, j) do m = 3, 2 * mx fvar(m - 1) = input(m, j) end do do m = 2 * mx, ix fvar(m) = 0.0 end do ! Inverse FFT call rfftb1(ix, fvar, ch, this%work, this%ifac) ! Copy output into grid-point field, scaling by cos(lat) if needed if (kcos == 1) then output(:, j) = fvar else output(:, j) = fvar * this%mod_geometry%cosgr(j) end if end do end function !> Transforms grid-point data to Fourier coefficients. function ModFourier_fourier(this, input) result(output) class(ModFourier_t), intent(in) :: this real(p), intent(in) :: input(ix, il) !! Input field real(p) :: output(2 * mx, il) !! Output field integer :: j, m real(p) :: fvar(ix), scale real(p) :: ch(ix) ! Copy grid-point data into working array do j = 1, il fvar = input(:, j) ! Direct FFT call rfftf1(ix, fvar, ch, this%work, this%ifac) ! Copy output into spectral field, dividing by no. of long. scale = 1.0 / float(ix) ! Mean value (a(0)) output(1, j) = fvar(1) * scale output(2, j) = 0.0 do m = 3, 2 * mx output(m, j) = fvar(m - 1) * scale end do end do end function end module