!>\file fv_sat_adj.F90 !! This file contains the GFDL in-core fast saturation adjustment. !! and it is an "intermediate physics" implemented in the remapping Lagrangian to !! Eulerian loop of FV3 solver. !*********************************************************************** !* GNU Lesser General Public License !* !* This file is part of the GFDL Cloud Microphysics. !* !* The GFDL Cloud Microphysics is free software: you can !8 redistribute it and/or modify it under the terms of the !* GNU Lesser General Public License as published by the !* Free Software Foundation, either version 3 of the License, or !* (at your option) any later version. !* !* The GFDL Cloud Microphysics is distributed in the hope it will be !* useful, but WITHOUT ANYWARRANTY; 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 Lesser General Public !* License along with the GFDL Cloud Microphysics. !* If not, see . !*********************************************************************** !> This module contains the GFDL in-core fast saturation adjustment !! called in FV3 dynamics solver. module fv_sat_adj ! Modules Included: ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
Module NameFunctions Included
constants_modrvgas, rdgas, grav, hlv, hlf, cp_air
fv_arrays_mod r_grid
fv_mp_modis_master
gfdl_cloud_microphys_modql_gen, qi_gen, qi0_max, ql_mlt, ql0_max, qi_lim, qs_mlt, ! tau_r2g, tau_smlt, tau_i2s, tau_v2l, tau_l2v, tau_imlt, tau_l2r, ! rad_rain, rad_snow, rad_graupel, dw_ocean, dw_land, tintqs
! DH* TODO - MAKE THIS INPUT ARGUMENTS *DH use physcons, only : rdgas => con_rd_dyn, & rvgas => con_rv_dyn, & grav => con_g_dyn, & hlv => con_hvap_dyn, & hlf => con_hfus_dyn, & cp_air => con_cp_dyn ! *DH use machine, only: kind_grid, kind_dyn use gfdl_cloud_microphys_mod, only: ql_gen, qi_gen, qi0_max, ql_mlt, ql0_max, qi_lim, qs_mlt use gfdl_cloud_microphys_mod, only: icloud_f, sat_adj0, t_sub, cld_min use gfdl_cloud_microphys_mod, only: tau_r2g, tau_smlt, tau_i2s, tau_v2l, tau_l2v, tau_imlt, tau_l2r use gfdl_cloud_microphys_mod, only: rad_rain, rad_snow, rad_graupel, dw_ocean, dw_land, tintqs #ifdef MULTI_GASES use ccpp_multi_gases_mod, only: multi_gases_init, & multi_gases_finalize, & virq_qpz, vicpqd_qpz, & vicvqd_qpz, num_gas #endif implicit none private public fv_sat_adj_init, fv_sat_adj_run, fv_sat_adj_finalize logical :: is_initialized = .false. real(kind=kind_dyn), parameter :: rrg = -rdgas/grav ! real, parameter :: cp_air = cp_air ! 1004.6, heat capacity of dry air at constant pressure, come from constants_mod real(kind=kind_dyn), parameter :: cp_vap = 4.0 * rvgas !< 1846.0, heat capacity of water vapor at constant pressure real(kind=kind_dyn), parameter :: cv_air = cp_air - rdgas !< 717.55, heat capacity of dry air at constant volume real(kind=kind_dyn), parameter :: cv_vap = 3.0 * rvgas !< 1384.5, heat capacity of water vapor at constant volume ! http: / / www.engineeringtoolbox.com / ice - thermal - properties - d_576.html ! c_ice = 2050.0 at 0 deg c ! c_ice = 1972.0 at - 15 deg c ! c_ice = 1818.0 at - 40 deg c ! http: / / www.engineeringtoolbox.com / water - thermal - properties - d_162.html ! c_liq = 4205.0 at 4 deg c ! c_liq = 4185.5 at 15 deg c ! c_liq = 4178.0 at 30 deg c ! real, parameter :: c_ice = 2106.0 ! ifs: heat capacity of ice at 0 deg c ! real, parameter :: c_liq = 4218.0 ! ifs: heat capacity of liquid at 0 deg c real(kind=kind_dyn), parameter :: c_ice = 1972.0 !< gfdl: heat capacity of ice at - 15 deg c real(kind=kind_dyn), parameter :: c_liq = 4185.5 !< gfdl: heat capacity of liquid at 15 deg c real(kind=kind_dyn), parameter :: dc_vap = cp_vap - c_liq !< - 2339.5, isobaric heating / cooling real(kind=kind_dyn), parameter :: dc_ice = c_liq - c_ice !< 2213.5, isobaric heating / colling real(kind=kind_dyn), parameter :: tice = 273.16 !< freezing temperature real(kind=kind_dyn), parameter :: t_wfr = tice - 40. !< homogeneous freezing temperature real(kind=kind_dyn), parameter :: lv0 = hlv - dc_vap * tice !< 3.13905782e6, evaporation latent heat coefficient at 0 deg k real(kind=kind_dyn), parameter :: li00 = hlf - dc_ice * tice !< - 2.7105966e5, fusion latent heat coefficient at 0 deg k ! real (kind_grid), parameter :: e00 = 610.71 ! gfdl: saturation vapor pressure at 0 deg c real (kind_grid), parameter :: e00 = 611.21 !< ifs: saturation vapor pressure at 0 deg c real (kind_grid), parameter :: d2ice = dc_vap + dc_ice !< - 126, isobaric heating / cooling real (kind_grid), parameter :: li2 = lv0 + li00 !< 2.86799816e6, sublimation latent heat coefficient at 0 deg k real(kind=kind_dyn), parameter :: lat2 = (hlv + hlf) ** 2 !< used in bigg mechanism real(kind=kind_dyn) :: d0_vap !< the same as dc_vap, except that cp_vap can be cp_vap or cv_vap real(kind=kind_dyn) :: lv00 !< the same as lv0, except that cp_vap can be cp_vap or cv_vap real(kind=kind_dyn), allocatable :: table (:), table2 (:), tablew (:), des2 (:), desw (:) contains !>\brief The subroutine 'fv_sat_adj_init' initializes lookup tables for the saturation mixing ratio. !! \section arg_table_fv_sat_adj_init Argument Table !! \htmlinclude fv_sat_adj_init.html !! subroutine fv_sat_adj_init(do_sat_adj, kmp, nwat, ngas, rilist, cpilist, & mpirank, mpiroot, errmsg, errflg) implicit none ! Interface variables logical, intent(in ) :: do_sat_adj integer, intent(in ) :: kmp integer, intent(in ) :: nwat integer, intent(in ) :: ngas real(kind_dyn), intent(in ) :: rilist(0:ngas) real(kind_dyn), intent(in ) :: cpilist(0:ngas) integer, intent(in ) :: mpirank integer, intent(in ) :: mpiroot character(len=*), intent( out) :: errmsg integer, intent( out) :: errflg ! Local variables integer, parameter :: length = 2621 integer :: i ! Initialize the CCPP error handling variables errmsg = '' errflg = 0 ! If saturation adjustment is not used, return immediately if (.not.do_sat_adj) then write(errmsg,'(a)') 'Logic error: fv_sat_adj_init is called but do_sat_adj is set to false' errflg = 1 return end if if (.not.nwat==6) then write(errmsg,'(a)') 'Logic error: fv_sat_adj requires six water species (nwat=6)' errflg = 1 return end if if (is_initialized) return ! generate es table (dt = 0.1 deg c) allocate (table (length)) allocate (table2 (length)) allocate (tablew (length)) allocate (des2 (length)) allocate (desw (length)) call qs_table (length) call qs_table2 (length) call qs_tablew (length) do i = 1, length - 1 des2 (i) = max (0., table2 (i + 1) - table2 (i)) desw (i) = max (0., tablew (i + 1) - tablew (i)) enddo des2 (length) = des2 (length - 1) desw (length) = desw (length - 1) #ifdef MULTI_GASES call multi_gases_init(ngas,nwat,rilist,cpilist,mpirank==mpiroot) #endif is_initialized = .true. end subroutine fv_sat_adj_init !\ingroup fast_sat_adj !>\brief The subroutine 'fv_sat_adj_finalize' deallocates lookup tables for the saturation mixing ratio. !! \section arg_table_fv_sat_adj_finalize Argument Table !! \htmlinclude fv_sat_adj_finalize.html !! subroutine fv_sat_adj_finalize (errmsg, errflg) implicit none character(len=*), intent(out) :: errmsg integer, intent(out) :: errflg ! Initialize the CCPP error handling variables errmsg = '' errflg = 0 if (.not.is_initialized) return if (allocated(table )) deallocate(table ) if (allocated(table2)) deallocate(table2) if (allocated(tablew)) deallocate(tablew) if (allocated(des2 )) deallocate(des2 ) if (allocated(desw )) deallocate(desw ) #ifdef MULTI_GASES call multi_gases_finalize() #endif is_initialized = .false. end subroutine fv_sat_adj_finalize !>\defgroup fast_sat_adj GFDL In-Core Fast Saturation Adjustment Module !> @{ !! The subroutine 'fv_sat_adj' implements the fast processes in the GFDL !! Cloud MP. It is part of the GFDL Cloud MP. !>\author Shian-Jiann Lin, Linjiong Zhou !! !>\brief The subroutine 'fv_sat_adj' performs the fast processes in the GFDL microphysics. !>\details This is designed for single-moment 6-class cloud microphysics schemes. !! It handles the heat release due to in situ phase changes. !! !! \section arg_table_fv_sat_adj_run Argument Table !! \htmlinclude fv_sat_adj_run.html !! subroutine fv_sat_adj_run(mdt, zvir, is, ie, isd, ied, kmp, km, kmdelz, js, je, jsd, jed, & ng, hydrostatic, fast_mp_consv, te0_2d, te0, ngas, qvi, qv, ql, qi, qr, & qs, qg, hs, peln, delz, delp, pt, pkz, q_con, akap, cappa, area, dtdt, & out_dt, last_step, do_qa, qa, & nthreads, errmsg, errflg) implicit none ! Interface variables real(kind=kind_dyn), intent(in) :: mdt real(kind=kind_dyn), intent(in) :: zvir integer, intent(in) :: is integer, intent(in) :: ie integer, intent(in) :: isd integer, intent(in) :: ied integer, intent(in) :: kmp integer, intent(in) :: km integer, intent(in) :: kmdelz integer, intent(in) :: js integer, intent(in) :: je integer, intent(in) :: jsd integer, intent(in) :: jed integer, intent(in) :: ng logical, intent(in) :: hydrostatic logical, intent(in) :: fast_mp_consv real(kind=kind_dyn), intent(inout) :: te0_2d(is:ie, js:je) real(kind=kind_dyn), intent( out) :: te0(isd:ied, jsd:jed, 1:km) ! If multi-gases physics are not used, ngas is one and qvi identical to qv integer, intent(in) :: ngas real(kind=kind_dyn), intent(inout) :: qvi(isd:ied, jsd:jed, 1:km, 1:ngas) real(kind=kind_dyn), intent(inout) :: qv(isd:ied, jsd:jed, 1:km) real(kind=kind_dyn), intent(inout) :: ql(isd:ied, jsd:jed, 1:km) real(kind=kind_dyn), intent(inout) :: qi(isd:ied, jsd:jed, 1:km) real(kind=kind_dyn), intent(inout) :: qr(isd:ied, jsd:jed, 1:km) real(kind=kind_dyn), intent(inout) :: qs(isd:ied, jsd:jed, 1:km) real(kind=kind_dyn), intent(inout) :: qg(isd:ied, jsd:jed, 1:km) real(kind=kind_dyn), intent(in) :: hs(isd:ied, jsd:jed) real(kind=kind_dyn), intent(in) :: peln(is:ie, 1:km+1, js:je) ! For hydrostatic build, kmdelz=1, otherwise kmdelz=km (see fv_arrays.F90) real(kind=kind_dyn), intent(in) :: delz(is:ie, js:je, 1:kmdelz) real(kind=kind_dyn), intent(in) :: delp(isd:ied, jsd:jed, 1:km) real(kind=kind_dyn), intent(inout) :: pt(isd:ied, jsd:jed, 1:km) real(kind=kind_dyn), intent(inout) :: pkz(is:ie, js:je, 1:km) #ifdef USE_COND real(kind=kind_dyn), intent(inout) :: q_con(isd:ied, jsd:jed, 1:km) #else real(kind=kind_dyn), intent(inout) :: q_con(isd:isd, jsd:jsd, 1) #endif real(kind=kind_dyn), intent(in) :: akap #ifdef MOIST_CAPPA real(kind=kind_dyn), intent(inout) :: cappa(isd:ied, jsd:jed, 1:km) #else real(kind=kind_dyn), intent(inout) :: cappa(isd:ied, jsd:jed, 1) #endif ! DH* WARNING, allocation in fv_arrays.F90 is area(isd_2d:ied_2d, jsd_2d:jed_2d), ! where normally isd_2d = isd etc, but for memory optimization, these can be set ! to isd_2d=0, ied_2d=-1 etc. I don't believe this optimization is actually used, ! as it would break a whole lot of code (including the one below)! ! Assume thus that isd_2d = isd etc. real(kind_grid), intent(in) :: area(isd:ied, jsd:jed) real(kind=kind_dyn), intent(inout) :: dtdt(is:ie, js:je, 1:km) logical, intent(in) :: out_dt logical, intent(in) :: last_step logical, intent(in) :: do_qa real(kind=kind_dyn), intent( out) :: qa(isd:ied, jsd:jed, 1:km) integer, intent(in) :: nthreads character(len=*), intent( out) :: errmsg integer, intent( out) :: errflg ! Local variables real(kind=kind_dyn), dimension(is:ie,js:je) :: dpln integer :: kdelz integer :: k, j, i ! Initialize the CCPP error handling variables errmsg = '' errflg = 0 #ifndef FV3 ! Open parallel region if not already opened by host model !$OMP parallel num_threads(nthreads) default(none) & !$OMP shared(kmp,km,js,je,is,ie,peln,mdt, & !$OMP isd,jsd,delz,q_con,cappa,qa, & !$OMP do_qa,last_step,out_dt,dtdt, & !$OMP area,delp,pt,hs,qg,qs,qr,qi, & !$OMP ql,qv,te0,fast_mp_consv, & !$OMP hydrostatic,ng,zvir,pkz, & !$OMP akap,te0_2d,ngas,qvi) & !$OMP private(k,j,i,kdelz,dpln) #endif !$OMP do do k=kmp,km do j=js,je do i=is,ie dpln(i,j) = peln(i,k+1,j) - peln(i,k,j) enddo enddo if (hydrostatic) then kdelz = 1 else kdelz = k end if call fv_sat_adj_work(abs(mdt), zvir, is, ie, js, je, ng, hydrostatic, fast_mp_consv, & te0(isd,jsd,k), & #ifdef MULTI_GASES qvi(isd,jsd,k,1:ngas), & #else qv(isd,jsd,k), & #endif ql(isd,jsd,k), qi(isd,jsd,k), & qr(isd,jsd,k), qs(isd,jsd,k), qg(isd,jsd,k), & hs, dpln, delz(is:,js:,kdelz), pt(isd,jsd,k), delp(isd,jsd,k),& q_con(isd:,jsd:,k), cappa(isd:,jsd:,k), area, dtdt(is,js,k), & out_dt, last_step, do_qa, qa(isd,jsd,k)) if ( .not. hydrostatic ) then do j=js,je do i=is,ie #ifdef MOIST_CAPPA pkz(i,j,k) = exp(cappa(i,j,k)*log(rrg*delp(i,j,k)/delz(i,j,k)*pt(i,j,k))) #else #ifdef MULTI_GASES pkz(i,j,k) = exp(akap*(virqd(q(i,j,k,1:num_gas))/vicpqd(q(i,j,k,1:num_gas))*log(rrg*delp(i,j,k)/delz(i,j,k)*pt(i,j,k))) #else pkz(i,j,k) = exp(akap*log(rrg*delp(i,j,k)/delz(i,j,k)*pt(i,j,k))) #endif #endif enddo enddo endif enddo !$OMP end do if ( fast_mp_consv ) then !$OMP do do j=js,je do i=is,ie do k=kmp,km te0_2d(i,j) = te0_2d(i,j) + te0(i,j,k) enddo enddo enddo !$OMP end do endif #ifndef FV3 !$OMP end parallel #endif return end subroutine fv_sat_adj_run !>\ingroup fast_sat_adj !> This subroutine includes the entity of the fast saturation adjustment processes. !>\section fast_gen GFDL Cloud Fast Physics General Algorithm !> @{ subroutine fv_sat_adj_work(mdt, zvir, is, ie, js, je, ng, hydrostatic, consv_te, te0, & #ifdef MULTI_GASES qvi, & #else qv, & #endif ql, qi, qr, qs, qg, hs, dpln, delz, pt, dp, q_con, cappa, & area, dtdt, out_dt, last_step, do_qa, qa) implicit none ! Interface variables integer, intent (in) :: is, ie, js, je, ng logical, intent (in) :: hydrostatic, consv_te, out_dt, last_step, do_qa real(kind=kind_dyn), intent (in) :: zvir, mdt ! remapping time step real(kind=kind_dyn), intent (in), dimension (is - ng:ie + ng, js - ng:je + ng) :: dp, hs real(kind=kind_dyn), intent (in), dimension (is:ie, js:je) :: dpln, delz real(kind=kind_dyn), intent (inout), dimension (is - ng:ie + ng, js - ng:je + ng) :: pt #ifdef MULTI_GASES real(kind=kind_dyn), intent (inout), dimension (is - ng:ie + ng, js - ng:je + ng, 1:1, 1:num_gas) :: qvi #else real(kind=kind_dyn), intent (inout), dimension (is - ng:ie + ng, js - ng:je + ng) :: qv #endif real(kind=kind_dyn), intent (inout), dimension (is - ng:ie + ng, js - ng:je + ng) :: ql, qi, qr, qs, qg real(kind=kind_dyn), intent (inout), dimension (is - ng:ie + ng, js - ng:je + ng) :: q_con, cappa real(kind=kind_dyn), intent (inout), dimension (is:ie, js:je) :: dtdt real(kind=kind_dyn), intent (out), dimension (is - ng:ie + ng, js - ng:je + ng) :: qa, te0 real (kind_grid), intent (in), dimension (is - ng:ie + ng, js - ng:je + ng) :: area ! Local variables #ifdef MULTI_GASES real, dimension (is - ng:ie + ng, js - ng:je + ng) :: qv #endif real(kind=kind_dyn), dimension (is:ie) :: wqsat, dq2dt, qpz, cvm, t0, pt1, qstar real(kind=kind_dyn), dimension (is:ie) :: icp2, lcp2, tcp2, tcp3 real(kind=kind_dyn), dimension (is:ie) :: den, q_liq, q_sol, q_cond, src, sink, hvar real(kind=kind_dyn), dimension (is:ie) :: mc_air, lhl, lhi real(kind=kind_dyn) :: qsw, rh real(kind=kind_dyn) :: tc, qsi, dqsdt, dq, dq0, pidep, qi_crt, tmp, dtmp real(kind=kind_dyn) :: tin, rqi, q_plus, q_minus real(kind=kind_dyn) :: sdt, dt_bigg, adj_fac real(kind=kind_dyn) :: fac_smlt, fac_r2g, fac_i2s, fac_imlt, fac_l2r, fac_v2l, fac_l2v real(kind=kind_dyn) :: factor, qim, tice0, c_air, c_vap, dw integer :: i, j #ifdef MULTI_GASES qv(:,:) = qvi(:,:,1,1) #endif sdt = 0.5 * mdt ! half remapping time step dt_bigg = mdt ! bigg mechinism time step tice0 = tice - 0.01 ! 273.15, standard freezing temperature ! ----------------------------------------------------------------------- !> - Define conversion scalar / factor. ! ----------------------------------------------------------------------- fac_i2s = 1. - exp (- mdt / tau_i2s) fac_v2l = 1. - exp (- sdt / tau_v2l) fac_r2g = 1. - exp (- mdt / tau_r2g) fac_l2r = 1. - exp (- mdt / tau_l2r) fac_l2v = 1. - exp (- sdt / tau_l2v) fac_l2v = min (sat_adj0, fac_l2v) fac_imlt = 1. - exp (- sdt / tau_imlt) fac_smlt = 1. - exp (- mdt / tau_smlt) ! ----------------------------------------------------------------------- !> - Define heat capacity of dry air and water vapor based on hydrostatical property. ! ----------------------------------------------------------------------- if (hydrostatic) then c_air = cp_air c_vap = cp_vap else c_air = cv_air c_vap = cv_vap endif d0_vap = c_vap - c_liq lv00 = hlv - d0_vap * tice ! dc_vap = cp_vap - c_liq ! - 2339.5 ! d0_vap = cv_vap - c_liq ! - 2801.0 do j = js, je ! start j loop do i = is, ie q_liq (i) = ql (i, j) + qr (i, j) q_sol (i) = qi (i, j) + qs (i, j) + qg (i, j) qpz (i) = q_liq (i) + q_sol (i) #ifdef MULTI_GASES pt1 (i) = pt (i, j) / virq_qpz(qvi(i,j,1,1:num_gas),qpz(i)) #else #ifdef USE_COND pt1 (i) = pt (i, j) / ((1 + zvir * qv (i, j)) * (1 - qpz (i))) #else pt1 (i) = pt (i, j) / (1 + zvir * qv (i, j)) #endif #endif t0 (i) = pt1 (i) ! true temperature qpz (i) = qpz (i) + qv (i, j) ! total_wat conserved in this routine enddo ! ----------------------------------------------------------------------- !> - Define air density based on hydrostatical property. ! ----------------------------------------------------------------------- if (hydrostatic) then do i = is, ie den (i) = dp (i, j) / (dpln (i, j) * rdgas * pt (i, j)) enddo else do i = is, ie den (i) = - dp (i, j) / (grav * delz (i, j)) ! moist_air density enddo endif ! ----------------------------------------------------------------------- !> - Define heat capacity and latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie #ifdef MULTI_GASES if (hydrostatic) then c_air = cp_air * vicpqd_qpz(qvi(i,j,1,1:num_gas),qpz(i)) else c_air = cv_air * vicvqd_qpz(qvi(i,j,1,1:num_gas),qpz(i)) endif #endif mc_air (i) = (1. - qpz (i)) * c_air ! constant cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice lhi (i) = li00 + dc_ice * pt1 (i) icp2 (i) = lhi (i) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - Fix energy conservation. ! ----------------------------------------------------------------------- if (consv_te) then if (hydrostatic) then do i = is, ie #ifdef MULTI_GASES c_air = cp_air * vicpqd_qpz(qvi(i,j,1,1:num_gas),qpz(i)) #endif te0 (i, j) = - c_air * t0 (i) enddo else do i = is, ie #ifdef USE_COND te0 (i, j) = - cvm (i) * t0 (i) #else #ifdef MULTI_GASES c_air = cv_air * vicvqd_qpz(qvi(i,j,1,1:num_gas),qpz(i)) #endif te0 (i, j) = - c_air * t0 (i) #endif enddo endif endif ! ----------------------------------------------------------------------- !> - Fix negative cloud ice with snow. ! ----------------------------------------------------------------------- do i = is, ie if (qi (i, j) < 0.) then qs (i, j) = qs (i, j) + qi (i, j) qi (i, j) = 0. endif enddo ! ----------------------------------------------------------------------- !> - Melting of cloud ice to cloud water and rain. ! ----------------------------------------------------------------------- do i = is, ie if (qi (i, j) > 1.e-8 .and. pt1 (i) > tice) then sink (i) = min (qi (i, j), fac_imlt * (pt1 (i) - tice) / icp2 (i)) qi (i, j) = qi (i, j) - sink (i) ! sjl, may 17, 2017 ! tmp = min (sink (i), dim (ql_mlt, ql (i, j))) ! max ql amount ! ql (i, j) = ql (i, j) + tmp ! qr (i, j) = qr (i, j) + sink (i) - tmp ! sjl, may 17, 2017 ql (i, j) = ql (i, j) + sink (i) q_liq (i) = q_liq (i) + sink (i) q_sol (i) = q_sol (i) - sink (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) - sink (i) * lhi (i) / cvm (i) endif enddo ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhi (i) = li00 + dc_ice * pt1 (i) icp2 (i) = lhi (i) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - Fix negative snow with graupel or graupel with available snow. ! ----------------------------------------------------------------------- do i = is, ie if (qs (i, j) < 0.) then qg (i, j) = qg (i, j) + qs (i, j) qs (i, j) = 0. elseif (qg (i, j) < 0.) then tmp = min (- qg (i, j), max (0., qs (i, j))) qg (i, j) = qg (i, j) + tmp qs (i, j) = qs (i, j) - tmp endif enddo ! after this point cloud ice & snow are positive definite ! ----------------------------------------------------------------------- !> - Fix negative cloud water with rain or rain with available cloud water. ! ----------------------------------------------------------------------- do i = is, ie if (ql (i, j) < 0.) then tmp = min (- ql (i, j), max (0., qr (i, j))) ql (i, j) = ql (i, j) + tmp qr (i, j) = qr (i, j) - tmp elseif (qr (i, j) < 0.) then tmp = min (- qr (i, j), max (0., ql (i, j))) ql (i, j) = ql (i, j) - tmp qr (i, j) = qr (i, j) + tmp endif enddo ! ----------------------------------------------------------------------- !> - Enforce complete freezing of cloud water to cloud ice below - 48 c. ! ----------------------------------------------------------------------- do i = is, ie dtmp = tice - 48. - pt1 (i) if (ql (i, j) > 0. .and. dtmp > 0.) then sink (i) = min (ql (i, j), dtmp / icp2 (i)) ql (i, j) = ql (i, j) - sink (i) qi (i, j) = qi (i, j) + sink (i) q_liq (i) = q_liq (i) - sink (i) q_sol (i) = q_sol (i) + sink (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) + sink (i) * lhi (i) / cvm (i) endif enddo ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhl (i) = lv00 + d0_vap * pt1 (i) lhi (i) = li00 + dc_ice * pt1 (i) lcp2 (i) = lhl (i) / cvm (i) icp2 (i) = lhi (i) / cvm (i) tcp3 (i) = lcp2 (i) + icp2 (i) * min (1., dim (tice, pt1 (i)) /48.) enddo ! ----------------------------------------------------------------------- !> - Condensation/evaporation between water vapor and cloud water. ! ----------------------------------------------------------------------- call wqs2_vect (is, ie, pt1, den, wqsat, dq2dt) adj_fac = sat_adj0 do i = is, ie dq0 = (qv (i, j) - wqsat (i)) / (1. + tcp3 (i) * dq2dt (i)) if (dq0 > 0.) then ! whole grid - box saturated src (i) = min (adj_fac * dq0, max (ql_gen - ql (i, j), fac_v2l * dq0)) else ! evaporation of ql ! sjl 20170703 added ql factor to prevent the situation of high ql and rh<1 ! factor = - min (1., fac_l2v * sqrt (max (0., ql (i, j)) / 1.e-5) * 10. * (1. - qv (i, j) / wqsat (i))) ! factor = - fac_l2v ! factor = - 1 factor = - min (1., fac_l2v * 10. * (1. - qv (i, j) / wqsat (i))) ! the rh dependent factor = 1 at 90% src (i) = - min (ql (i, j), factor * dq0) endif qv (i, j) = qv (i, j) - src (i) #ifdef MULTI_GASES qvi(i,j,1,1) = qv (i, j) #endif ql (i, j) = ql (i, j) + src (i) q_liq (i) = q_liq (i) + src (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) + src (i) * lhl (i) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhl (i) = lv00 + d0_vap * pt1 (i) lhi (i) = li00 + dc_ice * pt1 (i) lcp2 (i) = lhl (i) / cvm (i) icp2 (i) = lhi (i) / cvm (i) tcp3 (i) = lcp2 (i) + icp2 (i) * min (1., dim (tice, pt1 (i)) / 48.) enddo if (last_step) then ! ----------------------------------------------------------------------- !> - condensation/evaporation between water vapor and cloud water, last time step !! enforce upper (no super_sat) & lower (critical rh) bounds. ! final iteration: ! ----------------------------------------------------------------------- call wqs2_vect (is, ie, pt1, den, wqsat, dq2dt) do i = is, ie dq0 = (qv (i, j) - wqsat (i)) / (1. + tcp3 (i) * dq2dt (i)) if (dq0 > 0.) then ! remove super - saturation, prevent super saturation over water src (i) = dq0 else ! evaporation of ql ! factor = - min (1., fac_l2v * sqrt (max (0., ql (i, j)) / 1.e-5) * 10. * (1. - qv (i, j) / wqsat (i))) ! the rh dependent factor = 1 at 90% ! factor = - fac_l2v ! factor = - 1 factor = - min (1., fac_l2v * 10. * (1. - qv (i, j) / wqsat (i))) ! the rh dependent factor = 1 at 90% src (i) = - min (ql (i, j), factor * dq0) endif adj_fac = 1. qv (i, j) = qv (i, j) - src (i) #ifdef MULTI_GASES qvi(i,j,1,1) = qv(i,j) #endif ql (i, j) = ql (i, j) + src (i) q_liq (i) = q_liq (i) + src (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) + src (i) * lhl (i) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhl (i) = lv00 + d0_vap * pt1 (i) lhi (i) = li00 + dc_ice * pt1 (i) lcp2 (i) = lhl (i) / cvm (i) icp2 (i) = lhi (i) / cvm (i) enddo endif ! ----------------------------------------------------------------------- !> - Homogeneous freezing of cloud water to cloud ice. ! ----------------------------------------------------------------------- do i = is, ie dtmp = t_wfr - pt1 (i) ! [ - 40, - 48] if (ql (i, j) > 0. .and. dtmp > 0.) then sink (i) = min (ql (i, j), ql (i, j) * dtmp * 0.125, dtmp / icp2 (i)) ql (i, j) = ql (i, j) - sink (i) qi (i, j) = qi (i, j) + sink (i) q_liq (i) = q_liq (i) - sink (i) q_sol (i) = q_sol (i) + sink (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) + sink (i) * lhi (i) / cvm (i) endif enddo ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhi (i) = li00 + dc_ice * pt1 (i) icp2 (i) = lhi (i) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - bigg mechanism (heterogeneous freezing of cloud water to cloud ice). ! ----------------------------------------------------------------------- do i = is, ie tc = tice0 - pt1 (i) if (ql (i, j) > 0.0 .and. tc > 0.) then sink (i) = 3.3333e-10 * dt_bigg * (exp (0.66 * tc) - 1.) * den (i) * ql (i, j) ** 2 sink (i) = min (ql (i, j), tc / icp2 (i), sink (i)) ql (i, j) = ql (i, j) - sink (i) qi (i, j) = qi (i, j) + sink (i) q_liq (i) = q_liq (i) - sink (i) q_sol (i) = q_sol (i) + sink (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) + sink (i) * lhi (i) / cvm (i) endif enddo ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhi (i) = li00 + dc_ice * pt1 (i) icp2 (i) = lhi (i) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - Freezing of rain to graupel. ! ----------------------------------------------------------------------- do i = is, ie dtmp = (tice - 0.1) - pt1 (i) if (qr (i, j) > 1.e-7 .and. dtmp > 0.) then tmp = min (1., (dtmp * 0.025) ** 2) * qr (i, j) ! no limit on freezing below - 40 deg c sink (i) = min (tmp, fac_r2g * dtmp / icp2 (i)) qr (i, j) = qr (i, j) - sink (i) qg (i, j) = qg (i, j) + sink (i) q_liq (i) = q_liq (i) - sink (i) q_sol (i) = q_sol (i) + sink (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) + sink (i) * lhi (i) / cvm (i) endif enddo ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhi (i) = li00 + dc_ice * pt1 (i) icp2 (i) = lhi (i) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - Melting of snow to rain or cloud water. ! ----------------------------------------------------------------------- do i = is, ie dtmp = pt1 (i) - (tice + 0.1) if (qs (i, j) > 1.e-7 .and. dtmp > 0.) then tmp = min (1., (dtmp * 0.1) ** 2) * qs (i, j) ! no limter on melting above 10 deg c sink (i) = min (tmp, fac_smlt * dtmp / icp2 (i)) tmp = min (sink (i), dim (qs_mlt, ql (i, j))) ! max ql due to snow melt qs (i, j) = qs (i, j) - sink (i) ql (i, j) = ql (i, j) + tmp qr (i, j) = qr (i, j) + sink (i) - tmp ! qr (i, j) = qr (i, j) + sink (i) q_liq (i) = q_liq (i) + sink (i) q_sol (i) = q_sol (i) - sink (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) - sink (i) * lhi (i) / cvm (i) endif enddo ! ----------------------------------------------------------------------- !> - Autoconversion from cloud water to rain. ! ----------------------------------------------------------------------- do i = is, ie if (ql (i, j) > ql0_max) then sink (i) = fac_l2r * (ql (i, j) - ql0_max) qr (i, j) = qr (i, j) + sink (i) ql (i, j) = ql (i, j) - sink (i) endif enddo ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhi (i) = li00 + dc_ice * pt1 (i) lhl (i) = lv00 + d0_vap * pt1 (i) lcp2 (i) = lhl (i) / cvm (i) icp2 (i) = lhi (i) / cvm (i) tcp2 (i) = lcp2 (i) + icp2 (i) enddo ! ----------------------------------------------------------------------- !> - Sublimation/deposition between water vapor and cloud ice. ! ----------------------------------------------------------------------- do i = is, ie src (i) = 0. if (pt1 (i) < t_sub) then ! too cold to be accurate; freeze qv as a fix src (i) = dim (qv (i, j), 1.e-6) elseif (pt1 (i) < tice0) then qsi = iqs2 (pt1 (i), den (i), dqsdt) dq = qv (i, j) - qsi sink (i) = adj_fac * dq / (1. + tcp2 (i) * dqsdt) if (qi (i, j) > 1.e-8) then pidep = sdt * dq * 349138.78 * exp (0.875 * log (qi (i, j) * den (i))) & / (qsi * den (i) * lat2 / (0.0243 * rvgas * pt1 (i) ** 2) + 4.42478e4) else pidep = 0. endif if (dq > 0.) then ! vapor - > ice tmp = tice - pt1 (i) qi_crt = qi_gen * min (qi_lim, 0.1 * tmp) / den (i) src (i) = min (sink (i), max (qi_crt - qi (i, j), pidep), tmp / tcp2 (i)) else pidep = pidep * min (1., dim (pt1 (i), t_sub) * 0.2) src (i) = max (pidep, sink (i), - qi (i, j)) endif endif qv (i, j) = qv (i, j) - src (i) #ifdef MULTI_GASES qvi(i,j,1,1) = qv(i,j) #endif qi (i, j) = qi (i, j) + src (i) q_sol (i) = q_sol (i) + src (i) cvm (i) = mc_air (i) + qv (i, j) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice pt1 (i) = pt1 (i) + src (i) * (lhl (i) + lhi (i)) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - Virtual temperature updated. ! ----------------------------------------------------------------------- do i = is, ie #ifdef USE_COND q_con (i, j) = q_liq (i) + q_sol (i) #ifdef MULTI_GASES pt (i, j) = pt1 (i) * virq_qpz(qvi(i,j,1,1:num_gas),q_con(i,j)) #else tmp = 1. + zvir * qv (i, j) pt (i, j) = pt1 (i) * tmp * (1. - q_con (i, j)) #endif tmp = rdgas * tmp cappa (i, j) = tmp / (tmp + cvm (i)) #else #ifdef MULTI_GASES q_con (i, j) = q_liq (i) + q_sol (i) pt (i, j) = pt1 (i) * virq_qpz(qvi(i,j,1,1:num_gas),q_con(i,j)) * (1. - q_con(i,j)) #else pt (i, j) = pt1 (i) * (1. + zvir * qv (i, j)) #endif #endif enddo ! ----------------------------------------------------------------------- !> - Fix negative graupel with available cloud ice. ! ----------------------------------------------------------------------- do i = is, ie if (qg (i, j) < 0.) then tmp = min (- qg (i, j), max (0., qi (i, j))) qg (i, j) = qg (i, j) + tmp qi (i, j) = qi (i, j) - tmp endif enddo ! ----------------------------------------------------------------------- !> - Autoconversion from cloud ice to snow. ! ----------------------------------------------------------------------- do i = is, ie qim = qi0_max / den (i) if (qi (i, j) > qim) then sink (i) = fac_i2s * (qi (i, j) - qim) qi (i, j) = qi (i, j) - sink (i) qs (i, j) = qs (i, j) + sink (i) endif enddo if (out_dt) then do i = is, ie dtdt (i, j) = dtdt (i, j) + pt1 (i) - t0 (i) enddo endif ! ----------------------------------------------------------------------- !> - Fix energy conservation. ! ----------------------------------------------------------------------- if (consv_te) then do i = is, ie if (hydrostatic) then #ifdef MULTI_GASES c_air = cp_air * vicpqd_qpz(qvi(i,j,1,1:num_gas),qpz(i)) #endif te0 (i, j) = dp (i, j) * (te0 (i, j) + c_air * pt1 (i)) else #ifdef USE_COND te0 (i, j) = dp (i, j) * (te0 (i, j) + cvm (i) * pt1 (i)) #else #ifdef MULTI_GASES c_air = cv_air * vicvqd_qpz(qvi(i,j,1,1:num_gas),qpz(i)) #endif te0 (i, j) = dp (i, j) * (te0 (i, j) + c_air * pt1 (i)) #endif endif enddo endif ! ----------------------------------------------------------------------- !> - Update latend heat coefficient. ! ----------------------------------------------------------------------- do i = is, ie lhi (i) = li00 + dc_ice * pt1 (i) lhl (i) = lv00 + d0_vap * pt1 (i) cvm (i) = mc_air (i) + (qv (i, j) + q_liq (i) + q_sol (i)) * c_vap lcp2 (i) = lhl (i) / cvm (i) icp2 (i) = lhi (i) / cvm (i) enddo ! ----------------------------------------------------------------------- !> - Compute cloud fraction. ! ----------------------------------------------------------------------- if (do_qa .and. last_step) then ! ----------------------------------------------------------------------- !> - If it is the last step, combine water species. ! ----------------------------------------------------------------------- if (rad_snow) then if (rad_graupel) then do i = is, ie q_sol (i) = qi (i, j) + qs (i, j) + qg (i, j) enddo else do i = is, ie q_sol (i) = qi (i, j) + qs (i, j) enddo endif else do i = is, ie q_sol (i) = qi (i, j) enddo endif if (rad_rain) then do i = is, ie q_liq (i) = ql (i, j) + qr (i, j) enddo else do i = is, ie q_liq (i) = ql (i, j) enddo endif do i = is, ie q_cond (i) = q_sol (i) + q_liq (i) enddo ! ----------------------------------------------------------------------- !> - Use the "liquid - frozen water temperature" (tin) to compute saturated specific humidity. ! ----------------------------------------------------------------------- do i = is, ie if(tintqs) then tin = pt1(i) else tin = pt1 (i) - (lcp2 (i) * q_cond (i) + icp2 (i) * q_sol (i)) ! minimum temperature ! tin = pt1 (i) - ((lv00 + d0_vap * pt1 (i)) * q_cond (i) + & ! (li00 + dc_ice * pt1 (i)) * q_sol (i)) / (mc_air (i) + qpz (i) * c_vap) endif ! ----------------------------------------------------------------------- ! determine saturated specific humidity ! ----------------------------------------------------------------------- if (tin <= t_wfr) then ! ice phase: qstar (i) = iqs1 (tin, den (i)) elseif (tin >= tice) then ! liquid phase: qstar (i) = wqs1 (tin, den (i)) else ! mixed phase: qsi = iqs1 (tin, den (i)) qsw = wqs1 (tin, den (i)) if (q_cond (i) > 1.e-6) then rqi = q_sol (i) / q_cond (i) else ! mostly liquid water clouds at initial cloud development stage rqi = ((tice - tin) / (tice - t_wfr)) endif qstar (i) = rqi * qsi + (1. - rqi) * qsw endif !> - higher than 10 m is considered "land" and will have higher subgrid variability dw = dw_ocean + (dw_land - dw_ocean) * min (1., abs (hs (i, j)) / (10. * grav)) !> - "scale - aware" subgrid variability: 100 - km as the base hvar (i) = min (0.2, max (0.01, dw * sqrt (sqrt (area (i, j)) / 100.e3))) ! ----------------------------------------------------------------------- !> - calculate partial cloudiness by pdf; !! assuming subgrid linear distribution in horizontal; this is effectively a smoother for the !! binary cloud scheme; qa = 0.5 if qstar (i) == qpz ! ----------------------------------------------------------------------- rh = qpz (i) / qstar (i) ! ----------------------------------------------------------------------- ! icloud_f = 0: bug - fixed ! icloud_f = 1: old fvgfs gfdl) mp implementation ! icloud_f = 2: binary cloud scheme (0 / 1) ! ----------------------------------------------------------------------- if (rh > 0.75 .and. qpz (i) > 1.e-8) then dq = hvar (i) * qpz (i) q_plus = qpz (i) + dq q_minus = qpz (i) - dq if (icloud_f == 2) then if (qpz (i) > qstar (i)) then qa (i, j) = 1. elseif (qstar (i) < q_plus .and. q_cond (i) > 1.e-8) then qa (i, j) = ((q_plus - qstar (i)) / dq) ** 2 qa (i, j) = min (1., qa (i, j)) else qa (i, j) = 0. endif else if (qstar (i) < q_minus) then qa (i, j) = 1. else if (qstar (i) < q_plus) then if (icloud_f == 0) then qa (i, j) = (q_plus - qstar (i)) / (dq + dq) else qa (i, j) = (q_plus - qstar (i)) / (2. * dq * (1. - q_cond (i))) endif else qa (i, j) = 0. endif ! impose minimum cloudiness if substantial q_cond (i) exist if (q_cond (i) > 1.e-8) then qa (i, j) = max (cld_min, qa (i, j)) endif qa (i, j) = min (1., qa (i, j)) endif endif else qa (i, j) = 0. endif enddo endif enddo ! end j loop end subroutine fv_sat_adj_work !> @} ! ======================================================================= !>\ingroup fast_sat_adj !>\brief the function 'wqs1' computes the !! saturated specific humidity for table ii. ! ======================================================================= real(kind=kind_dyn) function wqs1 (ta, den) implicit none ! pure water phase; universal dry / moist formular using air density ! input "den" can be either dry or moist air density real(kind=kind_dyn), intent (in) :: ta, den real(kind=kind_dyn) :: es, ap1, tmin integer :: it tmin = tice - 160. ap1 = 10. * dim (ta, tmin) + 1. ap1 = min (2621., ap1) it = ap1 es = tablew (it) + (ap1 - it) * desw (it) wqs1 = es / (rvgas * ta * den) end function wqs1 ! ======================================================================= !>\ingroup fast_sat_adj !>\brief the function 'wqs1' computes the saturated specific humidity !! for table iii ! ======================================================================= real(kind=kind_dyn) function iqs1 (ta, den) implicit none ! water - ice phase; universal dry / moist formular using air density ! input "den" can be either dry or moist air density real(kind=kind_dyn), intent (in) :: ta, den real(kind=kind_dyn) :: es, ap1, tmin integer :: it tmin = tice - 160. ap1 = 10. * dim (ta, tmin) + 1. ap1 = min (2621., ap1) it = ap1 es = table2 (it) + (ap1 - it) * des2 (it) iqs1 = es / (rvgas * ta * den) end function iqs1 ! ======================================================================= !>\ingroup fast_sat_adj !>\brief The function 'wqs2'computes the gradient of saturated specific !! humidity for table ii ! ======================================================================= real(kind=kind_dyn) function wqs2 (ta, den, dqdt) implicit none ! pure water phase; universal dry / moist formular using air density ! input "den" can be either dry or moist air density real(kind=kind_dyn), intent (in) :: ta, den real(kind=kind_dyn), intent (out) :: dqdt real(kind=kind_dyn) :: es, ap1, tmin integer :: it tmin = tice - 160. ap1 = 10. * dim (ta, tmin) + 1. ap1 = min (2621., ap1) it = ap1 es = tablew (it) + (ap1 - it) * desw (it) wqs2 = es / (rvgas * ta * den) it = ap1 - 0.5 ! finite diff, del_t = 0.1: dqdt = 10. * (desw (it) + (ap1 - it) * (desw (it + 1) - desw (it))) / (rvgas * ta * den) end function wqs2 ! ======================================================================= !>\ingroup fast_sat_adj !>\brief The function wqs2_vect computes the gradient of saturated !! specific humidity for table ii. !! It is the same as "wqs2", but written as vector function. ! ======================================================================= subroutine wqs2_vect (is, ie, ta, den, wqsat, dqdt) implicit none ! pure water phase; universal dry / moist formular using air density ! input "den" can be either dry or moist air density integer, intent (in) :: is, ie real(kind=kind_dyn), intent (in), dimension (is:ie) :: ta, den real(kind=kind_dyn), intent (out), dimension (is:ie) :: wqsat, dqdt real(kind=kind_dyn) :: es, ap1, tmin integer :: i, it tmin = tice - 160. do i = is, ie ap1 = 10. * dim (ta (i), tmin) + 1. ap1 = min (2621., ap1) it = ap1 es = tablew (it) + (ap1 - it) * desw (it) wqsat (i) = es / (rvgas * ta (i) * den (i)) it = ap1 - 0.5 ! finite diff, del_t = 0.1: dqdt (i) = 10. * (desw (it) + (ap1 - it) * (desw (it + 1) - desw (it))) / (rvgas * ta (i) * den (i)) enddo end subroutine wqs2_vect ! ======================================================================= !>\ingroup fast_sat_adj !>\brief The function 'iqs2' computes the gradient of saturated specific !! humidity for table iii. ! ======================================================================= real(kind=kind_dyn) function iqs2 (ta, den, dqdt) implicit none ! water - ice phase; universal dry / moist formular using air density ! input "den" can be either dry or moist air density real(kind=kind_dyn), intent (in) :: ta, den real(kind=kind_dyn), intent (out) :: dqdt real(kind=kind_dyn) :: es, ap1, tmin integer :: it tmin = tice - 160. ap1 = 10. * dim (ta, tmin) + 1. ap1 = min (2621., ap1) it = ap1 es = table2 (it) + (ap1 - it) * des2 (it) iqs2 = es / (rvgas * ta * den) it = ap1 - 0.5 ! finite diff, del_t = 0.1: dqdt = 10. * (des2 (it) + (ap1 - it) * (des2 (it + 1) - des2 (it))) / (rvgas * ta * den) end function iqs2 ! ======================================================================= !>\ingroup fast_sat_adj !! saturation water vapor pressure table i ! 3 - phase table ! ======================================================================= subroutine qs_table (n) implicit none integer, intent (in) :: n real (kind_grid) :: delt = 0.1 real (kind_grid) :: tmin, tem, esh20 real (kind_grid) :: wice, wh2o, fac0, fac1, fac2 real (kind_grid) :: esupc (200) integer :: i tmin = tice - 160. ! ----------------------------------------------------------------------- ! compute es over ice between - 160 deg c and 0 deg c. ! ----------------------------------------------------------------------- do i = 1, 1600 tem = tmin + delt * real (i - 1) fac0 = (tem - tice) / (tem * tice) fac1 = fac0 * li2 fac2 = (d2ice * log (tem / tice) + fac1) / rvgas table (i) = e00 * exp (fac2) enddo ! ----------------------------------------------------------------------- ! compute es over water between - 20 deg c and 102 deg c. ! ----------------------------------------------------------------------- do i = 1, 1221 tem = 253.16 + delt * real (i - 1) fac0 = (tem - tice) / (tem * tice) fac1 = fac0 * lv0 fac2 = (dc_vap * log (tem / tice) + fac1) / rvgas esh20 = e00 * exp (fac2) if (i <= 200) then esupc (i) = esh20 else table (i + 1400) = esh20 endif enddo ! ----------------------------------------------------------------------- ! derive blended es over ice and supercooled water between - 20 deg c and 0 deg c ! ----------------------------------------------------------------------- do i = 1, 200 tem = 253.16 + delt * real (i - 1) wice = 0.05 * (tice - tem) wh2o = 0.05 * (tem - 253.16) table (i + 1400) = wice * table (i + 1400) + wh2o * esupc (i) enddo end subroutine qs_table ! ======================================================================= !>\ingroup fast_sat_adj !! saturation water vapor pressure table ii. ! 1 - phase table ! ======================================================================= subroutine qs_tablew (n) implicit none integer, intent (in) :: n real (kind_grid) :: delt = 0.1 real (kind_grid) :: tmin, tem, fac0, fac1, fac2 integer :: i tmin = tice - 160. ! ----------------------------------------------------------------------- ! compute es over water ! ----------------------------------------------------------------------- do i = 1, n tem = tmin + delt * real (i - 1) fac0 = (tem - tice) / (tem * tice) fac1 = fac0 * lv0 fac2 = (dc_vap * log (tem / tice) + fac1) / rvgas tablew (i) = e00 * exp (fac2) enddo end subroutine qs_tablew ! ======================================================================= !>\ingroup fast_sat_adj !! saturation water vapor pressure table iii. ! 2 - phase table ! ======================================================================= subroutine qs_table2 (n) implicit none integer, intent (in) :: n real (kind_grid) :: delt = 0.1 real (kind_grid) :: tmin, tem0, tem1, fac0, fac1, fac2 integer :: i, i0, i1 tmin = tice - 160. do i = 1, n tem0 = tmin + delt * real (i - 1) fac0 = (tem0 - tice) / (tem0 * tice) if (i <= 1600) then ! ----------------------------------------------------------------------- ! compute es over ice between - 160 deg c and 0 deg c. ! ----------------------------------------------------------------------- fac1 = fac0 * li2 fac2 = (d2ice * log (tem0 / tice) + fac1) / rvgas else ! ----------------------------------------------------------------------- ! compute es over water between 0 deg c and 102 deg c. ! ----------------------------------------------------------------------- fac1 = fac0 * lv0 fac2 = (dc_vap * log (tem0 / tice) + fac1) / rvgas endif table2 (i) = e00 * exp (fac2) enddo ! ----------------------------------------------------------------------- ! smoother around 0 deg c ! ----------------------------------------------------------------------- i0 = 1600 i1 = 1601 tem0 = 0.25 * (table2 (i0 - 1) + 2. * table (i0) + table2 (i0 + 1)) tem1 = 0.25 * (table2 (i1 - 1) + 2. * table (i1) + table2 (i1 + 1)) table2 (i0) = tem0 table2 (i1) = tem1 end subroutine qs_table2 end module fv_sat_adj !> @}