sppt.f90 Source File


This file depends on

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

Files dependent on this one

sourcefile~~sppt.f90~~AfferentGraph sourcefile~sppt.f90 sppt.f90 sourcefile~physics.f90 physics.f90 sourcefile~physics.f90->sourcefile~sppt.f90 sourcefile~initialization.f90 initialization.f90 sourcefile~initialization.f90->sourcefile~physics.f90 sourcefile~time_stepping.f90 time_stepping.f90 sourcefile~initialization.f90->sourcefile~time_stepping.f90 sourcefile~tendencies.f90 tendencies.f90 sourcefile~tendencies.f90->sourcefile~physics.f90 sourcefile~speedy.f90 speedy.f90 sourcefile~speedy.f90->sourcefile~initialization.f90 sourcefile~speedy.f90->sourcefile~time_stepping.f90 sourcefile~time_stepping.f90->sourcefile~tendencies.f90

Contents

Source Code


Source Code

!> author: Sam Hatfield
!  date: 29/04/2019
!  For computing stochastically perturbed parametrization tendency (SPPT)
!  patterns.
!
!  To be used as multiplicative noise applied to physical tendencies. SPPT is
!  a parametrization of model error.
!  See ECMWF Tech. Memo. #598 (Palmer et al. 2009).
module sppt
    use params

    implicit none

    private
    public mu, gen_sppt

    !> Array for tapering value of SPPT in the different layers of the
    !  atmosphere. A value of 1 means the tendency is not tapered at that level
    real :: mu(kx) = (/ 1, 1, 1, 1, 1, 1, 1, 1 /)

    !> SPPT pattern in spectral space
    complex :: sppt_spec(mx,nx,kx)

    !> Flag for controlling first-use behaviour
    logical :: first = .true.

    !> Decorrelation time of SPPT perturbation (in hours)
    real, parameter :: time_decorr = 6.0

    !> Time autocorrelation of spectral AR(1) signals
    real :: phi = exp(-(24/real(nsteps))/time_decorr)

    !> Correlation length scale of SPPT perturbation (in metres)
    real, parameter :: len_decorr = 500000.0

    !> Standard deviation of SPPT perturbation (in grid point space)
    real, parameter :: stddev = 0.33

    !> Total wavenumber-wise standard deviation of spectral signals
    real :: sigma(mx,nx,kx)

    contains
        !> Generate grid point space SPPT pattern distribution.
        function gen_sppt() result(sppt_grid)
            use spectral, only: el2, spec_to_grid
            use physical_constants, only: rearth

            real :: sppt_grid(ix,il,kx) !! The generated grid point pattern

            integer :: m, n, k
            complex :: eta(mx,nx,kx)
            real :: f0, randreal, randimag

            ! Seed RNG if first use of SPPT
            if (first) call time_seed()

            ! Generate Gaussian noise
            do m = 1, mx
                do n = 1, nx
                    do k = 1, kx
                        randreal = randn(0.0, 1.0)
                        randimag = randn(0.0, 1.0)

                        ! Clip noise to +- 10 standard deviations
                        eta(m,n,k) = cmplx(&
                            & min(10.0, abs(randreal)) * sign(1.0,randreal),&
                            & min(10.0, abs(randimag)) * sign(1.0,randimag))
                    end do
                end do
            end do

            ! If first timestep
            if (first) then
                ! Generate spatial amplitude pattern and time correlation
                f0 = sum((/ ((2*n+1)*exp(-0.5*(len_decorr/rearth)**2*n*(n+1)), n = 1, trunc) /))
                f0 = sqrt((stddev**2*(1-phi**2))/(2*f0))

                do k = 1, kx
                    sigma(:,:,k) = f0 * exp(-0.25*len_decorr**2 * el2)
                end do

                ! First AR(1) step
                sppt_spec = (1 - phi**2)**(-0.5) * sigma * eta

                first = .false.
            else
                ! Subsequent AR(1) steps
                sppt_spec = phi*sppt_spec + sigma*eta
            end if

            ! Convert to grid point space
             do k = 1, kx
                 sppt_grid(:,:,k) = spec_to_grid(sppt_spec(:,:,k), 1)
             end do

             ! Clip to +/- 1.0
             sppt_grid = min(1.0, abs(sppt_grid)) * sign(1.0,sppt_grid)
        end function

        !> Generates a random number drawn for the specified normal distribution.
        function randn(mean, stdev)
            real, intent(in) :: mean  !! The mean of the distribution to draw from
            real, intent(in) :: stdev !! The standard deviation of the distribution to draw from
            real             :: randn !! The generated random number

            real :: u, v
            real :: rand(2)

            call random_number(rand)

            ! Box-Muller method
            u = (-2.0 * log(rand(1))) ** 0.5
            v =   2.0 * 6.28318530718 * rand(2)
            randn = mean + stdev * u * sin(v)
        end function

        !> Seeds RNG from system clock.
        subroutine time_seed()
            integer :: i, n, clock
            integer, allocatable :: seed(:)

            call random_seed(size = n)
            allocate(seed(n))

            call system_clock(count=clock)

            seed = clock + 37 * (/ (i - 1, i = 1, n) /)
            call random_seed(put = seed)

            deallocate(seed)
        end subroutine
end module