surface_fluxes.f90 Source File


This file depends on

sourcefile~~surface_fluxes.f90~~EfferentGraph sourcefile~surface_fluxes.f90 surface_fluxes.f90 sourcefile~humidity.f90 humidity.f90 sourcefile~surface_fluxes.f90->sourcefile~humidity.f90 sourcefile~land_model.f90 land_model.f90 sourcefile~surface_fluxes.f90->sourcefile~land_model.f90 sourcefile~geometry.f90 geometry.f90 sourcefile~surface_fluxes.f90->sourcefile~geometry.f90 sourcefile~physical_constants.f90 physical_constants.f90 sourcefile~surface_fluxes.f90->sourcefile~physical_constants.f90 sourcefile~mod_radcon.f90 mod_radcon.f90 sourcefile~surface_fluxes.f90->sourcefile~mod_radcon.f90 sourcefile~params.f90 params.f90 sourcefile~surface_fluxes.f90->sourcefile~params.f90 sourcefile~humidity.f90->sourcefile~params.f90 sourcefile~land_model.f90->sourcefile~params.f90 sourcefile~date.f90 date.f90 sourcefile~land_model.f90->sourcefile~date.f90 sourcefile~input_output.f90 input_output.f90 sourcefile~land_model.f90->sourcefile~input_output.f90 sourcefile~boundaries.f90 boundaries.f90 sourcefile~land_model.f90->sourcefile~boundaries.f90 sourcefile~interpolation.f90 interpolation.f90 sourcefile~land_model.f90->sourcefile~interpolation.f90 sourcefile~auxiliaries.f90 auxiliaries.f90 sourcefile~land_model.f90->sourcefile~auxiliaries.f90 sourcefile~geometry.f90->sourcefile~physical_constants.f90 sourcefile~geometry.f90->sourcefile~params.f90 sourcefile~physical_constants.f90->sourcefile~params.f90 sourcefile~mod_radcon.f90->sourcefile~params.f90 sourcefile~date.f90->sourcefile~params.f90 sourcefile~input_output.f90->sourcefile~geometry.f90 sourcefile~input_output.f90->sourcefile~physical_constants.f90 sourcefile~input_output.f90->sourcefile~params.f90 sourcefile~input_output.f90->sourcefile~date.f90 sourcefile~spectral.f90 spectral.f90 sourcefile~input_output.f90->sourcefile~spectral.f90 sourcefile~boundaries.f90->sourcefile~physical_constants.f90 sourcefile~boundaries.f90->sourcefile~params.f90 sourcefile~boundaries.f90->sourcefile~input_output.f90 sourcefile~boundaries.f90->sourcefile~spectral.f90 sourcefile~interpolation.f90->sourcefile~params.f90 sourcefile~interpolation.f90->sourcefile~date.f90 sourcefile~auxiliaries.f90->sourcefile~params.f90 sourcefile~spectral.f90->sourcefile~geometry.f90 sourcefile~spectral.f90->sourcefile~physical_constants.f90 sourcefile~spectral.f90->sourcefile~params.f90 sourcefile~legendre.f90 legendre.f90 sourcefile~spectral.f90->sourcefile~legendre.f90 sourcefile~fourier.f90 fourier.f90 sourcefile~spectral.f90->sourcefile~fourier.f90 sourcefile~legendre.f90->sourcefile~geometry.f90 sourcefile~legendre.f90->sourcefile~physical_constants.f90 sourcefile~legendre.f90->sourcefile~params.f90 sourcefile~fourier.f90->sourcefile~geometry.f90 sourcefile~fourier.f90->sourcefile~params.f90

Files dependent on this one

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

Contents

Source Code


Source Code

!> Parametrization of surface fluxes
module surface_fluxes
    use params

    implicit none

    private
    public get_surface_fluxes, set_orog_land_sfc_drag

    !  Constants for surface fluxes
    real :: fwind0 = 0.95 !! Ratio of near-sfc wind to lowest-level wind

    !> Weight for near-sfc temperature extrapolation (0-1) :
    !  1 : linear extrapolation from two lowest levels
    !  0 : constant potential temperature ( = lowest level)
    real :: ftemp0 = 1.0

    !> Weight for near-sfc specific humidity extrapolation (0-1) :
    !  1 : extrap. with constant relative hum. ( = lowest level)
    !  0 : constant specific hum. ( = lowest level)
    real :: fhum0 = 0.0

    real :: cdl = 2.4e-3   !! Drag coefficient for momentum over land
    real :: cds = 1.0e-3   !! Drag coefficient for momentum over sea
    real :: chl = 1.2e-3   !! Heat exchange coefficient over land
    real :: chs = 0.9e-3   !! Heat exchange coefficient over sea
    real :: vgust = 5.0    !! Wind speed for sub-grid-scale gusts
    real :: ctday = 1.0e-2 !! Daily-cycle correction (dTskin/dSSRad)
    real :: dtheta = 3.0   !! Potential temp. gradient for stability correction
    real :: fstab = 0.67   !! Amplitude of stability correction (fraction)
    real :: hdrag = 2000.0 !! Height scale for orographic correction
    real :: clambda = 7.0  !! Heat conductivity in skin-to-root soil layer
    real :: clambsn = 7.0  !! Heat conductivity in soil for snow cover = 1


    real :: forog(ix,il) ! Time-invariant fields (initial. in SFLSET)

contains
    !> Compute surface fluxes of momentum, energy and moisture, and define surface
    !  skin temperature from energy balance
    subroutine get_surface_fluxes(psa, ua, va, ta, qa, rh, phi, phi0, fmask, tsea, ssrd, slrd, &
            & ustr, vstr, shf, evap, slru, hfluxn, tsfc, tskin, u0, v0, t0, lfluxland)
        use physical_constants, only: p0, rgas, cp, alhc, sbc, sigl, wvi
        use geometry, only: coa
        use mod_radcon, only: emisfc, alb_l, alb_s, snowc
        use land_model, only: stl_am, soilw_am
        use humidity, only: get_qsat, rel_hum_to_spec_hum

        real, intent(in) :: psa(ix,il)    !! Normalised surface pressure
        real, intent(in) :: ua(ix,il,kx)  !! u-wind
        real, intent(in) :: va(ix,il,kx)  !! v-wind
        real, intent(in) :: ta(ix,il,kx)  !! Temperature
        real, intent(in) :: qa(ix,il,kx)  !! Specific humidity [g/kg]
        real, intent(in) :: rh(ix,il,kx)  !! Relative humidity
        real, intent(in) :: phi(ix,il,kx) !! Geopotential
        real, intent(in) :: phi0(ix,il)   !! Surface geopotential
        real, intent(in) :: fmask(ix,il)  !! Fractional land-sea mask
        real, intent(in) :: tsea(ix,il)   !! Sea-surface temperature
        real, intent(in) :: ssrd(ix,il)   !! Downward flux of short-wave radiation at the surface
        real, intent(in) :: slrd(ix,il)   !! Downward flux of long-wave radiation at the surface
        logical, intent(in) :: lfluxland
        real, intent(out) :: ustr(ix,il,3) !! u-stress
        real, intent(out) :: vstr(ix,il,3) !! v-stress
        real, intent(out) :: shf(ix,il,3)  !! Sensible heat flux
        real, intent(out) :: evap(ix,il,3) !! Evaporation
        real, intent(out) :: slru(ix,il,3) !! Upward flux of long-wave radiation at the surface
        real, intent(out) :: hfluxn(ix,il,2) !! Net downward heat flux
        real, intent(out) :: tsfc(ix,il)   !! Surface temperature
        real, intent(out) :: tskin(ix,il)  !! Skin surface temperature
        real, intent(out) :: u0(ix,il) !! Near-surface u-wind
        real, intent(out) :: v0(ix,il) !! Near-surface v-wind
        real, intent(out) :: t0(ix,il) !! Near-surface temperature

        integer :: i, j, ks, nl1
        real, dimension(ix,il,2), save :: t1, q1
        real, dimension(ix,il,2) :: t2, qsat0
        real, save :: denvvs(ix,il,0:2)
        real :: dslr(ix,il), dtskin(ix,il), clamb(ix,il), astab, cdldv, cdsdv(ix,il), chlcp
        real :: dt1, dthl, dths, esbc, ghum0, gtemp0
        real :: rcp, rdth, tsk3(ix,il)

        logical lscasym, lskineb


        lscasym = .true.   ! true : use an asymmetric stability coefficient
        lskineb = .true.   ! true : redefine skin temp. from energy balance

        esbc  = emisfc*sbc

        ghum0 = 1.0 - fhum0

        ! =========================================================================
        ! Land surface
        ! =========================================================================

        if (lfluxland)  then
            ! 1. Extrapolation of wind, temp, hum. and density to the surface

            ! 1.1 Wind components
            u0 = fwind0 * ua(:,:,kx)
            v0 = fwind0 * va(:,:,kx)

            ! 1.2 Temperature
            gtemp0 = 1.0 - ftemp0
            rcp = 1.0/cp
            nl1 = kx-1

            do i = 1, ix
                do j = 1, il
                    ! Temperature difference between lowest level and sfc
                    dt1 = wvi(kx,2)*(ta(i,j,kx) - ta(i,j,nl1))

                    ! Extrapolated temperature using actual lapse rate (1:land, 2:sea)
                    t1(i,j,1) = ta(i,j,kx) + dt1
                    t1(i,j,2) = t1(i,j,1) - phi0(i,j)*dt1/(rgas*288.0*sigl(kx))

                    ! Extrapolated temperature using dry-adiab. lapse rate (1:land, 2:sea)
                    t2(i,j,2) = ta(i,j,kx) + rcp*phi(i,j,kx)
                    t2(i,j,1) = t2(i,j,2) - rcp*phi0(i,j)
                end do
            end do

            do i = 1, ix
                do j = 1, il
                    if (ta(i,j,kx) > ta(i,j,nl1)) then
                        ! Use extrapolated temp. if dT/dz < 0
                        t1(i,j,1) = ftemp0*t1(i,j,1) + gtemp0*t2(i,j,1)
                        t1(i,j,2) = ftemp0*t1(i,j,2) + gtemp0*t2(i,j,2)
                    else
                        ! Use temp. at lowest level if dT/dz > 0
                        t1(i,j,1) = ta(i,j,kx)
                        t1(i,j,2) = ta(i,j,kx)
                    endif
                    t0(i,j) = t1(i,j,2) + fmask(i,j)*(t1(i,j,1) - t1(i,j,2))
                end do
            end do

            ! 1.3 Density * wind speed (including gustiness factor)
            denvvs(:,:,0) = (p0*psa/(rgas*t0))*sqrt(u0**2.0 + v0**2.0 + vgust**2.0)

            ! 2. Compute land-sfc. fluxes using prescribed skin temperature

            ! 2.1 Define effective skin temperature to compensate for
            !     non-linearity of heat/moisture fluxes during the daily cycle
            do j = 1, il
                tskin(:,j) = stl_am(:,j) + ctday*sqrt(coa(j))*ssrd(:,j)*(1.0 - alb_l(:,j))*psa(:,j)
            end do

            ! 2.2 Stability correction = f[pot.temp.(sfc)-pot.temp.(air)]
            rdth  = fstab/dtheta
            astab = 1.0
            if (lscasym) astab = 0.5   ! to get smaller ds/dt in stable conditions

            do i = 1, ix
                do j = 1,il
                    ! Potential temp. difference (land+sea average)
                    if (tskin(i,j) > t2(i,j,1)) then
                        dthl = min(dtheta, tskin(i,j) - t2(i,j,1))
                    else
                        dthl = max(-dtheta, astab*(tskin(i,j) - t2(i,j,1)))
                    end if
                    denvvs(i,j,1) = denvvs(i,j,0)*(1.0 + dthl*rdth)
                end do
            end do

            ! 2.3 Wind stress
            do i = 1, ix
                do j = 1, il
                    cdldv       =  cdl*denvvs(i,j,0)*forog(i,j)
                    ustr(i,j,1) = -cdldv*ua(i,j,kx)
                    vstr(i,j,1) = -cdldv*va(i,j,kx)
                end do
            end do

            ! 2.4 Sensible heat flux
            chlcp = chl*cp
            shf(:,:,1) = chlcp*denvvs(:,:,1)*(tskin - t1(:,:,1))

            ! 2.5 Evaporation
            if (fhum0 > 0.0) then
                call rel_hum_to_spec_hum(t1, psa, 1.0, rh(:,:,kx), q1, qsat0(:,:,1))

                q1(:,:,1) = fhum0*q1(:,:,1) + ghum0*qa(:,:,kx)
            else
                q1(:,:,1) = qa(:,:,kx)
            end if

            qsat0(:,:,1) = get_qsat(tskin, psa, 1.0)
            evap(:,:,1) = chl*denvvs(:,:,1)*max(0.0, soilw_am*qsat0(:,:,1) - q1(:,:,1))

            ! 3. Compute land-surface energy balance;
            !    adjust skin temperature and heat fluxes

            ! 3.1. Emission of lw radiation from the surface
            !      and net heat fluxes into land surface
            tsk3 = tskin**3.0
            dslr = 4.0*esbc*tsk3
            slru(:,:,1) = esbc*tsk3*tskin
            hfluxn(:,:,1) = ssrd*(1.0 - alb_l) + slrd - (slru(:,:,1) + shf(:,:,1) + alhc*evap(:,:,1))

            ! 3.2 Re-definition of skin temperature from energy balance
            if (lskineb) then
                ! Compute net heat flux including flux into ground
                clamb = clambda + snowc*(clambsn - clambda)
                hfluxn(:,:,1) = hfluxn(:,:,1) - clamb*(tskin - stl_am)
                dtskin = tskin + 1.0

                ! Compute d(Evap) for a 1-degree increment of Tskin
                qsat0(:,:,2) = get_qsat(dtskin, psa, 1.0)

                do i = 1, ix
                    do j = 1, il
                        if (evap(i,j,1) > 0.0) then
                            qsat0(i,j,2) = soilw_am(i,j)*(qsat0(i,j,2) - qsat0(i,j,1))
                        else
                            qsat0(i,j,2) = 0.0
                        endif
                    end do
                end do

                ! Redefine skin temperature to balance the heat budget
                dtskin = hfluxn(:,:,1)/(clamb + dslr + chl*denvvs(:,:,1)*(cp + alhc*qsat0(:,:,2)))
                tskin = tskin + dtskin

                ! Add linear corrections to heat fluxes
                shf(:,:,1) = shf(:,:,1) + chlcp*denvvs(:,:,1)*dtskin
                evap(:,:,1) = evap(:,:,1) + chl*denvvs(:,:,1)*qsat0(:,:,2)*dtskin
                slru(:,:,1) = slru(:,:,1) + dslr*dtskin
                hfluxn(:,:,1) = clamb*(tskin - stl_am)
            end if

            rdth  = fstab/dtheta
            astab = 1.0
            if (lscasym) astab = 0.5   ! to get smaller dS/dT in stable conditions

            do i = 1, ix
                do j = 1, il
                    if (tsea(i,j) > t2(i,j,2)) then
                       dths = min(dtheta, tsea(i,j) - t2(i,j,2))
                    else
                       dths = max(-dtheta, astab*(tsea(i,j) - t2(i,j,2)))
                    end if
                    denvvs(i,j,2) = denvvs(i,j,0)*(1.0 + dths*rdth)
                end do
            end do

            if (fhum0 > 0.0) then
                call rel_hum_to_spec_hum(t1(:,:,2), psa, 1.0, rh(:,:,kx), q1(:,:,2), qsat0(:,:,2))

                q1(:,:,2) = fhum0*q1(:,:,2) + ghum0*qa(:,:,kx)
            else
                q1(:,:,2) = qa(:,:,kx)
            end if

            ! 4.2 Wind stress
            ks = 2

            cdsdv = cds*denvvs(:,:,ks)
            ustr(:,:,2) = -cdsdv*ua(:,:,kx)
            vstr(:,:,2) = -cdsdv*va(:,:,kx)
        end if

        ! =========================================================================
        ! Sea surface
        ! =========================================================================

        ! 4.3 Sensible heat flux
        shf(:,:,2) = chs*cp*denvvs(:,:,ks)*(tsea - t1(:,:,2))

        ! 4.4 Evaporation
        qsat0(:,:,2) = get_qsat(tsea, psa, 1.0)
        evap(:,:,2) = chs*denvvs(:,:,ks)*(qsat0(:,:,2) - q1(:,:,2))

        ! 4.5 Emission of lw radiation from the surface
        !     and net heat fluxes into sea surface
        slru(:,:,2) = esbc*tsea**4.0
        hfluxn(:,:,2) = ssrd*(1.0 - alb_s) + slrd - slru(:,:,2) + shf(:,:,2) + alhc*evap(:,:,2)

        ! =========================================================================
        ! Weighted average of surface fluxes and temperatures according to land-sea
        ! mask
        ! =========================================================================

        if (lfluxland)  then
            ustr(:,:,3) = ustr(:,:,2) + fmask*(ustr(:,:,1) - ustr(:,:,2))
            vstr(:,:,3) = vstr(:,:,2) + fmask*(vstr(:,:,1) - vstr(:,:,2))
            shf(:,:,3)  = shf(:,:,2)  + fmask*(shf(:,:,1)  - shf(:,:,2))
            evap(:,:,3) = evap(:,:,2) + fmask*(evap(:,:,1) - evap(:,:,2))
            slru(:,:,3) = slru(:,:,2) + fmask*(slru(:,:,1) - slru(:,:,2))

            tsfc  = tsea      + fmask*(stl_am - tsea)
            tskin = tsea      + fmask*(tskin  - tsea)
            t0    = t1(:,:,2) + fmask*(t1(:,:,1) - t1(:,:,2))
        end if
    end

    ! Compute orographic factor for land surface drag
    ! Input:   phi0 = surface geopotential
    subroutine set_orog_land_sfc_drag(phi0)
        use physical_constants, only: grav

        real, intent(in) :: phi0(ix,il)
        real :: rhdrag

        rhdrag = 1.0/(grav*hdrag)

        forog = 1.0 + rhdrag*(1.0 - exp(-max(phi0, 0.0)*rhdrag))
    end
end module