spectral.f90 Source File


This file depends on

sourcefile~~spectral.f90~~EfferentGraph sourcefile~spectral.f90 spectral.f90 sourcefile~fourier.f90 fourier.f90 sourcefile~spectral.f90->sourcefile~fourier.f90 sourcefile~geometry.f90 geometry.f90 sourcefile~spectral.f90->sourcefile~geometry.f90 sourcefile~physical_constants.f90 physical_constants.f90 sourcefile~spectral.f90->sourcefile~physical_constants.f90 sourcefile~legendre.f90 legendre.f90 sourcefile~spectral.f90->sourcefile~legendre.f90 sourcefile~params.f90 params.f90 sourcefile~spectral.f90->sourcefile~params.f90 sourcefile~fourier.f90->sourcefile~geometry.f90 sourcefile~fourier.f90->sourcefile~params.f90 sourcefile~geometry.f90->sourcefile~physical_constants.f90 sourcefile~geometry.f90->sourcefile~params.f90 sourcefile~physical_constants.f90->sourcefile~params.f90 sourcefile~legendre.f90->sourcefile~geometry.f90 sourcefile~legendre.f90->sourcefile~physical_constants.f90 sourcefile~legendre.f90->sourcefile~params.f90

Files dependent on this one

sourcefile~~spectral.f90~~AfferentGraph sourcefile~spectral.f90 spectral.f90 sourcefile~forcing.f90 forcing.f90 sourcefile~forcing.f90->sourcefile~spectral.f90 sourcefile~boundaries.f90 boundaries.f90 sourcefile~forcing.f90->sourcefile~boundaries.f90 sourcefile~sea_model.f90 sea_model.f90 sourcefile~forcing.f90->sourcefile~sea_model.f90 sourcefile~land_model.f90 land_model.f90 sourcefile~forcing.f90->sourcefile~land_model.f90 sourcefile~surface_fluxes.f90 surface_fluxes.f90 sourcefile~forcing.f90->sourcefile~surface_fluxes.f90 sourcefile~input_output.f90 input_output.f90 sourcefile~input_output.f90->sourcefile~spectral.f90 sourcefile~diagnostics.f90 diagnostics.f90 sourcefile~diagnostics.f90->sourcefile~spectral.f90 sourcefile~prognostics.f90 prognostics.f90 sourcefile~prognostics.f90->sourcefile~spectral.f90 sourcefile~prognostics.f90->sourcefile~input_output.f90 sourcefile~prognostics.f90->sourcefile~diagnostics.f90 sourcefile~prognostics.f90->sourcefile~boundaries.f90 sourcefile~boundaries.f90->sourcefile~spectral.f90 sourcefile~boundaries.f90->sourcefile~input_output.f90 sourcefile~initialization.f90 initialization.f90 sourcefile~initialization.f90->sourcefile~spectral.f90 sourcefile~initialization.f90->sourcefile~forcing.f90 sourcefile~initialization.f90->sourcefile~input_output.f90 sourcefile~initialization.f90->sourcefile~prognostics.f90 sourcefile~initialization.f90->sourcefile~boundaries.f90 sourcefile~physics.f90 physics.f90 sourcefile~initialization.f90->sourcefile~physics.f90 sourcefile~time_stepping.f90 time_stepping.f90 sourcefile~initialization.f90->sourcefile~time_stepping.f90 sourcefile~initialization.f90->sourcefile~sea_model.f90 sourcefile~coupler.f90 coupler.f90 sourcefile~initialization.f90->sourcefile~coupler.f90 sourcefile~tendencies.f90 tendencies.f90 sourcefile~tendencies.f90->sourcefile~spectral.f90 sourcefile~tendencies.f90->sourcefile~prognostics.f90 sourcefile~tendencies.f90->sourcefile~physics.f90 sourcefile~sppt.f90 sppt.f90 sourcefile~sppt.f90->sourcefile~spectral.f90 sourcefile~physics.f90->sourcefile~spectral.f90 sourcefile~physics.f90->sourcefile~boundaries.f90 sourcefile~physics.f90->sourcefile~sppt.f90 sourcefile~physics.f90->sourcefile~sea_model.f90 sourcefile~physics.f90->sourcefile~land_model.f90 sourcefile~physics.f90->sourcefile~surface_fluxes.f90 sourcefile~time_stepping.f90->sourcefile~spectral.f90 sourcefile~time_stepping.f90->sourcefile~prognostics.f90 sourcefile~time_stepping.f90->sourcefile~tendencies.f90 sourcefile~speedy.f90 speedy.f90 sourcefile~speedy.f90->sourcefile~forcing.f90 sourcefile~speedy.f90->sourcefile~input_output.f90 sourcefile~speedy.f90->sourcefile~diagnostics.f90 sourcefile~speedy.f90->sourcefile~prognostics.f90 sourcefile~speedy.f90->sourcefile~initialization.f90 sourcefile~speedy.f90->sourcefile~time_stepping.f90 sourcefile~speedy.f90->sourcefile~coupler.f90 sourcefile~sea_model.f90->sourcefile~input_output.f90 sourcefile~sea_model.f90->sourcefile~boundaries.f90 sourcefile~land_model.f90->sourcefile~input_output.f90 sourcefile~land_model.f90->sourcefile~boundaries.f90 sourcefile~surface_fluxes.f90->sourcefile~land_model.f90 sourcefile~coupler.f90->sourcefile~sea_model.f90 sourcefile~coupler.f90->sourcefile~land_model.f90

Contents

Source Code


Source Code

module spectral
    use params

    implicit none

    private
    public el2
    public initialize_spectral
    public laplacian, inverse_laplacian, spec_to_grid, grid_to_spec
    public grad, vds, uvspec, vdspec, trunct

    real, dimension(mx,nx) :: el2, elm2, el4, trfilt
    real :: gradx(mx), gradym(mx,nx), gradyp(mx,nx)
    real, dimension(mx,nx) :: uvdx, uvdym, uvdyp
    real, dimension(mx,nx) :: vddym, vddyp

contains
    ! Initialize spectral transforms
    subroutine initialize_spectral
        use physical_constants, only: rearth
        use fourier, only: initialize_fourier
        use legendre, only: initialize_legendre, epsi

        real :: el1
        integer :: m, m1, m2, n, wavenum_tot(mx,nx), mm(mx)

        ! Initialize Fourier transforms
        call initialize_fourier

        ! Initialize Legendre transforms
        call initialize_legendre

        !  MM = zonal wavenumber = m
        !  wavenum_tot = total wavenumber of spherical harmonic = l
        !  L2 = l*(l+1)
        !  EL2 = l*(l+1)/(a**2)
        !  EL4 = EL2*EL2 ; for biharmonic diffusion
        !  ELM2 = 1./EL2
        !  TRFILT used to filter out "non-triangular" part of rhomboidal truncation
        do n = 1, nx
            do m = 1, mx
                mm(m) = m - 1
                wavenum_tot(m,n) = mm(m) + n - 1
                el2(m,n) = float(wavenum_tot(m,n)*(wavenum_tot(m,n) + 1))/(rearth**2.0)
                el4(m,n) = el2(m,n)**2.0
                if (wavenum_tot(m,n) <= trunc) then
                    trfilt(m,n) = 1.0
                else
                    trfilt(m,n) = 0.0
                end if
            end do
        end do

        elm2(1,1) = 0.0
        elm2(2:mx,:) = 1.0/el2(2:mx,:)
        elm2(1,2:nx) = 1.0/el2(1,2:nx)

        ! quantities required by subroutines GRAD, UVSPEC, and VDS
        ! saved in spectral
        do m = 1, mx
            do n = 1, nx
                m1 = mm(m)
                m2 = m1 + 1
                el1 = float(wavenum_tot(m,n))
                if (n == 1) then
                    gradx(m)   = float(m1)/rearth
                    uvdx(m,1)  = -rearth/float(m1+1)
                    uvdym(m,1) = 0.0
                    vddym(m,1) = 0.0
                else
                    uvdx(m,n)   = -rearth*float(m1)/(el1*(el1 + 1))
                    gradym(m,n) = (el1 - 1.0)*epsi(m2,n)/rearth
                    uvdym(m,n)  = -rearth*epsi(m2,n)/el1
                    vddym(m,n)  = (el1 + 1)*epsi(m2,n)/rearth
                end if
                gradyp(m,n) = (el1 + 2.0)*epsi(m2,n+1)/rearth
                uvdyp(m,n)  = -rearth*epsi(m2,n+1)/(el1 + 1.0)
                vddyp(m,n)  = el1*epsi(m2,n+1)/rearth
            end do
        end do
    end

    function laplacian(input) result(output)
        complex, intent(in) :: input(mx,nx)
        complex :: output(mx,nx)

        output = -input*el2
    end function

    function inverse_laplacian(input) result(output)
        complex, intent(in) :: input(mx,nx)
        complex :: output(mx,nx)

        output = -input*elm2
    end function

    function spec_to_grid(vorm, kcos) result(vorg)
        use legendre, only: legendre_inv
        use fourier, only: fourier_inv

        complex, intent(in) :: vorm(mx,nx)
        integer, intent(in) :: kcos

        real :: vorg(ix,il)
        real :: vorm_r(2*mx,nx)

        vorm_r = reshape(transfer(vorm, vorm_r), (/ 2*mx, nx /))
        vorg = fourier_inv(legendre_inv(vorm_r), kcos)
    end function

    function grid_to_spec(vorg) result(vorm)
        use legendre, only: legendre_dir
        use fourier, only: fourier_dir

        real, intent(in) :: vorg(ix,il)
        complex :: vorm(mx,nx)
        real :: vorm_r(2*mx,nx)

        vorm_r = legendre_dir(fourier_dir(vorg))
        vorm = reshape(transfer(vorm_r, vorm), (/ mx, nx /))
    end function

    subroutine grad(psi,psdx,psdy)
        complex, dimension(mx,nx), intent(inout) :: psi
        complex, dimension(mx,nx), intent(inout) :: psdx, psdy

        integer :: n, m

        do n = 1, nx
            psdx(:,n) = gradx*psi(:,n)*(0.0, 1.0)
        end do

        do m=1,mx
            psdy(m,1)  =  gradyp(m,1)*psi(m,2)
            psdy(m,nx) = -gradym(m,nx)*psi(m,trunc+1)
        end do

        do n=2,trunc + 1
            do m=1,mx
                psdy(m,n) = -gradym(m,n)*psi(m,n-1) + gradyp(m,n)*psi(m,n+1)
            end do
        end do
    end

    subroutine vds(ucosm,vcosm,vorm,divm)
        complex, dimension(mx,nx) :: ucosm, vcosm
        complex, dimension(mx,nx), intent(inout) :: vorm, divm
        complex, dimension(mx,nx) :: zc, zp

        integer :: n, m

        do n=1,nx
            zp(:,n) = gradx*ucosm(:,n)*(0.0, 1.0)
            zc(:,n) = gradx*vcosm(:,n)*(0.0, 1.0)
        end do

        do m=1,mx
            vorm(m,1)  = zc(m,1) - vddyp(m,1)*ucosm(m,2)
            vorm(m,nx) = vddym(m,nx)*ucosm(m,trunc+1)
            divm(m,1)  = zp(m,1) + vddyp(m,1)*vcosm(m,2)
            divm(m,nx) = -vddym(m,nx)*vcosm(m,trunc+1)
        end do

        do n=2,trunc + 1
            do m=1,mx
                vorm(m,n) =  vddym(m,n)*ucosm(m,n-1) - vddyp(m,n)*ucosm(m,n+1) + zc(m,n)
                divm(m,n) = -vddym(m,n)*vcosm(m,n-1) + vddyp(m,n)*vcosm(m,n+1) + zp(m,n)
            end do
        end do
    end

    subroutine uvspec(vorm,divm,ucosm,vcosm)
        complex, dimension(mx,nx), intent(in) :: vorm,divm
        complex, dimension(mx,nx), intent(inout) :: ucosm,vcosm
        complex, dimension(mx,nx) :: zc,zp

        integer :: n, m

        zp = uvdx*vorm*(0.0, 1.0)
        zc = uvdx*divm*(0.0, 1.0)

        do m=1,mx
            ucosm(m,1)  =  zc(m,1) - uvdyp(m,1)*vorm(m,2)
            ucosm(m,nx) =  uvdym(m,nx)*vorm(m,trunc+1)
            vcosm(m,1)  =  zp(m,1) + uvdyp(m,1)*divm(m,2)
            vcosm(m,nx) = -uvdym(m,nx)*divm(m,trunc+1)
        end do

        do n=2,trunc + 1
            do m=1,mx
              vcosm(m,n) = -uvdym(m,n)*divm(m,n-1) + uvdyp(m,n)*divm(m,n+1) + zp(m,n)
              ucosm(m,n) =  uvdym(m,n)*vorm(m,n-1) - uvdyp(m,n)*vorm(m,n+1) + zc(m,n)
            end do
        end do
    end

    subroutine vdspec(ug,vg,vorm,divm,kcos)
        use geometry, only: cosgr, cosgr2

        real, intent(in) :: ug(ix,il), vg(ix,il)
        complex, intent(out) :: vorm(mx,nx), divm(mx,nx)
        integer, intent(in) :: kcos
        integer :: i, j
        real :: ug1(ix,il), vg1(ix,il)
        complex :: specu(mx,nx), specv(mx,nx)

        if (kcos.eq.2) then
            do j=1,il
                do i=1,ix
                    ug1(i,j)=ug(i,j)*cosgr(j)
                    vg1(i,j)=vg(i,j)*cosgr(j)
                end do
            end do
        else
            do j=1,il
                do i=1,ix
                    ug1(i,j)=ug(i,j)*cosgr2(j)
                    vg1(i,j)=vg(i,j)*cosgr2(j)
                end do
            end do
        end if

        specu = grid_to_spec(ug1)
        specv = grid_to_spec(vg1)
        call vds(specu,specv,vorm,divm)
    end

    subroutine trunct(vor)
        complex, intent(inout) :: vor(mx,nx)

        vor = vor * trfilt
    end
end module