From 404f9612609473259af6e7da09bc2dfb1d716639 Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Mon, 22 Jan 2024 15:06:49 +0000 Subject: [PATCH 01/10] deleted gfdl mp v1 files --- physics/MP/GFDL/v1/fv_sat_adj.F90 | 1431 +++++ physics/MP/GFDL/v1/fv_sat_adj.meta | 441 ++ physics/MP/GFDL/v1/gfdl_cloud_microphys.F90 | 331 ++ physics/MP/GFDL/v1/gfdl_cloud_microphys.meta | 482 ++ .../GFDL/v1/module_gfdl_cloud_microphys.F90 | 5075 +++++++++++++++++ 5 files changed, 7760 insertions(+) create mode 100644 physics/MP/GFDL/v1/fv_sat_adj.F90 create mode 100644 physics/MP/GFDL/v1/fv_sat_adj.meta create mode 100644 physics/MP/GFDL/v1/gfdl_cloud_microphys.F90 create mode 100644 physics/MP/GFDL/v1/gfdl_cloud_microphys.meta create mode 100644 physics/MP/GFDL/v1/module_gfdl_cloud_microphys.F90 diff --git a/physics/MP/GFDL/v1/fv_sat_adj.F90 b/physics/MP/GFDL/v1/fv_sat_adj.F90 new file mode 100644 index 000000000..53543485b --- /dev/null +++ b/physics/MP/GFDL/v1/fv_sat_adj.F90 @@ -0,0 +1,1431 @@ +!>\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 +!> @} diff --git a/physics/MP/GFDL/v1/fv_sat_adj.meta b/physics/MP/GFDL/v1/fv_sat_adj.meta new file mode 100644 index 000000000..c79eb6a25 --- /dev/null +++ b/physics/MP/GFDL/v1/fv_sat_adj.meta @@ -0,0 +1,441 @@ +[ccpp-table-properties] + name = fv_sat_adj + type = scheme + dependencies = ../../../hooks/machine.F,../../../hooks/physcons.F90 + dependencies = module_gfdl_cloud_microphys.F90,../multi_gases.F90 + dependencies = ../../module_mp_radar.F90 + +######################################################################## +[ccpp-arg-table] + name = fv_sat_adj_init + type = scheme +[do_sat_adj] + standard_name = flag_for_saturation_adjustment_for_microphysics_in_dynamics + long_name = flag for saturation adjustment for microphysics in dynamics + units = none + dimensions = () + type = logical + intent = in +[kmp] + standard_name = top_layer_index_for_fast_physics + long_name = top_layer_inder_for_gfdl_mp + units = index + dimensions = () + type = integer + intent = in +[nwat] + standard_name = number_of_water_species + long_name = number of water species + units = count + dimensions = () + type = integer + intent = in +[ngas] + standard_name = number_of_gases_for_multi_gases_physics + long_name = number of gases for multi gases physics + units = count + dimensions = () + type = integer + intent = in +[rilist] + standard_name = gas_constants_for_multi_gases_physics + long_name = gas constants for multi gases physics + units = J kg-1 K-1 + dimensions = (0:number_of_gases_for_multi_gases_physics) + type = real + kind = kind_dyn + intent = in +[cpilist] + standard_name = specific_heat_capacities_for_multi_gases_physics + long_name = specific heat capacities for multi gases physics + units = J kg-1 K-1 + dimensions = (0:number_of_gases_for_multi_gases_physics) + type = real + kind = kind_dyn + intent = in +[mpirank] + standard_name = mpi_rank_for_fast_physics + long_name = current MPI-rank for fast physics schemes + units = index + dimensions = () + type = integer + intent = in +[mpiroot] + standard_name = mpi_root_for_fast_physics + long_name = master MPI-rank for fast physics schemes + units = index + dimensions = () + type = integer + intent = in +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = fv_sat_adj_finalize + type = scheme +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = fv_sat_adj_run + type = scheme +[mdt] + standard_name = time_step_for_remapping_for_fast_physics + long_name = remapping time step for fast physics + units = s + dimensions = () + type = real + kind = kind_dyn + intent = in +[zvir] + standard_name = ratio_of_vapor_to_dry_air_gas_constants_minus_one_default_kind + long_name = zvir=rv/rd-1.0 + units = none + dimensions = () + type = real + kind = kind_dyn + intent = in +[is] + standard_name = starting_x_direction_index + long_name = starting X direction index + units = count + dimensions = () + type = integer + intent = in +[ie] + standard_name = ending_x_direction_index + long_name = ending X direction index + units = count + dimensions = () + type = integer + intent = in +[isd] + standard_name = starting_x_direction_index_domain + long_name = starting X direction index for domain + units = count + dimensions = () + type = integer + intent = in +[ied] + standard_name = ending_x_direction_index_domain + long_name = ending X direction index for domain + units = count + dimensions = () + type = integer + intent = in +[kmp] + standard_name = top_layer_index_for_fast_physics + long_name = top layer index for GFDL mp + units = index + dimensions = () + type = integer + intent = in +[km] + standard_name = vertical_dimension_for_fast_physics + long_name = number of vertical levels + units = count + dimensions = () + type = integer + intent = in +[kmdelz] + standard_name = vertical_dimension_for_thickness_at_Lagrangian_surface + long_name = vertical dimension for thickness at Lagrangian surface + units = count + dimensions = () + type = integer + intent = in +[js] + standard_name = starting_y_direction_index + long_name = starting Y direction index + units = count + dimensions = () + type = integer + intent = in +[je] + standard_name = ending_y_direction_index + long_name = ending Y direction index + units = count + dimensions = () + type = integer + intent = in +[jsd] + standard_name = starting_y_direction_index_domain + long_name = starting X direction index for domain + units = count + dimensions = () + type = integer + intent = in +[jed] + standard_name = ending_y_direction_index_domain + long_name = ending X direction index for domain + units = count + dimensions = () + type = integer + intent = in +[ng] + standard_name = number_of_ghost_zones + long_name = number of ghost zones defined in fv_mp + units = count + dimensions = () + type = integer + intent = in +[hydrostatic] + standard_name = flag_for_hydrostatic_solver_for_fast_physics + long_name = flag for use the hydrostatic or nonhydrostatic solver + units = flag + dimensions = () + type = logical + intent = in +[fast_mp_consv] + standard_name = flag_for_fast_microphysics_energy_conservation + long_name = flag for fast microphysics energy conservation + units = flag + dimensions = () + type = logical + intent = in +[te0_2d] + standard_name = atmosphere_energy_content_in_column + long_name = atmosphere total energy in columns + units = J m-2 + dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index) + type = real + kind = kind_dyn + intent = inout +[te0] + standard_name = atmosphere_energy_content_at_Lagrangian_surface + long_name = atmosphere total energy at Lagrangian surface + units = J m-2 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = out +[ngas] + standard_name = number_of_gases_for_multi_gases_physics + long_name = number of gases for multi gases physics + units = count + dimensions = () + type = integer + intent = in +[qvi] + standard_name = gas_tracers_for_multi_gas_physics_at_Lagrangian_surface + long_name = gas tracers for multi gas physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics,1:number_of_gases_for_multi_gases_physics) + type = real + kind = kind_dyn + intent = inout +[qv] + standard_name = water_vapor_specific_humidity_at_Lagrangian_surface + long_name = water vapor specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[ql] + standard_name = cloud_liquid_water_specific_humidity_at_Lagrangian_surface + long_name = cloud liquid water specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[qi] + standard_name = cloud_ice_specific_humidity_at_Lagrangian_surface + long_name = cloud ice specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[qr] + standard_name = cloud_rain_specific_humidity_at_Lagrangian_surface + long_name = cloud rain specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[qs] + standard_name = cloud_snow_specific_humidity_at_Lagrangian_surface + long_name = cloud snow specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[qg] + standard_name = cloud_graupel_specific_humidity_at_Lagrangian_surface + long_name = cloud graupel specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[hs] + standard_name = surface_geopotential_at_Lagrangian_surface + long_name = surface geopotential at Lagrangian surface + units = m2 s-2 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain) + type = real + kind = kind_dyn + intent = in +[peln] + standard_name = log_pressure_at_Lagrangian_surface + long_name = logarithm of pressure at Lagrangian surface + units = Pa + dimensions = (starting_x_direction_index:ending_x_direction_index,1:vertical_dimension_for_fast_physics_plus_one,starting_y_direction_index:ending_y_direction_index) + type = real + kind = kind_dyn + intent = in +[delz] + standard_name = thickness_at_Lagrangian_surface + long_name = thickness at Lagrangian_surface + units = m + dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_thickness_at_Lagrangian_surface) + type = real + kind = kind_dyn + intent = in +[delp] + standard_name = pressure_thickness_at_Lagrangian_surface + long_name = pressure thickness at Lagrangian surface + units = Pa + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = in +[pt] + standard_name = virtual_temperature_at_Lagrangian_surface + long_name = virtual temperature at Lagrangian surface + units = K + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[pkz] + standard_name = finite_volume_mean_edge_pressure_raised_to_the_power_of_kappa + long_name = finite-volume mean edge pressure in Pa raised to the power of kappa + units = 1 + dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[q_con] + standard_name = cloud_condensed_water_specific_humidity_at_Lagrangian_surface + long_name = cloud condensed water specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_condensed_water_at_Lagrangian_surface) + type = real + kind = kind_dyn + intent = inout +[akap] + standard_name = kappa_dry_for_fast_physics + long_name = modified kappa for dry air, fast physics + units = none + dimensions = () + type = real + kind = kind_dyn + intent = in +[cappa] + standard_name = cappa_moist_gas_constant_at_Lagrangian_surface + long_name = cappa(i,j,k) = rdgas / ( rdgas + cvm(i)/(1.+r_vir*q(i,j,k,sphum)) ) + units = none + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_cappa_at_Lagrangian_surface) + type = real + kind = kind_dyn + intent = inout +[area] + standard_name = cell_area_for_fast_physics + long_name = area of the grid cell for fast physics + units = m2 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain) + type = real + kind = kind_grid + intent = in +[dtdt] + standard_name = tendency_of_air_temperature_at_Lagrangian_surface + long_name = air temperature tendency due to fast physics at Lagrangian surface + units = K s-1 + dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[out_dt] + standard_name = flag_for_tendency_of_air_temperature_at_Lagrangian_surface + long_name = flag for calculating tendency of air temperature due to fast physics + units = flag + dimensions = () + type = logical + intent = in +[last_step] + standard_name = flag_for_the_last_step_of_k_split_remapping + long_name = flag for the last step of k-split remapping + units = flag + dimensions = () + type = logical + intent = in +[do_qa] + standard_name = flag_for_inline_cloud_fraction_calculation + long_name = flag for the inline cloud fraction calculation + units = flag + dimensions = () + type = logical + intent = in +[qa] + standard_name = cloud_fraction_at_Lagrangian_surface + long_name = cloud fraction at Lagrangian surface + units = none + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = out +[nthreads] + standard_name = omp_threads_for_fast_physics + long_name = number of OpenMP threads available for fast physics schemes + units = count + dimensions = () + type = integer + intent = in +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out diff --git a/physics/MP/GFDL/v1/gfdl_cloud_microphys.F90 b/physics/MP/GFDL/v1/gfdl_cloud_microphys.F90 new file mode 100644 index 000000000..0fd84c7ea --- /dev/null +++ b/physics/MP/GFDL/v1/gfdl_cloud_microphys.F90 @@ -0,0 +1,331 @@ +!> \file gfdl_cloud_microphys.F90 +!! This file contains the CCPP entry point for the column GFDL cloud microphysics ( Chen and Lin (2013) +!! \cite chen_and_lin_2013 ). +module gfdl_cloud_microphys + + use gfdl_cloud_microphys_mod, only: gfdl_cloud_microphys_mod_init, & + gfdl_cloud_microphys_mod_driver, & + gfdl_cloud_microphys_mod_end, & + cloud_diagnosis + + implicit none + + private + + public gfdl_cloud_microphys_run, gfdl_cloud_microphys_init, gfdl_cloud_microphys_finalize + + logical :: is_initialized = .false. + +contains + +! ----------------------------------------------------------------------- +! CCPP entry points for gfdl cloud microphysics +! ----------------------------------------------------------------------- + +!>\brief The subroutine initializes the GFDL +!! cloud microphysics. +!! +!> \section arg_table_gfdl_cloud_microphys_init Argument Table +!! \htmlinclude gfdl_cloud_microphys_init.html +!! + subroutine gfdl_cloud_microphys_init (me, master, nlunit, input_nml_file, logunit, fn_nml, & + imp_physics, imp_physics_gfdl, do_shoc, errmsg, errflg) + + implicit none + + integer, intent (in) :: me + integer, intent (in) :: master + integer, intent (in) :: nlunit + integer, intent (in) :: logunit + character(len=*), intent (in) :: fn_nml + character(len=*), intent (in) :: input_nml_file(:) + integer, intent( in) :: imp_physics + integer, intent( in) :: imp_physics_gfdl + logical, intent( in) :: do_shoc + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + if (is_initialized) return + + if (imp_physics/=imp_physics_gfdl) then + write(errmsg,'(*(a))') 'Namelist option for microphysics does not match choice in suite definition file' + errflg = 1 + return + end if + + if (do_shoc) then + write(errmsg,'(*(a))') 'SHOC is not currently compatible with GFDL MP' + errflg = 1 + return + endif + + call gfdl_cloud_microphys_mod_init(me, master, nlunit, input_nml_file, logunit, fn_nml, errmsg, errflg) + + is_initialized = .true. + + end subroutine gfdl_cloud_microphys_init + +! ======================================================================= +!>\brief The subroutine 'gfdl_cloud_microphys_finalize' terminates the GFDL +!! cloud microphysics. +!! +!! \section arg_table_gfdl_cloud_microphys_finalize Argument Table +!! \htmlinclude gfdl_cloud_microphys_finalize.html +!! + subroutine gfdl_cloud_microphys_finalize(errmsg, errflg) + + implicit none + + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + if (.not.is_initialized) return + + call gfdl_cloud_microphys_mod_end() + + is_initialized = .false. + + end subroutine gfdl_cloud_microphys_finalize + +!>\defgroup gfdlmp GFDL Cloud Microphysics Module +!! This is cloud microphysics package for GFDL global cloud resolving model. +!! The algorithms are originally derived from Lin et al. (1983) \cite lin_et_al_1983. +!! Most of the key elements have been simplified/improved. This code at this stage +!! bears little to no similarity to the original Lin MP. +!! Therefore, it is best to be called GFDL microphysics (GFDL MP) . +!! +!>\brief The module contains the GFDL cloud +!! microphysics (Chen and Lin (2013) \cite chen_and_lin_2013 ). +!> The module is paired with \ref fast_sat_adj, which performs the "fast" +!! processes. +!! +!>\brief The subroutine executes the full GFDL cloud microphysics. +!! \section arg_table_gfdl_cloud_microphys_run Argument Table +!! \htmlinclude gfdl_cloud_microphys_run.html +!! + subroutine gfdl_cloud_microphys_run( & + levs, im, rainmin, con_g, con_fvirt, con_rd, con_eps, frland, garea, islmsk, & + gq0, gq0_ntcw, gq0_ntrw, gq0_ntiw, gq0_ntsw, gq0_ntgl, gq0_ntclamt, & + gt0, gu0, gv0, vvl, prsl, phii, del, & + rain0, ice0, snow0, graupel0, prcp0, sr, & + dtp, hydrostatic, phys_hydrostatic, lradar, refl_10cm, & + reset, effr_in, rew, rei, rer, res, reg, & + cplchm, pfi_lsan, pfl_lsan, errmsg, errflg) + + use machine, only: kind_phys + + implicit none + + ! DH* TODO: CLEANUP, all of these should be coming in through the argument list + ! parameters + real(kind=kind_phys), parameter :: one = 1.0d0 + real(kind=kind_phys), parameter :: con_p001= 0.001d0 + real(kind=kind_phys), parameter :: con_day = 86400.d0 + !real(kind=kind_phys), parameter :: rainmin = 1.0d-13 + ! *DH + + ! interface variables + integer, intent(in ) :: levs, im + real(kind=kind_phys), intent(in ) :: con_g, con_fvirt, con_rd, con_eps, rainmin + real(kind=kind_phys), intent(in ), dimension(:) :: frland, garea + integer, intent(in ), dimension(:) :: islmsk + real(kind=kind_phys), intent(inout), dimension(:,:) :: gq0, gq0_ntcw, gq0_ntrw, gq0_ntiw, & + gq0_ntsw, gq0_ntgl, gq0_ntclamt + real(kind=kind_phys), intent(inout), dimension(:,:) :: gt0, gu0, gv0 + real(kind=kind_phys), intent(in ), dimension(:,:) :: vvl, prsl, del + real(kind=kind_phys), intent(in ), dimension(:,:) :: phii + + ! rain/snow/ice/graupel/precip amounts, fraction of frozen precip + real(kind_phys), intent(out ), dimension(:) :: rain0 + real(kind_phys), intent(out ), dimension(:) :: snow0 + real(kind_phys), intent(out ), dimension(:) :: ice0 + real(kind_phys), intent(out ), dimension(:) :: graupel0 + real(kind_phys), intent(out ), dimension(:) :: prcp0 + real(kind_phys), intent(out ), dimension(:) :: sr + + real(kind_phys), intent(in) :: dtp ! physics time step + logical, intent (in) :: hydrostatic, phys_hydrostatic + + logical, intent (in) :: lradar + real(kind=kind_phys), intent(inout), dimension(:,:) :: refl_10cm + logical, intent (in) :: reset, effr_in + real(kind=kind_phys), intent(inout), dimension(:,:) :: rew, rei, rer, res, reg + logical, intent (in) :: cplchm + ! ice and liquid water 3d precipitation fluxes - only allocated if cplchm is .true. + real(kind=kind_phys), intent(inout), dimension(:,:) :: pfi_lsan, pfl_lsan + + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! local variables + integer :: iis, iie, jjs, jje, kks, kke, kbot, ktop + integer :: i, k, kk + real(kind=kind_phys), dimension(1:im,1:levs) :: delp, dz, uin, vin, pt, qv1, ql1, qr1, qg1, qa1, qn1, qi1, & + qs1, pt_dt, qa_dt, u_dt, v_dt, w, qv_dt, ql_dt, qr_dt, qi_dt, & + qs_dt, qg_dt, p123, refl + real(kind=kind_phys), dimension(1:im,1,1:levs) :: pfils, pflls + real(kind=kind_phys), dimension(:,:), allocatable :: den + real(kind=kind_phys) :: onebg + real(kind=kind_phys) :: tem + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + iis = 1 + iie = im + jjs = 1 + jje = 1 + kks = 1 + kke = levs + ! flipping of vertical direction + ktop = 1 + kbot = levs + + onebg = one/con_g + + do k = 1, levs + kk = levs-k+1 + do i = 1, im + qv_dt(i,k) = 0.0 + ql_dt(i,k) = 0.0 + qr_dt(i,k) = 0.0 + qi_dt(i,k) = 0.0 + qs_dt(i,k) = 0.0 + qg_dt(i,k) = 0.0 + qa_dt(i,k) = 0.0 + pt_dt(i,k) = 0.0 + u_dt(i,k) = 0.0 + v_dt(i,k) = 0.0 + qn1(i,k) = 0.0 + pfils(i,1,k) = 0.0 + pflls(i,1,k) = 0.0 + ! flip vertical (k) coordinate + qv1(i,k) = gq0(i,kk) + ql1(i,k) = gq0_ntcw(i,kk) + qr1(i,k) = gq0_ntrw(i,kk) + qi1(i,k) = gq0_ntiw(i,kk) + qs1(i,k) = gq0_ntsw(i,kk) + qg1(i,k) = gq0_ntgl(i,kk) + qa1(i,k) = gq0_ntclamt(i,kk) + pt(i,k) = gt0(i,kk) + w(i,k) = -vvl(i,kk) * (one+con_fvirt * gq0(i,kk)) & + * gt0(i,kk) / prsl(i,kk) * (con_rd*onebg) + uin(i,k) = gu0(i,kk) + vin(i,k) = gv0(i,kk) + delp(i,k) = del(i,kk) + dz(i,k) = (phii(i,kk)-phii(i,kk+1))*onebg + p123(i,k) = prsl(i,kk) + refl(i,k) = refl_10cm(i,kk) + enddo + enddo + + ! reset precipitation amounts to zero + rain0 = 0 + ice0 = 0 + snow0 = 0 + graupel0 = 0 + + call gfdl_cloud_microphys_mod_driver(iis, iie, jjs, jje, kks, kke, ktop, kbot, & + qv1, ql1, qr1, qi1, qs1, qg1, qa1, qn1, qv_dt, ql_dt, qr_dt, qi_dt, & + qs_dt, qg_dt, qa_dt, pt_dt, pt, w, uin, vin, u_dt, v_dt, dz, delp, & + garea, dtp, frland, rain0, snow0, ice0, graupel0, hydrostatic, & + phys_hydrostatic, p123, lradar, refl, reset, pfils, pflls) + tem = dtp*con_p001/con_day + + ! fix negative values + do i = 1, im + !rain0(i) = max(con_d00, rain0(i)) + !snow0(i) = max(con_d00, snow0(i)) + !ice0(i) = max(con_d00, ice0(i)) + !graupel0(i) = max(con_d00, graupel0(i)) + if(rain0(i)*tem < rainmin) then + rain0(i) = 0.0 + endif + if(ice0(i)*tem < rainmin) then + ice0(i) = 0.0 + endif + if(snow0(i)*tem < rainmin) then + snow0(i) = 0.0 + endif + if(graupel0(i)*tem < rainmin) then + graupel0(i) = 0.0 + endif + enddo + + ! calculate fraction of frozen precipitation using unscaled + ! values of rain0, ice0, snow0, graupel0 (for bit-for-bit) + do i=1,im + prcp0(i) = (rain0(i)+snow0(i)+ice0(i)+graupel0(i)) * tem + if ( prcp0(i) > rainmin ) then + sr(i) = (snow0(i) + ice0(i) + graupel0(i)) & + / (rain0(i) + snow0(i) + ice0(i) + graupel0(i)) + else + sr(i) = 0.0 + endif + enddo + + ! convert rain0, ice0, snow0, graupel0 from mm per day to m per physics timestep + rain0 = rain0*tem + ice0 = ice0*tem + snow0 = snow0*tem + graupel0 = graupel0*tem + + ! flip vertical coordinate back + do k=1,levs + kk = levs-k+1 + do i=1,im + gq0(i,k) = qv1(i,kk) + qv_dt(i,kk) * dtp + gq0_ntcw(i,k) = ql1(i,kk) + ql_dt(i,kk) * dtp + gq0_ntrw(i,k) = qr1(i,kk) + qr_dt(i,kk) * dtp + gq0_ntiw(i,k) = qi1(i,kk) + qi_dt(i,kk) * dtp + gq0_ntsw(i,k) = qs1(i,kk) + qs_dt(i,kk) * dtp + gq0_ntgl(i,k) = qg1(i,kk) + qg_dt(i,kk) * dtp + gq0_ntclamt(i,k) = qa1(i,kk) + qa_dt(i,kk) * dtp + gt0(i,k) = gt0(i,k) + pt_dt(i,kk) * dtp + gu0(i,k) = gu0(i,k) + u_dt(i,kk) * dtp + gv0(i,k) = gv0(i,k) + v_dt(i,kk) * dtp + refl_10cm(i,k) = refl(i,kk) + enddo + enddo + + ! output ice and liquid water 3d precipitation fluxes if requested + if (cplchm) then + do k=1,levs + kk = levs-k+1 + do i=1,im + pfi_lsan(i,k) = pfils(i,1,kk) + pfl_lsan(i,k) = pflls(i,1,kk) + enddo + enddo + endif + + if(effr_in) then + allocate(den(1:im,1:levs)) + do k=1,levs + do i=1,im + den(i,k)=con_eps*prsl(i,k)/(con_rd*gt0(i,k)*(gq0(i,k)+con_eps)) + enddo + enddo + call cloud_diagnosis (1, im, 1, levs, den(1:im,1:levs), & + del(1:im,1:levs), islmsk(1:im), & + gq0_ntcw(1:im,1:levs), gq0_ntiw(1:im,1:levs), & + gq0_ntrw(1:im,1:levs), & + gq0_ntsw(1:im,1:levs) + gq0_ntgl(1:im,1:levs), & + gq0_ntgl(1:im,1:levs)*0.0, gt0(1:im,1:levs), & + rew(1:im,1:levs), rei(1:im,1:levs), rer(1:im,1:levs),& + res(1:im,1:levs), reg(1:im,1:levs)) + deallocate(den) + endif + + end subroutine gfdl_cloud_microphys_run + +end module gfdl_cloud_microphys diff --git a/physics/MP/GFDL/v1/gfdl_cloud_microphys.meta b/physics/MP/GFDL/v1/gfdl_cloud_microphys.meta new file mode 100644 index 000000000..236d81ed3 --- /dev/null +++ b/physics/MP/GFDL/v1/gfdl_cloud_microphys.meta @@ -0,0 +1,482 @@ +[ccpp-table-properties] + name = gfdl_cloud_microphys + type = scheme + dependencies = ../../../hooks/machine.F + dependencies = ../../module_mp_radar.F90 + dependencies = module_gfdl_cloud_microphys.F90 + +######################################################################## +[ccpp-arg-table] + name = gfdl_cloud_microphys_init + type = scheme +[me] + standard_name = mpi_rank + long_name = MPI rank of current process + units = index + dimensions = () + type = integer + intent = in +[master] + standard_name = mpi_root + long_name = MPI rank of master process + units = index + dimensions = () + type = integer + intent = in +[nlunit] + standard_name = iounit_of_namelist + long_name = fortran unit number for opening nameliust file + units = none + dimensions = () + type = integer + intent = in +[input_nml_file] + standard_name = filename_of_internal_namelist + long_name = character string to store full namelist contents + units = none + dimensions = (number_of_lines_in_internal_namelist) + type = character + kind = len=* + intent = in +[logunit] + standard_name = iounit_of_log + long_name = fortran unit number for writing logfile + units = none + dimensions = () + type = integer + intent = in +[fn_nml] + standard_name = filename_of_namelist + long_name = namelist filename + units = none + dimensions = () + type = character + kind = len=* + intent = in +[imp_physics] + standard_name = control_for_microphysics_scheme + long_name = choice of microphysics scheme + units = flag + dimensions = () + type = integer + intent = in +[imp_physics_gfdl] + standard_name = identifier_for_gfdl_microphysics_scheme + long_name = choice of GFDL microphysics scheme + units = flag + dimensions = () + type = integer + intent = in +[do_shoc] + standard_name = flag_for_shoc + long_name = flag to indicate use of SHOC + units = flag + dimensions = () + type = logical + intent = in +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = gfdl_cloud_microphys_finalize + type = scheme +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = gfdl_cloud_microphys_run + type = scheme +[levs] + standard_name = vertical_layer_dimension + long_name = number of vertical levels + units = count + dimensions = () + type = integer + intent = in +[im] + standard_name = horizontal_loop_extent + long_name = horizontal loop extent + units = count + dimensions = () + type = integer + intent = in +[rainmin] + standard_name = lwe_thickness_of_minimum_rain_amount + long_name = minimum rain amount + units = m + dimensions = () + type = real + kind = kind_phys + intent = in +[con_g] + standard_name = gravitational_acceleration + long_name = gravitational acceleration + units = m s-2 + dimensions = () + type = real + kind = kind_phys + intent = in +[con_fvirt] + standard_name = ratio_of_vapor_to_dry_air_gas_constants_minus_one + long_name = rv/rd - 1 (rv = ideal gas constant for water vapor) + units = none + dimensions = () + type = real + kind = kind_phys + intent = in +[con_rd] + standard_name = gas_constant_of_dry_air + long_name = ideal gas constant for dry air + units = J kg-1 K-1 + dimensions = () + type = real + kind = kind_phys + intent = in +[con_eps] + standard_name = ratio_of_dry_air_to_water_vapor_gas_constants + long_name = rd/rv + units = none + dimensions = () + type = real + kind = kind_phys + intent = in +[frland] + standard_name = land_area_fraction_for_microphysics + long_name = land area fraction used in microphysics schemes + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = in +[garea] + standard_name = cell_area + long_name = area of grid cell + units = m2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = in +[islmsk] + standard_name = sea_land_ice_mask + long_name = sea/land/ice mask (=0/1/2) + units = flag + dimensions = (horizontal_loop_extent) + type = integer + intent = in +[gq0] + standard_name = specific_humidity_of_new_state + long_name = water vapor specific humidity updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntcw] + standard_name = cloud_liquid_water_mixing_ratio_of_new_state + long_name = cloud condensed water mixing ratio updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntrw] + standard_name = rain_mixing_ratio_of_new_state + long_name = moist mixing ratio of rain updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntiw] + standard_name = cloud_ice_mixing_ratio_of_new_state + long_name = moist mixing ratio of cloud ice updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntsw] + standard_name = snow_mixing_ratio_of_new_state + long_name = moist mixing ratio of snow updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntgl] + standard_name = graupel_mixing_ratio_of_new_state + long_name = moist ratio of mass of graupel to mass of dry air plus vapor (without condensates) updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntclamt] + standard_name = cloud_area_fraction_in_atmosphere_layer_of_new_state + long_name = cloud fraction updated by physics + units = frac + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gt0] + standard_name = air_temperature_of_new_state + long_name = air temperature updated by physics + units = K + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gu0] + standard_name = x_wind_of_new_state + long_name = zonal wind updated by physics + units = m s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gv0] + standard_name = y_wind_of_new_state + long_name = meridional wind updated by physics + units = m s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[vvl] + standard_name = lagrangian_tendency_of_air_pressure + long_name = layer mean vertical velocity + units = Pa s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[prsl] + standard_name = air_pressure + long_name = mean layer pressure + units = Pa + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[phii] + standard_name = geopotential_at_interface + long_name = geopotential at model layer interfaces + units = m2 s-2 + dimensions = (horizontal_loop_extent,vertical_interface_dimension) + type = real + kind = kind_phys + intent = in +[del] + standard_name = air_pressure_difference_between_midlayers + long_name = air pressure difference between mid-layers + units = Pa + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[rain0] + standard_name = lwe_thickness_of_explicit_rain_amount + long_name = explicit rain on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[ice0] + standard_name = lwe_thickness_of_ice_amount + long_name = ice fall on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[snow0] + standard_name = lwe_thickness_of_snow_amount + long_name = snow fall on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[graupel0] + standard_name = lwe_thickness_of_graupel_amount + long_name = graupel fall on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[prcp0] + standard_name = lwe_thickness_of_explicit_precipitation_amount + long_name = explicit precipitation (rain, ice, snow, graupel) on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[sr] + standard_name = ratio_of_snowfall_to_rainfall + long_name = snow ratio: ratio of snow to total precipitation + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[dtp] + standard_name = timestep_for_physics + long_name = physics timestep + units = s + dimensions = () + type = real + kind = kind_phys + intent = in +[hydrostatic] + standard_name = flag_for_hydrostatic_solver + long_name = flag indicating hydrostatic solver + units = flag + dimensions = () + type = logical + intent = in +[phys_hydrostatic] + standard_name = flag_for_hydrostatic_heating_from_physics + long_name = flag indicating hydrostatic heating from physics + units = flag + dimensions = () + type = logical + intent = in +[lradar] + standard_name = flag_for_radar_reflectivity + long_name = flag for radar reflectivity + units = flag + dimensions = () + type = logical + intent = in +[refl_10cm] + standard_name = radar_reflectivity_10cm + long_name = instantaneous refl_10cm + units = dBZ + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[reset] + standard_name = flag_reset_maximum_hourly_fields + long_name = flag for resetting maximum hourly fields + units = flag + dimensions = () + type = logical + intent = in +[effr_in] + standard_name = flag_for_cloud_effective_radii + long_name = flag for cloud effective radii calculations in GFDL microphysics + units = flag + dimensions = () + type = logical + intent = in +[rew] + standard_name = effective_radius_of_stratiform_cloud_liquid_water_particle + long_name = eff. radius of cloud liquid water particle in micrometer + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[rei] + standard_name = effective_radius_of_stratiform_cloud_ice_particle + long_name = eff. radius of cloud ice water particle in micrometer + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[rer] + standard_name = effective_radius_of_stratiform_cloud_rain_particle + long_name = effective radius of cloud rain particle in micrometers + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[res] + standard_name = effective_radius_of_stratiform_cloud_snow_particle + long_name = effective radius of cloud snow particle in micrometers + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[reg] + standard_name = effective_radius_of_stratiform_cloud_graupel_particle + long_name = eff. radius of cloud graupel particle in micrometer + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[cplchm] + standard_name = flag_for_chemistry_coupling + long_name = flag controlling cplchm collection (default off) + units = flag + dimensions = () + type = logical + intent = in +[pfi_lsan] + standard_name = ice_flux_due_to_large_scale_precipitation + long_name = instantaneous 3D flux of ice from nonconvective precipitation + units = kg m-2 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[pfl_lsan] + standard_name = liquid_flux_due_to_large_scale_precipitation + long_name = instantaneous 3D flux of liquid water from nonconvective precipitation + units = kg m-2 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out diff --git a/physics/MP/GFDL/v1/module_gfdl_cloud_microphys.F90 b/physics/MP/GFDL/v1/module_gfdl_cloud_microphys.F90 new file mode 100644 index 000000000..5cab1abbc --- /dev/null +++ b/physics/MP/GFDL/v1/module_gfdl_cloud_microphys.F90 @@ -0,0 +1,5075 @@ +!> \file gfdl_cloud_microphys.F90 +!! This file contains the full GFDL cloud microphysics (Chen and Lin (2013) +!! \cite chen_and_lin_2013 and Zhou et al. 2019 \cite zhou_etal_2019). +!! The module is paired with 'gfdl_fv_sat_adj', which performs the "fast" +!! processes +!>author Shian-Jiann Lin, Linjiong Zhou +!*********************************************************************** +!* GNU Lesser General Public License +!* +!* This file is part of the GFDL Cloud Microphysics. +!* +!* The GFDL Cloud Microphysics is free software: you can +!* 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 . +!*********************************************************************** +! ======================================================================= +!>\defgroup mod_gfdl_cloud_mp GFDL Cloud MP modules +!!\ingroup gfdlmp +!! This module contains the column GFDL Cloud microphysics scheme. +module gfdl_cloud_microphys_mod + + ! use mpp_mod, only: stdlog, mpp_pe, mpp_root_pe, mpp_clock_id, & + ! mpp_clock_begin, mpp_clock_end, clock_routine, & + ! input_nml_file + ! use diag_manager_mod, only: register_diag_field, send_data + ! use time_manager_mod, only: time_type, get_time + ! use constants_mod, only: grav, rdgas, rvgas, cp_air, hlv, hlf, pi => pi_8 + ! use fms_mod, only: write_version_number, open_namelist_file, & + ! check_nml_error, file_exist, close_file + + use module_mp_radar + + implicit none + + private + + public gfdl_cloud_microphys_mod_driver, gfdl_cloud_microphys_mod_init, & + gfdl_cloud_microphys_mod_end, cloud_diagnosis +! public wqs1, wqs2, qs_blend, wqsat_moist, wqsat2_moist +! public qsmith_init, qsmith, es2_table1d, es3_table1d, esw_table1d +! public setup_con, wet_bulb + + real :: missing_value = - 1.e10 + + logical :: module_is_initialized = .false. + logical :: qsmith_tables_initialized = .false. + + character (len = 17) :: mod_name = 'gfdl_cloud_microphys' + + real, parameter :: n0r = 8.0e6, n0s = 3.0e6, n0g = 4.0e6 + real, parameter :: rhos = 0.1e3, rhog = 0.4e3 + real, parameter :: grav = 9.80665 !< gfs: acceleration due to gravity + real, parameter :: rdgas = 287.05 !< gfs: gas constant for dry air + real, parameter :: rvgas = 461.50 !< gfs: gas constant for water vapor + real, parameter :: cp_air = 1004.6 !< gfs: heat capacity of dry air at constant pressure + real, parameter :: hlv = 2.5e6 !< gfs: latent heat of evaporation + real, parameter :: hlf = 3.3358e5 !< gfs: latent heat of fusion + real, parameter :: pi = 3.1415926535897931 !< gfs: ratio of circle circumference to diameter + + ! real, parameter :: rdgas = 287.04 !< gfdl: gas constant for dry air + + ! real, parameter :: cp_air = rdgas * 7. / 2. ! 1004.675, heat capacity of dry air at constant pressure + real, parameter :: cp_vap = 4.0 * rvgas !< 1846.0, heat capacity of water vapore at constnat pressure + ! real, parameter :: cv_air = 717.56 ! satoh value + real, parameter :: cv_air = cp_air - rdgas !< 717.55, heat capacity of dry air at constant volume + ! real, parameter :: cv_vap = 1410.0 ! emanuel value + real, parameter :: cv_vap = 3.0 * rvgas !< 1384.5, heat capacity of water vapor at constant volume + + ! the following two are from emanuel's book "atmospheric convection" + ! real, parameter :: c_ice = 2106.0 ! heat capacity of ice at 0 deg c: c = c_ice + 7.3 * (t - tice) + ! real, parameter :: c_liq = 4190.0 ! heat capacity of water at 0 deg c + + real, parameter :: c_ice = 1972.0 !< gfdl: heat capacity of ice at - 15 deg c + real, parameter :: c_liq = 4185.5 !< gfdl: heat capacity of water at 15 deg c + ! real, parameter :: c_liq = 4218.0 ! ifs: heat capacity of liquid at 0 deg c + + real, parameter :: eps = rdgas / rvgas !< 0.6219934995 + real, parameter :: zvir = rvgas / rdgas - 1. !< 0.6077338443 + + real, parameter :: t_ice = 273.16 !< freezing temperature + real, parameter :: table_ice = 273.16 !< freezing point for qs table + + ! real, parameter :: e00 = 610.71 ! gfdl: saturation vapor pressure at 0 deg c + real, parameter :: e00 = 611.21 !< ifs: saturation vapor pressure at 0 deg c + + real, parameter :: dc_vap = cp_vap - c_liq !< - 2339.5, isobaric heating / cooling + real, parameter :: dc_ice = c_liq - c_ice !< 2213.5, isobaric heating / colling + + real, parameter :: hlv0 = hlv !< gfs: evaporation latent heat coefficient at 0 deg c + ! real, parameter :: hlv0 = 2.501e6 ! emanuel appendix - 2 + real, parameter :: hlf0 = hlf !< gfs: fussion latent heat coefficient at 0 deg c + ! real, parameter :: hlf0 = 3.337e5 ! emanuel + + real, parameter :: lv0 = hlv0 - dc_vap * t_ice !< 3.13905782e6, evaporation latent heat coefficient at 0 deg k + real, parameter :: li00 = hlf0 - dc_ice * t_ice !< - 2.7105966e5, fusion latent heat coefficient at 0 deg k + + real, parameter :: d2ice = dc_vap + dc_ice !< - 126, isobaric heating/cooling + real, parameter :: li2 = lv0 + li00 !< 2.86799816e6, sublimation latent heat coefficient at 0 deg k + + real, parameter :: qrmin = 1.e-8 !< min value for rain + real, parameter :: qvmin = 1.e-20 !< min value for water vapor (treated as zero) + real, parameter :: qcmin = 1.e-12 !< min value for cloud condensates + + real, parameter :: vr_min = 1.e-3 !< min fall speed for rain + real, parameter :: vf_min = 1.e-5 !< min fall speed for cloud ice, snow, graupel + + real, parameter :: dz_min = 1.e-2 !< use for correcting flipped height + + real, parameter :: sfcrho = 1.2 !< surface air density + real, parameter :: rhor = 1.e3 !< density of rain water, lin83 + ! intercept parameters + + real, parameter :: rnzr = 8.0e6 ! lin83 + real, parameter :: rnzs = 3.0e6 ! lin83 + real, parameter :: rnzg = 4.0e6 ! rh84 + real, parameter :: rnzh = 4.0e4 ! lin83 --- lmh 29 sep 17 + + ! density parameters + + real, parameter :: rhoh = 0.917e3 ! lin83 --- lmh 29 sep 17 + + public rhor, rhos, rhog, rhoh, rnzr, rnzs, rnzg, rnzh + real :: cracs, csacr, cgacr, cgacs, csacw, craci, csaci, cgacw, cgaci, cracw !< constants for accretions + real :: acco (3, 4) !< constants for accretions + real :: cssub (5), cgsub (5), crevp (5), cgfr (2), csmlt (5), cgmlt (5) + + real :: es0, ces0 + real :: pie, rgrav, fac_rc + real :: c_air, c_vap + + real :: lati, latv, lats, lat2, lcp, icp, tcp !< used in Bigg mechanism and wet bulk + + real :: d0_vap !< the same as dc_vap, except that cp_vap can be cp_vap or cv_vap + real :: lv00 !< the same as lv0, except that cp_vap can be cp_vap or cv_vap + + ! cloud microphysics switchers + + integer :: icloud_f = 0 !< cloud scheme + integer :: irain_f = 0 !< cloud water to rain auto conversion scheme + + logical :: de_ice = .false. !< to prevent excessive build - up of cloud ice from external sources + logical :: sedi_transport = .true. !< transport of momentum in sedimentation + logical :: do_sedi_w = .false. !< transport of vertical motion in sedimentation + logical :: do_sedi_heat = .true. !< transport of heat in sedimentation + logical :: prog_ccn = .false. !< do prognostic ccn (yi ming's method) + logical :: do_qa = .true. !< do inline cloud fraction + logical :: rad_snow = .true. !< consider snow in cloud fraciton calculation + logical :: rad_graupel = .true. !< consider graupel in cloud fraction calculation + logical :: rad_rain = .true. !< consider rain in cloud fraction calculation + logical :: fix_negative = .false. !< fix negative water species + logical :: do_setup = .true. !< setup constants and parameters + logical :: p_nonhydro = .false. !< perform hydrosatic adjustment on air density + + real, allocatable :: table (:), table2 (:), table3 (:), tablew (:) + real, allocatable :: des (:), des2 (:), des3 (:), desw (:) + + logical :: tables_are_initialized = .false. + + ! logical :: master + ! integer :: id_rh, id_vtr, id_vts, id_vtg, id_vti, id_rain, id_snow, id_graupel, & + ! id_ice, id_prec, id_cond, id_var, id_droplets + real, parameter :: dt_fr = 8. !< homogeneous freezing of all cloud water at t_wfr - dt_fr + ! minimum temperature water can exist (moore & molinero nov. 2011, nature) + ! dt_fr can be considered as the error bar + + real :: p_min = 100. !< minimum pressure (pascal) for mp to operate + + ! slj, the following parameters are for cloud - resolving resolution: 1 - 5 km + + ! qi0_crt = 0.8e-4 + ! qs0_crt = 0.6e-3 + ! c_psaci = 0.1 + ! c_pgacs = 0.1 + + ! ----------------------------------------------------------------------- + ! namelist parameters + ! ----------------------------------------------------------------------- + + real :: cld_min = 0.05 !< minimum cloud fraction + real :: tice = 273.16 !< set tice = 165. to trun off ice - phase phys (kessler emulator) + + real :: t_min = 178. !< min temp to freeze - dry all water vapor + real :: t_sub = 184. !< min temp for sublimation of cloud ice + real :: mp_time = 150. !< maximum micro - physics time step (sec) + + ! relative humidity increment + + real :: rh_inc = 0.25 !< rh increment for complete evaporation of cloud water and cloud ice + real :: rh_inr = 0.25 !< rh increment for minimum evaporation of rain + real :: rh_ins = 0.25 !< rh increment for sublimation of snow + + ! conversion time scale + + real :: tau_r2g = 900. !< rain freezing during fast_sat + real :: tau_smlt = 900. !< snow melting + real :: tau_g2r = 600. !< graupel melting to rain + real :: tau_imlt = 600. !< cloud ice melting + real :: tau_i2s = 1000. !< cloud ice to snow auto-conversion + real :: tau_l2r = 900. !< cloud water to rain auto-conversion + real :: tau_v2l = 150. !< water vapor to cloud water (condensation) + real :: tau_l2v = 300. !< cloud water to water vapor (evaporation) + real :: tau_g2v = 900. !< graupel sublimation + real :: tau_v2g = 21600. !< graupel deposition -- make it a slow process + + ! horizontal subgrid variability + + real :: dw_land = 0.20 !< base value for subgrid deviation / variability over land + real :: dw_ocean = 0.10 !< base value for ocean + + ! prescribed ccn + + real :: ccn_o = 90. !< ccn over ocean (cm^ - 3) + real :: ccn_l = 270. !< ccn over land (cm^ - 3) + + real :: rthresh = 10.0e-6 !< critical cloud drop radius (micro m) + + ! ----------------------------------------------------------------------- + ! wrf / wsm6 scheme: qi_gen = 4.92e-11 * (1.e3 * exp (0.1 * tmp)) ** 1.33 + ! optimized: qi_gen = 4.92e-11 * exp (1.33 * log (1.e3 * exp (0.1 * tmp))) + ! qi_gen ~ 4.808e-7 at 0 c; 1.818e-6 at - 10 c, 9.82679e-5 at - 40c + ! the following value is constructed such that qc_crt = 0 at zero c and @ - 10c matches + ! wrf / wsm6 ice initiation scheme; qi_crt = qi_gen * min (qi_lim, 0.1 * tmp) / den + ! ----------------------------------------------------------------------- + + real :: sat_adj0 = 0.90 !< adjustment factor (0: no, 1: full) during fast_sat_adj + + real :: qc_crt = 5.0e-8 !< mini condensate mixing ratio to allow partial cloudiness + + real :: qi_lim = 1. !< cloud ice limiter to prevent large ice build up + + real :: ql_mlt = 2.0e-3 !< max value of cloud water allowed from melted cloud ice + real :: qs_mlt = 1.0e-6 !< max cloud water due to snow melt + + real :: ql_gen = 1.0e-3 !< max cloud water generation during remapping step if fast_sat_adj = .t. + real :: qi_gen = 1.82e-6 !< max cloud ice generation during remapping step + + ! cloud condensate upper bounds: "safety valves" for ql & qi + + real :: ql0_max = 2.0e-3 !< max cloud water value (auto converted to rain) + real :: qi0_max = 1.0e-4 !< max cloud ice value (by other sources) + + real :: qi0_crt = 1.0e-4 !< cloud ice to snow autoconversion threshold (was 1.e-4); + !! qi0_crt is highly dependent on horizontal resolution + real :: qr0_crt = 1.0e-4 !< rain to snow or graupel/hail threshold + ! lfo used * mixing ratio * = 1.e-4 (hail in lfo) + real :: qs0_crt = 1.0e-3 !< snow to graupel density threshold (0.6e-3 in purdue lin scheme) + + real :: c_paut = 0.55 !< autoconversion cloud water to rain (use 0.5 to reduce autoconversion) + real :: c_psaci = 0.02 !< accretion: cloud ice to snow (was 0.1 in zetac) + real :: c_piacr = 5.0 !< accretion: rain to ice: + real :: c_cracw = 0.9 !< rain accretion efficiency + real :: c_pgacs = 2.0e-3 !< snow to graupel "accretion" eff. (was 0.1 in zetac) + + ! decreasing clin to reduce csacw (so as to reduce cloud water --- > snow) + + real :: alin = 842.0 !< "a" in lin1983 + real :: clin = 4.8 !< "c" in lin 1983, 4.8 -- > 6. (to ehance ql -- > qs) + + ! fall velocity tuning constants: + + logical :: const_vi = .false. !< if .t. the constants are specified by v * _fac + logical :: const_vs = .false. !< if .t. the constants are specified by v * _fac + logical :: const_vg = .false. !< if .t. the constants are specified by v * _fac + logical :: const_vr = .false. !< if .t. the constants are specified by v * _fac + + ! good values: + + real :: vi_fac = 1. !< if const_vi: 1 / 3 + real :: vs_fac = 1. !< if const_vs: 1. + real :: vg_fac = 1. !< if const_vg: 2. + real :: vr_fac = 1. !< if const_vr: 4. + + ! upper bounds of fall speed (with variable speed option) + + real :: vi_max = 0.5 !< max fall speed for ice + real :: vs_max = 5.0 !< max fall speed for snow + real :: vg_max = 8.0 !< max fall speed for graupel + real :: vr_max = 12. !< max fall speed for rain + + ! cloud microphysics switchers + + logical :: fast_sat_adj = .false. !< has fast saturation adjustments + logical :: z_slope_liq = .true. !< use linear mono slope for autocconversions + logical :: z_slope_ice = .false. !< use linear mono slope for autocconversions + logical :: use_ccn = .false. !< must be true when prog_ccn is false + logical :: use_ppm = .false. !< use ppm fall scheme + logical :: mono_prof = .true. !< perform terminal fall with mono ppm scheme + logical :: mp_print = .false. !< cloud microphysics debugging printout + logical :: do_hail = .false. !< use hail parameters instead of graupel + + ! real :: global_area = - 1. + + real :: log_10, tice0, t_wfr + + integer :: reiflag = 1 + ! 1: Heymsfield and Mcfarquhar, 1996 + ! 2: Wyser, 1998 + + logical :: tintqs = .false. !< use temperature in the saturation mixing in PDF + + real :: rewmin = 5.0, rewmax = 10.0 + real :: reimin = 10.0, reimax = 150.0 + real :: rermin = 10.0, rermax = 10000.0 + real :: resmin = 150.0, resmax = 10000.0 + real :: regmin = 300.0, regmax = 10000.0 + + ! ----------------------------------------------------------------------- + ! namelist + ! ----------------------------------------------------------------------- + + namelist / gfdl_cloud_microphysics_nml / & + mp_time, t_min, t_sub, tau_r2g, tau_smlt, tau_g2r, dw_land, dw_ocean, & + vi_fac, vr_fac, vs_fac, vg_fac, ql_mlt, do_qa, fix_negative, vi_max, & + vs_max, vg_max, vr_max, qs_mlt, qs0_crt, qi_gen, ql0_max, qi0_max, & + qi0_crt, qr0_crt, fast_sat_adj, rh_inc, rh_ins, rh_inr, const_vi, & + const_vs, const_vg, const_vr, use_ccn, rthresh, ccn_l, ccn_o, qc_crt, & + tau_g2v, tau_v2g, sat_adj0, c_piacr, tau_imlt, tau_v2l, tau_l2v, & + tau_i2s, tau_l2r, qi_lim, ql_gen, c_paut, c_psaci, c_pgacs, & + z_slope_liq, z_slope_ice, prog_ccn, c_cracw, alin, clin, tice, & + rad_snow, rad_graupel, rad_rain, cld_min, use_ppm, mono_prof, & + do_sedi_heat, sedi_transport, do_sedi_w, de_ice, icloud_f, irain_f, & + mp_print, reiflag, rewmin, rewmax, reimin, reimax, rermin, rermax, & + resmin, resmax, regmin, regmax, tintqs, do_hail + + public & + mp_time, t_min, t_sub, tau_r2g, tau_smlt, tau_g2r, dw_land, dw_ocean, & + vi_fac, vr_fac, vs_fac, vg_fac, ql_mlt, do_qa, fix_negative, vi_max, & + vs_max, vg_max, vr_max, qs_mlt, qs0_crt, qi_gen, ql0_max, qi0_max, & + qi0_crt, qr0_crt, fast_sat_adj, rh_inc, rh_ins, rh_inr, const_vi, & + const_vs, const_vg, const_vr, use_ccn, rthresh, ccn_l, ccn_o, qc_crt, & + tau_g2v, tau_v2g, sat_adj0, c_piacr, tau_imlt, tau_v2l, tau_l2v, & + tau_i2s, tau_l2r, qi_lim, ql_gen, c_paut, c_psaci, c_pgacs, & + z_slope_liq, z_slope_ice, prog_ccn, c_cracw, alin, clin, tice, & + rad_snow, rad_graupel, rad_rain, cld_min, use_ppm, mono_prof, & + do_sedi_heat, sedi_transport, do_sedi_w, de_ice, icloud_f, irain_f, & + mp_print, reiflag, rewmin, rewmax, reimin, reimax, rermin, rermax, & + resmin, resmax, regmin, regmax, tintqs, do_hail + +contains + +! ----------------------------------------------------------------------- +! the driver of the gfdl cloud microphysics +! ----------------------------------------------------------------------- + +!>\ingroup mod_gfdl_cloud_mp +!! This subroutine is the driver of the GFDL cloud microphysics +subroutine gfdl_cloud_microphys_mod_driver ( & + iis, iie, jjs, jje, kks, kke, ktop, kbot, & + qv, ql, qr, qi, qs, qg, qa, qn, & + qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt, qa_dt, pt_dt, pt, w, & + uin, vin, udt, vdt, dz, delp, area, dt_in, land, & + rain, snow, ice, graupel, hydrostatic, phys_hydrostatic, & + p, lradar, refl_10cm, reset, pfils, pflls) + + implicit none + + ! Interface variables + integer, intent (in) :: iis, iie, jjs, jje ! physics window + integer, intent (in) :: kks, kke ! vertical dimension + integer, intent (in) :: ktop, kbot ! vertical compute domain + + real, intent (in) :: dt_in ! physics time step + + real, intent (in), dimension (iis:iie, jjs:jje) :: area ! cell area + real, intent (in), dimension (iis:iie, jjs:jje) :: land ! land fraction + + real, intent (in), dimension (iis:iie, jjs:jje, kks:kke) :: delp, dz, uin, vin + real, intent (in), dimension (iis:iie, jjs:jje, kks:kke) :: pt, qv, ql, qr, qg, qa, qn + + real, intent (inout), dimension (iis:iie, jjs:jje, kks:kke) :: qi, qs + real, intent (inout), dimension (iis:iie, jjs:jje, kks:kke) :: pt_dt, qa_dt, udt, vdt, w + real, intent (inout), dimension (iis:iie, jjs:jje, kks:kke) :: qv_dt, ql_dt, qr_dt + real, intent (inout), dimension (iis:iie, jjs:jje, kks:kke) :: qi_dt, qs_dt, qg_dt + + real, intent (out), dimension (iis:iie, jjs:jje) :: rain, snow, ice, graupel + + logical, intent (in) :: hydrostatic, phys_hydrostatic + + !integer, intent (in) :: seconds + real, intent (in), dimension (iis:iie, jjs:jje, kks:kke) :: p + logical, intent (in) :: lradar + real, intent (out), dimension (iis:iie, jjs:jje, kks:kke) :: refl_10cm + logical, intent (in) :: reset + real, intent (out), dimension (iis:iie, jjs:jje, kks:kke) :: pfils, pflls + + ! Local variables + logical :: melti = .false. + + real :: mpdt, rdt, dts, convt, tot_prec + + integer :: i, j, k + integer :: is, ie, js, je ! physics window + integer :: ks, ke ! vertical dimension + integer :: days, ntimes, kflip + + real, dimension (iie-iis+1, jje-jjs+1) :: prec_mp, prec1, cond, w_var, rh0 + + real, dimension (iie-iis+1, jje-jjs+1,kke-kks+1) :: vt_r, vt_s, vt_g, vt_i, qn2 + + real, dimension (size(pt,1), size(pt,3)) :: m2_rain, m2_sol + + real :: allmax +!+---+-----------------------------------------------------------------+ +!For 3D reflectivity calculations + real, dimension(ktop:kbot):: qv1d, t1d, p1d, qr1d, qs1d, qg1d, dBZ +!+---+-----------------------------------------------------------------+ + + is = 1 + js = 1 + ks = 1 + ie = iie - iis + 1 + je = jje - jjs + 1 + ke = kke - kks + 1 + ! call mpp_clock_begin (gfdl_mp_clock) + + ! ----------------------------------------------------------------------- + ! define heat capacity of dry air and water vapor based on hydrostatical property + ! ----------------------------------------------------------------------- + + if (phys_hydrostatic .or. hydrostatic) then + c_air = cp_air + c_vap = cp_vap + p_nonhydro = .false. + else + c_air = cv_air + c_vap = cv_vap + p_nonhydro = .true. + endif + d0_vap = c_vap - c_liq + lv00 = hlv0 - d0_vap * t_ice + + if (hydrostatic) do_sedi_w = .false. + + ! ----------------------------------------------------------------------- + ! define latent heat coefficient used in wet bulb and Bigg mechanism + ! ----------------------------------------------------------------------- + + latv = hlv + lati = hlf + lats = latv + lati + lat2 = lats * lats + + lcp = latv / cp_air + icp = lati / cp_air + tcp = (latv + lati) / cp_air + + ! tendency zero out for am moist processes should be done outside the driver + + ! ----------------------------------------------------------------------- + ! define cloud microphysics sub time step + ! ----------------------------------------------------------------------- + + mpdt = min (dt_in, mp_time) + rdt = 1. / dt_in + ntimes = nint (dt_in / mpdt) + + ! small time step: + dts = dt_in / real (ntimes) + + ! call get_time (time, seconds, days) + + ! ----------------------------------------------------------------------- + ! initialize precipitation + ! ----------------------------------------------------------------------- + + do j = js, je + do i = is, ie + graupel (i, j) = 0. + rain (i, j) = 0. + snow (i, j) = 0. + ice (i, j) = 0. + cond (i, j) = 0. + enddo + enddo + + pfils = 0. + pflls = 0. + + ! ----------------------------------------------------------------------- + ! major cloud microphysics + ! ----------------------------------------------------------------------- + + do j = js, je + call mpdrv (hydrostatic, uin, vin, w, delp, pt, qv, ql, qr, qi, qs, qg,& + qa, qn, dz, is, ie, js, je, ks, ke, ktop, kbot, j, dt_in, ntimes, & + rain (:, j), snow (:, j), graupel (:, j), ice (:, j), m2_rain, & + m2_sol, cond (:, j), area (:, j), land (:, j), udt, vdt, pt_dt, & + qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt, qa_dt, w_var, vt_r, & + vt_s, vt_g, vt_i, qn2) + do k = ktop, kbot + do i = is, ie + pfils(i, j, k) = m2_sol (i, k) + pflls(i, j, k) = m2_rain(i, k) + enddo + enddo + enddo + + ! ----------------------------------------------------------------------- + ! no clouds allowed above ktop + ! ----------------------------------------------------------------------- + + if (ks < ktop) then + do k = ks, ktop + if (do_qa) then + do j = js, je + do i = is, ie + qa_dt (i, j, k) = 0. + enddo + enddo + else + do j = js, je + do i = is, ie + ! qa_dt (i, j, k) = - qa (i, j, k) * rdt + qa_dt (i, j, k) = 0. ! gfs + enddo + enddo + endif + enddo + endif + + ! ----------------------------------------------------------------------- + ! diagnostic output + ! ----------------------------------------------------------------------- + + ! if (id_vtr > 0) then + ! used = send_data (id_vtr, vt_r, time, is_in = iis, js_in = jjs) + ! endif + + ! if (id_vts > 0) then + ! used = send_data (id_vts, vt_s, time, is_in = iis, js_in = jjs) + ! endif + + ! if (id_vtg > 0) then + ! used = send_data (id_vtg, vt_g, time, is_in = iis, js_in = jjs) + ! endif + + ! if (id_vti > 0) then + ! used = send_data (id_vti, vt_i, time, is_in = iis, js_in = jjs) + ! endif + + ! if (id_droplets > 0) then + ! used = send_data (id_droplets, qn2, time, is_in = iis, js_in = jjs) + ! endif + + ! if (id_var > 0) then + ! used = send_data (id_var, w_var, time, is_in = iis, js_in = jjs) + ! endif + + ! convert to mm / day + + convt = 86400. * rdt * rgrav + do j = js, je + do i = is, ie + rain (i, j) = rain (i, j) * convt + snow (i, j) = snow (i, j) * convt + ice (i, j) = ice (i, j) * convt + graupel (i, j) = graupel (i, j) * convt + prec_mp (i, j) = rain (i, j) + snow (i, j) + ice (i, j) + graupel (i, j) + enddo + enddo + + ! if (id_cond > 0) then + ! do j = js, je + ! do i = is, ie + ! cond (i, j) = cond (i, j) * rgrav + ! enddo + ! enddo + ! used = send_data (id_cond, cond, time, is_in = iis, js_in = jjs) + ! endif + + ! if (id_snow > 0) then + ! used = send_data (id_snow, snow, time, iis, jjs) + ! used = send_data (id_snow, snow, time, is_in = iis, js_in = jjs) + ! if (mp_print .and. seconds == 0) then + ! tot_prec = g_sum (snow, is, ie, js, je, area, 1) + ! if (master) write (*, *) 'mean snow = ', tot_prec + ! endif + ! endif + ! + ! if (id_graupel > 0) then + ! used = send_data (id_graupel, graupel, time, iis, jjs) + ! used = send_data (id_graupel, graupel, time, is_in = iis, js_in = jjs) + ! if (mp_print .and. seconds == 0) then + ! tot_prec = g_sum (graupel, is, ie, js, je, area, 1) + ! if (master) write (*, *) 'mean graupel = ', tot_prec + ! endif + ! endif + ! + ! if (id_ice > 0) then + ! used = send_data (id_ice, ice, time, iis, jjs) + ! used = send_data (id_ice, ice, time, is_in = iis, js_in = jjs) + ! if (mp_print .and. seconds == 0) then + ! tot_prec = g_sum (ice, is, ie, js, je, area, 1) + ! if (master) write (*, *) 'mean ice_mp = ', tot_prec + ! endif + ! endif + ! + ! if (id_rain > 0) then + ! used = send_data (id_rain, rain, time, iis, jjs) + ! used = send_data (id_rain, rain, time, is_in = iis, js_in = jjs) + ! if (mp_print .and. seconds == 0) then + ! tot_prec = g_sum (rain, is, ie, js, je, area, 1) + ! if (master) write (*, *) 'mean rain = ', tot_prec + ! endif + ! endif + ! + ! if (id_rh > 0) then !not used? + ! used = send_data (id_rh, rh0, time, iis, jjs) + ! used = send_data (id_rh, rh0, time, is_in = iis, js_in = jjs) + ! endif + ! + ! + ! if (id_prec > 0) then + ! used = send_data (id_prec, prec_mp, time, iis, jjs) + ! used = send_data (id_prec, prec_mp, time, is_in = iis, js_in = jjs) + ! endif + + ! if (mp_print) then + ! prec1 (:, :) = prec1 (:, :) + prec_mp (:, :) + ! if (seconds == 0) then + ! prec1 (:, :) = prec1 (:, :) * dt_in / 86400. + ! tot_prec = g_sum (prec1, is, ie, js, je, area, 1) + ! if (master) write (*, *) 'daily prec_mp = ', tot_prec + ! prec1 (:, :) = 0. + ! endif + ! endif + + ! call mpp_clock_end (gfdl_mp_clock) + if(lradar) then + ! Only set melti to true at the output times + if (reset) then + melti=.true. + else + melti=.false. + endif + do j = js, je + do i = is, ie + do k = ktop,kbot + kflip = kbot-ktop+1-k+1 + t1d(k) = pt(i,j,kflip) + p1d(k) = p(i,j,kflip) + qv1d(k) = qv(i,j,kflip)/(1-qv(i,j,kflip)) + qr1d(k) = qr(i,j,kflip) + qs1d(k) = qs(i,j,kflip) + qg1d(k) = qg(i,j,kflip) + enddo + call refl10cm_gfdl (qv1d, qr1d, qs1d, qg1d, & + t1d, p1d, dBZ, ktop, kbot, i, j, melti) + do k = ktop,kbot + kflip = kbot-ktop+1-k+1 + refl_10cm(i,j,kflip) = MAX(-35., dBZ(k)) + enddo + enddo + enddo + endif + +end subroutine gfdl_cloud_microphys_mod_driver + +! ----------------------------------------------------------------------- +!>\ingroup mod_gfdl_cloud_mp +!>\brief GFDL cloud microphysics, major program, and is based on +!! Lin et al.(1983) \cite lin_et_al_1983 and +!! Rutledge and Hobbs (1984) \cite rutledge_and_hobbs_1984. +!! +!>\section detmpdrv GFDL Cloud mpdrv General Algorithm +subroutine mpdrv (hydrostatic, uin, vin, w, delp, pt, qv, ql, qr, qi, qs, & + qg, qa, qn, dz, is, ie, js, je, ks, ke, ktop, kbot, j, dt_in, ntimes, & + rain, snow, graupel, ice, m2_rain, m2_sol, cond, area1, land, & + u_dt, v_dt, pt_dt, qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt, qa_dt, & + w_var, vt_r, vt_s, vt_g, vt_i, qn2) + + implicit none + + logical, intent (in) :: hydrostatic + + integer, intent (in) :: j, is, ie, js, je, ks, ke + integer, intent (in) :: ntimes, ktop, kbot + + real, intent (in) :: dt_in + + real, intent (in), dimension (is:) :: area1, land + + real, intent (in), dimension (is:, js:, ks:) :: uin, vin, delp, pt, dz + real, intent (in), dimension (is:, js:, ks:) :: qv, ql, qr, qg, qa, qn + + real, intent (inout), dimension (is:, js:, ks:) :: qi, qs + real, intent (inout), dimension (is:, js:, ks:) :: u_dt, v_dt, w, pt_dt, qa_dt + real, intent (inout), dimension (is:, js:, ks:) :: qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt + + real, intent (inout), dimension (is:) :: rain, snow, ice, graupel, cond + + real, intent (out), dimension (is:, js:) :: w_var + + real, intent (out), dimension (is:, js:, ks:) :: vt_r, vt_s, vt_g, vt_i, qn2 + + real, intent (out), dimension (is:, ks:) :: m2_rain, m2_sol + + real, dimension (ktop:kbot) :: qvz, qlz, qrz, qiz, qsz, qgz, qaz + real, dimension (ktop:kbot) :: vtiz, vtsz, vtgz, vtrz + real, dimension (ktop:kbot) :: dp0, dp1, dz0, dz1 + real, dimension (ktop:kbot) :: qv0, ql0, qr0, qi0, qs0, qg0, qa0 + real, dimension (ktop:kbot) :: t0, den, den0, tz, p1, denfac + real, dimension (ktop:kbot) :: ccn, c_praut, m1_rain, m1_sol, m1 + real, dimension (ktop:kbot) :: u0, v0, u1, v1, w1 + + real :: cpaut, rh_adj, rh_rain + real :: r1, s1, i1, g1, rdt, ccn0 + real :: dt_rain, dts + real :: s_leng, t_land, t_ocean, h_var + real :: cvm, tmp, omq + real :: dqi, qio, qin + + integer :: i, k, n + + dts = dt_in / real (ntimes) + dt_rain = dts * 0.5 + rdt = 1. / dt_in + + ! ----------------------------------------------------------------------- + ! use local variables + ! ----------------------------------------------------------------------- + + !GJF: assign values to intent(out) variables that are commented out + w_var = 0.0 + vt_r = 0.0 + vt_s = 0.0 + vt_g = 0.0 + vt_i = 0.0 + qn2 = 0.0 + !GJF + + do i = is, ie + + do k = ktop, kbot + qiz (k) = qi (i, j, k) + qsz (k) = qs (i, j, k) + enddo + + ! ----------------------------------------------------------------------- + !> - Prevent excessive build-up of cloud ice from external sources. + ! ----------------------------------------------------------------------- + + if (de_ice) then + do k = ktop, kbot + qio = qiz (k) - dt_in * qi_dt (i, j, k) ! original qi before phys + qin = max (qio, qi0_max) ! adjusted value + if (qiz (k) > qin) then + qsz (k) = qsz (k) + qiz (k) - qin + qiz (k) = qin + dqi = (qin - qio) * rdt ! modified qi tendency + qs_dt (i, j, k) = qs_dt (i, j, k) + qi_dt (i, j, k) - dqi + qi_dt (i, j, k) = dqi + qi (i, j, k) = qiz (k) + qs (i, j, k) = qsz (k) + endif + enddo + endif + + do k = ktop, kbot + + t0 (k) = pt (i, j, k) + tz (k) = t0 (k) + dp1 (k) = delp (i, j, k) + dp0 (k) = dp1 (k) ! moist air mass * grav + + ! ----------------------------------------------------------------------- + !> - Convert moist mixing ratios to dry mixing ratios. + ! ----------------------------------------------------------------------- + + qvz (k) = qv (i, j, k) + qlz (k) = ql (i, j, k) + qrz (k) = qr (i, j, k) + qgz (k) = qg (i, j, k) + + ! dp1: dry air_mass + ! dp1 (k) = dp1 (k) * (1. - (qvz (k) + qlz (k) + qrz (k) + qiz (k) + qsz (k) + qgz (k))) + dp1 (k) = dp1 (k) * (1. - qvz (k)) ! gfs + omq = dp0 (k) / dp1 (k) + + qvz (k) = qvz (k) * omq + qlz (k) = qlz (k) * omq + qrz (k) = qrz (k) * omq + qiz (k) = qiz (k) * omq + qsz (k) = qsz (k) * omq + qgz (k) = qgz (k) * omq + + qa0 (k) = qa (i, j, k) + qaz (k) = 0. + dz0 (k) = dz (i, j, k) + + den0 (k) = - dp1 (k) / (grav * dz0 (k)) ! density of dry air + p1 (k) = den0 (k) * rdgas * t0 (k) ! dry air pressure + + ! ----------------------------------------------------------------------- + ! save a copy of old value for computing tendencies + ! ----------------------------------------------------------------------- + + qv0 (k) = qvz (k) + ql0 (k) = qlz (k) + qr0 (k) = qrz (k) + qi0 (k) = qiz (k) + qs0 (k) = qsz (k) + qg0 (k) = qgz (k) + + ! ----------------------------------------------------------------------- + ! for sedi_momentum + ! ----------------------------------------------------------------------- + + m1 (k) = 0. + u0 (k) = uin (i, j, k) + v0 (k) = vin (i, j, k) + u1 (k) = u0 (k) + v1 (k) = v0 (k) + + enddo + + if (do_sedi_w) then + do k = ktop, kbot + w1 (k) = w (i, j, k) + enddo + ! Set to -999 if not used + else + w1(:) = -999.0 + endif + + ! ----------------------------------------------------------------------- + !> - Calculate cloud condensation nuclei (ccn), + !! following klein eq. 15 + ! ----------------------------------------------------------------------- + + cpaut = c_paut * 0.104 * grav / 1.717e-5 + + if (prog_ccn) then + do k = ktop, kbot + ! convert # / cc to # / m^3 + ccn (k) = qn (i, j, k) * 1.e6 + c_praut (k) = cpaut * (ccn (k) * rhor) ** (- 1. / 3.) + enddo + use_ccn = .false. + else + ccn0 = (ccn_l * land (i) + ccn_o * (1. - land (i))) * 1.e6 + if (use_ccn) then + ! ----------------------------------------------------------------------- + ! ccn is formulted as ccn = ccn_surface * (den / den_surface) + ! ----------------------------------------------------------------------- + ccn0 = ccn0 * rdgas * tz (kbot) / p1 (kbot) + endif + tmp = cpaut * (ccn0 * rhor) ** (- 1. / 3.) + do k = ktop, kbot + c_praut (k) = tmp + ccn (k) = ccn0 + enddo + endif + + ! ----------------------------------------------------------------------- + !> - Calculate horizontal subgrid variability, which is used in cloud + !! fraction, relative humidity calculation, evaporation and condensation + !! processes. Horizontal sub-grid variability is a function of cell area + !! and land/sea mask: + !!\n Over land: + !!\f[ + !! t_{land}=dw_{land}(\frac{A_{r}}{10^{10}})^{0.25} + !!\f] + !!\n Over ocean: + !!\f[ + !! t_{ocean}=dw_{ocean}(\frac{A_{r}}{10^{10}})^{0.25} + !!\f] + !! where \f$A_{r}\f$ is cell area. \f$dw_{land}=0.16\f$ and \f$dw_{ocean}=0.10\f$ + !! are base value for sub-grid variability over land and ocean. + !! The total horizontal sub-grid variability is: + !!\f[ + !! h_{var}=t_{land}\times fr_{land}+t_{ocean}\times (1-fr_{land}) + !!\f] + !!\f[ + !! h_{var}=min[0.2,max(0.01,h_{var})] + !!\f] + ! total water subgrid deviation in horizontal direction + ! default area dependent form: use dx ~ 100 km as the base + ! ----------------------------------------------------------------------- + + s_leng = sqrt (sqrt (area1 (i) / 1.e10)) + t_land = dw_land * s_leng + t_ocean = dw_ocean * s_leng + h_var = t_land * land (i) + t_ocean * (1. - land (i)) + h_var = min (0.20, max (0.01, h_var)) + ! if (id_var > 0) w_var (i, j) = h_var + + ! ----------------------------------------------------------------------- + !> - Calculate relative humidity increment. + ! ----------------------------------------------------------------------- + + rh_adj = 1. - h_var - rh_inc + rh_rain = max (0.35, rh_adj - rh_inr) ! rh_inr = 0.25 + + ! ----------------------------------------------------------------------- + !> - If requested, call neg_adj() and fix all negative water species. + ! ----------------------------------------------------------------------- + + if (fix_negative) & + call neg_adj (ktop, kbot, tz, dp1, qvz, qlz, qrz, qiz, qsz, qgz) + + m2_rain (i, :) = 0. + m2_sol (i, :) = 0. + + !> - Do loop on cloud microphysics sub time step. + do n = 1, ntimes + + ! ----------------------------------------------------------------------- + !> - Define air density based on hydrostatical property. + ! ----------------------------------------------------------------------- + + if (p_nonhydro) then + do k = ktop, kbot + dz1 (k) = dz0 (k) + den (k) = den0 (k) ! dry air density remains the same + denfac (k) = sqrt (sfcrho / den (k)) + enddo + else + do k = ktop, kbot + dz1 (k) = dz0 (k) * tz (k) / t0 (k) ! hydrostatic balance + den (k) = den0 (k) * dz0 (k) / dz1 (k) + denfac (k) = sqrt (sfcrho / den (k)) + enddo + endif + + ! ----------------------------------------------------------------------- + !> - Call warm_rain() - time-split warm rain processes: 1st pass. + ! ----------------------------------------------------------------------- + + call warm_rain (dt_rain, ktop, kbot, dp1, dz1, tz, qvz, qlz, qrz, qiz, qsz, & + qgz, den, denfac, ccn, c_praut, rh_rain, vtrz, r1, m1_rain, w1, h_var) + + rain (i) = rain (i) + r1 + + do k = ktop, kbot + m2_rain (i, k) = m2_rain (i, k) + m1_rain (k) + m1 (k) = m1 (k) + m1_rain (k) + enddo + + ! ----------------------------------------------------------------------- + !> - Sedimentation of cloud ice, snow, and graupel. + ! ----------------------------------------------------------------------- + + !> - Call fall_speed() to calculate the fall velocity of cloud ice, snow + !! and graupel. + call fall_speed (ktop, kbot, den, qsz, qiz, qgz, qlz, tz, vtsz, vtiz, vtgz) + + !> - Call terminal_fall() to calculate the terminal fall speed. + call terminal_fall (dts, ktop, kbot, tz, qvz, qlz, qrz, qgz, qsz, qiz, & + dz1, dp1, den, vtgz, vtsz, vtiz, r1, g1, s1, i1, m1_sol, w1) + + rain (i) = rain (i) + r1 ! from melted snow & ice that reached the ground + snow (i) = snow (i) + s1 + graupel (i) = graupel (i) + g1 + ice (i) = ice (i) + i1 + + ! ----------------------------------------------------------------------- + !> - Call sedi_heat() to calculate heat transportation during sedimentation. + ! ----------------------------------------------------------------------- + + if (do_sedi_heat) & + call sedi_heat (ktop, kbot, dp1, m1_sol, dz1, tz, qvz, qlz, qrz, qiz, & + qsz, qgz, c_ice) + + ! ----------------------------------------------------------------------- + !> - Call warm_rain() to - time-split warm rain processes: 2nd pass + ! ----------------------------------------------------------------------- + + call warm_rain (dt_rain, ktop, kbot, dp1, dz1, tz, qvz, qlz, qrz, qiz, qsz, & + qgz, den, denfac, ccn, c_praut, rh_rain, vtrz, r1, m1_rain, w1, h_var) + + rain (i) = rain (i) + r1 + + do k = ktop, kbot + m2_rain (i, k) = m2_rain (i, k) + m1_rain (k) + m2_sol (i, k) = m2_sol (i, k) + m1_sol (k) + m1 (k) = m1 (k) + m1_rain (k) + m1_sol (k) + enddo + + ! ----------------------------------------------------------------------- + !> - Call icloud(): ice-phase microphysics + ! ----------------------------------------------------------------------- + + call icloud (ktop, kbot, tz, p1, qvz, qlz, qrz, qiz, qsz, qgz, dp1, den, & + denfac, vtsz, vtgz, vtrz, qaz, rh_adj, rh_rain, dts, h_var) + + enddo + + ! convert units from Pa*kg/kg to kg/m^2/s + m2_rain (i, :) = m2_rain (i, :) * rdt * rgrav + m2_sol (i, :) = m2_sol (i, :) * rdt * rgrav + + ! ----------------------------------------------------------------------- + !> - Calculate momentum transportation during sedimentation. + ! note: dp1 is dry mass; dp0 is the old moist (total) mass + ! ----------------------------------------------------------------------- + + if (sedi_transport) then + do k = ktop + 1, kbot + u1 (k) = (dp0 (k) * u1 (k) + m1 (k - 1) * u1 (k - 1)) / (dp0 (k) + m1 (k - 1)) + v1 (k) = (dp0 (k) * v1 (k) + m1 (k - 1) * v1 (k - 1)) / (dp0 (k) + m1 (k - 1)) + u_dt (i, j, k) = u_dt (i, j, k) + (u1 (k) - u0 (k)) * rdt + v_dt (i, j, k) = v_dt (i, j, k) + (v1 (k) - v0 (k)) * rdt + enddo + endif + + if (do_sedi_w) then + do k = ktop, kbot + w (i, j, k) = w1 (k) + enddo + endif + + ! ----------------------------------------------------------------------- + !> - Update moist air mass (actually hydrostatic pressure). + ! convert to dry mixing ratios + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + omq = dp1 (k) / dp0 (k) + qv_dt (i, j, k) = qv_dt (i, j, k) + rdt * (qvz (k) - qv0 (k)) * omq + ql_dt (i, j, k) = ql_dt (i, j, k) + rdt * (qlz (k) - ql0 (k)) * omq + qr_dt (i, j, k) = qr_dt (i, j, k) + rdt * (qrz (k) - qr0 (k)) * omq + qi_dt (i, j, k) = qi_dt (i, j, k) + rdt * (qiz (k) - qi0 (k)) * omq + qs_dt (i, j, k) = qs_dt (i, j, k) + rdt * (qsz (k) - qs0 (k)) * omq + qg_dt (i, j, k) = qg_dt (i, j, k) + rdt * (qgz (k) - qg0 (k)) * omq + cvm = c_air + qvz (k) * c_vap + (qrz (k) + qlz (k)) * c_liq + (qiz (k) + qsz (k) + qgz (k)) * c_ice + pt_dt (i, j, k) = pt_dt (i, j, k) + rdt * (tz (k) - t0 (k)) * cvm / cp_air + enddo + + ! ----------------------------------------------------------------------- + !> - Update cloud fraction tendency. + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + if (do_qa) then + qa_dt (i, j, k) = 0. + else + qa_dt (i, j, k) = qa_dt (i, j, k) + rdt * (qaz (k) / real (ntimes) - qa0 (k)) + endif + enddo + + ! ----------------------------------------------------------------------- + ! fms diagnostics: + ! ----------------------------------------------------------------------- + + ! if (id_cond > 0) then + ! do k = ktop, kbot ! total condensate + ! cond (i) = cond (i) + dp1 (k) * (qlz (k) + qrz (k) + qsz (k) + qiz (k) + qgz (k)) + ! enddo + ! endif + ! + ! if (id_vtr > 0) then + ! do k = ktop, kbot + ! vt_r (i, j, k) = vtrz (k) + ! enddo + ! endif + ! + ! if (id_vts > 0) then + ! do k = ktop, kbot + ! vt_s (i, j, k) = vtsz (k) + ! enddo + ! endif + ! + ! if (id_vtg > 0) then + ! do k = ktop, kbot + ! vt_g (i, j, k) = vtgz (k) + ! enddo + ! endif + ! + ! if (id_vts > 0) then + ! do k = ktop, kbot + ! vt_i (i, j, k) = vtiz (k) + ! enddo + ! endif + ! + ! if (id_droplets > 0) then + ! do k = ktop, kbot + ! qn2 (i, j, k) = ccn (k) + ! enddo + ! endif + + enddo + +end subroutine mpdrv + +! ----------------------------------------------------------------------- +!>\ingroup mod_gfdl_cloud_mp +!>\brief This subroutine calculates sedimentation of heat. +subroutine sedi_heat (ktop, kbot, dm, m1, dz, tz, qv, ql, qr, qi, qs, qg, cw) + + implicit none + + ! input q fields are dry mixing ratios, and dm is dry air mass + + integer, intent (in) :: ktop, kbot + + real, intent (in), dimension (ktop:kbot) :: dm, m1, dz, qv, ql, qr, qi, qs, qg + + real, intent (inout), dimension (ktop:kbot) :: tz + + real, intent (in) :: cw ! heat capacity + + real, dimension (ktop:kbot) :: dgz, cvn + + real :: tmp + + integer :: k + + do k = ktop, kbot + dgz (k) = - 0.5 * grav * dz (k) ! > 0 + cvn (k) = dm (k) * (cv_air + qv (k) * cv_vap + (qr (k) + ql (k)) * & + c_liq + (qi (k) + qs (k) + qg (k)) * c_ice) + enddo + + ! ----------------------------------------------------------------------- + ! sjl, july 2014 + ! assumption: the ke in the falling condensates is negligible compared to the potential energy + ! that was unaccounted for. local thermal equilibrium is assumed, and the loss in pe is transformed + ! into internal energy (to heat the whole grid box) + ! backward time - implicit upwind transport scheme: + ! dm here is dry air mass + ! ----------------------------------------------------------------------- + + k = ktop + tmp = cvn (k) + m1 (k) * cw + tz (k) = (tmp * tz (k) + m1 (k) * dgz (k)) / tmp + + ! ----------------------------------------------------------------------- + ! implicit algorithm: can't be vectorized + ! needs an inner i - loop for vectorization + ! ----------------------------------------------------------------------- + + do k = ktop + 1, kbot + tz (k) = ((cvn (k) + cw * (m1 (k) - m1 (k - 1))) * tz (k) + m1 (k - 1) * & + cw * tz (k - 1) + dgz (k) * (m1 (k - 1) + m1 (k))) / (cvn (k) + cw * m1 (k)) + enddo + +end subroutine sedi_heat + +! ----------------------------------------------------------------------- +!>\ingroup mod_gfdl_cloud_mp +!> This subroutine includes warm rain cloud microphysics. +!>\section warm_gen GFDL Cloud warm_rain General Algorithm +subroutine warm_rain (dt, ktop, kbot, dp, dz, tz, qv, ql, qr, qi, qs, qg, & + den, denfac, ccn, c_praut, rh_rain, vtr, r1, m1_rain, w1, h_var) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in) :: dt ! time step (s) + real, intent (in) :: rh_rain, h_var + + real, intent (in), dimension (ktop:kbot) :: dp, dz, den + real, intent (in), dimension (ktop:kbot) :: denfac, ccn, c_praut + + real, intent (inout), dimension (ktop:kbot) :: tz, vtr + real, intent (inout), dimension (ktop:kbot) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ktop:kbot) :: m1_rain, w1 + + real, intent (out) :: r1 + + real, parameter :: so3 = 7. / 3. + + real, dimension (ktop:kbot) :: dl, dm + real, dimension (ktop:kbot + 1) :: ze, zt + + real :: sink, dq, qc0, qc + real :: qden + real :: zs = 0. + real :: dt5 + + integer :: k + + ! fall velocity constants: + + real, parameter :: vconr = 2503.23638966667 + real, parameter :: normr = 25132741228.7183 + real, parameter :: thr = 1.e-8 + + logical :: no_fall + + dt5 = 0.5 * dt + + ! ----------------------------------------------------------------------- + !> - Call check_column() to check if the water species is large enough to fall. + ! ----------------------------------------------------------------------- + + m1_rain (:) = 0. + + call check_column (ktop, kbot, qr, no_fall) + + if (no_fall) then + vtr (:) = vf_min + r1 = 0. + else + + ! ----------------------------------------------------------------------- + !> - Calculate fall speed of rain. + ! ----------------------------------------------------------------------- + + if (const_vr) then + vtr (:) = vr_fac ! ifs_2016: 4.0 + else + do k = ktop, kbot + qden = qr (k) * den (k) + if (qr (k) < thr) then + vtr (k) = vr_min + else + vtr (k) = vr_fac * vconr * sqrt (min (10., sfcrho / den (k))) * & + exp (0.2 * log (qden / normr)) + vtr (k) = min (vr_max, max (vr_min, vtr (k))) + endif + enddo + endif + + ze (kbot + 1) = zs + do k = kbot, ktop, - 1 + ze (k) = ze (k + 1) - dz (k) ! dz < 0 + enddo + + ! ----------------------------------------------------------------------- + !> - Call revap_racc(), to calculate evaporation and accretion + !! of rain for the first 1/2 time step. + ! ----------------------------------------------------------------------- + + ! if (.not. fast_sat_adj) & + call revap_racc (ktop, kbot, dt5, tz, qv, ql, qr, qi, qs, qg, den, denfac, rh_rain, h_var) + + if (do_sedi_w) then + do k = ktop, kbot + dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) + enddo + endif + + ! ----------------------------------------------------------------------- + !> - Calculate mass flux induced by falling rain + !! ( use_ppm =.false, call implicit_fall(): time-implicit monotonic fall scheme.) + ! ----------------------------------------------------------------------- + + if (use_ppm) then + zt (ktop) = ze (ktop) + do k = ktop + 1, kbot + zt (k) = ze (k) - dt5 * (vtr (k - 1) + vtr (k)) + enddo + zt (kbot + 1) = zs - dt * vtr (kbot) + + do k = ktop, kbot + if (zt (k + 1) >= zt (k)) zt (k + 1) = zt (k) - dz_min + enddo + call lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, qr, r1, m1_rain, mono_prof) + else + call implicit_fall (dt, ktop, kbot, ze, vtr, dp, qr, r1, m1_rain) + endif + + ! ----------------------------------------------------------------------- + ! - Calculate vertical velocity transportation during sedimentation. + ! (do_sedi_w =.true. to turn on vertical motion tranport during sedimentation + ! .false. by default) + ! ----------------------------------------------------------------------- + + if (do_sedi_w) then + w1 (ktop) = (dm (ktop) * w1 (ktop) + m1_rain (ktop) * vtr (ktop)) / (dm (ktop) - m1_rain (ktop)) + do k = ktop + 1, kbot + w1 (k) = (dm (k) * w1 (k) - m1_rain (k - 1) * vtr (k - 1) + m1_rain (k) * vtr (k)) & + / (dm (k) + m1_rain (k - 1) - m1_rain (k)) + enddo + endif + + ! ----------------------------------------------------------------------- + !> - Call sedi_heat() to calculate heat transportation during sedimentation. + ! ----------------------------------------------------------------------- + + if (do_sedi_heat) & + call sedi_heat (ktop, kbot, dp, m1_rain, dz, tz, qv, ql, qr, qi, qs, qg, c_liq) + + ! ----------------------------------------------------------------------- + !> - Call revap_racc() to calculate evaporation and accretion + !! of rain for the remaing 1/2 time step. + ! ----------------------------------------------------------------------- + + call revap_racc (ktop, kbot, dt5, tz, qv, ql, qr, qi, qs, qg, den, denfac, rh_rain, h_var) + + endif + + ! ----------------------------------------------------------------------- + !> - Auto-conversion + !! (assuming linear subgrid vertical distribution of cloud water + !! following Lin et al. (1994) \cite lin_et_al_1994.) + ! ----------------------------------------------------------------------- + + if (irain_f /= 0) then + + ! ----------------------------------------------------------------------- + ! no subgrid varaibility + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + qc0 = fac_rc * ccn (k) + if (tz (k) > t_wfr) then + if (use_ccn) then + ! ----------------------------------------------------------------------- + ! ccn is formulted as ccn = ccn_surface * (den / den_surface) + ! ----------------------------------------------------------------------- + qc = qc0 + else + qc = qc0 / den (k) + endif + dq = ql (k) - qc + if (dq > 0.) then + sink = min (dq, dt * c_praut (k) * den (k) * exp (so3 * log (ql (k)))) + ql (k) = ql (k) - sink + qr (k) = qr (k) + sink + endif + endif + enddo + + else + + ! ----------------------------------------------------------------------- + !> - Call linear_prof() to calculate vertical subgrid variability of cloud water. + ! ----------------------------------------------------------------------- + + call linear_prof (kbot - ktop + 1, ql (ktop), dl (ktop), z_slope_liq, h_var) + + do k = ktop, kbot + qc0 = fac_rc * ccn (k) + if (tz (k) > t_wfr + dt_fr) then + dl (k) = min (max (1.e-6, dl (k)), 0.5 * ql (k)) + ! -------------------------------------------------------------------- + ! as in klein's gfdl am2 stratiform scheme (with subgrid variations) + ! -------------------------------------------------------------------- + if (use_ccn) then + ! -------------------------------------------------------------------- + ! ccn is formulted as ccn = ccn_surface * (den / den_surface) + ! -------------------------------------------------------------------- + qc = qc0 + else + qc = qc0 / den (k) + endif + dq = 0.5 * (ql (k) + dl (k) - qc) + ! -------------------------------------------------------------------- + ! dq = dl if qc == q_minus = ql - dl + ! dq = 0 if qc == q_plus = ql + dl + ! -------------------------------------------------------------------- + if (dq > 0.) then ! q_plus > qc + ! -------------------------------------------------------------------- + !> - Revised continuous form: linearly decays (with subgrid dl) to zero at qc == ql + dl + ! -------------------------------------------------------------------- + sink = min (1., dq / dl (k)) * dt * c_praut (k) * den (k) * exp (so3 * log (ql (k))) + ql (k) = ql (k) - sink + qr (k) = qr (k) + sink + endif + endif + enddo + endif + +end subroutine warm_rain + +! ----------------------------------------------------------------------- +!>\ingroup mod_gfdl_cloud_mp +!> This subroutine calculates evaporation of rain and accretion of rain. +!!\section gen_ravap GFDL Cloud revap_racc General Algorithm +subroutine revap_racc (ktop, kbot, dt, tz, qv, ql, qr, qi, qs, qg, den, denfac, rh_rain, h_var) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in) :: dt ! time step (s) + real, intent (in) :: rh_rain, h_var + + real, intent (in), dimension (ktop:kbot) :: den, denfac + + real, intent (inout), dimension (ktop:kbot) :: tz, qv, qr, ql, qi, qs, qg + + real, dimension (ktop:kbot) :: lhl, cvm, q_liq, q_sol, lcpk + + real :: dqv, qsat, dqsdt, evap, t2, qden, q_plus, q_minus, sink + real :: qpz, dq, dqh, tin + + integer :: k + + do k = ktop, kbot + + if (tz (k) > t_wfr .and. qr (k) > qrmin) then + + ! ----------------------------------------------------------------------- + !> - Define heat capacity and latent heat coefficient. + ! ----------------------------------------------------------------------- + + lhl (k) = lv00 + d0_vap * tz (k) + q_liq (k) = ql (k) + qr (k) + q_sol (k) = qi (k) + qs (k) + qg (k) + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + lcpk (k) = lhl (k) / cvm (k) + + tin = tz (k) - lcpk (k) * ql (k) ! presence of clouds suppresses the rain evap + qpz = qv (k) + ql (k) + qsat = wqs2 (tin, den (k), dqsdt) + dqh = max (ql (k), h_var * max (qpz, qcmin)) + dqh = min (dqh, 0.2 * qpz) ! new limiter + dqv = qsat - qv (k) ! use this to prevent super - sat the gird box + q_minus = qpz - dqh + q_plus = qpz + dqh + + ! ----------------------------------------------------------------------- + !> - qsat must be > q_minus to activate evaporation; + !! qsat must be < q_plus to activate accretion + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + !> - rain evaporation (\f$evap\f$) + ! ----------------------------------------------------------------------- + + if (dqv > qvmin .and. qsat > q_minus) then + if (qsat > q_plus) then + dq = qsat - qpz + else + ! ----------------------------------------------------------------------- + ! q_minus < qsat < q_plus + ! dq == dqh if qsat == q_minus + ! ----------------------------------------------------------------------- + dq = 0.25 * (q_minus - qsat) ** 2 / dqh + endif + qden = qr (k) * den (k) + t2 = tin * tin + evap = crevp (1) * t2 * dq * (crevp (2) * sqrt (qden) + crevp (3) * & + exp (0.725 * log (qden))) / (crevp (4) * t2 + crevp (5) * qsat * den (k)) + evap = min (qr (k), dt * evap, dqv / (1. + lcpk (k) * dqsdt)) + ! ----------------------------------------------------------------------- + ! alternative minimum evap in dry environmental air + ! sink = min (qr (k), dim (rh_rain * qsat, qv (k)) / (1. + lcpk (k) * dqsdt)) + ! evap = max (evap, sink) + ! ----------------------------------------------------------------------- + qr (k) = qr (k) - evap + qv (k) = qv (k) + evap + q_liq (k) = q_liq (k) - evap + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) - evap * lhl (k) / cvm (k) + endif + + ! ----------------------------------------------------------------------- + !> - accretion: \f$P_{racc}\f$ + ! ----------------------------------------------------------------------- + + ! if (qr (k) > qrmin .and. ql (k) > 1.e-7 .and. qsat < q_plus) then + if (qr (k) > qrmin .and. ql (k) > 1.e-6 .and. qsat < q_minus) then + sink = dt * denfac (k) * cracw * exp (0.95 * log (qr (k) * den (k))) + sink = sink / (1. + sink) * ql (k) + ql (k) = ql (k) - sink + qr (k) = qr (k) + sink + endif + + endif ! warm - rain + enddo + +end subroutine revap_racc + +! ----------------------------------------------------------------------- +!>\ingroup mod_gfdl_cloud_mp +!> Definition of vertical subgrid variability +!! used for cloud ice and cloud water autoconversion. +! qi -- > ql & ql -- > qr +! edges: qe == qbar + / - dm +!>\section gen_linear GFDL cloud linear_prof General Algorithm +subroutine linear_prof (km, q, dm, z_var, h_var) + + implicit none + + integer, intent (in) :: km + + real, intent (in) :: q (km), h_var + + real, intent (out) :: dm (km) + + logical, intent (in) :: z_var + + real :: dq (km) + + integer :: k + + if (z_var) then + do k = 2, km + dq (k) = 0.5 * (q (k) - q (k - 1)) + enddo + dm (1) = 0. + + ! ----------------------------------------------------------------------- + !> - Use twice the strength of the positive definiteness limiter (Lin et al.(1994) + !! \cite lin_et_al_1994). + ! ----------------------------------------------------------------------- + + do k = 2, km - 1 + dm (k) = 0.5 * min (abs (dq (k) + dq (k + 1)), 0.5 * q (k)) + if (dq (k) * dq (k + 1) <= 0.) then + if (dq (k) > 0.) then ! local max + dm (k) = min (dm (k), dq (k), - dq (k + 1)) + else + dm (k) = 0. + endif + endif + enddo + dm (km) = 0. + + ! ----------------------------------------------------------------------- + !> - Impose the background horizontal variability (\f$h_{var}\f$) that + !! is proportional to the value itself. + ! ----------------------------------------------------------------------- + + do k = 1, km + dm (k) = max (dm (k), qvmin, h_var * q (k)) + enddo + else + do k = 1, km + dm (k) = max (qvmin, h_var * q (k)) + enddo + endif + +end subroutine linear_prof + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!> This subroutine includes cloud ice microphysics processes. +!>\author Shian-Jiann Lin, GFDL +!! +!! This scheme is featured with: +!! - bulk cloud microphysics +!! - processes splitting with some un-split sub-grouping +!! - time implicit (when possible) accretion and autoconversion +!>\section det_icloud GFDL icloud Detailed Algorithm +subroutine icloud (ktop, kbot, tzk, p1, qvk, qlk, qrk, qik, qsk, qgk, dp1, & + den, denfac, vts, vtg, vtr, qak, rh_adj, rh_rain, dts, h_var) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in), dimension (ktop:kbot) :: p1, dp1, den, denfac, vts, vtg, vtr + + real, intent (inout), dimension (ktop:kbot) :: tzk, qvk, qlk, qrk, qik, qsk, qgk, qak + + real, intent (in) :: rh_adj, rh_rain, dts, h_var + + real, dimension (ktop:kbot) :: lcpk, icpk, tcpk, di, lhl, lhi + real, dimension (ktop:kbot) :: cvm, q_liq, q_sol + + real :: rdts, fac_g2v, fac_v2g, fac_i2s, fac_imlt + real :: tz, qv, ql, qr, qi, qs, qg, melt + real :: pracs, psacw, pgacw, psacr, pgacr, pgaci, praci, psaci + real :: pgmlt, psmlt, pgfr, pgaut, psaut, pgsub + real :: tc, tsq, dqs0, qden, qim, qsm + real :: dt5, factor, sink, qi_crt + real :: tmp, qsw, qsi, dqsdt, dq + real :: dtmp, qc, q_plus, q_minus + + integer :: k + + dt5 = 0.5 * dts + + rdts = 1. / dts + + ! ----------------------------------------------------------------------- + !> - Define conversion scalar/factor. + ! ----------------------------------------------------------------------- + + fac_i2s = 1. - exp (- dts / tau_i2s) + fac_g2v = 1. - exp (- dts / tau_g2v) + fac_v2g = 1. - exp (- dts / tau_v2g) + + fac_imlt = 1. - exp (- dt5 / tau_imlt) + + ! ----------------------------------------------------------------------- + !> - Define heat capacity and latend heat coefficient. + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + lhi (k) = li00 + dc_ice * tzk (k) + q_liq (k) = qlk (k) + qrk (k) + q_sol (k) = qik (k) + qsk (k) + qgk (k) + cvm (k) = c_air + qvk (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + icpk (k) = lhi (k) / cvm (k) + enddo + + ! ----------------------------------------------------------------------- + ! sources of cloud ice: pihom, cold rain, and the sat_adj + ! (initiation plus deposition) + ! sources of snow: cold rain, auto conversion + accretion (from cloud ice) + ! sat_adj (deposition; requires pre - existing snow) ; initial snow comes from auto conversion + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + if (tzk (k) > tice .and. qik (k) > qcmin) then + + ! ----------------------------------------------------------------------- + !> - Calculate \f$P_{imlt}\f$: instant melting of cloud ice. + ! ----------------------------------------------------------------------- + + melt = min (qik (k), fac_imlt * (tzk (k) - tice) / icpk (k)) + tmp = min (melt, dim (ql_mlt, qlk (k))) ! max ql amount + qlk (k) = qlk (k) + tmp + qrk (k) = qrk (k) + melt - tmp + qik (k) = qik (k) - melt + q_liq (k) = q_liq (k) + melt + q_sol (k) = q_sol (k) - melt + cvm (k) = c_air + qvk (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tzk (k) = tzk (k) - melt * lhi (k) / cvm (k) + + elseif (tzk (k) < t_wfr .and. qlk (k) > qcmin) then + + ! ----------------------------------------------------------------------- + !> - Calculate \f$P_{ihom}\f$: homogeneous freezing of cloud water into cloud ice. + !! This is the 1st occurance of liquid water freezing in the split MP process. + ! ----------------------------------------------------------------------- + + dtmp = t_wfr - tzk (k) + factor = min (1., dtmp / dt_fr) + sink = min (qlk (k) * factor, dtmp / icpk (k)) + qi_crt = qi_gen * min (qi_lim, 0.1 * (tice - tzk (k))) / den (k) + tmp = min (sink, dim (qi_crt, qik (k))) + qlk (k) = qlk (k) - sink + qsk (k) = qsk (k) + sink - tmp + qik (k) = qik (k) + tmp + q_liq (k) = q_liq (k) - sink + q_sol (k) = q_sol (k) + sink + cvm (k) = c_air + qvk (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tzk (k) = tzk (k) + sink * lhi (k) / cvm (k) + + endif + enddo + + ! ----------------------------------------------------------------------- + !> - Call linear_prof() to calculate vertical subgrid variability of cloud ice. + ! ----------------------------------------------------------------------- + + call linear_prof (kbot - ktop + 1, qik (ktop), di (ktop), z_slope_ice, h_var) + + ! ----------------------------------------------------------------------- + !> - Update capacity heat and latend heat coefficient. + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + lhl (k) = lv00 + d0_vap * tzk (k) + lhi (k) = li00 + dc_ice * tzk (k) + lcpk (k) = lhl (k) / cvm (k) + icpk (k) = lhi (k) / cvm (k) + tcpk (k) = lcpk (k) + icpk (k) + enddo + + do k = ktop, kbot + + ! ----------------------------------------------------------------------- + ! do nothing above p_min + ! ----------------------------------------------------------------------- + + if (p1 (k) < p_min) cycle + + tz = tzk (k) + qv = qvk (k) + ql = qlk (k) + qi = qik (k) + qr = qrk (k) + qs = qsk (k) + qg = qgk (k) + + pgacr = 0. + pgacw = 0. + tc = tz - tice + + if (tc .ge. 0.) then + + ! ----------------------------------------------------------------------- + !> - Melting of snow: + ! ----------------------------------------------------------------------- + + dqs0 = ces0 / p1 (k) - qv + + if (qs > qcmin) then + + ! ----------------------------------------------------------------------- + !> - \f$P_{sacw}\f$: accretion of cloud water by snow + ! only rate is used (for snow melt) since tc > 0. + ! ----------------------------------------------------------------------- + + if (ql > qrmin) then + factor = denfac (k) * csacw * exp (0.8125 * log (qs * den (k))) + psacw = factor / (1. + dts * factor) * ql ! rate + else + psacw = 0. + endif + + ! ----------------------------------------------------------------------- + !> - \f$P_{sacr}\f$: accretion of rain by melted snow + !> - \f$P_{racs}\f$: accretion of snow by rain + ! ----------------------------------------------------------------------- + + if (qr > qrmin) then + psacr = min (acr3d (vts (k), vtr (k), qr, qs, csacr, acco (1, 2), & + den (k)), qr * rdts) + pracs = acr3d (vtr (k), vts (k), qs, qr, cracs, acco (1, 1), den (k)) + else + psacr = 0. + pracs = 0. + endif + + ! ----------------------------------------------------------------------- + !> - Total snow sink: + !! \f$P_{smlt}\f$: snow melt (smlt(); due to rain accretion) + ! ----------------------------------------------------------------------- + + psmlt = max (0., smlt (tc, dqs0, qs * den (k), psacw, psacr, csmlt, & + den (k), denfac (k))) + sink = min (qs, dts * (psmlt + pracs), tc / icpk (k)) + qs = qs - sink + ! sjl, 20170321: + tmp = min (sink, dim (qs_mlt, ql)) ! max ql due to snow melt + ql = ql + tmp + qr = qr + sink - tmp + ! qr = qr + sink + ! sjl, 20170321: + q_liq (k) = q_liq (k) + sink + q_sol (k) = q_sol (k) - sink + cvm (k) = c_air + qv * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz = tz - sink * lhi (k) / cvm (k) + tc = tz - tice + + endif + + ! ----------------------------------------------------------------------- + !> - Update capacity heat and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhi (k) = li00 + dc_ice * tz + icpk (k) = lhi (k) / cvm (k) + + ! ----------------------------------------------------------------------- + !> - Melting of graupel: + ! ----------------------------------------------------------------------- + + if (qg > qcmin .and. tc > 0.) then + + ! ----------------------------------------------------------------------- + !> - \f$P_{gacr}\f$: accretion of rain by graupel + ! ----------------------------------------------------------------------- + + if (qr > qrmin) & + pgacr = min (acr3d (vtg (k), vtr (k), qr, qg, cgacr, acco (1, 3), & + den (k)), rdts * qr) + + ! ----------------------------------------------------------------------- + !> - \f$P_{gacw}\f$: accretion of cloud water by graupel + ! ----------------------------------------------------------------------- + + qden = qg * den (k) + if (ql > qrmin) then + factor = cgacw * qden / sqrt (den (k) * sqrt (sqrt (qden))) + pgacw = factor / (1. + dts * factor) * ql ! rate + endif + + ! ----------------------------------------------------------------------- + !> - \f$P_{gmlt}\f$: graupel melt (gmlt()) + ! ----------------------------------------------------------------------- + + pgmlt = dts * gmlt (tc, dqs0, qden, pgacw, pgacr, cgmlt, den (k)) + pgmlt = min (max (0., pgmlt), qg, tc / icpk (k)) + qg = qg - pgmlt + qr = qr + pgmlt + q_liq (k) = q_liq (k) + pgmlt + q_sol (k) = q_sol (k) - pgmlt + cvm (k) = c_air + qv * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz = tz - pgmlt * lhi (k) / cvm (k) + + endif + + else + + ! ----------------------------------------------------------------------- + !> - Cloud ice processes: + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + !> - \f$P_{saci}\f$: accretion of cloud ice by snow + ! ----------------------------------------------------------------------- + + if (qi > 3.e-7) then ! cloud ice sink terms + + if (qs > 1.e-7) then + ! ----------------------------------------------------------------------- + ! sjl added (following lin eq. 23) the temperature dependency + ! to reduce accretion, use esi = exp (0.05 * tc) as in hong et al 2004 + ! ----------------------------------------------------------------------- + factor = dts * denfac (k) * csaci * exp (0.05 * tc + 0.8125 * log (qs * den (k))) + psaci = factor / (1. + factor) * qi + else + psaci = 0. + endif + + ! ----------------------------------------------------------------------- + !> - \f$P_{saut}\f$: autoconversion: cloud ice \f$\rightarrow\f$ snow. + !!\n similar to Lin et al.(1983) \cite lin_et_al_1983 eq. 21 solved implicitly; + !! threshold from wsm6 scheme, Hong et al. (2004) \cite hong_et_al_2004, + !! eq (13) : qi0_crt ~0.8e-4. + ! ----------------------------------------------------------------------- + if (qi0_crt < 0.) then + qim = - qi0_crt + else + qim = qi0_crt / den (k) + endif + ! ----------------------------------------------------------------------- + ! assuming linear subgrid vertical distribution of cloud ice + ! the mismatch computation following lin et al. 1994, mwr + ! ----------------------------------------------------------------------- + + if (const_vi) then + tmp = fac_i2s + else + tmp = fac_i2s * exp (0.025 * tc) + endif + + di (k) = max (di (k), qrmin) + q_plus = qi + di (k) + if (q_plus > (qim + qrmin)) then + if (qim > (qi - di (k))) then + dq = (0.25 * (q_plus - qim) ** 2) / di (k) + else + dq = qi - qim + endif + psaut = tmp * dq + else + psaut = 0. + endif + ! ----------------------------------------------------------------------- + ! sink is no greater than 75% of qi + ! ----------------------------------------------------------------------- + sink = min (0.75 * qi, psaci + psaut) + qi = qi - sink + qs = qs + sink + + ! ----------------------------------------------------------------------- + !> - \f$P_{gaci}\f$: accretion of cloud ice by graupel + ! ----------------------------------------------------------------------- + + if (qg > 1.e-6) then + ! ----------------------------------------------------------------------- + ! factor = dts * cgaci / sqrt (den (k)) * exp (0.05 * tc + 0.875 * log (qg * den (k))) + ! simplified form: remove temp dependency & set the exponent "0.875" -- > 1 + ! ----------------------------------------------------------------------- + factor = dts * cgaci * sqrt (den (k)) * qg + pgaci = factor / (1. + factor) * qi + qi = qi - pgaci + qg = qg + pgaci + endif + + endif + + ! ----------------------------------------------------------------------- + !> - Cold-rain processes: + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + ! rain to ice, snow, graupel processes: + ! ----------------------------------------------------------------------- + + tc = tz - tice + + if (qr > 1.e-7 .and. tc < 0.) then + + ! ----------------------------------------------------------------------- + ! * sink * terms to qr: psacr + pgfr + ! source terms to qs: psacr + ! source terms to qg: pgfr + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + !> - \f$P_{sacr}\f$: accretion of rain by snow (acr3d()) + ! ----------------------------------------------------------------------- + + if (qs > 1.e-7) then ! if snow exists + psacr = dts * acr3d (vts (k), vtr (k), qr, qs, csacr, acco (1, 2), den (k)) + else + psacr = 0. + endif + + ! ----------------------------------------------------------------------- + !> - \f$P_{gfr}\f$: rain freezing \f$\rightarrow\f$ graupel + ! ----------------------------------------------------------------------- + + pgfr = dts * cgfr (1) / den (k) * (exp (- cgfr (2) * tc) - 1.) * & + exp (1.75 * log (qr * den (k))) + + ! ----------------------------------------------------------------------- + !> - Calculate total sink to \f$q_r\f$ : + !!\n Sink terms to \f$q_r\f$: \f$P_{sacr}+P_{gfr}\f$ + !!\n source term to \f$q_s\f$: \f$P_{sacr}\f$ + !!\n source term to \f$q_g\f$: \f$P_{gfr}\f$ + ! ----------------------------------------------------------------------- + + sink = psacr + pgfr + factor = min (sink, qr, - tc / icpk (k)) / max (sink, qrmin) + + psacr = factor * psacr + pgfr = factor * pgfr + + sink = psacr + pgfr + qr = qr - sink + qs = qs + psacr + qg = qg + pgfr + q_liq (k) = q_liq (k) - sink + q_sol (k) = q_sol (k) + sink + cvm (k) = c_air + qv * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz = tz + sink * lhi (k) / cvm (k) + + endif + + ! ----------------------------------------------------------------------- + !> - Update capacity heat and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhi (k) = li00 + dc_ice * tz + icpk (k) = lhi (k) / cvm (k) + + ! ----------------------------------------------------------------------- + !> - Graupel production terms: + ! ----------------------------------------------------------------------- + + if (qs > 1.e-7) then + + ! ----------------------------------------------------------------------- + !> - accretion: snow \f$\rightarrow\f$ graupel (acr3d()) + ! ----------------------------------------------------------------------- + + if (qg > qrmin) then + sink = dts * acr3d (vtg (k), vts (k), qs, qg, cgacs, acco (1, 4), den (k)) + else + sink = 0. + endif + + ! ----------------------------------------------------------------------- + !> - autoconversion: snow \f$\rightarrow\f$ graupel + ! ----------------------------------------------------------------------- + + qsm = qs0_crt / den (k) + if (qs > qsm) then + factor = dts * 1.e-3 * exp (0.09 * (tz - tice)) + sink = sink + factor / (1. + factor) * (qs - qsm) + endif + sink = min (qs, sink) + qs = qs - sink + qg = qg + sink + + endif ! snow existed + + if (qg > 1.e-7 .and. tz < tice0) then + + ! ----------------------------------------------------------------------- + !> - \f$P_{gacw}\f$: accretion of cloud water by graupel + ! ----------------------------------------------------------------------- + + if (ql > 1.e-6) then + qden = qg * den (k) + factor = dts * cgacw * qden / sqrt (den (k) * sqrt (sqrt (qden))) + pgacw = factor / (1. + factor) * ql + else + pgacw = 0. + endif + + ! ----------------------------------------------------------------------- + !> - \f$P_{gacr}\f$: accretion of rain by graupel (acr3d()) + ! ----------------------------------------------------------------------- + + if (qr > 1.e-6) then + pgacr = min (dts * acr3d (vtg (k), vtr (k), qr, qg, cgacr, acco (1, 3), & + den (k)), qr) + else + pgacr = 0. + endif + + sink = pgacr + pgacw + factor = min (sink, dim (tice, tz) / icpk (k)) / max (sink, qrmin) + pgacr = factor * pgacr + pgacw = factor * pgacw + + sink = pgacr + pgacw + qg = qg + sink + qr = qr - pgacr + ql = ql - pgacw + q_liq (k) = q_liq (k) - sink + q_sol (k) = q_sol (k) + sink + cvm (k) = c_air + qv * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz = tz + sink * lhi (k) / cvm (k) + + endif + + endif + + tzk (k) = tz + qvk (k) = qv + qlk (k) = ql + qik (k) = qi + qrk (k) = qr + qsk (k) = qs + qgk (k) = qg + + enddo + + ! ----------------------------------------------------------------------- + !> - Call subgrid_z_proc() for subgrid cloud microphysics. + ! ----------------------------------------------------------------------- + + call subgrid_z_proc (ktop, kbot, p1, den, denfac, dts, rh_adj, tzk, qvk, & + qlk, qrk, qik, qsk, qgk, qak, h_var, rh_rain) + +end subroutine icloud + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!> This subroutine calculates temperature sentive high vertical resolution processes. +!>\section gen_subz GFDL Cloud subgrid_z_proc General Algorithm +subroutine subgrid_z_proc (ktop, kbot, p1, den, denfac, dts, rh_adj, tz, qv, & + ql, qr, qi, qs, qg, qa, h_var, rh_rain) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in), dimension (ktop:kbot) :: p1, den, denfac + + real, intent (in) :: dts, rh_adj, h_var, rh_rain + + real, intent (inout), dimension (ktop:kbot) :: tz, qv, ql, qr, qi, qs, qg, qa + + real, dimension (ktop:kbot) :: lcpk, icpk, tcpk, tcp3, lhl, lhi + real, dimension (ktop:kbot) :: cvm, q_liq, q_sol, q_cond + + real :: fac_v2l, fac_l2v + + real :: pidep, qi_crt + + ! ----------------------------------------------------------------------- + ! qstar over water may be accurate only down to - 80 deg c with ~10% uncertainty + ! must not be too large to allow psc + ! ----------------------------------------------------------------------- + + real :: rh, rqi, tin, qsw, qsi, qpz, qstar + real :: dqsdt, dwsdt, dq, dq0, factor, tmp + real :: q_plus, q_minus, dt_evap, dt_pisub + real :: evap, sink, tc, pisub, q_adj, dtmp + real :: pssub, pgsub, tsq, qden, fac_g2v, fac_v2g + + integer :: k + + if (fast_sat_adj) then + dt_evap = 0.5 * dts + else + dt_evap = dts + endif + + ! ----------------------------------------------------------------------- + !> - Define conversion scalar/factor. + ! ----------------------------------------------------------------------- + + fac_v2l = 1. - exp (- dt_evap / tau_v2l) + fac_l2v = 1. - exp (- dt_evap / tau_l2v) + + fac_g2v = 1. - exp (- dts / tau_g2v) + fac_v2g = 1. - exp (- dts / tau_v2g) + + ! ----------------------------------------------------------------------- + !> - Define heat capacity and latend heat coefficient. + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + lhl (k) = lv00 + d0_vap * tz (k) + lhi (k) = li00 + dc_ice * tz (k) + q_liq (k) = ql (k) + qr (k) + q_sol (k) = qi (k) + qs (k) + qg (k) + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + lcpk (k) = lhl (k) / cvm (k) + icpk (k) = lhi (k) / cvm (k) + tcpk (k) = lcpk (k) + icpk (k) + tcp3 (k) = lcpk (k) + icpk (k) * min (1., dim (tice, tz (k)) / (tice - t_wfr)) + enddo + + do k = ktop, kbot + + if (p1 (k) < p_min) cycle + + ! ----------------------------------------------------------------------- + !> - Instant deposit all water vapor to cloud ice when temperature is super low. + ! ----------------------------------------------------------------------- + + if (tz (k) < t_min) then + sink = dim (qv (k), 1.e-7) + qv (k) = qv (k) - sink + qi (k) = qi (k) + sink + q_sol (k) = q_sol (k) + sink + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) + sink * (lhl (k) + lhi (k)) / cvm (k) + if (.not. do_qa) qa (k) = qa (k) + 1. ! air fully saturated; 100 % cloud cover + cycle + endif + + ! ----------------------------------------------------------------------- + !> - Update heat capacity and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhl (k) = lv00 + d0_vap * tz (k) + lhi (k) = li00 + dc_ice * tz (k) + lcpk (k) = lhl (k) / cvm (k) + icpk (k) = lhi (k) / cvm (k) + tcpk (k) = lcpk (k) + icpk (k) + tcp3 (k) = lcpk (k) + icpk (k) * min (1., dim (tice, tz (k)) / (tice - t_wfr)) + + ! ----------------------------------------------------------------------- + !> - Instant evaporation/sublimation of all clouds if rh < rh_adj \f$\rightarrow\f$ cloud free. + ! ----------------------------------------------------------------------- + + qpz = qv (k) + ql (k) + qi (k) + tin = tz (k) - (lhl (k) * (ql (k) + qi (k)) + lhi (k) * qi (k)) / (c_air + & + qpz * c_vap + qr (k) * c_liq + (qs (k) + qg (k)) * c_ice) + if (tin > t_sub + 6.) then + rh = qpz / iqs1 (tin, den (k)) + if (rh < rh_adj) then ! qpz / rh_adj < qs + tz (k) = tin + qv (k) = qpz + ql (k) = 0. + qi (k) = 0. + cycle ! cloud free + endif + endif + + ! ----------------------------------------------------------------------- + !> - cloud water \f$\Leftrightarrow\f$ vapor adjustment: + ! ----------------------------------------------------------------------- + + qsw = wqs2 (tz (k), den (k), dwsdt) + dq0 = qsw - qv (k) + if (dq0 > 0.) then + ! SJL 20170703 added ql factor to prevent the situation of high ql and low RH + ! factor = min (1., fac_l2v * sqrt (max (0., ql (k)) / 1.e-5) * 10. * dq0 / qsw) + ! factor = fac_l2v + ! factor = 1 + factor = min (1., fac_l2v * (10. * dq0 / qsw)) ! the rh dependent factor = 1 at 90% + evap = min (ql (k), factor * dq0 / (1. + tcp3 (k) * dwsdt)) + else ! condensate all excess vapor into cloud water + ! ----------------------------------------------------------------------- + ! evap = fac_v2l * dq0 / (1. + tcp3 (k) * dwsdt) + ! sjl, 20161108 + ! ----------------------------------------------------------------------- + evap = dq0 / (1. + tcp3 (k) * dwsdt) + endif + qv (k) = qv (k) + evap + ql (k) = ql (k) - evap + q_liq (k) = q_liq (k) - evap + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) - evap * lhl (k) / cvm (k) + + ! ----------------------------------------------------------------------- + !> - Update heat capacity and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhi (k) = li00 + dc_ice * tz (k) + icpk (k) = lhi (k) / cvm (k) + + ! ----------------------------------------------------------------------- + !> - Enforce complete freezing below \f$-48^oC\f$. + ! ----------------------------------------------------------------------- + + dtmp = t_wfr - tz (k) ! [ - 40, - 48] + if (dtmp > 0. .and. ql (k) > qcmin) then + sink = min (ql (k), ql (k) * dtmp * 0.125, dtmp / icpk (k)) + ql (k) = ql (k) - sink + qi (k) = qi (k) + sink + q_liq (k) = q_liq (k) - sink + q_sol (k) = q_sol (k) + sink + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) + sink * lhi (k) / cvm (k) + endif + + ! ----------------------------------------------------------------------- + !> - Update heat capacity and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhi (k) = li00 + dc_ice * tz (k) + icpk (k) = lhi (k) / cvm (k) + + ! ----------------------------------------------------------------------- + !> - Apply Bigg mechanism. + ! ----------------------------------------------------------------------- + + if (fast_sat_adj) then + dt_pisub = 0.5 * dts + else + dt_pisub = dts + tc = tice - tz (k) + if (ql (k) > qrmin .and. tc > 0.) then + sink = 3.3333e-10 * dts * (exp (0.66 * tc) - 1.) * den (k) * ql (k) * ql (k) + sink = min (ql (k), tc / icpk (k), sink) + ql (k) = ql (k) - sink + qi (k) = qi (k) + sink + q_liq (k) = q_liq (k) - sink + q_sol (k) = q_sol (k) + sink + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) + sink * lhi (k) / cvm (k) + endif ! significant ql existed + endif + + ! ----------------------------------------------------------------------- + !> - Update capacity heat and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhl (k) = lv00 + d0_vap * tz (k) + lhi (k) = li00 + dc_ice * tz (k) + lcpk (k) = lhl (k) / cvm (k) + icpk (k) = lhi (k) / cvm (k) + tcpk (k) = lcpk (k) + icpk (k) + + ! ----------------------------------------------------------------------- + !> - Sublimation/deposition of ice. + ! ----------------------------------------------------------------------- + + if (tz (k) < tice) then + qsi = iqs2 (tz (k), den (k), dqsdt) + dq = qv (k) - qsi + sink = dq / (1. + tcpk (k) * dqsdt) + if (qi (k) > qrmin) then + ! eq 9, hong et al. 2004, mwr + ! for a and b, see dudhia 1989: page 3103 eq (b7) and (b8) + pidep = dt_pisub * dq * 349138.78 * exp (0.875 * log (qi (k) * den (k))) & + / (qsi * den (k) * lat2 / (0.0243 * rvgas * tz (k) ** 2) + 4.42478e4) + else + pidep = 0. + endif + if (dq > 0.) then ! vapor - > ice + tmp = tice - tz (k) + ! 20160912: the following should produce more ice at higher altitude + ! qi_crt = 4.92e-11 * exp (1.33 * log (1.e3 * exp (0.1 * tmp))) / den (k) + qi_crt = qi_gen * min (qi_lim, 0.1 * tmp) / den (k) + sink = min (sink, max (qi_crt - qi (k), pidep), tmp / tcpk (k)) + else ! ice -- > vapor + pidep = pidep * min (1., dim (tz (k), t_sub) * 0.2) + sink = max (pidep, sink, - qi (k)) + endif + qv (k) = qv (k) - sink + qi (k) = qi (k) + sink + q_sol (k) = q_sol (k) + sink + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) + sink * (lhl (k) + lhi (k)) / cvm (k) + endif + + ! ----------------------------------------------------------------------- + !> - Update capacity heat and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhl (k) = lv00 + d0_vap * tz (k) + lhi (k) = li00 + dc_ice * tz (k) + lcpk (k) = lhl (k) / cvm (k) + icpk (k) = lhi (k) / cvm (k) + tcpk (k) = lcpk (k) + icpk (k) + + ! ----------------------------------------------------------------------- + !> - Sublimation/deposition of snow. + ! this process happens for all temp rage + ! ----------------------------------------------------------------------- + + if (qs (k) > qrmin) then + qsi = iqs2 (tz (k), den (k), dqsdt) + qden = qs (k) * den (k) + tmp = exp (0.65625 * log (qden)) + tsq = tz (k) * tz (k) + dq = (qsi - qv (k)) / (1. + tcpk (k) * dqsdt) + pssub = cssub (1) * tsq * (cssub (2) * sqrt (qden) + cssub (3) * tmp * & + sqrt (denfac (k))) / (cssub (4) * tsq + cssub (5) * qsi * den (k)) + pssub = (qsi - qv (k)) * dts * pssub + if (pssub > 0.) then ! qs -- > qv, sublimation + pssub = min (pssub * min (1., dim (tz (k), t_sub) * 0.2), qs (k)) + else + if (tz (k) > tice) then + pssub = 0. ! no deposition + else + pssub = max (pssub, dq, (tz (k) - tice) / tcpk (k)) + endif + endif + qs (k) = qs (k) - pssub + qv (k) = qv (k) + pssub + q_sol (k) = q_sol (k) - pssub + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) - pssub * (lhl (k) + lhi (k)) / cvm (k) + endif + + ! ----------------------------------------------------------------------- + !> - Update capacity heat and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhl (k) = lv00 + d0_vap * tz (k) + lhi (k) = li00 + dc_ice * tz (k) + lcpk (k) = lhl (k) / cvm (k) + icpk (k) = lhi (k) / cvm (k) + tcpk (k) = lcpk (k) + icpk (k) + + ! ----------------------------------------------------------------------- + !> - Simplified 2-way grapuel sublimation-deposition mechanism. + ! ----------------------------------------------------------------------- + + if (qg (k) > qrmin) then + qsi = iqs2 (tz (k), den (k), dqsdt) + dq = (qv (k) - qsi) / (1. + tcpk (k) * dqsdt) + pgsub = (qv (k) / qsi - 1.) * qg (k) + if (pgsub > 0.) then ! deposition + if (tz (k) > tice) then + pgsub = 0. ! no deposition + else + pgsub = min (fac_v2g * pgsub, 0.2 * dq, ql (k) + qr (k), & + (tice - tz (k)) / tcpk (k)) + endif + else ! submilation + pgsub = max (fac_g2v * pgsub, dq) * min (1., dim (tz (k), t_sub) * 0.1) + endif + qg (k) = qg (k) + pgsub + qv (k) = qv (k) - pgsub + q_sol (k) = q_sol (k) + pgsub + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) + pgsub * (lhl (k) + lhi (k)) / cvm (k) + endif + +#ifdef USE_MIN_EVAP + ! ----------------------------------------------------------------------- + !> - Update capacity heat and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhl (k) = lv00 + d0_vap * tz (k) + lcpk (k) = lhl (k) / cvm (k) + + ! ----------------------------------------------------------------------- + !> - Minimum evap of rain in dry environmental air. + ! ----------------------------------------------------------------------- + + if (qr (k) > qcmin) then + qsw = wqs2 (tz (k), den (k), dqsdt) + sink = min (qr (k), dim (rh_rain * qsw, qv (k)) / (1. + lcpk (k) * dqsdt)) + qv (k) = qv (k) + sink + qr (k) = qr (k) - sink + q_liq (k) = q_liq (k) - sink + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) - sink * lhl (k) / cvm (k) + endif +#endif + + ! ----------------------------------------------------------------------- + !> - Update capacity heat and latend heat coefficient. + ! ----------------------------------------------------------------------- + + lhl (k) = lv00 + d0_vap * tz (k) + cvm (k) = c_air + (qv (k) + q_liq (k) + q_sol (k)) * c_vap + lcpk (k) = lhl (k) / cvm (k) + + ! ----------------------------------------------------------------------- + ! compute cloud fraction + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + !> - Combine water species. + ! ----------------------------------------------------------------------- + + if (do_qa) cycle + + if (rad_snow) then + q_sol (k) = qi (k) + qs (k) + else + q_sol (k) = qi (k) + endif + if (rad_rain) then + q_liq (k) = ql (k) + qr (k) + else + q_liq (k) = ql (k) + endif + q_cond (k) = q_liq (k) + q_sol (k) + + qpz = qv (k) + q_cond (k) ! qpz is conserved + + ! ----------------------------------------------------------------------- + !> - Use the "liquid-frozen water temperature" (tin) to compute saturated specific humidity. + ! ----------------------------------------------------------------------- + + tin = tz (k) - (lcpk (k) * q_cond (k) + icpk (k) * q_sol (k)) ! minimum temperature + ! tin = tz (k) - ((lv00 + d0_vap * tz (k)) * q_cond (k) + & + ! (li00 + dc_ice * tz (k)) * q_sol (k)) / (c_air + qpz * c_vap) + + ! ----------------------------------------------------------------------- + ! determine saturated specific humidity + ! ----------------------------------------------------------------------- + + if (tin <= t_wfr) then + ! ice phase: + qstar = iqs1 (tin, den (k)) + elseif (tin >= tice) then + ! liquid phase: + qstar = wqs1 (tin, den (k)) + else + ! mixed phase: + qsi = iqs1 (tin, den (k)) + qsw = wqs1 (tin, den (k)) + if (q_cond (k) > 3.e-6) then + rqi = q_sol (k) / q_cond (k) + else + ! ----------------------------------------------------------------------- + ! mostly liquid water q_cond (k) at initial cloud development stage + ! ----------------------------------------------------------------------- + rqi = (tice - tin) / (tice - t_wfr) + endif + qstar = rqi * qsi + (1. - rqi) * qsw + endif + + ! ----------------------------------------------------------------------- + !> - Compute cloud fraction, assuming subgrid linear distribution in horizontal; + !! this is effectively a smoother for the binary cloud scheme. + ! ----------------------------------------------------------------------- + + if (qpz > qrmin) then + ! partial cloudiness by pdf: + dq = max (qcmin, h_var * qpz) + q_plus = qpz + dq ! cloud free if qstar > q_plus + q_minus = qpz - dq + if (qstar < q_minus) then + qa (k) = qa (k) + 1. ! air fully saturated; 100 % cloud cover + elseif (qstar < q_plus .and. q_cond (k) > qc_crt) then + qa (k) = qa (k) + (q_plus - qstar) / (dq + dq) ! partial cloud cover + ! qa (k) = sqrt (qa (k) + (q_plus - qstar) / (dq + dq)) + endif + endif + + enddo + +end subroutine subgrid_z_proc + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!> This subroutine calculates rain evaporation. +subroutine revap_rac1 (hydrostatic, is, ie, dt, tz, qv, ql, qr, qi, qs, qg, den, hvar) + + implicit none + + logical, intent (in) :: hydrostatic + + integer, intent (in) :: is, ie + + real, intent (in) :: dt ! time step (s) + + real, intent (in), dimension (is:ie) :: den, hvar, qi, qs, qg + + real, intent (inout), dimension (is:ie) :: tz, qv, qr, ql + + real, dimension (is:ie) :: lcp2, denfac, q_liq, q_sol, cvm, lhl + + real :: dqv, qsat, dqsdt, evap, qden, q_plus, q_minus, sink + real :: tin, t2, qpz, dq, dqh + + integer :: i + + ! ----------------------------------------------------------------------- + ! define latend heat coefficient + ! ----------------------------------------------------------------------- + + do i = is, ie + lhl (i) = lv00 + d0_vap * tz (i) + q_liq (i) = ql (i) + qr (i) + q_sol (i) = qi (i) + qs (i) + qg (i) + cvm (i) = c_air + qv (i) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice + lcp2 (i) = lhl (i) / cvm (i) + ! denfac (i) = sqrt (sfcrho / den (i)) + enddo + + do i = is, ie + if (qr (i) > qrmin .and. tz (i) > t_wfr) then + qpz = qv (i) + ql (i) + tin = tz (i) - lcp2 (i) * ql (i) ! presence of clouds suppresses the rain evap + qsat = wqs2 (tin, den (i), dqsdt) + dqh = max (ql (i), hvar (i) * max (qpz, qcmin)) + dqv = qsat - qv (i) + q_minus = qpz - dqh + q_plus = qpz + dqh + + ! ----------------------------------------------------------------------- + ! qsat must be > q_minus to activate evaporation + ! qsat must be < q_plus to activate accretion + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + ! rain evaporation + ! ----------------------------------------------------------------------- + + if (dqv > qvmin .and. qsat > q_minus) then + if (qsat > q_plus) then + dq = qsat - qpz + else + ! q_minus < qsat < q_plus + ! dq == dqh if qsat == q_minus + dq = 0.25 * (q_minus - qsat) ** 2 / dqh + endif + qden = qr (i) * den (i) + t2 = tin * tin + evap = crevp (1) * t2 * dq * (crevp (2) * sqrt (qden) + crevp (3) * exp (0.725 * log (qden))) & + / (crevp (4) * t2 + crevp (5) * qsat * den (i)) + evap = min (qr (i), dt * evap, dqv / (1. + lcp2 (i) * dqsdt)) + qr (i) = qr (i) - evap + qv (i) = qv (i) + evap + q_liq (i) = q_liq (i) - evap + cvm (i) = c_air + qv (i) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice + tz (i) = tz (i) - evap * lhl (i) / cvm (i) + endif + + ! ----------------------------------------------------------------------- + ! accretion: pracc + ! ----------------------------------------------------------------------- + + if (qr (i) > qrmin .and. ql (i) > 1.e-8 .and. qsat < q_plus) then + denfac (i) = sqrt (sfcrho / den (i)) + sink = dt * denfac (i) * cracw * exp (0.95 * log (qr (i) * den (i))) + sink = sink / (1. + sink) * ql (i) + ql (i) = ql (i) - sink + qr (i) = qr (i) + sink + endif + endif + enddo + +end subroutine revap_rac1 + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!>@brief The subroutine 'terminal_fall' computes terminal fall speed. +!>@details It considers cloud ice, snow, and graupel's melting during fall. +subroutine terminal_fall (dtm, ktop, kbot, tz, qv, ql, qr, qg, qs, qi, dz, dp, & + den, vtg, vts, vti, r1, g1, s1, i1, m1_sol, w1) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in) :: dtm ! time step (s) + + real, intent (in), dimension (ktop:kbot) :: vtg, vts, vti, den, dp, dz + + real, intent (inout), dimension (ktop:kbot) :: qv, ql, qr, qg, qs, qi, tz, m1_sol, w1 + + real, intent (out) :: r1, g1, s1, i1 + + real, dimension (ktop:kbot + 1) :: ze, zt + + real :: qsat, dqsdt, dt5, evap, dtime + real :: factor, frac + real :: tmp, precip, tc, sink + + real, dimension (ktop:kbot) :: lcpk, icpk, cvm, q_liq, q_sol, lhl, lhi + real, dimension (ktop:kbot) :: m1, dm + + real :: zs = 0. + real :: fac_imlt + + integer :: k, k0, m + + logical :: no_fall + + dt5 = 0.5 * dtm + fac_imlt = 1. - exp (- dt5 / tau_imlt) + + ! ----------------------------------------------------------------------- + ! define heat capacity and latend heat coefficient + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + m1_sol (k) = 0. + lhl (k) = lv00 + d0_vap * tz (k) + lhi (k) = li00 + dc_ice * tz (k) + q_liq (k) = ql (k) + qr (k) + q_sol (k) = qi (k) + qs (k) + qg (k) + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + lcpk (k) = lhl (k) / cvm (k) + icpk (k) = lhi (k) / cvm (k) + enddo + + ! ----------------------------------------------------------------------- + ! find significant melting level + ! ----------------------------------------------------------------------- + + k0 = kbot + do k = ktop, kbot - 1 + if (tz (k) > tice) then + k0 = k + exit + endif + enddo + + ! ----------------------------------------------------------------------- + ! melting of cloud_ice (before fall) : + ! ----------------------------------------------------------------------- + + do k = k0, kbot + tc = tz (k) - tice + if (qi (k) > qcmin .and. tc > 0.) then + sink = min (qi (k), fac_imlt * tc / icpk (k)) + tmp = min (sink, dim (ql_mlt, ql (k))) + ql (k) = ql (k) + tmp + qr (k) = qr (k) + sink - tmp + qi (k) = qi (k) - sink + q_liq (k) = q_liq (k) + sink + q_sol (k) = q_sol (k) - sink + cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + tz (k) = tz (k) - sink * lhi (k) / cvm (k) + tc = tz (k) - tice + endif + enddo + + ! ----------------------------------------------------------------------- + ! turn off melting when cloud microphysics time step is small + ! ----------------------------------------------------------------------- + + if (dtm < 60.) k0 = kbot + + ! sjl, turn off melting of falling cloud ice, snow and graupel + k0 = kbot + ! sjl, turn off melting of falling cloud ice, snow and graupel + + ze (kbot + 1) = zs + do k = kbot, ktop, - 1 + ze (k) = ze (k + 1) - dz (k) ! dz < 0 + enddo + + zt (ktop) = ze (ktop) + + ! ----------------------------------------------------------------------- + ! update capacity heat and latend heat coefficient + ! ----------------------------------------------------------------------- + + do k = k0, kbot + lhi (k) = li00 + dc_ice * tz (k) + icpk (k) = lhi (k) / cvm (k) + enddo + + ! ----------------------------------------------------------------------- + ! melting of falling cloud ice into rain + ! ----------------------------------------------------------------------- + + call check_column (ktop, kbot, qi, no_fall) + + if (vi_fac < 1.e-5 .or. no_fall) then + i1 = 0. + else + + do k = ktop + 1, kbot + zt (k) = ze (k) - dt5 * (vti (k - 1) + vti (k)) + enddo + zt (kbot + 1) = zs - dtm * vti (kbot) + + do k = ktop, kbot + if (zt (k + 1) >= zt (k)) zt (k + 1) = zt (k) - dz_min + enddo + + if (k0 < kbot) then + do k = kbot - 1, k0, - 1 + if (qi (k) > qrmin) then + do m = k + 1, kbot + if (zt (k + 1) >= ze (m)) exit + if (zt (k) < ze (m + 1) .and. tz (m) > tice) then + dtime = min (1.0, (ze (m) - ze (m + 1)) / (max (vr_min, vti (k)) * tau_imlt)) + sink = min (qi (k) * dp (k) / dp (m), dtime * (tz (m) - tice) / icpk (m)) + tmp = min (sink, dim (ql_mlt, ql (m))) + ql (m) = ql (m) + tmp + qr (m) = qr (m) - tmp + sink + tz (m) = tz (m) - sink * icpk (m) + qi (k) = qi (k) - sink * dp (m) / dp (k) + endif + enddo + endif + enddo + endif + + if (do_sedi_w) then + do k = ktop, kbot + dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) + enddo + endif + + if (use_ppm) then + call lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, qi, i1, m1_sol, mono_prof) + else + call implicit_fall (dtm, ktop, kbot, ze, vti, dp, qi, i1, m1_sol) + endif + + if (do_sedi_w) then + w1 (ktop) = (dm (ktop) * w1 (ktop) + m1_sol (ktop) * vti (ktop)) / (dm (ktop) - m1_sol (ktop)) + do k = ktop + 1, kbot + w1 (k) = (dm (k) * w1 (k) - m1_sol (k - 1) * vti (k - 1) + m1_sol (k) * vti (k)) & + / (dm (k) + m1_sol (k - 1) - m1_sol (k)) + enddo + endif + + endif + + ! ----------------------------------------------------------------------- + ! melting of falling snow into rain + ! ----------------------------------------------------------------------- + + r1 = 0. + + call check_column (ktop, kbot, qs, no_fall) + + if (no_fall) then + s1 = 0. + else + + do k = ktop + 1, kbot + zt (k) = ze (k) - dt5 * (vts (k - 1) + vts (k)) + enddo + zt (kbot + 1) = zs - dtm * vts (kbot) + + do k = ktop, kbot + if (zt (k + 1) >= zt (k)) zt (k + 1) = zt (k) - dz_min + enddo + + if (k0 < kbot) then + do k = kbot - 1, k0, - 1 + if (qs (k) > qrmin) then + do m = k + 1, kbot + if (zt (k + 1) >= ze (m)) exit + dtime = min (dtm, (ze (m) - ze (m + 1)) / (vr_min + vts (k))) + if (zt (k) < ze (m + 1) .and. tz (m) > tice) then + dtime = min (1.0, dtime / tau_smlt) + sink = min (qs (k) * dp (k) / dp (m), dtime * (tz (m) - tice) / icpk (m)) + tz (m) = tz (m) - sink * icpk (m) + qs (k) = qs (k) - sink * dp (m) / dp (k) + if (zt (k) < zs) then + r1 = r1 + sink * dp (m) ! precip as rain + else + ! qr source here will fall next time step (therefore, can evap) + qr (m) = qr (m) + sink + endif + endif + if (qs (k) < qrmin) exit + enddo + endif + enddo + endif + + if (do_sedi_w) then + do k = ktop, kbot + dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) + enddo + endif + + if (use_ppm) then + call lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, qs, s1, m1, mono_prof) + else + call implicit_fall (dtm, ktop, kbot, ze, vts, dp, qs, s1, m1) + endif + + do k = ktop, kbot + m1_sol (k) = m1_sol (k) + m1 (k) + enddo + + if (do_sedi_w) then + w1 (ktop) = (dm (ktop) * w1 (ktop) + m1 (ktop) * vts (ktop)) / (dm (ktop) - m1 (ktop)) + do k = ktop + 1, kbot + w1 (k) = (dm (k) * w1 (k) - m1 (k - 1) * vts (k - 1) + m1 (k) * vts (k)) & + / (dm (k) + m1 (k - 1) - m1 (k)) + enddo + endif + + endif + + ! ---------------------------------------------- + ! melting of falling graupel into rain + ! ---------------------------------------------- + + call check_column (ktop, kbot, qg, no_fall) + + if (no_fall) then + g1 = 0. + else + + do k = ktop + 1, kbot + zt (k) = ze (k) - dt5 * (vtg (k - 1) + vtg (k)) + enddo + zt (kbot + 1) = zs - dtm * vtg (kbot) + + do k = ktop, kbot + if (zt (k + 1) >= zt (k)) zt (k + 1) = zt (k) - dz_min + enddo + + if (k0 < kbot) then + do k = kbot - 1, k0, - 1 + if (qg (k) > qrmin) then + do m = k + 1, kbot + if (zt (k + 1) >= ze (m)) exit + dtime = min (dtm, (ze (m) - ze (m + 1)) / vtg (k)) + if (zt (k) < ze (m + 1) .and. tz (m) > tice) then + dtime = min (1., dtime / tau_g2r) + sink = min (qg (k) * dp (k) / dp (m), dtime * (tz (m) - tice) / icpk (m)) + tz (m) = tz (m) - sink * icpk (m) + qg (k) = qg (k) - sink * dp (m) / dp (k) + if (zt (k) < zs) then + r1 = r1 + sink * dp (m) + else + qr (m) = qr (m) + sink + endif + endif + if (qg (k) < qrmin) exit + enddo + endif + enddo + endif + + if (do_sedi_w) then + do k = ktop, kbot + dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) + enddo + endif + + if (use_ppm) then + call lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, qg, g1, m1, mono_prof) + else + call implicit_fall (dtm, ktop, kbot, ze, vtg, dp, qg, g1, m1) + endif + + do k = ktop, kbot + m1_sol (k) = m1_sol (k) + m1 (k) + enddo + + if (do_sedi_w) then + w1 (ktop) = (dm (ktop) * w1 (ktop) + m1 (ktop) * vtg (ktop)) / (dm (ktop) - m1 (ktop)) + do k = ktop + 1, kbot + w1 (k) = (dm (k) * w1 (k) - m1 (k - 1) * vtg (k - 1) + m1 (k) * vtg (k)) & + / (dm (k) + m1 (k - 1) - m1 (k)) + enddo + endif + + endif + +end subroutine terminal_fall + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!>@brief The subroutine 'check_column' checks +!! if the water species is large enough to fall. +subroutine check_column (ktop, kbot, q, no_fall) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in) :: q (ktop:kbot) + + logical, intent (out) :: no_fall + + integer :: k + + no_fall = .true. + + do k = ktop, kbot + if (q (k) > qrmin) then + no_fall = .false. + exit + endif + enddo + +end subroutine check_column + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!>@brief The subroutine computes the time-implicit monotonic +!! fall scheme. +!>@author Shian-Jiann Lin, 2016 +subroutine implicit_fall (dt, ktop, kbot, ze, vt, dp, q, precip, m1) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in) :: dt + + real, intent (in), dimension (ktop:kbot + 1) :: ze + + real, intent (in), dimension (ktop:kbot) :: vt, dp + + real, intent (inout), dimension (ktop:kbot) :: q + + real, intent (out), dimension (ktop:kbot) :: m1 + + real, intent (out) :: precip + + real, dimension (ktop:kbot) :: dz, qm, dd + + integer :: k + + do k = ktop, kbot + dz (k) = ze (k) - ze (k + 1) + dd (k) = dt * vt (k) + q (k) = q (k) * dp (k) + enddo + + ! ----------------------------------------------------------------------- + ! sedimentation: non - vectorizable loop + ! ----------------------------------------------------------------------- + + qm (ktop) = q (ktop) / (dz (ktop) + dd (ktop)) + do k = ktop + 1, kbot + qm (k) = (q (k) + dd (k - 1) * qm (k - 1)) / (dz (k) + dd (k)) + enddo + + ! ----------------------------------------------------------------------- + ! qm is density at this stage + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + qm (k) = qm (k) * dz (k) + enddo + + ! ----------------------------------------------------------------------- + ! output mass fluxes: non - vectorizable loop + ! ----------------------------------------------------------------------- + + m1 (ktop) = q (ktop) - qm (ktop) + do k = ktop + 1, kbot + m1 (k) = m1 (k - 1) + q (k) - qm (k) + enddo + precip = m1 (kbot) + + ! ----------------------------------------------------------------------- + ! update: + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + q (k) = qm (k) / dp (k) + enddo + +end subroutine implicit_fall + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! Lagrangian scheme +!> \author S.J. Lin +subroutine lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, q, precip, m1, mono) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in) :: zs + + logical, intent (in) :: mono + + real, intent (in), dimension (ktop:kbot + 1) :: ze, zt + + real, intent (in), dimension (ktop:kbot) :: dp + + ! m1: flux + real, intent (inout), dimension (ktop:kbot) :: q, m1 + + real, intent (out) :: precip + + real, dimension (ktop:kbot) :: qm, dz + + real :: a4 (4, ktop:kbot) + + real :: pl, pr, delz, esl + + integer :: k, k0, n, m + + real, parameter :: r3 = 1. / 3., r23 = 2. / 3. + + ! ----------------------------------------------------------------------- + ! density: + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + dz (k) = zt (k) - zt (k + 1) ! note: dz is positive + q (k) = q (k) * dp (k) + a4 (1, k) = q (k) / dz (k) + qm (k) = 0. + enddo + + ! ----------------------------------------------------------------------- + ! construct vertical profile with zt as coordinate + ! ----------------------------------------------------------------------- + + call cs_profile (a4 (1, ktop), dz (ktop), kbot - ktop + 1, mono) + + k0 = ktop + do k = ktop, kbot + do n = k0, kbot + if (ze (k) <= zt (n) .and. ze (k) >= zt (n + 1)) then + pl = (zt (n) - ze (k)) / dz (n) + if (zt (n + 1) <= ze (k + 1)) then + ! entire new grid is within the original grid + pr = (zt (n) - ze (k + 1)) / dz (n) + qm (k) = a4 (2, n) + 0.5 * (a4 (4, n) + a4 (3, n) - a4 (2, n)) * (pr + pl) - & + a4 (4, n) * r3 * (pr * (pr + pl) + pl ** 2) + qm (k) = qm (k) * (ze (k) - ze (k + 1)) + k0 = n + goto 555 + else + qm (k) = (ze (k) - zt (n + 1)) * (a4 (2, n) + 0.5 * (a4 (4, n) + & + a4 (3, n) - a4 (2, n)) * (1. + pl) - a4 (4, n) * (r3 * (1. + pl * (1. + pl)))) + if (n < kbot) then + do m = n + 1, kbot + ! locate the bottom edge: ze (k + 1) + if (ze (k + 1) < zt (m + 1)) then + qm (k) = qm (k) + q (m) + else + delz = zt (m) - ze (k + 1) + esl = delz / dz (m) + qm (k) = qm (k) + delz * (a4 (2, m) + 0.5 * esl * & + (a4 (3, m) - a4 (2, m) + a4 (4, m) * (1. - r23 * esl))) + k0 = m + goto 555 + endif + enddo + endif + goto 555 + endif + endif + enddo + 555 continue + enddo + + m1 (ktop) = q (ktop) - qm (ktop) + do k = ktop + 1, kbot + m1 (k) = m1 (k - 1) + q (k) - qm (k) + enddo + precip = m1 (kbot) + + ! convert back to * dry * mixing ratio: + ! dp must be dry air_mass (because moist air mass will be changed due to terminal fall) . + + do k = ktop, kbot + q (k) = qm (k) / dp (k) + enddo + +end subroutine lagrangian_fall_ppm + +!>\ingroup mod_gfdl_cloud_mp +subroutine cs_profile (a4, del, km, do_mono) + + implicit none + + integer, intent (in) :: km ! vertical dimension + + real, intent (in) :: del (km) + + logical, intent (in) :: do_mono + + real, intent (inout) :: a4 (4, km) + + real, parameter :: qp_min = 1.e-6 + + real :: gam (km) + real :: q (km + 1) + real :: d4, bet, a_bot, grat, pmp, lac + real :: pmp_1, lac_1, pmp_2, lac_2 + real :: da1, da2, a6da + + integer :: k + + logical extm (km) + + grat = del (2) / del (1) ! grid ratio + bet = grat * (grat + 0.5) + q (1) = (2. * grat * (grat + 1.) * a4 (1, 1) + a4 (1, 2)) / bet + gam (1) = (1. + grat * (grat + 1.5)) / bet + + do k = 2, km + d4 = del (k - 1) / del (k) + bet = 2. + 2. * d4 - gam (k - 1) + q (k) = (3. * (a4 (1, k - 1) + d4 * a4 (1, k)) - q (k - 1)) / bet + gam (k) = d4 / bet + enddo + + a_bot = 1. + d4 * (d4 + 1.5) + q (km + 1) = (2. * d4 * (d4 + 1.) * a4 (1, km) + a4 (1, km - 1) - a_bot * q (km)) & + / (d4 * (d4 + 0.5) - a_bot * gam (km)) + + do k = km, 1, - 1 + q (k) = q (k) - gam (k) * q (k + 1) + enddo + + ! ----------------------------------------------------------------------- + ! apply constraints + ! ----------------------------------------------------------------------- + + do k = 2, km + gam (k) = a4 (1, k) - a4 (1, k - 1) + enddo + + ! ----------------------------------------------------------------------- + ! apply large - scale constraints to all fields if not local max / min + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + ! top: + ! ----------------------------------------------------------------------- + + q (1) = max (q (1), 0.) + q (2) = min (q (2), max (a4 (1, 1), a4 (1, 2))) + q (2) = max (q (2), min (a4 (1, 1), a4 (1, 2)), 0.) + + ! ----------------------------------------------------------------------- + ! interior: + ! ----------------------------------------------------------------------- + + do k = 3, km - 1 + if (gam (k - 1) * gam (k + 1) > 0.) then + q (k) = min (q (k), max (a4 (1, k - 1), a4 (1, k))) + q (k) = max (q (k), min (a4 (1, k - 1), a4 (1, k))) + else + if (gam (k - 1) > 0.) then + ! there exists a local max + q (k) = max (q (k), min (a4 (1, k - 1), a4 (1, k))) + else + ! there exists a local min + q (k) = min (q (k), max (a4 (1, k - 1), a4 (1, k))) + q (k) = max (q (k), 0.0) + endif + endif + enddo + + ! ----------------------------------------------------------------------- + ! bottom : + ! ----------------------------------------------------------------------- + + q (km) = min (q (km), max (a4 (1, km - 1), a4 (1, km))) + q (km) = max (q (km), min (a4 (1, km - 1), a4 (1, km)), 0.) + ! q (km + 1) = max (q (km + 1), 0.) + + ! ----------------------------------------------------------------------- + ! f (s) = al + s * [ (ar - al) + a6 * (1 - s) ] (0 <= s <= 1) + ! ----------------------------------------------------------------------- + + do k = 1, km - 1 + a4 (2, k) = q (k) + a4 (3, k) = q (k + 1) + enddo + + do k = 2, km - 1 + if (gam (k) * gam (k + 1) > 0.0) then + extm (k) = .false. + else + extm (k) = .true. + endif + enddo + + if (do_mono) then + do k = 3, km - 2 + if (extm (k)) then + ! positive definite constraint only if true local extrema + if (a4 (1, k) < qp_min .or. extm (k - 1) .or. extm (k + 1)) then + a4 (2, k) = a4 (1, k) + a4 (3, k) = a4 (1, k) + endif + else + a4 (4, k) = 6. * a4 (1, k) - 3. * (a4 (2, k) + a4 (3, k)) + if (abs (a4 (4, k)) > abs (a4 (2, k) - a4 (3, k))) then + ! check within the smooth region if subgrid profile is non - monotonic + pmp_1 = a4 (1, k) - 2.0 * gam (k + 1) + lac_1 = pmp_1 + 1.5 * gam (k + 2) + a4 (2, k) = min (max (a4 (2, k), min (a4 (1, k), pmp_1, lac_1)), & + max (a4 (1, k), pmp_1, lac_1)) + pmp_2 = a4 (1, k) + 2.0 * gam (k) + lac_2 = pmp_2 - 1.5 * gam (k - 1) + a4 (3, k) = min (max (a4 (3, k), min (a4 (1, k), pmp_2, lac_2)), & + max (a4 (1, k), pmp_2, lac_2)) + endif + endif + enddo + else + do k = 3, km - 2 + if (extm (k)) then + if (a4 (1, k) < qp_min .or. extm (k - 1) .or. extm (k + 1)) then + a4 (2, k) = a4 (1, k) + a4 (3, k) = a4 (1, k) + endif + endif + enddo + endif + + do k = 1, km - 1 + a4 (4, k) = 6. * a4 (1, k) - 3. * (a4 (2, k) + a4 (3, k)) + enddo + + k = km - 1 + if (extm (k)) then + a4 (2, k) = a4 (1, k) + a4 (3, k) = a4 (1, k) + a4 (4, k) = 0. + else + da1 = a4 (3, k) - a4 (2, k) + da2 = da1 ** 2 + a6da = a4 (4, k) * da1 + if (a6da < - da2) then + a4 (4, k) = 3. * (a4 (2, k) - a4 (1, k)) + a4 (3, k) = a4 (2, k) - a4 (4, k) + elseif (a6da > da2) then + a4 (4, k) = 3. * (a4 (3, k) - a4 (1, k)) + a4 (2, k) = a4 (3, k) - a4 (4, k) + endif + endif + + call cs_limiters (km - 1, a4) + + ! ----------------------------------------------------------------------- + ! bottom layer: + ! ----------------------------------------------------------------------- + + a4 (2, km) = a4 (1, km) + a4 (3, km) = a4 (1, km) + a4 (4, km) = 0. + +end subroutine cs_profile + +!>\ingroup mod_gfdl_cloud_mp +!! This subroutine perform positive definite constraint. +subroutine cs_limiters (km, a4) + + implicit none + + integer, intent (in) :: km + + real, intent (inout) :: a4 (4, km) ! ppm array + + real, parameter :: r12 = 1. / 12. + + integer :: k + + ! ----------------------------------------------------------------------- + ! positive definite constraint + ! ----------------------------------------------------------------------- + + do k = 1, km + if (abs (a4 (3, k) - a4 (2, k)) < - a4 (4, k)) then + if ((a4 (1, k) + 0.25 * (a4 (3, k) - a4 (2, k)) ** 2 / a4 (4, k) + a4 (4, k) * r12) < 0.) then + if (a4 (1, k) < a4 (3, k) .and. a4 (1, k) < a4 (2, k)) then + a4 (3, k) = a4 (1, k) + a4 (2, k) = a4 (1, k) + a4 (4, k) = 0. + elseif (a4 (3, k) > a4 (2, k)) then + a4 (4, k) = 3. * (a4 (2, k) - a4 (1, k)) + a4 (3, k) = a4 (2, k) - a4 (4, k) + else + a4 (4, k) = 3. * (a4 (3, k) - a4 (1, k)) + a4 (2, k) = a4 (3, k) - a4 (4, k) + endif + endif + endif + enddo + +end subroutine cs_limiters + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine calculates vertical fall speed of snow/ice/graupel. +subroutine fall_speed (ktop, kbot, den, qs, qi, qg, ql, tk, vts, vti, vtg) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in), dimension (ktop:kbot) :: den, qs, qi, qg, ql, tk + real, intent (out), dimension (ktop:kbot) :: vts, vti, vtg + + ! fall velocity constants: + + real, parameter :: thi = 1.0e-8 !< cloud ice threshold for terminal fall + real, parameter :: thg = 1.0e-8 + real, parameter :: ths = 1.0e-8 + + ! coefficient for the parameterization of mass weighted fall velocity + ! as a function of temperature and IWC. + ! Table 1 in Deng and Mace (2008) \cite deng_and_mace_2008. + real, parameter :: aa = - 4.14122e-5 + real, parameter :: bb = - 0.00538922 + real, parameter :: cc = - 0.0516344 + real, parameter :: dd = 0.00216078 + real, parameter :: ee = 1.9714 + + ! marshall - palmer constants + + real, parameter :: vcons = 6.6280504 + real, parameter :: vcong = 87.2382675 + real, parameter :: vconh = vcong * sqrt (rhoh / rhog) + real, parameter :: norms = 942477796.076938 + real, parameter :: normg = 5026548245.74367 + real, parameter :: normh = pi * rhoh * rnzh + + real, dimension (ktop:kbot) :: qden, tc, rhof + + real :: vi0 + + integer :: k + + ! ----------------------------------------------------------------------- + ! marshall - palmer formula + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + ! try the local air density -- for global model; the true value could be + ! much smaller than sfcrho over high mountains + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + rhof (k) = sqrt (min (10., sfcrho / den (k))) + enddo + + ! ----------------------------------------------------------------------- + !> - ice: use Deng and Mace (2008) \cite deng_and_mace_2008, which gives smaler + !! fall speed than Heymsfield and Donner (1990) \cite heymsfield_and_donner_1990. + ! ----------------------------------------------------------------------- + + if (const_vi) then + vti (:) = vi_fac + else + ! ----------------------------------------------------------------------- + ! use deng and mace (2008, grl), which gives smaller fall speed than hd90 formula + ! ----------------------------------------------------------------------- + vi0 = 0.01 * vi_fac + do k = ktop, kbot + if (qi (k) < thi) then ! this is needed as the fall - speed maybe problematic for small qi + vti (k) = vf_min + else + tc (k) = tk (k) - tice + vti (k) = (3. + log10 (qi (k) * den (k))) * (tc (k) * (aa * tc (k) + bb) + cc) + dd * tc (k) + ee + vti (k) = vi0 * exp (log_10 * vti (k)) * 0.9 + vti (k) = min (vi_max, max (vf_min, vti (k))) + endif + enddo + endif + + ! ----------------------------------------------------------------------- + !> - snow: + ! ----------------------------------------------------------------------- + + if (const_vs) then + vts (:) = vs_fac ! 1. ifs_2016 + else + do k = ktop, kbot + if (qs (k) < ths) then + vts (k) = vf_min + else + vts (k) = vs_fac * vcons * rhof (k) * exp (0.0625 * log (qs (k) * den (k) / norms)) + vts (k) = min (vs_max, max (vf_min, vts (k))) + endif + enddo + endif + + ! ----------------------------------------------------------------------- + !> - graupel: + ! ----------------------------------------------------------------------- + if (const_vg) then + vtg (:) = vg_fac ! 2. + else + if (do_hail) then + do k = ktop, kbot + if (qg (k) < thg) then + vtg (k) = vf_min + else + vtg (k) = vg_fac * vconh * rhof (k) * sqrt (sqrt (sqrt (qg (k) * den (k) / normh))) + vtg (k) = min (vg_max, max (vf_min, vtg (k))) + endif + enddo + else + do k = ktop, kbot + if (qg (k) < thg) then + vtg (k) = vf_min + else + vtg (k) = vg_fac * vcong * rhof (k) * sqrt (sqrt (sqrt (qg (k) * den (k) / normg))) + vtg (k) = min (vg_max, max (vf_min, vtg (k))) + endif + enddo + endif + endif + +end subroutine fall_speed + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine sets up gfdl cloud microphysics parameters. +subroutine setupm + + implicit none + + real :: gcon, cd, scm3, pisq, act (8) + real :: vdifu, tcond + real :: visk + real :: ch2o, hltf + real :: hlts, hltc, ri50 + + real, parameter :: gam263 = 1.456943, gam275 = 1.608355, gam290 = 1.827363, & + gam325 = 2.54925, gam350 = 3.323363, gam380 = 4.694155, & + gam425 = 8.285063, gam450 = 11.631769, gam480 = 17.837789, & + gam625 = 184.860962, gam680 = 496.604067 + + ! intercept parameters + +! real, parameter :: rnzr = 8.0e6 ! lin83 +! real, parameter :: rnzs = 3.0e6 ! lin83 +! real, parameter :: rnzg = 4.0e6 ! rh84 + + ! density parameters + +! real, parameter :: rhos = 0.1e3 !< lin83 (snow density; 1 / 10 of water) +! real, parameter :: rhog = 0.4e3 !< rh84 (graupel density) + real, parameter :: acc (3) = (/ 5.0, 2.0, 0.5 /) + + real den_rc + + integer :: i, k + + pie = 4. * atan (1.0) + + ! s. klein's formular (eq 16) from am2 + + fac_rc = (4. / 3.) * pie * rhor * rthresh ** 3 + + if (prog_ccn) then + ! if (master) write (*, *) 'prog_ccn option is .t.' + else + den_rc = fac_rc * ccn_o * 1.e6 + ! if (master) write (*, *) 'mp: for ccn_o = ', ccn_o, 'ql_rc = ', den_rc + den_rc = fac_rc * ccn_l * 1.e6 + ! if (master) write (*, *) 'mp: for ccn_l = ', ccn_l, 'ql_rc = ', den_rc + endif + + vdifu = 2.11e-5 + tcond = 2.36e-2 + + visk = 1.259e-5 + hlts = 2.8336e6 + hltc = 2.5e6 + hltf = 3.336e5 + + ch2o = 4.1855e3 + ri50 = 1.e-4 + + pisq = pie * pie + scm3 = (visk / vdifu) ** (1. / 3.) + + cracs = pisq * rnzr * rnzs * rhos + csacr = pisq * rnzr * rnzs * rhor + if (do_hail) then + cgacr = pisq * rnzr * rnzh * rhor + cgacs = pisq * rnzh * rnzs * rhos + else + cgacr = pisq * rnzr * rnzg * rhor + cgacs = pisq * rnzg * rnzs * rhos + endif + cgacs = cgacs * c_pgacs + + ! act: 1 - 2:racs (s - r) ; 3 - 4:sacr (r - s) ; + ! 5 - 6:gacr (r - g) ; 7 - 8:gacs (s - g) + + act (1) = pie * rnzs * rhos + act (2) = pie * rnzr * rhor + if (do_hail) then + act (6) = pie * rnzh * rhoh + else + act (6) = pie * rnzg * rhog + endif + act (3) = act (2) + act (4) = act (1) + act (5) = act (2) + act (7) = act (1) + act (8) = act (6) + + do i = 1, 3 + do k = 1, 4 + acco (i, k) = acc (i) / (act (2 * k - 1) ** ((7 - i) * 0.25) * act (2 * k) ** (i * 0.25)) + enddo + enddo + + gcon = 40.74 * sqrt (sfcrho) ! 44.628 + + csacw = pie * rnzs * clin * gam325 / (4. * act (1) ** 0.8125) + ! decreasing csacw to reduce cloud water --- > snow + + craci = pie * rnzr * alin * gam380 / (4. * act (2) ** 0.95) + csaci = csacw * c_psaci + + if (do_hail) then + cgacw = pie * rnzh * gam350 * gcon / (4. * act (6) ** 0.875) + else + cgacw = pie * rnzg * gam350 * gcon / (4. * act (6) ** 0.875) + endif + ! cgaci = cgacw * 0.1 + + ! sjl, may 28, 2012 + cgaci = cgacw * 0.05 + ! sjl, may 28, 2012 + + cracw = craci ! cracw = 3.27206196043822 + cracw = c_cracw * cracw + + ! subl and revp: five constants for three separate processes + + cssub (1) = 2. * pie * vdifu * tcond * rvgas * rnzs + if (do_hail) then + cgsub (1) = 2. * pie * vdifu * tcond * rvgas * rnzh + else + cgsub (1) = 2. * pie * vdifu * tcond * rvgas * rnzg + endif + crevp (1) = 2. * pie * vdifu * tcond * rvgas * rnzr + cssub (2) = 0.78 / sqrt (act (1)) + cgsub (2) = 0.78 / sqrt (act (6)) + crevp (2) = 0.78 / sqrt (act (2)) + cssub (3) = 0.31 * scm3 * gam263 * sqrt (clin / visk) / act (1) ** 0.65625 + cgsub (3) = 0.31 * scm3 * gam275 * sqrt (gcon / visk) / act (6) ** 0.6875 + crevp (3) = 0.31 * scm3 * gam290 * sqrt (alin / visk) / act (2) ** 0.725 + cssub (4) = tcond * rvgas + cssub (5) = hlts ** 2 * vdifu + cgsub (4) = cssub (4) + crevp (4) = cssub (4) + cgsub (5) = cssub (5) + crevp (5) = hltc ** 2 * vdifu + + cgfr (1) = 20.e2 * pisq * rnzr * rhor / act (2) ** 1.75 + cgfr (2) = 0.66 + + ! smlt: five constants (lin et al. 1983) + + csmlt (1) = 2. * pie * tcond * rnzs / hltf + csmlt (2) = 2. * pie * vdifu * rnzs * hltc / hltf + csmlt (3) = cssub (2) + csmlt (4) = cssub (3) + csmlt (5) = ch2o / hltf + + ! gmlt: five constants + + if (do_hail) then + cgmlt (1) = 2. * pie * tcond * rnzh / hltf + cgmlt (2) = 2. * pie * vdifu * rnzh * hltc / hltf + else + cgmlt (1) = 2. * pie * tcond * rnzg / hltf + cgmlt (2) = 2. * pie * vdifu * rnzg * hltc / hltf + endif + cgmlt (3) = cgsub (2) + cgmlt (4) = cgsub (3) + cgmlt (5) = ch2o / hltf + + es0 = 6.107799961e2 ! ~6.1 mb + ces0 = eps * es0 + +end subroutine setupm + +! ======================================================================= +! initialization of gfdl cloud microphysics +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine 'gfdl_cloud_microphys_init' initializes the GFDL +!! cloud microphysics. +subroutine gfdl_cloud_microphys_mod_init (me, master, nlunit, input_nml_file, logunit, & + fn_nml, errmsg, errflg) + + implicit none + + integer, intent (in) :: me + integer, intent (in) :: master + integer, intent (in) :: nlunit + integer, intent (in) :: logunit + + character (len = 64), intent (in) :: fn_nml + character (len = *), intent (in) :: input_nml_file(:) + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + integer :: ios + logical :: exists + + ! integer, intent (in) :: id, jd, kd + ! integer, intent (in) :: axes (4) + ! type (time_type), intent (in) :: time + + ! integer :: unit, io, ierr, k, logunit + ! logical :: flag + ! real :: tmp, q1, q2 + + ! master = (mpp_pe () .eq.mpp_root_pe ()) + + ! Initialize CCPP error-handling + errflg = 0 + errmsg = '' + +#ifdef INTERNAL_FILE_NML + read (input_nml_file, nml = gfdl_cloud_microphysics_nml) +#else + inquire (file = trim (fn_nml), exist = exists) + if (.not. exists) then + write (6, *) 'gfdl - mp :: namelist file: ', trim (fn_nml), ' does not exist' + errflg = 1 + errmsg = 'ERROR(gfdl_cloud_microphys_mod_init): namelist file '//trim (fn_nml)//' does not exist' + return + else + open (unit = nlunit, file = fn_nml, action = 'read' , status = 'old', iostat = ios) + endif + rewind (nlunit) + read (nlunit, nml = gfdl_cloud_microphysics_nml) + close (nlunit) +#endif + + ! write version number and namelist to log file + if (me == master) then + write (logunit, *) " ================================================================== " + write (logunit, *) "gfdl_cloud_microphys_mod" + write (logunit, nml = gfdl_cloud_microphysics_nml) + endif + + if (do_setup) then + call setup_con + call setupm + do_setup = .false. + endif + + log_10 = log (10.) + + tice0 = tice - 0.01 + t_wfr = tice - 40.0 ! supercooled water can exist down to - 48 c, which is the "absolute" + + ! if (master) write (logunit, nml = gfdl_cloud_microphys_nml) + ! + ! id_vtr = register_diag_field (mod_name, 'vt_r', axes (1:3), time, & + ! 'rain fall speed', 'm / s', missing_value = missing_value) + ! id_vts = register_diag_field (mod_name, 'vt_s', axes (1:3), time, & + ! 'snow fall speed', 'm / s', missing_value = missing_value) + ! id_vtg = register_diag_field (mod_name, 'vt_g', axes (1:3), time, & + ! 'graupel fall speed', 'm / s', missing_value = missing_value) + ! id_vti = register_diag_field (mod_name, 'vt_i', axes (1:3), time, & + ! 'ice fall speed', 'm / s', missing_value = missing_value) + + ! id_droplets = register_diag_field (mod_name, 'droplets', axes (1:3), time, & + ! 'droplet number concentration', '# / m3', missing_value = missing_value) + ! id_rh = register_diag_field (mod_name, 'rh_lin', axes (1:2), time, & + ! 'relative humidity', 'n / a', missing_value = missing_value) + + ! id_rain = register_diag_field (mod_name, 'rain_lin', axes (1:2), time, & + ! 'rain_lin', 'mm / day', missing_value = missing_value) + ! id_snow = register_diag_field (mod_name, 'snow_lin', axes (1:2), time, & + ! 'snow_lin', 'mm / day', missing_value = missing_value) + ! id_graupel = register_diag_field (mod_name, 'graupel_lin', axes (1:2), time, & + ! 'graupel_lin', 'mm / day', missing_value = missing_value) + ! id_ice = register_diag_field (mod_name, 'ice_lin', axes (1:2), time, & + ! 'ice_lin', 'mm / day', missing_value = missing_value) + ! id_prec = register_diag_field (mod_name, 'prec_lin', axes (1:2), time, & + ! 'prec_lin', 'mm / day', missing_value = missing_value) + + ! if (master) write (*, *) 'prec_lin diagnostics initialized.', id_prec + + ! id_cond = register_diag_field (mod_name, 'cond_lin', axes (1:2), time, & + ! 'total condensate', 'kg / m ** 2', missing_value = missing_value) + ! id_var = register_diag_field (mod_name, 'var_lin', axes (1:2), time, & + ! 'subgrid variance', 'n / a', missing_value = missing_value) + + ! call qsmith_init + + ! testing the water vapor tables + + ! if (mp_debug .and. master) then + ! write (*, *) 'testing water vapor tables in gfdl_cloud_microphys' + ! tmp = tice - 90. + ! do k = 1, 25 + ! q1 = wqsat_moist (tmp, 0., 1.e5) + ! q2 = qs1d_m (tmp, 0., 1.e5) + ! write (*, *) nint (tmp - tice), q1, q2, 'dq = ', q1 - q2 + ! tmp = tmp + 5. + ! enddo + ! endif + + ! if (master) write (*, *) 'gfdl_cloud_micrphys diagnostics initialized.' + + module_is_initialized = .true. + +!+---+-----------------------------------------------------------------+ +!..Set these variables needed for computing radar reflectivity. These +!.. get used within radar_init to create other variables used in the +!.. radar module. + + xam_r = pi*rhor/6. + xbm_r = 3. + xmu_r = 0. + xam_s = pi*rhos/6. + xbm_s = 3. + xmu_s = 0. + xam_g = pi*rhog/6. + xbm_g = 3. + xmu_g = 0. + + call radar_init + +end subroutine gfdl_cloud_microphys_mod_init + +! ======================================================================= +! end of gfdl cloud microphysics +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine 'gfdl_cloud_microphys_init' terminates the GFDL +!! cloud microphysics. +subroutine gfdl_cloud_microphys_mod_end() + + implicit none + + deallocate (table) + deallocate (table2) + deallocate (table3) + deallocate (tablew) + deallocate (des) + deallocate (des2) + deallocate (des3) + deallocate (desw) + + tables_are_initialized = .false. + +end subroutine gfdl_cloud_microphys_mod_end + +! ======================================================================= +! qsmith table initialization +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine 'setup_con' sets up constants and calls 'qsmith_init'. +subroutine setup_con + + implicit none + + ! master = (mpp_pe () .eq.mpp_root_pe ()) + + rgrav = 1. / grav + + if (.not. qsmith_tables_initialized) call qsmith_init + + qsmith_tables_initialized = .true. + +end subroutine setup_con + +! ======================================================================= +!>\ingroup gfdlmp +!>@brief The function is an accretion function (Lin et al.(1983) +!! \cite lin_et_al_1983 ) +! ======================================================================= + +real function acr3d (v1, v2, q1, q2, c, cac, rho) + + implicit none + + real, intent (in) :: v1, v2, c, rho + real, intent (in) :: q1, q2 ! mixing ratio!!! + real, intent (in) :: cac (3) + + real :: t1, s1, s2 + + ! integer :: k + ! + ! real :: a + ! + ! a = 0.0 + ! do k = 1, 3 + ! a = a + cac (k) * ((q1 * rho) ** ((7 - k) * 0.25) * (q2 * rho) ** (k * 0.25)) + ! enddo + ! acr3d = c * abs (v1 - v2) * a / rho + + ! optimized + + t1 = sqrt (q1 * rho) + s1 = sqrt (q2 * rho) + s2 = sqrt (s1) ! s1 = s2 ** 2 + acr3d = c * abs (v1 - v2) * q1 * s2 * (cac (1) * t1 + cac (2) * sqrt (t1) * s2 + cac (3) * s1) + +end function acr3d + +! ======================================================================= +!>\ingroup gfdlmp +!>@brief Melting of snow function (Lin et al.(1983) \cite lin_et_al_1983) +!! note: psacw and psacr must be calc before smlt is called +! ======================================================================= + +real function smlt (tc, dqs, qsrho, psacw, psacr, c, rho, rhofac) + + implicit none + + real, intent (in) :: tc, dqs, qsrho, psacw, psacr, c (5), rho, rhofac + + smlt = (c (1) * tc / rho - c (2) * dqs) * (c (3) * sqrt (qsrho) + & + c (4) * qsrho ** 0.65625 * sqrt (rhofac)) + c (5) * tc * (psacw + psacr) + +end function smlt + +! ======================================================================= +!>@brief Melting of graupel function (Eq.(47) in Lin et al. 1983 \cite lin_et_al_1983) +!!\n note: \f$P_{gacw}\f$ and \f$P_{gacr}\f$ must be calculated before gmlt is called. +! ======================================================================= + +real function gmlt (tc, dqs, qgrho, pgacw, pgacr, c, rho) + + implicit none + + real, intent (in) :: tc, dqs, qgrho, pgacw, pgacr, c (5), rho + + gmlt = (c (1) * tc / rho - c (2) * dqs) * (c (3) * sqrt (qgrho) + & + c (4) * qgrho ** 0.6875 / rho ** 0.25) + c (5) * tc * (pgacw + pgacr) + +end function gmlt + +! ======================================================================= +! initialization +! prepare saturation water vapor pressure tables +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!>@brief The subroutine 'qsmith_init' initializes lookup tables for saturation +!! water vapor pressure for the following utility routines that are designed +!! to return qs consistent with the assumptions in FV3. +!>@details The calculations are highly accurate values based on the Clausius-Clapeyron +!! equation. +! ======================================================================= +subroutine qsmith_init + + implicit none + + integer, parameter :: length = 2621 + + integer :: i + + if (.not. tables_are_initialized) then + + ! master = (mpp_pe () .eq. mpp_root_pe ()) + ! if (master) print *, ' gfdl mp: initializing qs tables' + + ! debug code + ! print *, mpp_pe (), allocated (table), allocated (table2), & + ! allocated (table3), allocated (tablew), allocated (des), & + ! allocated (des2), allocated (des3), allocated (desw) + ! end debug code + + ! generate es table (dt = 0.1 deg. c) + + allocate (table (length)) + allocate (table2 (length)) + allocate (table3 (length)) + allocate (tablew (length)) + allocate (des (length)) + allocate (des2 (length)) + allocate (des3 (length)) + allocate (desw (length)) + + call qs_table (length) + call qs_table2 (length) + call qs_table3 (length) + call qs_tablew (length) + + do i = 1, length - 1 + des (i) = max (0., table (i + 1) - table (i)) + des2 (i) = max (0., table2 (i + 1) - table2 (i)) + des3 (i) = max (0., table3 (i + 1) - table3 (i)) + desw (i) = max (0., tablew (i + 1) - tablew (i)) + enddo + des (length) = des (length - 1) + des2 (length) = des2 (length - 1) + des3 (length) = des3 (length - 1) + desw (length) = desw (length - 1) + + tables_are_initialized = .true. + + endif + +end subroutine qsmith_init + +! ======================================================================= +! compute the saturated specific humidity for table ii +!>\ingroup mod_gfdl_cloud_mp +!>@brief The function 'wqs1' returns the saturation vapor pressure over pure +!! liquid water for a given temperature and air density. +real 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, intent (in) :: ta, den + + real :: es, ap1, tmin + + integer :: it + + tmin = table_ice - 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 + +! ======================================================================= +! compute the gradient of saturated specific humidity for table ii +!>@brief The function 'wqs2' returns the saturation vapor pressure over pure +!! liquid water for a given temperature and air density, as well as the +!! analytic dqs/dT: rate of change of saturation vapor pressure WRT temperature. +! ======================================================================= + +real 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, intent (in) :: ta, den + + real, intent (out) :: dqdt + + real :: es, ap1, tmin + + integer :: it + + tmin = table_ice - 160. + + if (.not. tables_are_initialized) call qsmith_init + + 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 + +! ======================================================================= +! compute wet buld temperature +!>@brief The function 'wet_bulb' uses 'wqs2' to compute the wet-bulb temperature +!! from the mixing ratio and the temperature. +! ======================================================================= + +real function wet_bulb (q, t, den) + + implicit none + + real, intent (in) :: t, q, den + + real :: qs, tp, dqdt + + wet_bulb = t + qs = wqs2 (wet_bulb, den, dqdt) + tp = 0.5 * (qs - q) / (1. + lcp * dqdt) * lcp + wet_bulb = wet_bulb - tp + + ! tp is negative if super - saturated + if (tp > 0.01) then + qs = wqs2 (wet_bulb, den, dqdt) + tp = (qs - q) / (1. + lcp * dqdt) * lcp + wet_bulb = wet_bulb - tp + endif + +end function wet_bulb + +! ======================================================================= +!>@brief The function 'iqs1' computes the saturated specific humidity +!! for table iii +! ======================================================================= + +real 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, intent (in) :: ta, den + + real :: es, ap1, tmin + + integer :: it + + tmin = table_ice - 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 + +! ======================================================================= +!>@brief The function 'iqs2' computes the gradient of saturated specific +!! humidity for table iii +! ======================================================================= + +real 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, intent (in) :: ta, den + + real, intent (out) :: dqdt + + real :: es, ap1, tmin + + integer :: it + + tmin = table_ice - 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 + dqdt = 10. * (des2 (it) + (ap1 - it) * (des2 (it + 1) - des2 (it))) / (rvgas * ta * den) + +end function iqs2 + +! ======================================================================= +!>@brief The function 'qs1d_moist' computes the gradient of saturated +!! specific humidity for table iii. +! ======================================================================= + +real function qs1d_moist (ta, qv, pa, dqdt) + + implicit none + + real, intent (in) :: ta, pa, qv + + real, intent (out) :: dqdt + + real :: es, ap1, tmin, eps10 + + integer :: it + + tmin = table_ice - 160. + eps10 = 10. * eps + ap1 = 10. * dim (ta, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es = table2 (it) + (ap1 - it) * des2 (it) + qs1d_moist = eps * es * (1. + zvir * qv) / pa + it = ap1 - 0.5 + dqdt = eps10 * (des2 (it) + (ap1 - it) * (des2 (it + 1) - des2 (it))) * (1. + zvir * qv) / pa + +end function qs1d_moist + +! ======================================================================= +! compute the gradient of saturated specific humidity for table ii +!>@brief The function 'wqsat2_moist' computes the saturated specific humidity +!! for pure liquid water , as well as des/dT. +! ======================================================================= + +real function wqsat2_moist (ta, qv, pa, dqdt) + + implicit none + + real, intent (in) :: ta, pa, qv + + real, intent (out) :: dqdt + + real :: es, ap1, tmin, eps10 + + integer :: it + + tmin = table_ice - 160. + eps10 = 10. * eps + ap1 = 10. * dim (ta, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es = tablew (it) + (ap1 - it) * desw (it) + wqsat2_moist = eps * es * (1. + zvir * qv) / pa + it = ap1 - 0.5 + dqdt = eps10 * (desw (it) + (ap1 - it) * (desw (it + 1) - desw (it))) * (1. + zvir * qv) / pa + +end function wqsat2_moist + +! ======================================================================= +! compute the saturated specific humidity for table ii +!>@brief The function 'wqsat_moist' computes the saturated specific humidity +!! for pure liquid water. +! ======================================================================= + +real function wqsat_moist (ta, qv, pa) + + implicit none + + real, intent (in) :: ta, pa, qv + + real :: es, ap1, tmin + + integer :: it + + tmin = table_ice - 160. + ap1 = 10. * dim (ta, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es = tablew (it) + (ap1 - it) * desw (it) + wqsat_moist = eps * es * (1. + zvir * qv) / pa + +end function wqsat_moist + +! ======================================================================= +!>@brief The function 'qs1d_m' computes the saturated specific humidity +!! for table iii +! ======================================================================= + +real function qs1d_m (ta, qv, pa) + + implicit none + + real, intent (in) :: ta, pa, qv + + real :: es, ap1, tmin + + integer :: it + + tmin = table_ice - 160. + ap1 = 10. * dim (ta, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es = table2 (it) + (ap1 - it) * des2 (it) + qs1d_m = eps * es * (1. + zvir * qv) / pa + +end function qs1d_m + +! ======================================================================= +!>@brief The function 'd_sat' computes the difference in saturation +!! vapor * density * between water and ice +! ======================================================================= + +real function d_sat (ta, den) + + implicit none + + real, intent (in) :: ta, den + + real :: es_w, es_i, ap1, tmin + + integer :: it + + tmin = table_ice - 160. + ap1 = 10. * dim (ta, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es_w = tablew (it) + (ap1 - it) * desw (it) + es_i = table2 (it) + (ap1 - it) * des2 (it) + d_sat = dim (es_w, es_i) / (rvgas * ta * den) ! take positive difference + +end function d_sat + +! ======================================================================= +!>@brief The function 'esw_table' computes the saturated water vapor +!! pressure for table ii +! ======================================================================= + +real function esw_table (ta) + + implicit none + + real, intent (in) :: ta + + real :: ap1, tmin + + integer :: it + + tmin = table_ice - 160. + ap1 = 10. * dim (ta, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + esw_table = tablew (it) + (ap1 - it) * desw (it) + +end function esw_table + +! ======================================================================= +!>@brief The function 'es2_table' computes the saturated water +!! vapor pressure for table iii +! ======================================================================= + +real function es2_table (ta) + + implicit none + + real, intent (in) :: ta + + real :: ap1, tmin + + integer :: it + + tmin = table_ice - 160. + ap1 = 10. * dim (ta, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es2_table = table2 (it) + (ap1 - it) * des2 (it) + +end function es2_table + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine 'esw_table1d' computes the saturated water vapor +!! pressure for table ii. +subroutine esw_table1d (ta, es, n) + + implicit none + + integer, intent (in) :: n + + real, intent (in) :: ta (n) + + real, intent (out) :: es (n) + + real :: ap1, tmin + + integer :: i, it + + tmin = table_ice - 160. + + do i = 1, n + ap1 = 10. * dim (ta (i), tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es (i) = tablew (it) + (ap1 - it) * desw (it) + enddo + +end subroutine esw_table1d + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine 'es3_table1d' computes the saturated water vapor +!! pressure for table iii. +subroutine es2_table1d (ta, es, n) + + implicit none + + integer, intent (in) :: n + + real, intent (in) :: ta (n) + + real, intent (out) :: es (n) + + real :: ap1, tmin + + integer :: i, it + + tmin = table_ice - 160. + + do i = 1, n + ap1 = 10. * dim (ta (i), tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es (i) = table2 (it) + (ap1 - it) * des2 (it) + enddo + +end subroutine es2_table1d + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine 'es3_table1d' computes the saturated water vapor +!! pressure for table iv. +subroutine es3_table1d (ta, es, n) + + implicit none + + integer, intent (in) :: n + + real, intent (in) :: ta (n) + + real, intent (out) :: es (n) + + real :: ap1, tmin + + integer :: i, it + + tmin = table_ice - 160. + + do i = 1, n + ap1 = 10. * dim (ta (i), tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es (i) = table3 (it) + (ap1 - it) * des3 (it) + enddo + +end subroutine es3_table1d + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! saturation water vapor pressure table ii +! 1 - phase table +subroutine qs_tablew (n) + + implicit none + + integer, intent (in) :: n + + real :: delt = 0.1 + real :: tmin, tem, fac0, fac1, fac2 + + integer :: i + + tmin = table_ice - 160. + + ! ----------------------------------------------------------------------- + ! compute es over water + ! ----------------------------------------------------------------------- + + do i = 1, n + tem = tmin + delt * real (i - 1) + fac0 = (tem - t_ice) / (tem * t_ice) + fac1 = fac0 * lv0 + fac2 = (dc_vap * log (tem / t_ice) + fac1) / rvgas + tablew (i) = e00 * exp (fac2) + enddo + +end subroutine qs_tablew + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!>@brief saturation water vapor pressure table iii +! 2 - phase table +subroutine qs_table2 (n) + + implicit none + + integer, intent (in) :: n + + real :: delt = 0.1 + real :: tmin, tem0, tem1, fac0, fac1, fac2 + + integer :: i, i0, i1 + + tmin = table_ice - 160. + + do i = 1, n + tem0 = tmin + delt * real (i - 1) + fac0 = (tem0 - t_ice) / (tem0 * t_ice) + if (i <= 1600) then + ! ----------------------------------------------------------------------- + ! compute es over ice between - 160 deg c and 0 deg c. + ! ----------------------------------------------------------------------- + fac1 = fac0 * li2 + fac2 = (d2ice * log (tem0 / t_ice) + fac1) / rvgas + else + ! ----------------------------------------------------------------------- + ! compute es over water between 0 deg c and 102 deg c. + ! ----------------------------------------------------------------------- + fac1 = fac0 * lv0 + fac2 = (dc_vap * log (tem0 / t_ice) + 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 + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! saturation water vapor pressure table iv +! 2 - phase table with " - 2 c" as the transition point +subroutine qs_table3 (n) + + implicit none + + integer, intent (in) :: n + + real :: delt = 0.1 + real :: esbasw, tbasw, esbasi, tmin, tem, aa, b, c, d, e + real :: tem0, tem1 + + integer :: i, i0, i1 + + esbasw = 1013246.0 + tbasw = table_ice + 100. + esbasi = 6107.1 + tmin = table_ice - 160. + + do i = 1, n + tem = tmin + delt * real (i - 1) + ! if (i <= 1600) then + if (i <= 1580) then ! change to - 2 c + ! ----------------------------------------------------------------------- + ! compute es over ice between - 160 deg c and 0 deg c. + ! see smithsonian meteorological tables page 350. + ! ----------------------------------------------------------------------- + aa = - 9.09718 * (table_ice / tem - 1.) + b = - 3.56654 * alog10 (table_ice / tem) + c = 0.876793 * (1. - tem / table_ice) + e = alog10 (esbasi) + table3 (i) = 0.1 * 10 ** (aa + b + c + e) + else + ! ----------------------------------------------------------------------- + ! compute es over water between - 2 deg c and 102 deg c. + ! see smithsonian meteorological tables page 350. + ! ----------------------------------------------------------------------- + aa = - 7.90298 * (tbasw / tem - 1.) + b = 5.02808 * alog10 (tbasw / tem) + c = - 1.3816e-7 * (10 ** ((1. - tem / tbasw) * 11.344) - 1.) + d = 8.1328e-3 * (10 ** ((tbasw / tem - 1.) * (- 3.49149)) - 1.) + e = alog10 (esbasw) + table3 (i) = 0.1 * 10 ** (aa + b + c + d + e) + endif + enddo + + ! ----------------------------------------------------------------------- + ! smoother around - 2 deg c + ! ----------------------------------------------------------------------- + + i0 = 1580 + i1 = 1581 + tem0 = 0.25 * (table3 (i0 - 1) + 2. * table (i0) + table3 (i0 + 1)) + tem1 = 0.25 * (table3 (i1 - 1) + 2. * table (i1) + table3 (i1 + 1)) + table3 (i0) = tem0 + table3 (i1) = tem1 + +end subroutine qs_table3 + +! ======================================================================= +! compute the saturated specific humidity for table +! note: this routine is based on "moist" mixing ratio +!>\ingroup mod_gfdl_cloud_mp +!! The function 'qs_blend' computes the saturated specific humidity +!! with a blend of water and ice depending on the temperature. +real function qs_blend (t, p, q) + + implicit none + + real, intent (in) :: t, p, q + + real :: es, ap1, tmin + + integer :: it + + tmin = table_ice - 160. + ap1 = 10. * dim (t, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es = table (it) + (ap1 - it) * des (it) + qs_blend = eps * es * (1. + zvir * q) / p + +end function qs_blend + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!! saturation water vapor pressure table i +! 3 - phase table +subroutine qs_table (n) + + implicit none + + integer, intent (in) :: n + + real :: delt = 0.1 + real :: tmin, tem, esh20 + real :: wice, wh2o, fac0, fac1, fac2 + real :: esupc (200) + + integer :: i + + tmin = table_ice - 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 - t_ice) / (tem * t_ice) + fac1 = fac0 * li2 + fac2 = (d2ice * log (tem / t_ice) + 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 - t_ice) / (tem * t_ice) + fac1 = fac0 * lv0 + fac2 = (dc_vap * log (tem / t_ice) + 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 * (table_ice - tem) + wh2o = 0.05 * (tem - 253.16) + table (i + 1400) = wice * table (i + 1400) + wh2o * esupc (i) + enddo + +end subroutine qs_table + +! ======================================================================= +! compute the saturated specific humidity and the gradient of saturated specific humidity +! input t in deg k, p in pa; p = rho rdry tv, moist pressure +!>\ingroup mod_gfdl_cloud_mp +!! The function 'qsmith' computes the saturated specific humidity +!! with a blend of water and ice depending on the temperature in 3D. +!@details It als oincludes the option for computing des/dT. +subroutine qsmith (im, km, ks, t, p, q, qs, dqdt) + + implicit none + + integer, intent (in) :: im, km, ks + + real, intent (in), dimension (im, km) :: t, p, q + + real, intent (out), dimension (im, km) :: qs + + real, intent (out), dimension (im, km), optional :: dqdt + + real :: eps10, ap1, tmin + + real, dimension (im, km) :: es + + integer :: i, k, it + + tmin = table_ice - 160. + eps10 = 10. * eps + + if (.not. tables_are_initialized) then + call qsmith_init + endif + + do k = ks, km + do i = 1, im + ap1 = 10. * dim (t (i, k), tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es (i, k) = table (it) + (ap1 - it) * des (it) + qs (i, k) = eps * es (i, k) * (1. + zvir * q (i, k)) / p (i, k) + enddo + enddo + + if (present (dqdt)) then + do k = ks, km + do i = 1, im + ap1 = 10. * dim (t (i, k), tmin) + 1. + ap1 = min (2621., ap1) - 0.5 + it = ap1 + dqdt (i, k) = eps10 * (des (it) + (ap1 - it) * (des (it + 1) - des (it))) * (1. + zvir * q (i, k)) / p (i, k) + enddo + enddo + endif + +end subroutine qsmith + +! ======================================================================= +!>\ingroup mod_gfdl_cloud_mp +!>@brief The subroutine 'neg_adj' fixes negative water species. +!>@details This is designed for 6-class micro-physics schemes. +subroutine neg_adj (ktop, kbot, pt, dp, qv, ql, qr, qi, qs, qg) + + implicit none + + integer, intent (in) :: ktop, kbot + + real, intent (in), dimension (ktop:kbot) :: dp + + real, intent (inout), dimension (ktop:kbot) :: pt, qv, ql, qr, qi, qs, qg + + real, dimension (ktop:kbot) :: lcpk, icpk + + real :: dq, cvm + + integer :: k + + ! ----------------------------------------------------------------------- + ! define heat capacity and latent heat coefficient + ! ----------------------------------------------------------------------- + + do k = ktop, kbot + cvm = c_air + qv (k) * c_vap + (qr (k) + ql (k)) * c_liq + (qi (k) + qs (k) + qg (k)) * c_ice + lcpk (k) = (lv00 + d0_vap * pt (k)) / cvm + icpk (k) = (li00 + dc_ice * pt (k)) / cvm + enddo + + do k = ktop, kbot + + ! ----------------------------------------------------------------------- + ! ice phase: + ! ----------------------------------------------------------------------- + + ! if cloud ice < 0, borrow from snow + if (qi (k) < 0.) then + qs (k) = qs (k) + qi (k) + qi (k) = 0. + endif + ! if snow < 0, borrow from graupel + if (qs (k) < 0.) then + qg (k) = qg (k) + qs (k) + qs (k) = 0. + endif + ! if graupel < 0, borrow from rain + if (qg (k) < 0.) then + qr (k) = qr (k) + qg (k) + pt (k) = pt (k) - qg (k) * icpk (k) ! heating + qg (k) = 0. + endif + + ! ----------------------------------------------------------------------- + ! liquid phase: + ! ----------------------------------------------------------------------- + + ! if rain < 0, borrow from cloud water + if (qr (k) < 0.) then + ql (k) = ql (k) + qr (k) + qr (k) = 0. + endif + ! if cloud water < 0, borrow from water vapor + if (ql (k) < 0.) then + qv (k) = qv (k) + ql (k) + pt (k) = pt (k) - ql (k) * lcpk (k) ! heating + ql (k) = 0. + endif + + enddo + + ! ----------------------------------------------------------------------- + ! fix water vapor; borrow from below + ! ----------------------------------------------------------------------- + + do k = ktop, kbot - 1 + if (qv (k) < 0.) then + qv (k + 1) = qv (k + 1) + qv (k) * dp (k) / dp (k + 1) + qv (k) = 0. + endif + enddo + + ! ----------------------------------------------------------------------- + ! bottom layer; borrow from above + ! ----------------------------------------------------------------------- + + if (qv (kbot) < 0. .and. qv (kbot - 1) > 0.) then + dq = min (- qv (kbot) * dp (kbot), qv (kbot - 1) * dp (kbot - 1)) + qv (kbot - 1) = qv (kbot - 1) - dq / dp (kbot - 1) + qv (kbot) = qv (kbot) + dq / dp (kbot) + endif + +end subroutine neg_adj + +! ======================================================================= +! compute global sum +!>@brief quick local sum algorithm +! ======================================================================= + +!real function g_sum (p, ifirst, ilast, jfirst, jlast, area, mode) +! +! use mpp_mod, only: mpp_sum +! +! implicit none +! +! integer, intent (in) :: ifirst, ilast, jfirst, jlast +! integer, intent (in) :: mode ! if == 1 divided by area +! +! real, intent (in), dimension (ifirst:ilast, jfirst:jlast) :: p, area +! +! integer :: i, j +! +! real :: gsum +! +! if (global_area < 0.) then +! global_area = 0. +! do j = jfirst, jlast +! do i = ifirst, ilast +! global_area = global_area + area (i, j) +! enddo +! enddo +! call mpp_sum (global_area) +! endif +! +! gsum = 0. +! do j = jfirst, jlast +! do i = ifirst, ilast +! gsum = gsum + p (i, j) * area (i, j) +! enddo +! enddo +! call mpp_sum (gsum) +! +! if (mode == 1) then +! g_sum = gsum / global_area +! else +! g_sum = gsum +! endif +! +!end function g_sum + +! ========================================================================== +!>\ingroup mod_gfdl_cloud_mp +!! The subroutine 'interpolate_z' interpolates to a prescribed height. +subroutine interpolate_z (is, ie, js, je, km, zl, hgt, a3, a2) + + implicit none + + integer, intent (in) :: is, ie, js, je, km + + real, intent (in), dimension (is:ie, js:je, km) :: a3 + + real, intent (in), dimension (is:ie, js:je, km + 1) :: hgt ! hgt (k) > hgt (k + 1) + + real, intent (in) :: zl + + real, intent (out), dimension (is:ie, js:je) :: a2 + + real, dimension (km) :: zm !< middle layer height + + integer :: i, j, k + + !$omp parallel do default (none) shared (is, ie, js, je, km, hgt, zl, a2, a3) private (zm) + + do j = js, je + do i = is, ie + do k = 1, km + zm (k) = 0.5 * (hgt (i, j, k) + hgt (i, j, k + 1)) + enddo + if (zl >= zm (1)) then + a2 (i, j) = a3 (i, j, 1) + elseif (zl <= zm (km)) then + a2 (i, j) = a3 (i, j, km) + else + do k = 1, km - 1 + if (zl <= zm (k) .and. zl >= zm (k + 1)) then + a2 (i, j) = a3 (i, j, k) + (a3 (i, j, k + 1) - a3 (i, j, k)) * (zm (k) - zl) / (zm (k) - zm (k + 1)) + exit + endif + enddo + endif + enddo + enddo + +end subroutine interpolate_z + +! ======================================================================= +!> \ingroup mod_gfdl_cloud_mp +!! The subroutine 'cloud_diagnosis' diagnoses the radius of cloud +!! species. +!>\author Linjiong Zhoum, Shian-Jiann Lin +! ======================================================================= +subroutine cloud_diagnosis (is, ie, ks, ke, den, delp, lsm, qmw, qmi, qmr, qms, qmg, t, & + rew, rei, rer, res, reg) + + implicit none + + integer, intent (in) :: is, ie, ks, ke + integer, intent (in), dimension (is:ie) :: lsm ! land sea mask, 0: ocean, 1: land, 2: sea ice + + real, intent (in), dimension (is:ie, ks:ke) :: den, delp, t + real, intent (in), dimension (is:ie, ks:ke) :: qmw, qmi, qmr, qms, qmg !< units: kg / kg + + real, intent (out), dimension (is:ie, ks:ke) :: rew, rei, rer, res, reg !< units: micron + + real, dimension (is:ie, ks:ke) :: qcw, qci, qcr, qcs, qcg !< units: g / m^2 + + integer :: i, k + + real :: lambdar, lambdas, lambdag + real :: dpg, rei_fac, mask, ccn, bw + real, parameter :: rho_0 = 50.e-3 + + real :: rhow = 1.0e3, rhor = 1.0e3, rhos = 1.0e2, rhog = 4.0e2 + real :: n0r = 8.0e6, n0s = 3.0e6, n0g = 4.0e6 + real :: alphar = 0.8, alphas = 0.25, alphag = 0.5 + real :: gammar = 17.837789, gammas = 8.2850630, gammag = 11.631769 + real :: qmin = 1.0e-12, beta = 1.22, qmin1 = 9.e-6 + + do k = ks, ke + do i = is, ie + + dpg = abs (delp (i, k)) / grav + mask = min (max (real(lsm (i)), 0.0), 2.0) + + ! ----------------------------------------------------------------------- + ! cloud water (Martin et al., 1994) + ! ----------------------------------------------------------------------- + + ccn = 0.80 * (- 1.15e-3 * (ccn_o ** 2) + 0.963 * ccn_o + 5.30) * abs (mask - 1.0) + & + 0.67 * (- 2.10e-4 * (ccn_l ** 2) + 0.568 * ccn_l - 27.9) * (1.0 - abs (mask - 1.0)) + + if (qmw (i, k) .gt. qmin) then + qcw (i, k) = dpg * qmw (i, k) * 1.0e3 + rew (i, k) = exp (1.0 / 3.0 * log ((3.0 * den (i, k) * qmw (i, k)) / (4.0 * pi * rhow * ccn))) * 1.0e4 + rew (i, k) = max (rewmin, min (rewmax, rew (i, k))) + else + qcw (i, k) = 0.0 + rew (i, k) = rewmin + endif + + if (reiflag .eq. 1) then + + ! ----------------------------------------------------------------------- + ! cloud ice (Heymsfield and Mcfarquhar, 1996) + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qmin1) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + rei_fac = log (1.0e3 * qmi (i, k) * den (i, k)) + if (t (i, k) - tice .lt. - 50) then + rei (i, k) = beta / 9.917 * exp (0.109 * rei_fac) * 1.0e3 + elseif (t (i, k) - tice .lt. - 40) then + rei (i, k) = beta / 9.337 * exp (0.080 * rei_fac) * 1.0e3 + elseif (t (i, k) - tice .lt. - 30) then + rei (i, k) = beta / 9.208 * exp (0.055 * rei_fac) * 1.0e3 + else + rei (i, k) = beta / 9.387 * exp (0.031 * rei_fac) * 1.0e3 + endif + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + if (reiflag .eq. 2) then + + ! ----------------------------------------------------------------------- + ! cloud ice (Wyser, 1998) + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qmin1) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + bw = - 2. + 1.e-3 * log10 (den (i, k) * qmi (i, k) / rho_0) * max (0.0, tice - t (i, k)) ** 1.5 + rei (i, k) = 377.4 + bw * (203.3 + bw * (37.91 + 2.3696 * bw)) + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + ! ----------------------------------------------------------------------- + ! rain (Lin et al., 1983) + ! ----------------------------------------------------------------------- + + if (qmr (i, k) .gt. qmin) then + qcr (i, k) = dpg * qmr (i, k) * 1.0e3 + lambdar = exp (0.25 * log (pi * rhor * n0r / qmr (i, k) / den (i, k))) + rer (i, k) = 0.5 * exp (log (gammar / 6) / alphar) / lambdar * 1.0e6 + rer (i, k) = max (rermin, min (rermax, rer (i, k))) + else + qcr (i, k) = 0.0 + rer (i, k) = rermin + endif + + ! ----------------------------------------------------------------------- + ! snow (Lin et al., 1983) + ! ----------------------------------------------------------------------- + + if (qms (i, k) .gt. qmin1) then + qcs (i, k) = dpg * qms (i, k) * 1.0e3 + lambdas = exp (0.25 * log (pi * rhos * n0s / qms (i, k) / den (i, k))) + res (i, k) = 0.5 * exp (log (gammas / 6) / alphas) / lambdas * 1.0e6 + res (i, k) = max (resmin, min (resmax, res (i, k))) + else + qcs (i, k) = 0.0 + res (i, k) = resmin + endif + + ! ----------------------------------------------------------------------- + ! graupel (Lin et al., 1983) + ! ----------------------------------------------------------------------- + + if (qmg (i, k) .gt. qmin) then + qcg (i, k) = dpg * qmg (i, k) * 1.0e3 + lambdag = exp (0.25 * log (pi * rhog * n0g / qmg (i, k) / den (i, k))) + reg (i, k) = 0.5 * exp (log (gammag / 6) / alphag) / lambdag * 1.0e6 + reg (i, k) = max (regmin, min (regmax, reg (i, k))) + else + qcg (i, k) = 0.0 + reg (i, k) = regmin + endif + + enddo + enddo + +end subroutine cloud_diagnosis + +!+---+-----------------------------------------------------------------+ +!>\ingroup mod_gfdl_cloud_mp +!! This subroutine calculates radar reflectivity. + subroutine refl10cm_gfdl (qv1d, qr1d, qs1d, qg1d, & + t1d, p1d, dBZ, kts, kte, ii, jj, melti) + + IMPLICIT NONE + +!..Sub arguments + INTEGER, INTENT(IN):: kts, kte, ii,jj + REAL, DIMENSION(kts:kte), INTENT(IN):: & + qv1d, qr1d, qs1d, qg1d, t1d, p1d + REAL, DIMENSION(kts:kte), INTENT(INOUT):: dBZ + +!..Local variables + REAL, DIMENSION(kts:kte):: temp, pres, qv, rho + REAL, DIMENSION(kts:kte):: rr, rs, rg +! REAL:: temp_C + + DOUBLE PRECISION, DIMENSION(kts:kte):: ilamr, ilams, ilamg + DOUBLE PRECISION, DIMENSION(kts:kte):: N0_r, N0_s, N0_g + DOUBLE PRECISION:: lamr, lams, lamg + LOGICAL, DIMENSION(kts:kte):: L_qr, L_qs, L_qg + + REAL, DIMENSION(kts:kte):: ze_rain, ze_snow, ze_graupel + DOUBLE PRECISION:: fmelt_s, fmelt_g + + INTEGER:: i, k, k_0, kbot, n + LOGICAL, INTENT(IN):: melti + DOUBLE PRECISION:: cback, x, eta, f_d +!+---+ + + do k = kts, kte + dBZ(k) = -35.0 + enddo + +!+---+-----------------------------------------------------------------+ +!..Put column of data into local arrays. +!+---+-----------------------------------------------------------------+ + do k = kts, kte + temp(k) = t1d(k) +! temp_C = min(-0.001, temp(K)-273.15) + qv(k) = MAX(1.E-10, qv1d(k)) + pres(k) = p1d(k) + rho(k) = 0.622*pres(k)/(rdgas*temp(k)*(qv(k)+0.622)) + + if (qr1d(k) .gt. 1.E-9) then + rr(k) = qr1d(k)*rho(k) + N0_r(k) = n0r + lamr = (xam_r*xcrg(3)*N0_r(k)/rr(k))**(1./xcre(1)) + ilamr(k) = 1./lamr + L_qr(k) = .true. + else + rr(k) = 1.E-12 + L_qr(k) = .false. + endif + + if (qs1d(k) .gt. 1.E-9) then + rs(k) = qs1d(k)*rho(k) + N0_s(k) = n0s + lams = (xam_s*xcsg(3)*N0_s(k)/rs(k))**(1./xcse(1)) + ilams(k) = 1./lams + L_qs(k) = .true. + else + rs(k) = 1.E-12 + L_qs(k) = .false. + endif + + if (qg1d(k) .gt. 1.E-9) then + rg(k) = qg1d(k)*rho(k) + N0_g(k) = n0g + lamg = (xam_g*xcgg(3)*N0_g(k)/rg(k))**(1./xcge(1)) + ilamg(k) = 1./lamg + L_qg(k) = .true. + else + rg(k) = 1.E-12 + L_qg(k) = .false. + endif + enddo + +!+---+-----------------------------------------------------------------+ +!..Locate K-level of start of melting (k_0 is level above). +!+---+-----------------------------------------------------------------+ + k_0 = kts + K_LOOP:do k = kte-1, kts, -1 + if ( melti .and. (temp(k).gt.273.15) .and. L_qr(k) & + .and. (L_qs(k+1).or.L_qg(k+1)) ) then + k_0 = MAX(k+1, k_0) + EXIT K_LOOP + endif + enddo K_LOOP +!+---+-----------------------------------------------------------------+ +!..Assume Rayleigh approximation at 10 cm wavelength. Rain (all temps) +!.. and non-water-coated snow and graupel when below freezing are +!.. simple. Integrations of m(D)*m(D)*N(D)*dD. +!+---+-----------------------------------------------------------------+ + do k = kts, kte + ze_rain(k) = 1.e-22 + ze_snow(k) = 1.e-22 + ze_graupel(k) = 1.e-22 + if (L_qr(k)) ze_rain(k) = N0_r(k)*xcrg(4)*ilamr(k)**xcre(4) + if (L_qs(k)) ze_snow(k) = (0.176/0.93) * (6.0/PI)*(6.0/PI) & + * (xam_s/900.0)*(xam_s/900.0) & + * N0_s(k)*xcsg(4)*ilams(k)**xcse(4) + if (L_qg(k)) ze_graupel(k) = (0.176/0.93) * (6.0/PI)*(6.0/PI) & + * (xam_g/900.0)*(xam_g/900.0) & + * N0_g(k)*xcgg(4)*ilamg(k)**xcge(4) + enddo + + +!+---+-----------------------------------------------------------------+ +!..Special case of melting ice (snow/graupel) particles. Assume the +!.. ice is surrounded by the liquid water. Fraction of meltwater is +!.. extremely simple based on amount found above the melting level. +!.. Uses code from Uli Blahak (rayleigh_soak_wetgraupel and supporting +!.. routines). +!+---+-----------------------------------------------------------------+ + + if (melti .and. k_0.ge.kts+1) then + do k = k_0-1, kts, -1 + +!..Reflectivity contributed by melting snow + if (L_qs(k) .and. L_qs(k_0) ) then + fmelt_s = MAX(0.005d0, MIN(1.0d0-rs(k)/rs(k_0), 0.99d0)) + eta = 0.d0 + lams = 1./ilams(k) + do n = 1, nrbins + x = xam_s * xxDs(n)**xbm_s + call rayleigh_soak_wetgraupel (x,DBLE(xocms),DBLE(xobms), & + fmelt_s, melt_outside_s, m_w_0, m_i_0, lamda_radar, & + CBACK, mixingrulestring_s, matrixstring_s, & + inclusionstring_s, hoststring_s, & + hostmatrixstring_s, hostinclusionstring_s) + f_d = N0_s(k)*xxDs(n)**xmu_s * DEXP(-lams*xxDs(n)) + eta = eta + f_d * CBACK * simpson(n) * xdts(n) + enddo + ze_snow(k) = SNGL(lamda4 / (pi5 * K_w) * eta) + endif + + +!..Reflectivity contributed by melting graupel + + if (L_qg(k) .and. L_qg(k_0) ) then + fmelt_g = MAX(0.005d0, MIN(1.0d0-rg(k)/rg(k_0), 0.99d0)) + eta = 0.d0 + lamg = 1./ilamg(k) + do n = 1, nrbins + x = xam_g * xxDg(n)**xbm_g + call rayleigh_soak_wetgraupel (x,DBLE(xocmg),DBLE(xobmg), & + fmelt_g, melt_outside_g, m_w_0, m_i_0, lamda_radar, & + CBACK, mixingrulestring_g, matrixstring_g, & + inclusionstring_g, hoststring_g, & + hostmatrixstring_g, hostinclusionstring_g) + f_d = N0_g(k)*xxDg(n)**xmu_g * DEXP(-lamg*xxDg(n)) + eta = eta + f_d * CBACK * simpson(n) * xdtg(n) + enddo + ze_graupel(k) = SNGL(lamda4 / (pi5 * K_w) * eta) + endif + + enddo + endif + + do k = kte, kts, -1 + dBZ(k) = 10.*log10((ze_rain(k)+ze_snow(k)+ze_graupel(k))*1.d18) + enddo + + + end subroutine refl10cm_gfdl +!+---+-----------------------------------------------------------------+ + +end module gfdl_cloud_microphys_mod From 737f62a516004b4b4e45fcd49ff3097c1f0be484 Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Mon, 22 Jan 2024 16:25:30 +0000 Subject: [PATCH 02/10] removed the gfdlmp v1 files in the GFDL directory and moved them to v1 subdirectory --- physics/MP/GFDL/fv_sat_adj.F90 | 1431 ----- physics/MP/GFDL/fv_sat_adj.meta | 441 -- physics/MP/GFDL/gfdl_cloud_microphys.F90 | 331 -- physics/MP/GFDL/gfdl_cloud_microphys.meta | 482 -- .../MP/GFDL/module_gfdl_cloud_microphys.F90 | 5075 ----------------- 5 files changed, 7760 deletions(-) delete mode 100644 physics/MP/GFDL/fv_sat_adj.F90 delete mode 100644 physics/MP/GFDL/fv_sat_adj.meta delete mode 100644 physics/MP/GFDL/gfdl_cloud_microphys.F90 delete mode 100644 physics/MP/GFDL/gfdl_cloud_microphys.meta delete mode 100644 physics/MP/GFDL/module_gfdl_cloud_microphys.F90 diff --git a/physics/MP/GFDL/fv_sat_adj.F90 b/physics/MP/GFDL/fv_sat_adj.F90 deleted file mode 100644 index 53543485b..000000000 --- a/physics/MP/GFDL/fv_sat_adj.F90 +++ /dev/null @@ -1,1431 +0,0 @@ -!>\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 -!> @} diff --git a/physics/MP/GFDL/fv_sat_adj.meta b/physics/MP/GFDL/fv_sat_adj.meta deleted file mode 100644 index c91e438b7..000000000 --- a/physics/MP/GFDL/fv_sat_adj.meta +++ /dev/null @@ -1,441 +0,0 @@ -[ccpp-table-properties] - name = fv_sat_adj - type = scheme - dependencies = ../../hooks/machine.F,../../hooks/physcons.F90 - dependencies = module_gfdl_cloud_microphys.F90,multi_gases.F90 - dependencies = ../module_mp_radar.F90 - -######################################################################## -[ccpp-arg-table] - name = fv_sat_adj_init - type = scheme -[do_sat_adj] - standard_name = flag_for_saturation_adjustment_for_microphysics_in_dynamics - long_name = flag for saturation adjustment for microphysics in dynamics - units = none - dimensions = () - type = logical - intent = in -[kmp] - standard_name = top_layer_index_for_fast_physics - long_name = top_layer_inder_for_gfdl_mp - units = index - dimensions = () - type = integer - intent = in -[nwat] - standard_name = number_of_water_species - long_name = number of water species - units = count - dimensions = () - type = integer - intent = in -[ngas] - standard_name = number_of_gases_for_multi_gases_physics - long_name = number of gases for multi gases physics - units = count - dimensions = () - type = integer - intent = in -[rilist] - standard_name = gas_constants_for_multi_gases_physics - long_name = gas constants for multi gases physics - units = J kg-1 K-1 - dimensions = (0:number_of_gases_for_multi_gases_physics) - type = real - kind = kind_dyn - intent = in -[cpilist] - standard_name = specific_heat_capacities_for_multi_gases_physics - long_name = specific heat capacities for multi gases physics - units = J kg-1 K-1 - dimensions = (0:number_of_gases_for_multi_gases_physics) - type = real - kind = kind_dyn - intent = in -[mpirank] - standard_name = mpi_rank_for_fast_physics - long_name = current MPI-rank for fast physics schemes - units = index - dimensions = () - type = integer - intent = in -[mpiroot] - standard_name = mpi_root_for_fast_physics - long_name = master MPI-rank for fast physics schemes - units = index - dimensions = () - type = integer - intent = in -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - -######################################################################## -[ccpp-arg-table] - name = fv_sat_adj_finalize - type = scheme -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - -######################################################################## -[ccpp-arg-table] - name = fv_sat_adj_run - type = scheme -[mdt] - standard_name = time_step_for_remapping_for_fast_physics - long_name = remapping time step for fast physics - units = s - dimensions = () - type = real - kind = kind_dyn - intent = in -[zvir] - standard_name = ratio_of_vapor_to_dry_air_gas_constants_minus_one_default_kind - long_name = zvir=rv/rd-1.0 - units = none - dimensions = () - type = real - kind = kind_dyn - intent = in -[is] - standard_name = starting_x_direction_index - long_name = starting X direction index - units = count - dimensions = () - type = integer - intent = in -[ie] - standard_name = ending_x_direction_index - long_name = ending X direction index - units = count - dimensions = () - type = integer - intent = in -[isd] - standard_name = starting_x_direction_index_domain - long_name = starting X direction index for domain - units = count - dimensions = () - type = integer - intent = in -[ied] - standard_name = ending_x_direction_index_domain - long_name = ending X direction index for domain - units = count - dimensions = () - type = integer - intent = in -[kmp] - standard_name = top_layer_index_for_fast_physics - long_name = top layer index for GFDL mp - units = index - dimensions = () - type = integer - intent = in -[km] - standard_name = vertical_dimension_for_fast_physics - long_name = number of vertical levels - units = count - dimensions = () - type = integer - intent = in -[kmdelz] - standard_name = vertical_dimension_for_thickness_at_Lagrangian_surface - long_name = vertical dimension for thickness at Lagrangian surface - units = count - dimensions = () - type = integer - intent = in -[js] - standard_name = starting_y_direction_index - long_name = starting Y direction index - units = count - dimensions = () - type = integer - intent = in -[je] - standard_name = ending_y_direction_index - long_name = ending Y direction index - units = count - dimensions = () - type = integer - intent = in -[jsd] - standard_name = starting_y_direction_index_domain - long_name = starting X direction index for domain - units = count - dimensions = () - type = integer - intent = in -[jed] - standard_name = ending_y_direction_index_domain - long_name = ending X direction index for domain - units = count - dimensions = () - type = integer - intent = in -[ng] - standard_name = number_of_ghost_zones - long_name = number of ghost zones defined in fv_mp - units = count - dimensions = () - type = integer - intent = in -[hydrostatic] - standard_name = flag_for_hydrostatic_solver_for_fast_physics - long_name = flag for use the hydrostatic or nonhydrostatic solver - units = flag - dimensions = () - type = logical - intent = in -[fast_mp_consv] - standard_name = flag_for_fast_microphysics_energy_conservation - long_name = flag for fast microphysics energy conservation - units = flag - dimensions = () - type = logical - intent = in -[te0_2d] - standard_name = atmosphere_energy_content_in_column - long_name = atmosphere total energy in columns - units = J m-2 - dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index) - type = real - kind = kind_dyn - intent = inout -[te0] - standard_name = atmosphere_energy_content_at_Lagrangian_surface - long_name = atmosphere total energy at Lagrangian surface - units = J m-2 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = out -[ngas] - standard_name = number_of_gases_for_multi_gases_physics - long_name = number of gases for multi gases physics - units = count - dimensions = () - type = integer - intent = in -[qvi] - standard_name = gas_tracers_for_multi_gas_physics_at_Lagrangian_surface - long_name = gas tracers for multi gas physics at Lagrangian surface - units = kg kg-1 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics,1:number_of_gases_for_multi_gases_physics) - type = real - kind = kind_dyn - intent = inout -[qv] - standard_name = water_vapor_specific_humidity_at_Lagrangian_surface - long_name = water vapor specific humidity updated by fast physics at Lagrangian surface - units = kg kg-1 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[ql] - standard_name = cloud_liquid_water_specific_humidity_at_Lagrangian_surface - long_name = cloud liquid water specific humidity updated by fast physics at Lagrangian surface - units = kg kg-1 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[qi] - standard_name = cloud_ice_specific_humidity_at_Lagrangian_surface - long_name = cloud ice specific humidity updated by fast physics at Lagrangian surface - units = kg kg-1 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[qr] - standard_name = cloud_rain_specific_humidity_at_Lagrangian_surface - long_name = cloud rain specific humidity updated by fast physics at Lagrangian surface - units = kg kg-1 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[qs] - standard_name = cloud_snow_specific_humidity_at_Lagrangian_surface - long_name = cloud snow specific humidity updated by fast physics at Lagrangian surface - units = kg kg-1 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[qg] - standard_name = cloud_graupel_specific_humidity_at_Lagrangian_surface - long_name = cloud graupel specific humidity updated by fast physics at Lagrangian surface - units = kg kg-1 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[hs] - standard_name = surface_geopotential_at_Lagrangian_surface - long_name = surface geopotential at Lagrangian surface - units = m2 s-2 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain) - type = real - kind = kind_dyn - intent = in -[peln] - standard_name = log_pressure_at_Lagrangian_surface - long_name = logarithm of pressure at Lagrangian surface - units = Pa - dimensions = (starting_x_direction_index:ending_x_direction_index,1:vertical_dimension_for_fast_physics_plus_one,starting_y_direction_index:ending_y_direction_index) - type = real - kind = kind_dyn - intent = in -[delz] - standard_name = thickness_at_Lagrangian_surface - long_name = thickness at Lagrangian_surface - units = m - dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_thickness_at_Lagrangian_surface) - type = real - kind = kind_dyn - intent = in -[delp] - standard_name = pressure_thickness_at_Lagrangian_surface - long_name = pressure thickness at Lagrangian surface - units = Pa - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = in -[pt] - standard_name = virtual_temperature_at_Lagrangian_surface - long_name = virtual temperature at Lagrangian surface - units = K - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[pkz] - standard_name = finite_volume_mean_edge_pressure_raised_to_the_power_of_kappa - long_name = finite-volume mean edge pressure in Pa raised to the power of kappa - units = 1 - dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[q_con] - standard_name = cloud_condensed_water_specific_humidity_at_Lagrangian_surface - long_name = cloud condensed water specific humidity updated by fast physics at Lagrangian surface - units = kg kg-1 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_condensed_water_at_Lagrangian_surface) - type = real - kind = kind_dyn - intent = inout -[akap] - standard_name = kappa_dry_for_fast_physics - long_name = modified kappa for dry air, fast physics - units = none - dimensions = () - type = real - kind = kind_dyn - intent = in -[cappa] - standard_name = cappa_moist_gas_constant_at_Lagrangian_surface - long_name = cappa(i,j,k) = rdgas / ( rdgas + cvm(i)/(1.+r_vir*q(i,j,k,sphum)) ) - units = none - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_cappa_at_Lagrangian_surface) - type = real - kind = kind_dyn - intent = inout -[area] - standard_name = cell_area_for_fast_physics - long_name = area of the grid cell for fast physics - units = m2 - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain) - type = real - kind = kind_grid - intent = in -[dtdt] - standard_name = tendency_of_air_temperature_at_Lagrangian_surface - long_name = air temperature tendency due to fast physics at Lagrangian surface - units = K s-1 - dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = inout -[out_dt] - standard_name = flag_for_tendency_of_air_temperature_at_Lagrangian_surface - long_name = flag for calculating tendency of air temperature due to fast physics - units = flag - dimensions = () - type = logical - intent = in -[last_step] - standard_name = flag_for_the_last_step_of_k_split_remapping - long_name = flag for the last step of k-split remapping - units = flag - dimensions = () - type = logical - intent = in -[do_qa] - standard_name = flag_for_inline_cloud_fraction_calculation - long_name = flag for the inline cloud fraction calculation - units = flag - dimensions = () - type = logical - intent = in -[qa] - standard_name = cloud_fraction_at_Lagrangian_surface - long_name = cloud fraction at Lagrangian surface - units = none - dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) - type = real - kind = kind_dyn - intent = out -[nthreads] - standard_name = omp_threads_for_fast_physics - long_name = number of OpenMP threads available for fast physics schemes - units = count - dimensions = () - type = integer - intent = in -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out diff --git a/physics/MP/GFDL/gfdl_cloud_microphys.F90 b/physics/MP/GFDL/gfdl_cloud_microphys.F90 deleted file mode 100644 index 0fd84c7ea..000000000 --- a/physics/MP/GFDL/gfdl_cloud_microphys.F90 +++ /dev/null @@ -1,331 +0,0 @@ -!> \file gfdl_cloud_microphys.F90 -!! This file contains the CCPP entry point for the column GFDL cloud microphysics ( Chen and Lin (2013) -!! \cite chen_and_lin_2013 ). -module gfdl_cloud_microphys - - use gfdl_cloud_microphys_mod, only: gfdl_cloud_microphys_mod_init, & - gfdl_cloud_microphys_mod_driver, & - gfdl_cloud_microphys_mod_end, & - cloud_diagnosis - - implicit none - - private - - public gfdl_cloud_microphys_run, gfdl_cloud_microphys_init, gfdl_cloud_microphys_finalize - - logical :: is_initialized = .false. - -contains - -! ----------------------------------------------------------------------- -! CCPP entry points for gfdl cloud microphysics -! ----------------------------------------------------------------------- - -!>\brief The subroutine initializes the GFDL -!! cloud microphysics. -!! -!> \section arg_table_gfdl_cloud_microphys_init Argument Table -!! \htmlinclude gfdl_cloud_microphys_init.html -!! - subroutine gfdl_cloud_microphys_init (me, master, nlunit, input_nml_file, logunit, fn_nml, & - imp_physics, imp_physics_gfdl, do_shoc, errmsg, errflg) - - implicit none - - integer, intent (in) :: me - integer, intent (in) :: master - integer, intent (in) :: nlunit - integer, intent (in) :: logunit - character(len=*), intent (in) :: fn_nml - character(len=*), intent (in) :: input_nml_file(:) - integer, intent( in) :: imp_physics - integer, intent( in) :: imp_physics_gfdl - logical, intent( in) :: do_shoc - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - if (is_initialized) return - - if (imp_physics/=imp_physics_gfdl) then - write(errmsg,'(*(a))') 'Namelist option for microphysics does not match choice in suite definition file' - errflg = 1 - return - end if - - if (do_shoc) then - write(errmsg,'(*(a))') 'SHOC is not currently compatible with GFDL MP' - errflg = 1 - return - endif - - call gfdl_cloud_microphys_mod_init(me, master, nlunit, input_nml_file, logunit, fn_nml, errmsg, errflg) - - is_initialized = .true. - - end subroutine gfdl_cloud_microphys_init - -! ======================================================================= -!>\brief The subroutine 'gfdl_cloud_microphys_finalize' terminates the GFDL -!! cloud microphysics. -!! -!! \section arg_table_gfdl_cloud_microphys_finalize Argument Table -!! \htmlinclude gfdl_cloud_microphys_finalize.html -!! - subroutine gfdl_cloud_microphys_finalize(errmsg, errflg) - - implicit none - - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - if (.not.is_initialized) return - - call gfdl_cloud_microphys_mod_end() - - is_initialized = .false. - - end subroutine gfdl_cloud_microphys_finalize - -!>\defgroup gfdlmp GFDL Cloud Microphysics Module -!! This is cloud microphysics package for GFDL global cloud resolving model. -!! The algorithms are originally derived from Lin et al. (1983) \cite lin_et_al_1983. -!! Most of the key elements have been simplified/improved. This code at this stage -!! bears little to no similarity to the original Lin MP. -!! Therefore, it is best to be called GFDL microphysics (GFDL MP) . -!! -!>\brief The module contains the GFDL cloud -!! microphysics (Chen and Lin (2013) \cite chen_and_lin_2013 ). -!> The module is paired with \ref fast_sat_adj, which performs the "fast" -!! processes. -!! -!>\brief The subroutine executes the full GFDL cloud microphysics. -!! \section arg_table_gfdl_cloud_microphys_run Argument Table -!! \htmlinclude gfdl_cloud_microphys_run.html -!! - subroutine gfdl_cloud_microphys_run( & - levs, im, rainmin, con_g, con_fvirt, con_rd, con_eps, frland, garea, islmsk, & - gq0, gq0_ntcw, gq0_ntrw, gq0_ntiw, gq0_ntsw, gq0_ntgl, gq0_ntclamt, & - gt0, gu0, gv0, vvl, prsl, phii, del, & - rain0, ice0, snow0, graupel0, prcp0, sr, & - dtp, hydrostatic, phys_hydrostatic, lradar, refl_10cm, & - reset, effr_in, rew, rei, rer, res, reg, & - cplchm, pfi_lsan, pfl_lsan, errmsg, errflg) - - use machine, only: kind_phys - - implicit none - - ! DH* TODO: CLEANUP, all of these should be coming in through the argument list - ! parameters - real(kind=kind_phys), parameter :: one = 1.0d0 - real(kind=kind_phys), parameter :: con_p001= 0.001d0 - real(kind=kind_phys), parameter :: con_day = 86400.d0 - !real(kind=kind_phys), parameter :: rainmin = 1.0d-13 - ! *DH - - ! interface variables - integer, intent(in ) :: levs, im - real(kind=kind_phys), intent(in ) :: con_g, con_fvirt, con_rd, con_eps, rainmin - real(kind=kind_phys), intent(in ), dimension(:) :: frland, garea - integer, intent(in ), dimension(:) :: islmsk - real(kind=kind_phys), intent(inout), dimension(:,:) :: gq0, gq0_ntcw, gq0_ntrw, gq0_ntiw, & - gq0_ntsw, gq0_ntgl, gq0_ntclamt - real(kind=kind_phys), intent(inout), dimension(:,:) :: gt0, gu0, gv0 - real(kind=kind_phys), intent(in ), dimension(:,:) :: vvl, prsl, del - real(kind=kind_phys), intent(in ), dimension(:,:) :: phii - - ! rain/snow/ice/graupel/precip amounts, fraction of frozen precip - real(kind_phys), intent(out ), dimension(:) :: rain0 - real(kind_phys), intent(out ), dimension(:) :: snow0 - real(kind_phys), intent(out ), dimension(:) :: ice0 - real(kind_phys), intent(out ), dimension(:) :: graupel0 - real(kind_phys), intent(out ), dimension(:) :: prcp0 - real(kind_phys), intent(out ), dimension(:) :: sr - - real(kind_phys), intent(in) :: dtp ! physics time step - logical, intent (in) :: hydrostatic, phys_hydrostatic - - logical, intent (in) :: lradar - real(kind=kind_phys), intent(inout), dimension(:,:) :: refl_10cm - logical, intent (in) :: reset, effr_in - real(kind=kind_phys), intent(inout), dimension(:,:) :: rew, rei, rer, res, reg - logical, intent (in) :: cplchm - ! ice and liquid water 3d precipitation fluxes - only allocated if cplchm is .true. - real(kind=kind_phys), intent(inout), dimension(:,:) :: pfi_lsan, pfl_lsan - - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! local variables - integer :: iis, iie, jjs, jje, kks, kke, kbot, ktop - integer :: i, k, kk - real(kind=kind_phys), dimension(1:im,1:levs) :: delp, dz, uin, vin, pt, qv1, ql1, qr1, qg1, qa1, qn1, qi1, & - qs1, pt_dt, qa_dt, u_dt, v_dt, w, qv_dt, ql_dt, qr_dt, qi_dt, & - qs_dt, qg_dt, p123, refl - real(kind=kind_phys), dimension(1:im,1,1:levs) :: pfils, pflls - real(kind=kind_phys), dimension(:,:), allocatable :: den - real(kind=kind_phys) :: onebg - real(kind=kind_phys) :: tem - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - iis = 1 - iie = im - jjs = 1 - jje = 1 - kks = 1 - kke = levs - ! flipping of vertical direction - ktop = 1 - kbot = levs - - onebg = one/con_g - - do k = 1, levs - kk = levs-k+1 - do i = 1, im - qv_dt(i,k) = 0.0 - ql_dt(i,k) = 0.0 - qr_dt(i,k) = 0.0 - qi_dt(i,k) = 0.0 - qs_dt(i,k) = 0.0 - qg_dt(i,k) = 0.0 - qa_dt(i,k) = 0.0 - pt_dt(i,k) = 0.0 - u_dt(i,k) = 0.0 - v_dt(i,k) = 0.0 - qn1(i,k) = 0.0 - pfils(i,1,k) = 0.0 - pflls(i,1,k) = 0.0 - ! flip vertical (k) coordinate - qv1(i,k) = gq0(i,kk) - ql1(i,k) = gq0_ntcw(i,kk) - qr1(i,k) = gq0_ntrw(i,kk) - qi1(i,k) = gq0_ntiw(i,kk) - qs1(i,k) = gq0_ntsw(i,kk) - qg1(i,k) = gq0_ntgl(i,kk) - qa1(i,k) = gq0_ntclamt(i,kk) - pt(i,k) = gt0(i,kk) - w(i,k) = -vvl(i,kk) * (one+con_fvirt * gq0(i,kk)) & - * gt0(i,kk) / prsl(i,kk) * (con_rd*onebg) - uin(i,k) = gu0(i,kk) - vin(i,k) = gv0(i,kk) - delp(i,k) = del(i,kk) - dz(i,k) = (phii(i,kk)-phii(i,kk+1))*onebg - p123(i,k) = prsl(i,kk) - refl(i,k) = refl_10cm(i,kk) - enddo - enddo - - ! reset precipitation amounts to zero - rain0 = 0 - ice0 = 0 - snow0 = 0 - graupel0 = 0 - - call gfdl_cloud_microphys_mod_driver(iis, iie, jjs, jje, kks, kke, ktop, kbot, & - qv1, ql1, qr1, qi1, qs1, qg1, qa1, qn1, qv_dt, ql_dt, qr_dt, qi_dt, & - qs_dt, qg_dt, qa_dt, pt_dt, pt, w, uin, vin, u_dt, v_dt, dz, delp, & - garea, dtp, frland, rain0, snow0, ice0, graupel0, hydrostatic, & - phys_hydrostatic, p123, lradar, refl, reset, pfils, pflls) - tem = dtp*con_p001/con_day - - ! fix negative values - do i = 1, im - !rain0(i) = max(con_d00, rain0(i)) - !snow0(i) = max(con_d00, snow0(i)) - !ice0(i) = max(con_d00, ice0(i)) - !graupel0(i) = max(con_d00, graupel0(i)) - if(rain0(i)*tem < rainmin) then - rain0(i) = 0.0 - endif - if(ice0(i)*tem < rainmin) then - ice0(i) = 0.0 - endif - if(snow0(i)*tem < rainmin) then - snow0(i) = 0.0 - endif - if(graupel0(i)*tem < rainmin) then - graupel0(i) = 0.0 - endif - enddo - - ! calculate fraction of frozen precipitation using unscaled - ! values of rain0, ice0, snow0, graupel0 (for bit-for-bit) - do i=1,im - prcp0(i) = (rain0(i)+snow0(i)+ice0(i)+graupel0(i)) * tem - if ( prcp0(i) > rainmin ) then - sr(i) = (snow0(i) + ice0(i) + graupel0(i)) & - / (rain0(i) + snow0(i) + ice0(i) + graupel0(i)) - else - sr(i) = 0.0 - endif - enddo - - ! convert rain0, ice0, snow0, graupel0 from mm per day to m per physics timestep - rain0 = rain0*tem - ice0 = ice0*tem - snow0 = snow0*tem - graupel0 = graupel0*tem - - ! flip vertical coordinate back - do k=1,levs - kk = levs-k+1 - do i=1,im - gq0(i,k) = qv1(i,kk) + qv_dt(i,kk) * dtp - gq0_ntcw(i,k) = ql1(i,kk) + ql_dt(i,kk) * dtp - gq0_ntrw(i,k) = qr1(i,kk) + qr_dt(i,kk) * dtp - gq0_ntiw(i,k) = qi1(i,kk) + qi_dt(i,kk) * dtp - gq0_ntsw(i,k) = qs1(i,kk) + qs_dt(i,kk) * dtp - gq0_ntgl(i,k) = qg1(i,kk) + qg_dt(i,kk) * dtp - gq0_ntclamt(i,k) = qa1(i,kk) + qa_dt(i,kk) * dtp - gt0(i,k) = gt0(i,k) + pt_dt(i,kk) * dtp - gu0(i,k) = gu0(i,k) + u_dt(i,kk) * dtp - gv0(i,k) = gv0(i,k) + v_dt(i,kk) * dtp - refl_10cm(i,k) = refl(i,kk) - enddo - enddo - - ! output ice and liquid water 3d precipitation fluxes if requested - if (cplchm) then - do k=1,levs - kk = levs-k+1 - do i=1,im - pfi_lsan(i,k) = pfils(i,1,kk) - pfl_lsan(i,k) = pflls(i,1,kk) - enddo - enddo - endif - - if(effr_in) then - allocate(den(1:im,1:levs)) - do k=1,levs - do i=1,im - den(i,k)=con_eps*prsl(i,k)/(con_rd*gt0(i,k)*(gq0(i,k)+con_eps)) - enddo - enddo - call cloud_diagnosis (1, im, 1, levs, den(1:im,1:levs), & - del(1:im,1:levs), islmsk(1:im), & - gq0_ntcw(1:im,1:levs), gq0_ntiw(1:im,1:levs), & - gq0_ntrw(1:im,1:levs), & - gq0_ntsw(1:im,1:levs) + gq0_ntgl(1:im,1:levs), & - gq0_ntgl(1:im,1:levs)*0.0, gt0(1:im,1:levs), & - rew(1:im,1:levs), rei(1:im,1:levs), rer(1:im,1:levs),& - res(1:im,1:levs), reg(1:im,1:levs)) - deallocate(den) - endif - - end subroutine gfdl_cloud_microphys_run - -end module gfdl_cloud_microphys diff --git a/physics/MP/GFDL/gfdl_cloud_microphys.meta b/physics/MP/GFDL/gfdl_cloud_microphys.meta deleted file mode 100644 index 719a340e5..000000000 --- a/physics/MP/GFDL/gfdl_cloud_microphys.meta +++ /dev/null @@ -1,482 +0,0 @@ -[ccpp-table-properties] - name = gfdl_cloud_microphys - type = scheme - dependencies = ../../hooks/machine.F - dependencies = ../module_mp_radar.F90 - dependencies = module_gfdl_cloud_microphys.F90 - -######################################################################## -[ccpp-arg-table] - name = gfdl_cloud_microphys_init - type = scheme -[me] - standard_name = mpi_rank - long_name = MPI rank of current process - units = index - dimensions = () - type = integer - intent = in -[master] - standard_name = mpi_root - long_name = MPI rank of master process - units = index - dimensions = () - type = integer - intent = in -[nlunit] - standard_name = iounit_of_namelist - long_name = fortran unit number for opening nameliust file - units = none - dimensions = () - type = integer - intent = in -[input_nml_file] - standard_name = filename_of_internal_namelist - long_name = character string to store full namelist contents - units = none - dimensions = (number_of_lines_in_internal_namelist) - type = character - kind = len=* - intent = in -[logunit] - standard_name = iounit_of_log - long_name = fortran unit number for writing logfile - units = none - dimensions = () - type = integer - intent = in -[fn_nml] - standard_name = filename_of_namelist - long_name = namelist filename - units = none - dimensions = () - type = character - kind = len=* - intent = in -[imp_physics] - standard_name = control_for_microphysics_scheme - long_name = choice of microphysics scheme - units = flag - dimensions = () - type = integer - intent = in -[imp_physics_gfdl] - standard_name = identifier_for_gfdl_microphysics_scheme - long_name = choice of GFDL microphysics scheme - units = flag - dimensions = () - type = integer - intent = in -[do_shoc] - standard_name = flag_for_shoc - long_name = flag to indicate use of SHOC - units = flag - dimensions = () - type = logical - intent = in -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - -######################################################################## -[ccpp-arg-table] - name = gfdl_cloud_microphys_finalize - type = scheme -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - -######################################################################## -[ccpp-arg-table] - name = gfdl_cloud_microphys_run - type = scheme -[levs] - standard_name = vertical_layer_dimension - long_name = number of vertical levels - units = count - dimensions = () - type = integer - intent = in -[im] - standard_name = horizontal_loop_extent - long_name = horizontal loop extent - units = count - dimensions = () - type = integer - intent = in -[rainmin] - standard_name = lwe_thickness_of_minimum_rain_amount - long_name = minimum rain amount - units = m - dimensions = () - type = real - kind = kind_phys - intent = in -[con_g] - standard_name = gravitational_acceleration - long_name = gravitational acceleration - units = m s-2 - dimensions = () - type = real - kind = kind_phys - intent = in -[con_fvirt] - standard_name = ratio_of_vapor_to_dry_air_gas_constants_minus_one - long_name = rv/rd - 1 (rv = ideal gas constant for water vapor) - units = none - dimensions = () - type = real - kind = kind_phys - intent = in -[con_rd] - standard_name = gas_constant_of_dry_air - long_name = ideal gas constant for dry air - units = J kg-1 K-1 - dimensions = () - type = real - kind = kind_phys - intent = in -[con_eps] - standard_name = ratio_of_dry_air_to_water_vapor_gas_constants - long_name = rd/rv - units = none - dimensions = () - type = real - kind = kind_phys - intent = in -[frland] - standard_name = land_area_fraction_for_microphysics - long_name = land area fraction used in microphysics schemes - units = frac - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = in -[garea] - standard_name = cell_area - long_name = area of grid cell - units = m2 - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = in -[islmsk] - standard_name = sea_land_ice_mask - long_name = sea/land/ice mask (=0/1/2) - units = flag - dimensions = (horizontal_loop_extent) - type = integer - intent = in -[gq0] - standard_name = specific_humidity_of_new_state - long_name = water vapor specific humidity updated by physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gq0_ntcw] - standard_name = cloud_liquid_water_mixing_ratio_of_new_state - long_name = cloud condensed water mixing ratio updated by physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gq0_ntrw] - standard_name = rain_mixing_ratio_of_new_state - long_name = moist mixing ratio of rain updated by physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gq0_ntiw] - standard_name = cloud_ice_mixing_ratio_of_new_state - long_name = moist mixing ratio of cloud ice updated by physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gq0_ntsw] - standard_name = snow_mixing_ratio_of_new_state - long_name = moist mixing ratio of snow updated by physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gq0_ntgl] - standard_name = graupel_mixing_ratio_of_new_state - long_name = moist ratio of mass of graupel to mass of dry air plus vapor (without condensates) updated by physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gq0_ntclamt] - standard_name = cloud_area_fraction_in_atmosphere_layer_of_new_state - long_name = cloud fraction updated by physics - units = frac - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gt0] - standard_name = air_temperature_of_new_state - long_name = air temperature updated by physics - units = K - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gu0] - standard_name = x_wind_of_new_state - long_name = zonal wind updated by physics - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[gv0] - standard_name = y_wind_of_new_state - long_name = meridional wind updated by physics - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[vvl] - standard_name = lagrangian_tendency_of_air_pressure - long_name = layer mean vertical velocity - units = Pa s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[prsl] - standard_name = air_pressure - long_name = mean layer pressure - units = Pa - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[phii] - standard_name = geopotential_at_interface - long_name = geopotential at model layer interfaces - units = m2 s-2 - dimensions = (horizontal_loop_extent,vertical_interface_dimension) - type = real - kind = kind_phys - intent = in -[del] - standard_name = air_pressure_difference_between_midlayers - long_name = air pressure difference between mid-layers - units = Pa - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[rain0] - standard_name = lwe_thickness_of_explicit_rain_amount - long_name = explicit rain on physics timestep - units = m - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = out -[ice0] - standard_name = lwe_thickness_of_ice_amount - long_name = ice fall on physics timestep - units = m - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = out -[snow0] - standard_name = lwe_thickness_of_snow_amount - long_name = snow fall on physics timestep - units = m - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = out -[graupel0] - standard_name = lwe_thickness_of_graupel_amount - long_name = graupel fall on physics timestep - units = m - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = out -[prcp0] - standard_name = lwe_thickness_of_explicit_precipitation_amount - long_name = explicit precipitation (rain, ice, snow, graupel) on physics timestep - units = m - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = out -[sr] - standard_name = ratio_of_snowfall_to_rainfall - long_name = snow ratio: ratio of snow to total precipitation - units = frac - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = out -[dtp] - standard_name = timestep_for_physics - long_name = physics timestep - units = s - dimensions = () - type = real - kind = kind_phys - intent = in -[hydrostatic] - standard_name = flag_for_hydrostatic_solver - long_name = flag indicating hydrostatic solver - units = flag - dimensions = () - type = logical - intent = in -[phys_hydrostatic] - standard_name = flag_for_hydrostatic_heating_from_physics - long_name = flag indicating hydrostatic heating from physics - units = flag - dimensions = () - type = logical - intent = in -[lradar] - standard_name = flag_for_radar_reflectivity - long_name = flag for radar reflectivity - units = flag - dimensions = () - type = logical - intent = in -[refl_10cm] - standard_name = radar_reflectivity_10cm - long_name = instantaneous refl_10cm - units = dBZ - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[reset] - standard_name = flag_reset_maximum_hourly_fields - long_name = flag for resetting maximum hourly fields - units = flag - dimensions = () - type = logical - intent = in -[effr_in] - standard_name = flag_for_cloud_effective_radii - long_name = flag for cloud effective radii calculations in GFDL microphysics - units = flag - dimensions = () - type = logical - intent = in -[rew] - standard_name = effective_radius_of_stratiform_cloud_liquid_water_particle - long_name = eff. radius of cloud liquid water particle in micrometer - units = um - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[rei] - standard_name = effective_radius_of_stratiform_cloud_ice_particle - long_name = eff. radius of cloud ice water particle in micrometer - units = um - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[rer] - standard_name = effective_radius_of_stratiform_cloud_rain_particle - long_name = effective radius of cloud rain particle in micrometers - units = um - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[res] - standard_name = effective_radius_of_stratiform_cloud_snow_particle - long_name = effective radius of cloud snow particle in micrometers - units = um - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[reg] - standard_name = effective_radius_of_stratiform_cloud_graupel_particle - long_name = eff. radius of cloud graupel particle in micrometer - units = um - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[cplchm] - standard_name = flag_for_chemistry_coupling - long_name = flag controlling cplchm collection (default off) - units = flag - dimensions = () - type = logical - intent = in -[pfi_lsan] - standard_name = ice_flux_due_to_large_scale_precipitation - long_name = instantaneous 3D flux of ice from nonconvective precipitation - units = kg m-2 s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[pfl_lsan] - standard_name = liquid_flux_due_to_large_scale_precipitation - long_name = instantaneous 3D flux of liquid water from nonconvective precipitation - units = kg m-2 s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out diff --git a/physics/MP/GFDL/module_gfdl_cloud_microphys.F90 b/physics/MP/GFDL/module_gfdl_cloud_microphys.F90 deleted file mode 100644 index 5cab1abbc..000000000 --- a/physics/MP/GFDL/module_gfdl_cloud_microphys.F90 +++ /dev/null @@ -1,5075 +0,0 @@ -!> \file gfdl_cloud_microphys.F90 -!! This file contains the full GFDL cloud microphysics (Chen and Lin (2013) -!! \cite chen_and_lin_2013 and Zhou et al. 2019 \cite zhou_etal_2019). -!! The module is paired with 'gfdl_fv_sat_adj', which performs the "fast" -!! processes -!>author Shian-Jiann Lin, Linjiong Zhou -!*********************************************************************** -!* GNU Lesser General Public License -!* -!* This file is part of the GFDL Cloud Microphysics. -!* -!* The GFDL Cloud Microphysics is free software: you can -!* 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 . -!*********************************************************************** -! ======================================================================= -!>\defgroup mod_gfdl_cloud_mp GFDL Cloud MP modules -!!\ingroup gfdlmp -!! This module contains the column GFDL Cloud microphysics scheme. -module gfdl_cloud_microphys_mod - - ! use mpp_mod, only: stdlog, mpp_pe, mpp_root_pe, mpp_clock_id, & - ! mpp_clock_begin, mpp_clock_end, clock_routine, & - ! input_nml_file - ! use diag_manager_mod, only: register_diag_field, send_data - ! use time_manager_mod, only: time_type, get_time - ! use constants_mod, only: grav, rdgas, rvgas, cp_air, hlv, hlf, pi => pi_8 - ! use fms_mod, only: write_version_number, open_namelist_file, & - ! check_nml_error, file_exist, close_file - - use module_mp_radar - - implicit none - - private - - public gfdl_cloud_microphys_mod_driver, gfdl_cloud_microphys_mod_init, & - gfdl_cloud_microphys_mod_end, cloud_diagnosis -! public wqs1, wqs2, qs_blend, wqsat_moist, wqsat2_moist -! public qsmith_init, qsmith, es2_table1d, es3_table1d, esw_table1d -! public setup_con, wet_bulb - - real :: missing_value = - 1.e10 - - logical :: module_is_initialized = .false. - logical :: qsmith_tables_initialized = .false. - - character (len = 17) :: mod_name = 'gfdl_cloud_microphys' - - real, parameter :: n0r = 8.0e6, n0s = 3.0e6, n0g = 4.0e6 - real, parameter :: rhos = 0.1e3, rhog = 0.4e3 - real, parameter :: grav = 9.80665 !< gfs: acceleration due to gravity - real, parameter :: rdgas = 287.05 !< gfs: gas constant for dry air - real, parameter :: rvgas = 461.50 !< gfs: gas constant for water vapor - real, parameter :: cp_air = 1004.6 !< gfs: heat capacity of dry air at constant pressure - real, parameter :: hlv = 2.5e6 !< gfs: latent heat of evaporation - real, parameter :: hlf = 3.3358e5 !< gfs: latent heat of fusion - real, parameter :: pi = 3.1415926535897931 !< gfs: ratio of circle circumference to diameter - - ! real, parameter :: rdgas = 287.04 !< gfdl: gas constant for dry air - - ! real, parameter :: cp_air = rdgas * 7. / 2. ! 1004.675, heat capacity of dry air at constant pressure - real, parameter :: cp_vap = 4.0 * rvgas !< 1846.0, heat capacity of water vapore at constnat pressure - ! real, parameter :: cv_air = 717.56 ! satoh value - real, parameter :: cv_air = cp_air - rdgas !< 717.55, heat capacity of dry air at constant volume - ! real, parameter :: cv_vap = 1410.0 ! emanuel value - real, parameter :: cv_vap = 3.0 * rvgas !< 1384.5, heat capacity of water vapor at constant volume - - ! the following two are from emanuel's book "atmospheric convection" - ! real, parameter :: c_ice = 2106.0 ! heat capacity of ice at 0 deg c: c = c_ice + 7.3 * (t - tice) - ! real, parameter :: c_liq = 4190.0 ! heat capacity of water at 0 deg c - - real, parameter :: c_ice = 1972.0 !< gfdl: heat capacity of ice at - 15 deg c - real, parameter :: c_liq = 4185.5 !< gfdl: heat capacity of water at 15 deg c - ! real, parameter :: c_liq = 4218.0 ! ifs: heat capacity of liquid at 0 deg c - - real, parameter :: eps = rdgas / rvgas !< 0.6219934995 - real, parameter :: zvir = rvgas / rdgas - 1. !< 0.6077338443 - - real, parameter :: t_ice = 273.16 !< freezing temperature - real, parameter :: table_ice = 273.16 !< freezing point for qs table - - ! real, parameter :: e00 = 610.71 ! gfdl: saturation vapor pressure at 0 deg c - real, parameter :: e00 = 611.21 !< ifs: saturation vapor pressure at 0 deg c - - real, parameter :: dc_vap = cp_vap - c_liq !< - 2339.5, isobaric heating / cooling - real, parameter :: dc_ice = c_liq - c_ice !< 2213.5, isobaric heating / colling - - real, parameter :: hlv0 = hlv !< gfs: evaporation latent heat coefficient at 0 deg c - ! real, parameter :: hlv0 = 2.501e6 ! emanuel appendix - 2 - real, parameter :: hlf0 = hlf !< gfs: fussion latent heat coefficient at 0 deg c - ! real, parameter :: hlf0 = 3.337e5 ! emanuel - - real, parameter :: lv0 = hlv0 - dc_vap * t_ice !< 3.13905782e6, evaporation latent heat coefficient at 0 deg k - real, parameter :: li00 = hlf0 - dc_ice * t_ice !< - 2.7105966e5, fusion latent heat coefficient at 0 deg k - - real, parameter :: d2ice = dc_vap + dc_ice !< - 126, isobaric heating/cooling - real, parameter :: li2 = lv0 + li00 !< 2.86799816e6, sublimation latent heat coefficient at 0 deg k - - real, parameter :: qrmin = 1.e-8 !< min value for rain - real, parameter :: qvmin = 1.e-20 !< min value for water vapor (treated as zero) - real, parameter :: qcmin = 1.e-12 !< min value for cloud condensates - - real, parameter :: vr_min = 1.e-3 !< min fall speed for rain - real, parameter :: vf_min = 1.e-5 !< min fall speed for cloud ice, snow, graupel - - real, parameter :: dz_min = 1.e-2 !< use for correcting flipped height - - real, parameter :: sfcrho = 1.2 !< surface air density - real, parameter :: rhor = 1.e3 !< density of rain water, lin83 - ! intercept parameters - - real, parameter :: rnzr = 8.0e6 ! lin83 - real, parameter :: rnzs = 3.0e6 ! lin83 - real, parameter :: rnzg = 4.0e6 ! rh84 - real, parameter :: rnzh = 4.0e4 ! lin83 --- lmh 29 sep 17 - - ! density parameters - - real, parameter :: rhoh = 0.917e3 ! lin83 --- lmh 29 sep 17 - - public rhor, rhos, rhog, rhoh, rnzr, rnzs, rnzg, rnzh - real :: cracs, csacr, cgacr, cgacs, csacw, craci, csaci, cgacw, cgaci, cracw !< constants for accretions - real :: acco (3, 4) !< constants for accretions - real :: cssub (5), cgsub (5), crevp (5), cgfr (2), csmlt (5), cgmlt (5) - - real :: es0, ces0 - real :: pie, rgrav, fac_rc - real :: c_air, c_vap - - real :: lati, latv, lats, lat2, lcp, icp, tcp !< used in Bigg mechanism and wet bulk - - real :: d0_vap !< the same as dc_vap, except that cp_vap can be cp_vap or cv_vap - real :: lv00 !< the same as lv0, except that cp_vap can be cp_vap or cv_vap - - ! cloud microphysics switchers - - integer :: icloud_f = 0 !< cloud scheme - integer :: irain_f = 0 !< cloud water to rain auto conversion scheme - - logical :: de_ice = .false. !< to prevent excessive build - up of cloud ice from external sources - logical :: sedi_transport = .true. !< transport of momentum in sedimentation - logical :: do_sedi_w = .false. !< transport of vertical motion in sedimentation - logical :: do_sedi_heat = .true. !< transport of heat in sedimentation - logical :: prog_ccn = .false. !< do prognostic ccn (yi ming's method) - logical :: do_qa = .true. !< do inline cloud fraction - logical :: rad_snow = .true. !< consider snow in cloud fraciton calculation - logical :: rad_graupel = .true. !< consider graupel in cloud fraction calculation - logical :: rad_rain = .true. !< consider rain in cloud fraction calculation - logical :: fix_negative = .false. !< fix negative water species - logical :: do_setup = .true. !< setup constants and parameters - logical :: p_nonhydro = .false. !< perform hydrosatic adjustment on air density - - real, allocatable :: table (:), table2 (:), table3 (:), tablew (:) - real, allocatable :: des (:), des2 (:), des3 (:), desw (:) - - logical :: tables_are_initialized = .false. - - ! logical :: master - ! integer :: id_rh, id_vtr, id_vts, id_vtg, id_vti, id_rain, id_snow, id_graupel, & - ! id_ice, id_prec, id_cond, id_var, id_droplets - real, parameter :: dt_fr = 8. !< homogeneous freezing of all cloud water at t_wfr - dt_fr - ! minimum temperature water can exist (moore & molinero nov. 2011, nature) - ! dt_fr can be considered as the error bar - - real :: p_min = 100. !< minimum pressure (pascal) for mp to operate - - ! slj, the following parameters are for cloud - resolving resolution: 1 - 5 km - - ! qi0_crt = 0.8e-4 - ! qs0_crt = 0.6e-3 - ! c_psaci = 0.1 - ! c_pgacs = 0.1 - - ! ----------------------------------------------------------------------- - ! namelist parameters - ! ----------------------------------------------------------------------- - - real :: cld_min = 0.05 !< minimum cloud fraction - real :: tice = 273.16 !< set tice = 165. to trun off ice - phase phys (kessler emulator) - - real :: t_min = 178. !< min temp to freeze - dry all water vapor - real :: t_sub = 184. !< min temp for sublimation of cloud ice - real :: mp_time = 150. !< maximum micro - physics time step (sec) - - ! relative humidity increment - - real :: rh_inc = 0.25 !< rh increment for complete evaporation of cloud water and cloud ice - real :: rh_inr = 0.25 !< rh increment for minimum evaporation of rain - real :: rh_ins = 0.25 !< rh increment for sublimation of snow - - ! conversion time scale - - real :: tau_r2g = 900. !< rain freezing during fast_sat - real :: tau_smlt = 900. !< snow melting - real :: tau_g2r = 600. !< graupel melting to rain - real :: tau_imlt = 600. !< cloud ice melting - real :: tau_i2s = 1000. !< cloud ice to snow auto-conversion - real :: tau_l2r = 900. !< cloud water to rain auto-conversion - real :: tau_v2l = 150. !< water vapor to cloud water (condensation) - real :: tau_l2v = 300. !< cloud water to water vapor (evaporation) - real :: tau_g2v = 900. !< graupel sublimation - real :: tau_v2g = 21600. !< graupel deposition -- make it a slow process - - ! horizontal subgrid variability - - real :: dw_land = 0.20 !< base value for subgrid deviation / variability over land - real :: dw_ocean = 0.10 !< base value for ocean - - ! prescribed ccn - - real :: ccn_o = 90. !< ccn over ocean (cm^ - 3) - real :: ccn_l = 270. !< ccn over land (cm^ - 3) - - real :: rthresh = 10.0e-6 !< critical cloud drop radius (micro m) - - ! ----------------------------------------------------------------------- - ! wrf / wsm6 scheme: qi_gen = 4.92e-11 * (1.e3 * exp (0.1 * tmp)) ** 1.33 - ! optimized: qi_gen = 4.92e-11 * exp (1.33 * log (1.e3 * exp (0.1 * tmp))) - ! qi_gen ~ 4.808e-7 at 0 c; 1.818e-6 at - 10 c, 9.82679e-5 at - 40c - ! the following value is constructed such that qc_crt = 0 at zero c and @ - 10c matches - ! wrf / wsm6 ice initiation scheme; qi_crt = qi_gen * min (qi_lim, 0.1 * tmp) / den - ! ----------------------------------------------------------------------- - - real :: sat_adj0 = 0.90 !< adjustment factor (0: no, 1: full) during fast_sat_adj - - real :: qc_crt = 5.0e-8 !< mini condensate mixing ratio to allow partial cloudiness - - real :: qi_lim = 1. !< cloud ice limiter to prevent large ice build up - - real :: ql_mlt = 2.0e-3 !< max value of cloud water allowed from melted cloud ice - real :: qs_mlt = 1.0e-6 !< max cloud water due to snow melt - - real :: ql_gen = 1.0e-3 !< max cloud water generation during remapping step if fast_sat_adj = .t. - real :: qi_gen = 1.82e-6 !< max cloud ice generation during remapping step - - ! cloud condensate upper bounds: "safety valves" for ql & qi - - real :: ql0_max = 2.0e-3 !< max cloud water value (auto converted to rain) - real :: qi0_max = 1.0e-4 !< max cloud ice value (by other sources) - - real :: qi0_crt = 1.0e-4 !< cloud ice to snow autoconversion threshold (was 1.e-4); - !! qi0_crt is highly dependent on horizontal resolution - real :: qr0_crt = 1.0e-4 !< rain to snow or graupel/hail threshold - ! lfo used * mixing ratio * = 1.e-4 (hail in lfo) - real :: qs0_crt = 1.0e-3 !< snow to graupel density threshold (0.6e-3 in purdue lin scheme) - - real :: c_paut = 0.55 !< autoconversion cloud water to rain (use 0.5 to reduce autoconversion) - real :: c_psaci = 0.02 !< accretion: cloud ice to snow (was 0.1 in zetac) - real :: c_piacr = 5.0 !< accretion: rain to ice: - real :: c_cracw = 0.9 !< rain accretion efficiency - real :: c_pgacs = 2.0e-3 !< snow to graupel "accretion" eff. (was 0.1 in zetac) - - ! decreasing clin to reduce csacw (so as to reduce cloud water --- > snow) - - real :: alin = 842.0 !< "a" in lin1983 - real :: clin = 4.8 !< "c" in lin 1983, 4.8 -- > 6. (to ehance ql -- > qs) - - ! fall velocity tuning constants: - - logical :: const_vi = .false. !< if .t. the constants are specified by v * _fac - logical :: const_vs = .false. !< if .t. the constants are specified by v * _fac - logical :: const_vg = .false. !< if .t. the constants are specified by v * _fac - logical :: const_vr = .false. !< if .t. the constants are specified by v * _fac - - ! good values: - - real :: vi_fac = 1. !< if const_vi: 1 / 3 - real :: vs_fac = 1. !< if const_vs: 1. - real :: vg_fac = 1. !< if const_vg: 2. - real :: vr_fac = 1. !< if const_vr: 4. - - ! upper bounds of fall speed (with variable speed option) - - real :: vi_max = 0.5 !< max fall speed for ice - real :: vs_max = 5.0 !< max fall speed for snow - real :: vg_max = 8.0 !< max fall speed for graupel - real :: vr_max = 12. !< max fall speed for rain - - ! cloud microphysics switchers - - logical :: fast_sat_adj = .false. !< has fast saturation adjustments - logical :: z_slope_liq = .true. !< use linear mono slope for autocconversions - logical :: z_slope_ice = .false. !< use linear mono slope for autocconversions - logical :: use_ccn = .false. !< must be true when prog_ccn is false - logical :: use_ppm = .false. !< use ppm fall scheme - logical :: mono_prof = .true. !< perform terminal fall with mono ppm scheme - logical :: mp_print = .false. !< cloud microphysics debugging printout - logical :: do_hail = .false. !< use hail parameters instead of graupel - - ! real :: global_area = - 1. - - real :: log_10, tice0, t_wfr - - integer :: reiflag = 1 - ! 1: Heymsfield and Mcfarquhar, 1996 - ! 2: Wyser, 1998 - - logical :: tintqs = .false. !< use temperature in the saturation mixing in PDF - - real :: rewmin = 5.0, rewmax = 10.0 - real :: reimin = 10.0, reimax = 150.0 - real :: rermin = 10.0, rermax = 10000.0 - real :: resmin = 150.0, resmax = 10000.0 - real :: regmin = 300.0, regmax = 10000.0 - - ! ----------------------------------------------------------------------- - ! namelist - ! ----------------------------------------------------------------------- - - namelist / gfdl_cloud_microphysics_nml / & - mp_time, t_min, t_sub, tau_r2g, tau_smlt, tau_g2r, dw_land, dw_ocean, & - vi_fac, vr_fac, vs_fac, vg_fac, ql_mlt, do_qa, fix_negative, vi_max, & - vs_max, vg_max, vr_max, qs_mlt, qs0_crt, qi_gen, ql0_max, qi0_max, & - qi0_crt, qr0_crt, fast_sat_adj, rh_inc, rh_ins, rh_inr, const_vi, & - const_vs, const_vg, const_vr, use_ccn, rthresh, ccn_l, ccn_o, qc_crt, & - tau_g2v, tau_v2g, sat_adj0, c_piacr, tau_imlt, tau_v2l, tau_l2v, & - tau_i2s, tau_l2r, qi_lim, ql_gen, c_paut, c_psaci, c_pgacs, & - z_slope_liq, z_slope_ice, prog_ccn, c_cracw, alin, clin, tice, & - rad_snow, rad_graupel, rad_rain, cld_min, use_ppm, mono_prof, & - do_sedi_heat, sedi_transport, do_sedi_w, de_ice, icloud_f, irain_f, & - mp_print, reiflag, rewmin, rewmax, reimin, reimax, rermin, rermax, & - resmin, resmax, regmin, regmax, tintqs, do_hail - - public & - mp_time, t_min, t_sub, tau_r2g, tau_smlt, tau_g2r, dw_land, dw_ocean, & - vi_fac, vr_fac, vs_fac, vg_fac, ql_mlt, do_qa, fix_negative, vi_max, & - vs_max, vg_max, vr_max, qs_mlt, qs0_crt, qi_gen, ql0_max, qi0_max, & - qi0_crt, qr0_crt, fast_sat_adj, rh_inc, rh_ins, rh_inr, const_vi, & - const_vs, const_vg, const_vr, use_ccn, rthresh, ccn_l, ccn_o, qc_crt, & - tau_g2v, tau_v2g, sat_adj0, c_piacr, tau_imlt, tau_v2l, tau_l2v, & - tau_i2s, tau_l2r, qi_lim, ql_gen, c_paut, c_psaci, c_pgacs, & - z_slope_liq, z_slope_ice, prog_ccn, c_cracw, alin, clin, tice, & - rad_snow, rad_graupel, rad_rain, cld_min, use_ppm, mono_prof, & - do_sedi_heat, sedi_transport, do_sedi_w, de_ice, icloud_f, irain_f, & - mp_print, reiflag, rewmin, rewmax, reimin, reimax, rermin, rermax, & - resmin, resmax, regmin, regmax, tintqs, do_hail - -contains - -! ----------------------------------------------------------------------- -! the driver of the gfdl cloud microphysics -! ----------------------------------------------------------------------- - -!>\ingroup mod_gfdl_cloud_mp -!! This subroutine is the driver of the GFDL cloud microphysics -subroutine gfdl_cloud_microphys_mod_driver ( & - iis, iie, jjs, jje, kks, kke, ktop, kbot, & - qv, ql, qr, qi, qs, qg, qa, qn, & - qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt, qa_dt, pt_dt, pt, w, & - uin, vin, udt, vdt, dz, delp, area, dt_in, land, & - rain, snow, ice, graupel, hydrostatic, phys_hydrostatic, & - p, lradar, refl_10cm, reset, pfils, pflls) - - implicit none - - ! Interface variables - integer, intent (in) :: iis, iie, jjs, jje ! physics window - integer, intent (in) :: kks, kke ! vertical dimension - integer, intent (in) :: ktop, kbot ! vertical compute domain - - real, intent (in) :: dt_in ! physics time step - - real, intent (in), dimension (iis:iie, jjs:jje) :: area ! cell area - real, intent (in), dimension (iis:iie, jjs:jje) :: land ! land fraction - - real, intent (in), dimension (iis:iie, jjs:jje, kks:kke) :: delp, dz, uin, vin - real, intent (in), dimension (iis:iie, jjs:jje, kks:kke) :: pt, qv, ql, qr, qg, qa, qn - - real, intent (inout), dimension (iis:iie, jjs:jje, kks:kke) :: qi, qs - real, intent (inout), dimension (iis:iie, jjs:jje, kks:kke) :: pt_dt, qa_dt, udt, vdt, w - real, intent (inout), dimension (iis:iie, jjs:jje, kks:kke) :: qv_dt, ql_dt, qr_dt - real, intent (inout), dimension (iis:iie, jjs:jje, kks:kke) :: qi_dt, qs_dt, qg_dt - - real, intent (out), dimension (iis:iie, jjs:jje) :: rain, snow, ice, graupel - - logical, intent (in) :: hydrostatic, phys_hydrostatic - - !integer, intent (in) :: seconds - real, intent (in), dimension (iis:iie, jjs:jje, kks:kke) :: p - logical, intent (in) :: lradar - real, intent (out), dimension (iis:iie, jjs:jje, kks:kke) :: refl_10cm - logical, intent (in) :: reset - real, intent (out), dimension (iis:iie, jjs:jje, kks:kke) :: pfils, pflls - - ! Local variables - logical :: melti = .false. - - real :: mpdt, rdt, dts, convt, tot_prec - - integer :: i, j, k - integer :: is, ie, js, je ! physics window - integer :: ks, ke ! vertical dimension - integer :: days, ntimes, kflip - - real, dimension (iie-iis+1, jje-jjs+1) :: prec_mp, prec1, cond, w_var, rh0 - - real, dimension (iie-iis+1, jje-jjs+1,kke-kks+1) :: vt_r, vt_s, vt_g, vt_i, qn2 - - real, dimension (size(pt,1), size(pt,3)) :: m2_rain, m2_sol - - real :: allmax -!+---+-----------------------------------------------------------------+ -!For 3D reflectivity calculations - real, dimension(ktop:kbot):: qv1d, t1d, p1d, qr1d, qs1d, qg1d, dBZ -!+---+-----------------------------------------------------------------+ - - is = 1 - js = 1 - ks = 1 - ie = iie - iis + 1 - je = jje - jjs + 1 - ke = kke - kks + 1 - ! call mpp_clock_begin (gfdl_mp_clock) - - ! ----------------------------------------------------------------------- - ! define heat capacity of dry air and water vapor based on hydrostatical property - ! ----------------------------------------------------------------------- - - if (phys_hydrostatic .or. hydrostatic) then - c_air = cp_air - c_vap = cp_vap - p_nonhydro = .false. - else - c_air = cv_air - c_vap = cv_vap - p_nonhydro = .true. - endif - d0_vap = c_vap - c_liq - lv00 = hlv0 - d0_vap * t_ice - - if (hydrostatic) do_sedi_w = .false. - - ! ----------------------------------------------------------------------- - ! define latent heat coefficient used in wet bulb and Bigg mechanism - ! ----------------------------------------------------------------------- - - latv = hlv - lati = hlf - lats = latv + lati - lat2 = lats * lats - - lcp = latv / cp_air - icp = lati / cp_air - tcp = (latv + lati) / cp_air - - ! tendency zero out for am moist processes should be done outside the driver - - ! ----------------------------------------------------------------------- - ! define cloud microphysics sub time step - ! ----------------------------------------------------------------------- - - mpdt = min (dt_in, mp_time) - rdt = 1. / dt_in - ntimes = nint (dt_in / mpdt) - - ! small time step: - dts = dt_in / real (ntimes) - - ! call get_time (time, seconds, days) - - ! ----------------------------------------------------------------------- - ! initialize precipitation - ! ----------------------------------------------------------------------- - - do j = js, je - do i = is, ie - graupel (i, j) = 0. - rain (i, j) = 0. - snow (i, j) = 0. - ice (i, j) = 0. - cond (i, j) = 0. - enddo - enddo - - pfils = 0. - pflls = 0. - - ! ----------------------------------------------------------------------- - ! major cloud microphysics - ! ----------------------------------------------------------------------- - - do j = js, je - call mpdrv (hydrostatic, uin, vin, w, delp, pt, qv, ql, qr, qi, qs, qg,& - qa, qn, dz, is, ie, js, je, ks, ke, ktop, kbot, j, dt_in, ntimes, & - rain (:, j), snow (:, j), graupel (:, j), ice (:, j), m2_rain, & - m2_sol, cond (:, j), area (:, j), land (:, j), udt, vdt, pt_dt, & - qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt, qa_dt, w_var, vt_r, & - vt_s, vt_g, vt_i, qn2) - do k = ktop, kbot - do i = is, ie - pfils(i, j, k) = m2_sol (i, k) - pflls(i, j, k) = m2_rain(i, k) - enddo - enddo - enddo - - ! ----------------------------------------------------------------------- - ! no clouds allowed above ktop - ! ----------------------------------------------------------------------- - - if (ks < ktop) then - do k = ks, ktop - if (do_qa) then - do j = js, je - do i = is, ie - qa_dt (i, j, k) = 0. - enddo - enddo - else - do j = js, je - do i = is, ie - ! qa_dt (i, j, k) = - qa (i, j, k) * rdt - qa_dt (i, j, k) = 0. ! gfs - enddo - enddo - endif - enddo - endif - - ! ----------------------------------------------------------------------- - ! diagnostic output - ! ----------------------------------------------------------------------- - - ! if (id_vtr > 0) then - ! used = send_data (id_vtr, vt_r, time, is_in = iis, js_in = jjs) - ! endif - - ! if (id_vts > 0) then - ! used = send_data (id_vts, vt_s, time, is_in = iis, js_in = jjs) - ! endif - - ! if (id_vtg > 0) then - ! used = send_data (id_vtg, vt_g, time, is_in = iis, js_in = jjs) - ! endif - - ! if (id_vti > 0) then - ! used = send_data (id_vti, vt_i, time, is_in = iis, js_in = jjs) - ! endif - - ! if (id_droplets > 0) then - ! used = send_data (id_droplets, qn2, time, is_in = iis, js_in = jjs) - ! endif - - ! if (id_var > 0) then - ! used = send_data (id_var, w_var, time, is_in = iis, js_in = jjs) - ! endif - - ! convert to mm / day - - convt = 86400. * rdt * rgrav - do j = js, je - do i = is, ie - rain (i, j) = rain (i, j) * convt - snow (i, j) = snow (i, j) * convt - ice (i, j) = ice (i, j) * convt - graupel (i, j) = graupel (i, j) * convt - prec_mp (i, j) = rain (i, j) + snow (i, j) + ice (i, j) + graupel (i, j) - enddo - enddo - - ! if (id_cond > 0) then - ! do j = js, je - ! do i = is, ie - ! cond (i, j) = cond (i, j) * rgrav - ! enddo - ! enddo - ! used = send_data (id_cond, cond, time, is_in = iis, js_in = jjs) - ! endif - - ! if (id_snow > 0) then - ! used = send_data (id_snow, snow, time, iis, jjs) - ! used = send_data (id_snow, snow, time, is_in = iis, js_in = jjs) - ! if (mp_print .and. seconds == 0) then - ! tot_prec = g_sum (snow, is, ie, js, je, area, 1) - ! if (master) write (*, *) 'mean snow = ', tot_prec - ! endif - ! endif - ! - ! if (id_graupel > 0) then - ! used = send_data (id_graupel, graupel, time, iis, jjs) - ! used = send_data (id_graupel, graupel, time, is_in = iis, js_in = jjs) - ! if (mp_print .and. seconds == 0) then - ! tot_prec = g_sum (graupel, is, ie, js, je, area, 1) - ! if (master) write (*, *) 'mean graupel = ', tot_prec - ! endif - ! endif - ! - ! if (id_ice > 0) then - ! used = send_data (id_ice, ice, time, iis, jjs) - ! used = send_data (id_ice, ice, time, is_in = iis, js_in = jjs) - ! if (mp_print .and. seconds == 0) then - ! tot_prec = g_sum (ice, is, ie, js, je, area, 1) - ! if (master) write (*, *) 'mean ice_mp = ', tot_prec - ! endif - ! endif - ! - ! if (id_rain > 0) then - ! used = send_data (id_rain, rain, time, iis, jjs) - ! used = send_data (id_rain, rain, time, is_in = iis, js_in = jjs) - ! if (mp_print .and. seconds == 0) then - ! tot_prec = g_sum (rain, is, ie, js, je, area, 1) - ! if (master) write (*, *) 'mean rain = ', tot_prec - ! endif - ! endif - ! - ! if (id_rh > 0) then !not used? - ! used = send_data (id_rh, rh0, time, iis, jjs) - ! used = send_data (id_rh, rh0, time, is_in = iis, js_in = jjs) - ! endif - ! - ! - ! if (id_prec > 0) then - ! used = send_data (id_prec, prec_mp, time, iis, jjs) - ! used = send_data (id_prec, prec_mp, time, is_in = iis, js_in = jjs) - ! endif - - ! if (mp_print) then - ! prec1 (:, :) = prec1 (:, :) + prec_mp (:, :) - ! if (seconds == 0) then - ! prec1 (:, :) = prec1 (:, :) * dt_in / 86400. - ! tot_prec = g_sum (prec1, is, ie, js, je, area, 1) - ! if (master) write (*, *) 'daily prec_mp = ', tot_prec - ! prec1 (:, :) = 0. - ! endif - ! endif - - ! call mpp_clock_end (gfdl_mp_clock) - if(lradar) then - ! Only set melti to true at the output times - if (reset) then - melti=.true. - else - melti=.false. - endif - do j = js, je - do i = is, ie - do k = ktop,kbot - kflip = kbot-ktop+1-k+1 - t1d(k) = pt(i,j,kflip) - p1d(k) = p(i,j,kflip) - qv1d(k) = qv(i,j,kflip)/(1-qv(i,j,kflip)) - qr1d(k) = qr(i,j,kflip) - qs1d(k) = qs(i,j,kflip) - qg1d(k) = qg(i,j,kflip) - enddo - call refl10cm_gfdl (qv1d, qr1d, qs1d, qg1d, & - t1d, p1d, dBZ, ktop, kbot, i, j, melti) - do k = ktop,kbot - kflip = kbot-ktop+1-k+1 - refl_10cm(i,j,kflip) = MAX(-35., dBZ(k)) - enddo - enddo - enddo - endif - -end subroutine gfdl_cloud_microphys_mod_driver - -! ----------------------------------------------------------------------- -!>\ingroup mod_gfdl_cloud_mp -!>\brief GFDL cloud microphysics, major program, and is based on -!! Lin et al.(1983) \cite lin_et_al_1983 and -!! Rutledge and Hobbs (1984) \cite rutledge_and_hobbs_1984. -!! -!>\section detmpdrv GFDL Cloud mpdrv General Algorithm -subroutine mpdrv (hydrostatic, uin, vin, w, delp, pt, qv, ql, qr, qi, qs, & - qg, qa, qn, dz, is, ie, js, je, ks, ke, ktop, kbot, j, dt_in, ntimes, & - rain, snow, graupel, ice, m2_rain, m2_sol, cond, area1, land, & - u_dt, v_dt, pt_dt, qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt, qa_dt, & - w_var, vt_r, vt_s, vt_g, vt_i, qn2) - - implicit none - - logical, intent (in) :: hydrostatic - - integer, intent (in) :: j, is, ie, js, je, ks, ke - integer, intent (in) :: ntimes, ktop, kbot - - real, intent (in) :: dt_in - - real, intent (in), dimension (is:) :: area1, land - - real, intent (in), dimension (is:, js:, ks:) :: uin, vin, delp, pt, dz - real, intent (in), dimension (is:, js:, ks:) :: qv, ql, qr, qg, qa, qn - - real, intent (inout), dimension (is:, js:, ks:) :: qi, qs - real, intent (inout), dimension (is:, js:, ks:) :: u_dt, v_dt, w, pt_dt, qa_dt - real, intent (inout), dimension (is:, js:, ks:) :: qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt - - real, intent (inout), dimension (is:) :: rain, snow, ice, graupel, cond - - real, intent (out), dimension (is:, js:) :: w_var - - real, intent (out), dimension (is:, js:, ks:) :: vt_r, vt_s, vt_g, vt_i, qn2 - - real, intent (out), dimension (is:, ks:) :: m2_rain, m2_sol - - real, dimension (ktop:kbot) :: qvz, qlz, qrz, qiz, qsz, qgz, qaz - real, dimension (ktop:kbot) :: vtiz, vtsz, vtgz, vtrz - real, dimension (ktop:kbot) :: dp0, dp1, dz0, dz1 - real, dimension (ktop:kbot) :: qv0, ql0, qr0, qi0, qs0, qg0, qa0 - real, dimension (ktop:kbot) :: t0, den, den0, tz, p1, denfac - real, dimension (ktop:kbot) :: ccn, c_praut, m1_rain, m1_sol, m1 - real, dimension (ktop:kbot) :: u0, v0, u1, v1, w1 - - real :: cpaut, rh_adj, rh_rain - real :: r1, s1, i1, g1, rdt, ccn0 - real :: dt_rain, dts - real :: s_leng, t_land, t_ocean, h_var - real :: cvm, tmp, omq - real :: dqi, qio, qin - - integer :: i, k, n - - dts = dt_in / real (ntimes) - dt_rain = dts * 0.5 - rdt = 1. / dt_in - - ! ----------------------------------------------------------------------- - ! use local variables - ! ----------------------------------------------------------------------- - - !GJF: assign values to intent(out) variables that are commented out - w_var = 0.0 - vt_r = 0.0 - vt_s = 0.0 - vt_g = 0.0 - vt_i = 0.0 - qn2 = 0.0 - !GJF - - do i = is, ie - - do k = ktop, kbot - qiz (k) = qi (i, j, k) - qsz (k) = qs (i, j, k) - enddo - - ! ----------------------------------------------------------------------- - !> - Prevent excessive build-up of cloud ice from external sources. - ! ----------------------------------------------------------------------- - - if (de_ice) then - do k = ktop, kbot - qio = qiz (k) - dt_in * qi_dt (i, j, k) ! original qi before phys - qin = max (qio, qi0_max) ! adjusted value - if (qiz (k) > qin) then - qsz (k) = qsz (k) + qiz (k) - qin - qiz (k) = qin - dqi = (qin - qio) * rdt ! modified qi tendency - qs_dt (i, j, k) = qs_dt (i, j, k) + qi_dt (i, j, k) - dqi - qi_dt (i, j, k) = dqi - qi (i, j, k) = qiz (k) - qs (i, j, k) = qsz (k) - endif - enddo - endif - - do k = ktop, kbot - - t0 (k) = pt (i, j, k) - tz (k) = t0 (k) - dp1 (k) = delp (i, j, k) - dp0 (k) = dp1 (k) ! moist air mass * grav - - ! ----------------------------------------------------------------------- - !> - Convert moist mixing ratios to dry mixing ratios. - ! ----------------------------------------------------------------------- - - qvz (k) = qv (i, j, k) - qlz (k) = ql (i, j, k) - qrz (k) = qr (i, j, k) - qgz (k) = qg (i, j, k) - - ! dp1: dry air_mass - ! dp1 (k) = dp1 (k) * (1. - (qvz (k) + qlz (k) + qrz (k) + qiz (k) + qsz (k) + qgz (k))) - dp1 (k) = dp1 (k) * (1. - qvz (k)) ! gfs - omq = dp0 (k) / dp1 (k) - - qvz (k) = qvz (k) * omq - qlz (k) = qlz (k) * omq - qrz (k) = qrz (k) * omq - qiz (k) = qiz (k) * omq - qsz (k) = qsz (k) * omq - qgz (k) = qgz (k) * omq - - qa0 (k) = qa (i, j, k) - qaz (k) = 0. - dz0 (k) = dz (i, j, k) - - den0 (k) = - dp1 (k) / (grav * dz0 (k)) ! density of dry air - p1 (k) = den0 (k) * rdgas * t0 (k) ! dry air pressure - - ! ----------------------------------------------------------------------- - ! save a copy of old value for computing tendencies - ! ----------------------------------------------------------------------- - - qv0 (k) = qvz (k) - ql0 (k) = qlz (k) - qr0 (k) = qrz (k) - qi0 (k) = qiz (k) - qs0 (k) = qsz (k) - qg0 (k) = qgz (k) - - ! ----------------------------------------------------------------------- - ! for sedi_momentum - ! ----------------------------------------------------------------------- - - m1 (k) = 0. - u0 (k) = uin (i, j, k) - v0 (k) = vin (i, j, k) - u1 (k) = u0 (k) - v1 (k) = v0 (k) - - enddo - - if (do_sedi_w) then - do k = ktop, kbot - w1 (k) = w (i, j, k) - enddo - ! Set to -999 if not used - else - w1(:) = -999.0 - endif - - ! ----------------------------------------------------------------------- - !> - Calculate cloud condensation nuclei (ccn), - !! following klein eq. 15 - ! ----------------------------------------------------------------------- - - cpaut = c_paut * 0.104 * grav / 1.717e-5 - - if (prog_ccn) then - do k = ktop, kbot - ! convert # / cc to # / m^3 - ccn (k) = qn (i, j, k) * 1.e6 - c_praut (k) = cpaut * (ccn (k) * rhor) ** (- 1. / 3.) - enddo - use_ccn = .false. - else - ccn0 = (ccn_l * land (i) + ccn_o * (1. - land (i))) * 1.e6 - if (use_ccn) then - ! ----------------------------------------------------------------------- - ! ccn is formulted as ccn = ccn_surface * (den / den_surface) - ! ----------------------------------------------------------------------- - ccn0 = ccn0 * rdgas * tz (kbot) / p1 (kbot) - endif - tmp = cpaut * (ccn0 * rhor) ** (- 1. / 3.) - do k = ktop, kbot - c_praut (k) = tmp - ccn (k) = ccn0 - enddo - endif - - ! ----------------------------------------------------------------------- - !> - Calculate horizontal subgrid variability, which is used in cloud - !! fraction, relative humidity calculation, evaporation and condensation - !! processes. Horizontal sub-grid variability is a function of cell area - !! and land/sea mask: - !!\n Over land: - !!\f[ - !! t_{land}=dw_{land}(\frac{A_{r}}{10^{10}})^{0.25} - !!\f] - !!\n Over ocean: - !!\f[ - !! t_{ocean}=dw_{ocean}(\frac{A_{r}}{10^{10}})^{0.25} - !!\f] - !! where \f$A_{r}\f$ is cell area. \f$dw_{land}=0.16\f$ and \f$dw_{ocean}=0.10\f$ - !! are base value for sub-grid variability over land and ocean. - !! The total horizontal sub-grid variability is: - !!\f[ - !! h_{var}=t_{land}\times fr_{land}+t_{ocean}\times (1-fr_{land}) - !!\f] - !!\f[ - !! h_{var}=min[0.2,max(0.01,h_{var})] - !!\f] - ! total water subgrid deviation in horizontal direction - ! default area dependent form: use dx ~ 100 km as the base - ! ----------------------------------------------------------------------- - - s_leng = sqrt (sqrt (area1 (i) / 1.e10)) - t_land = dw_land * s_leng - t_ocean = dw_ocean * s_leng - h_var = t_land * land (i) + t_ocean * (1. - land (i)) - h_var = min (0.20, max (0.01, h_var)) - ! if (id_var > 0) w_var (i, j) = h_var - - ! ----------------------------------------------------------------------- - !> - Calculate relative humidity increment. - ! ----------------------------------------------------------------------- - - rh_adj = 1. - h_var - rh_inc - rh_rain = max (0.35, rh_adj - rh_inr) ! rh_inr = 0.25 - - ! ----------------------------------------------------------------------- - !> - If requested, call neg_adj() and fix all negative water species. - ! ----------------------------------------------------------------------- - - if (fix_negative) & - call neg_adj (ktop, kbot, tz, dp1, qvz, qlz, qrz, qiz, qsz, qgz) - - m2_rain (i, :) = 0. - m2_sol (i, :) = 0. - - !> - Do loop on cloud microphysics sub time step. - do n = 1, ntimes - - ! ----------------------------------------------------------------------- - !> - Define air density based on hydrostatical property. - ! ----------------------------------------------------------------------- - - if (p_nonhydro) then - do k = ktop, kbot - dz1 (k) = dz0 (k) - den (k) = den0 (k) ! dry air density remains the same - denfac (k) = sqrt (sfcrho / den (k)) - enddo - else - do k = ktop, kbot - dz1 (k) = dz0 (k) * tz (k) / t0 (k) ! hydrostatic balance - den (k) = den0 (k) * dz0 (k) / dz1 (k) - denfac (k) = sqrt (sfcrho / den (k)) - enddo - endif - - ! ----------------------------------------------------------------------- - !> - Call warm_rain() - time-split warm rain processes: 1st pass. - ! ----------------------------------------------------------------------- - - call warm_rain (dt_rain, ktop, kbot, dp1, dz1, tz, qvz, qlz, qrz, qiz, qsz, & - qgz, den, denfac, ccn, c_praut, rh_rain, vtrz, r1, m1_rain, w1, h_var) - - rain (i) = rain (i) + r1 - - do k = ktop, kbot - m2_rain (i, k) = m2_rain (i, k) + m1_rain (k) - m1 (k) = m1 (k) + m1_rain (k) - enddo - - ! ----------------------------------------------------------------------- - !> - Sedimentation of cloud ice, snow, and graupel. - ! ----------------------------------------------------------------------- - - !> - Call fall_speed() to calculate the fall velocity of cloud ice, snow - !! and graupel. - call fall_speed (ktop, kbot, den, qsz, qiz, qgz, qlz, tz, vtsz, vtiz, vtgz) - - !> - Call terminal_fall() to calculate the terminal fall speed. - call terminal_fall (dts, ktop, kbot, tz, qvz, qlz, qrz, qgz, qsz, qiz, & - dz1, dp1, den, vtgz, vtsz, vtiz, r1, g1, s1, i1, m1_sol, w1) - - rain (i) = rain (i) + r1 ! from melted snow & ice that reached the ground - snow (i) = snow (i) + s1 - graupel (i) = graupel (i) + g1 - ice (i) = ice (i) + i1 - - ! ----------------------------------------------------------------------- - !> - Call sedi_heat() to calculate heat transportation during sedimentation. - ! ----------------------------------------------------------------------- - - if (do_sedi_heat) & - call sedi_heat (ktop, kbot, dp1, m1_sol, dz1, tz, qvz, qlz, qrz, qiz, & - qsz, qgz, c_ice) - - ! ----------------------------------------------------------------------- - !> - Call warm_rain() to - time-split warm rain processes: 2nd pass - ! ----------------------------------------------------------------------- - - call warm_rain (dt_rain, ktop, kbot, dp1, dz1, tz, qvz, qlz, qrz, qiz, qsz, & - qgz, den, denfac, ccn, c_praut, rh_rain, vtrz, r1, m1_rain, w1, h_var) - - rain (i) = rain (i) + r1 - - do k = ktop, kbot - m2_rain (i, k) = m2_rain (i, k) + m1_rain (k) - m2_sol (i, k) = m2_sol (i, k) + m1_sol (k) - m1 (k) = m1 (k) + m1_rain (k) + m1_sol (k) - enddo - - ! ----------------------------------------------------------------------- - !> - Call icloud(): ice-phase microphysics - ! ----------------------------------------------------------------------- - - call icloud (ktop, kbot, tz, p1, qvz, qlz, qrz, qiz, qsz, qgz, dp1, den, & - denfac, vtsz, vtgz, vtrz, qaz, rh_adj, rh_rain, dts, h_var) - - enddo - - ! convert units from Pa*kg/kg to kg/m^2/s - m2_rain (i, :) = m2_rain (i, :) * rdt * rgrav - m2_sol (i, :) = m2_sol (i, :) * rdt * rgrav - - ! ----------------------------------------------------------------------- - !> - Calculate momentum transportation during sedimentation. - ! note: dp1 is dry mass; dp0 is the old moist (total) mass - ! ----------------------------------------------------------------------- - - if (sedi_transport) then - do k = ktop + 1, kbot - u1 (k) = (dp0 (k) * u1 (k) + m1 (k - 1) * u1 (k - 1)) / (dp0 (k) + m1 (k - 1)) - v1 (k) = (dp0 (k) * v1 (k) + m1 (k - 1) * v1 (k - 1)) / (dp0 (k) + m1 (k - 1)) - u_dt (i, j, k) = u_dt (i, j, k) + (u1 (k) - u0 (k)) * rdt - v_dt (i, j, k) = v_dt (i, j, k) + (v1 (k) - v0 (k)) * rdt - enddo - endif - - if (do_sedi_w) then - do k = ktop, kbot - w (i, j, k) = w1 (k) - enddo - endif - - ! ----------------------------------------------------------------------- - !> - Update moist air mass (actually hydrostatic pressure). - ! convert to dry mixing ratios - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - omq = dp1 (k) / dp0 (k) - qv_dt (i, j, k) = qv_dt (i, j, k) + rdt * (qvz (k) - qv0 (k)) * omq - ql_dt (i, j, k) = ql_dt (i, j, k) + rdt * (qlz (k) - ql0 (k)) * omq - qr_dt (i, j, k) = qr_dt (i, j, k) + rdt * (qrz (k) - qr0 (k)) * omq - qi_dt (i, j, k) = qi_dt (i, j, k) + rdt * (qiz (k) - qi0 (k)) * omq - qs_dt (i, j, k) = qs_dt (i, j, k) + rdt * (qsz (k) - qs0 (k)) * omq - qg_dt (i, j, k) = qg_dt (i, j, k) + rdt * (qgz (k) - qg0 (k)) * omq - cvm = c_air + qvz (k) * c_vap + (qrz (k) + qlz (k)) * c_liq + (qiz (k) + qsz (k) + qgz (k)) * c_ice - pt_dt (i, j, k) = pt_dt (i, j, k) + rdt * (tz (k) - t0 (k)) * cvm / cp_air - enddo - - ! ----------------------------------------------------------------------- - !> - Update cloud fraction tendency. - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - if (do_qa) then - qa_dt (i, j, k) = 0. - else - qa_dt (i, j, k) = qa_dt (i, j, k) + rdt * (qaz (k) / real (ntimes) - qa0 (k)) - endif - enddo - - ! ----------------------------------------------------------------------- - ! fms diagnostics: - ! ----------------------------------------------------------------------- - - ! if (id_cond > 0) then - ! do k = ktop, kbot ! total condensate - ! cond (i) = cond (i) + dp1 (k) * (qlz (k) + qrz (k) + qsz (k) + qiz (k) + qgz (k)) - ! enddo - ! endif - ! - ! if (id_vtr > 0) then - ! do k = ktop, kbot - ! vt_r (i, j, k) = vtrz (k) - ! enddo - ! endif - ! - ! if (id_vts > 0) then - ! do k = ktop, kbot - ! vt_s (i, j, k) = vtsz (k) - ! enddo - ! endif - ! - ! if (id_vtg > 0) then - ! do k = ktop, kbot - ! vt_g (i, j, k) = vtgz (k) - ! enddo - ! endif - ! - ! if (id_vts > 0) then - ! do k = ktop, kbot - ! vt_i (i, j, k) = vtiz (k) - ! enddo - ! endif - ! - ! if (id_droplets > 0) then - ! do k = ktop, kbot - ! qn2 (i, j, k) = ccn (k) - ! enddo - ! endif - - enddo - -end subroutine mpdrv - -! ----------------------------------------------------------------------- -!>\ingroup mod_gfdl_cloud_mp -!>\brief This subroutine calculates sedimentation of heat. -subroutine sedi_heat (ktop, kbot, dm, m1, dz, tz, qv, ql, qr, qi, qs, qg, cw) - - implicit none - - ! input q fields are dry mixing ratios, and dm is dry air mass - - integer, intent (in) :: ktop, kbot - - real, intent (in), dimension (ktop:kbot) :: dm, m1, dz, qv, ql, qr, qi, qs, qg - - real, intent (inout), dimension (ktop:kbot) :: tz - - real, intent (in) :: cw ! heat capacity - - real, dimension (ktop:kbot) :: dgz, cvn - - real :: tmp - - integer :: k - - do k = ktop, kbot - dgz (k) = - 0.5 * grav * dz (k) ! > 0 - cvn (k) = dm (k) * (cv_air + qv (k) * cv_vap + (qr (k) + ql (k)) * & - c_liq + (qi (k) + qs (k) + qg (k)) * c_ice) - enddo - - ! ----------------------------------------------------------------------- - ! sjl, july 2014 - ! assumption: the ke in the falling condensates is negligible compared to the potential energy - ! that was unaccounted for. local thermal equilibrium is assumed, and the loss in pe is transformed - ! into internal energy (to heat the whole grid box) - ! backward time - implicit upwind transport scheme: - ! dm here is dry air mass - ! ----------------------------------------------------------------------- - - k = ktop - tmp = cvn (k) + m1 (k) * cw - tz (k) = (tmp * tz (k) + m1 (k) * dgz (k)) / tmp - - ! ----------------------------------------------------------------------- - ! implicit algorithm: can't be vectorized - ! needs an inner i - loop for vectorization - ! ----------------------------------------------------------------------- - - do k = ktop + 1, kbot - tz (k) = ((cvn (k) + cw * (m1 (k) - m1 (k - 1))) * tz (k) + m1 (k - 1) * & - cw * tz (k - 1) + dgz (k) * (m1 (k - 1) + m1 (k))) / (cvn (k) + cw * m1 (k)) - enddo - -end subroutine sedi_heat - -! ----------------------------------------------------------------------- -!>\ingroup mod_gfdl_cloud_mp -!> This subroutine includes warm rain cloud microphysics. -!>\section warm_gen GFDL Cloud warm_rain General Algorithm -subroutine warm_rain (dt, ktop, kbot, dp, dz, tz, qv, ql, qr, qi, qs, qg, & - den, denfac, ccn, c_praut, rh_rain, vtr, r1, m1_rain, w1, h_var) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in) :: dt ! time step (s) - real, intent (in) :: rh_rain, h_var - - real, intent (in), dimension (ktop:kbot) :: dp, dz, den - real, intent (in), dimension (ktop:kbot) :: denfac, ccn, c_praut - - real, intent (inout), dimension (ktop:kbot) :: tz, vtr - real, intent (inout), dimension (ktop:kbot) :: qv, ql, qr, qi, qs, qg - real, intent (inout), dimension (ktop:kbot) :: m1_rain, w1 - - real, intent (out) :: r1 - - real, parameter :: so3 = 7. / 3. - - real, dimension (ktop:kbot) :: dl, dm - real, dimension (ktop:kbot + 1) :: ze, zt - - real :: sink, dq, qc0, qc - real :: qden - real :: zs = 0. - real :: dt5 - - integer :: k - - ! fall velocity constants: - - real, parameter :: vconr = 2503.23638966667 - real, parameter :: normr = 25132741228.7183 - real, parameter :: thr = 1.e-8 - - logical :: no_fall - - dt5 = 0.5 * dt - - ! ----------------------------------------------------------------------- - !> - Call check_column() to check if the water species is large enough to fall. - ! ----------------------------------------------------------------------- - - m1_rain (:) = 0. - - call check_column (ktop, kbot, qr, no_fall) - - if (no_fall) then - vtr (:) = vf_min - r1 = 0. - else - - ! ----------------------------------------------------------------------- - !> - Calculate fall speed of rain. - ! ----------------------------------------------------------------------- - - if (const_vr) then - vtr (:) = vr_fac ! ifs_2016: 4.0 - else - do k = ktop, kbot - qden = qr (k) * den (k) - if (qr (k) < thr) then - vtr (k) = vr_min - else - vtr (k) = vr_fac * vconr * sqrt (min (10., sfcrho / den (k))) * & - exp (0.2 * log (qden / normr)) - vtr (k) = min (vr_max, max (vr_min, vtr (k))) - endif - enddo - endif - - ze (kbot + 1) = zs - do k = kbot, ktop, - 1 - ze (k) = ze (k + 1) - dz (k) ! dz < 0 - enddo - - ! ----------------------------------------------------------------------- - !> - Call revap_racc(), to calculate evaporation and accretion - !! of rain for the first 1/2 time step. - ! ----------------------------------------------------------------------- - - ! if (.not. fast_sat_adj) & - call revap_racc (ktop, kbot, dt5, tz, qv, ql, qr, qi, qs, qg, den, denfac, rh_rain, h_var) - - if (do_sedi_w) then - do k = ktop, kbot - dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) - enddo - endif - - ! ----------------------------------------------------------------------- - !> - Calculate mass flux induced by falling rain - !! ( use_ppm =.false, call implicit_fall(): time-implicit monotonic fall scheme.) - ! ----------------------------------------------------------------------- - - if (use_ppm) then - zt (ktop) = ze (ktop) - do k = ktop + 1, kbot - zt (k) = ze (k) - dt5 * (vtr (k - 1) + vtr (k)) - enddo - zt (kbot + 1) = zs - dt * vtr (kbot) - - do k = ktop, kbot - if (zt (k + 1) >= zt (k)) zt (k + 1) = zt (k) - dz_min - enddo - call lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, qr, r1, m1_rain, mono_prof) - else - call implicit_fall (dt, ktop, kbot, ze, vtr, dp, qr, r1, m1_rain) - endif - - ! ----------------------------------------------------------------------- - ! - Calculate vertical velocity transportation during sedimentation. - ! (do_sedi_w =.true. to turn on vertical motion tranport during sedimentation - ! .false. by default) - ! ----------------------------------------------------------------------- - - if (do_sedi_w) then - w1 (ktop) = (dm (ktop) * w1 (ktop) + m1_rain (ktop) * vtr (ktop)) / (dm (ktop) - m1_rain (ktop)) - do k = ktop + 1, kbot - w1 (k) = (dm (k) * w1 (k) - m1_rain (k - 1) * vtr (k - 1) + m1_rain (k) * vtr (k)) & - / (dm (k) + m1_rain (k - 1) - m1_rain (k)) - enddo - endif - - ! ----------------------------------------------------------------------- - !> - Call sedi_heat() to calculate heat transportation during sedimentation. - ! ----------------------------------------------------------------------- - - if (do_sedi_heat) & - call sedi_heat (ktop, kbot, dp, m1_rain, dz, tz, qv, ql, qr, qi, qs, qg, c_liq) - - ! ----------------------------------------------------------------------- - !> - Call revap_racc() to calculate evaporation and accretion - !! of rain for the remaing 1/2 time step. - ! ----------------------------------------------------------------------- - - call revap_racc (ktop, kbot, dt5, tz, qv, ql, qr, qi, qs, qg, den, denfac, rh_rain, h_var) - - endif - - ! ----------------------------------------------------------------------- - !> - Auto-conversion - !! (assuming linear subgrid vertical distribution of cloud water - !! following Lin et al. (1994) \cite lin_et_al_1994.) - ! ----------------------------------------------------------------------- - - if (irain_f /= 0) then - - ! ----------------------------------------------------------------------- - ! no subgrid varaibility - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - qc0 = fac_rc * ccn (k) - if (tz (k) > t_wfr) then - if (use_ccn) then - ! ----------------------------------------------------------------------- - ! ccn is formulted as ccn = ccn_surface * (den / den_surface) - ! ----------------------------------------------------------------------- - qc = qc0 - else - qc = qc0 / den (k) - endif - dq = ql (k) - qc - if (dq > 0.) then - sink = min (dq, dt * c_praut (k) * den (k) * exp (so3 * log (ql (k)))) - ql (k) = ql (k) - sink - qr (k) = qr (k) + sink - endif - endif - enddo - - else - - ! ----------------------------------------------------------------------- - !> - Call linear_prof() to calculate vertical subgrid variability of cloud water. - ! ----------------------------------------------------------------------- - - call linear_prof (kbot - ktop + 1, ql (ktop), dl (ktop), z_slope_liq, h_var) - - do k = ktop, kbot - qc0 = fac_rc * ccn (k) - if (tz (k) > t_wfr + dt_fr) then - dl (k) = min (max (1.e-6, dl (k)), 0.5 * ql (k)) - ! -------------------------------------------------------------------- - ! as in klein's gfdl am2 stratiform scheme (with subgrid variations) - ! -------------------------------------------------------------------- - if (use_ccn) then - ! -------------------------------------------------------------------- - ! ccn is formulted as ccn = ccn_surface * (den / den_surface) - ! -------------------------------------------------------------------- - qc = qc0 - else - qc = qc0 / den (k) - endif - dq = 0.5 * (ql (k) + dl (k) - qc) - ! -------------------------------------------------------------------- - ! dq = dl if qc == q_minus = ql - dl - ! dq = 0 if qc == q_plus = ql + dl - ! -------------------------------------------------------------------- - if (dq > 0.) then ! q_plus > qc - ! -------------------------------------------------------------------- - !> - Revised continuous form: linearly decays (with subgrid dl) to zero at qc == ql + dl - ! -------------------------------------------------------------------- - sink = min (1., dq / dl (k)) * dt * c_praut (k) * den (k) * exp (so3 * log (ql (k))) - ql (k) = ql (k) - sink - qr (k) = qr (k) + sink - endif - endif - enddo - endif - -end subroutine warm_rain - -! ----------------------------------------------------------------------- -!>\ingroup mod_gfdl_cloud_mp -!> This subroutine calculates evaporation of rain and accretion of rain. -!!\section gen_ravap GFDL Cloud revap_racc General Algorithm -subroutine revap_racc (ktop, kbot, dt, tz, qv, ql, qr, qi, qs, qg, den, denfac, rh_rain, h_var) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in) :: dt ! time step (s) - real, intent (in) :: rh_rain, h_var - - real, intent (in), dimension (ktop:kbot) :: den, denfac - - real, intent (inout), dimension (ktop:kbot) :: tz, qv, qr, ql, qi, qs, qg - - real, dimension (ktop:kbot) :: lhl, cvm, q_liq, q_sol, lcpk - - real :: dqv, qsat, dqsdt, evap, t2, qden, q_plus, q_minus, sink - real :: qpz, dq, dqh, tin - - integer :: k - - do k = ktop, kbot - - if (tz (k) > t_wfr .and. qr (k) > qrmin) then - - ! ----------------------------------------------------------------------- - !> - Define heat capacity and latent heat coefficient. - ! ----------------------------------------------------------------------- - - lhl (k) = lv00 + d0_vap * tz (k) - q_liq (k) = ql (k) + qr (k) - q_sol (k) = qi (k) + qs (k) + qg (k) - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - lcpk (k) = lhl (k) / cvm (k) - - tin = tz (k) - lcpk (k) * ql (k) ! presence of clouds suppresses the rain evap - qpz = qv (k) + ql (k) - qsat = wqs2 (tin, den (k), dqsdt) - dqh = max (ql (k), h_var * max (qpz, qcmin)) - dqh = min (dqh, 0.2 * qpz) ! new limiter - dqv = qsat - qv (k) ! use this to prevent super - sat the gird box - q_minus = qpz - dqh - q_plus = qpz + dqh - - ! ----------------------------------------------------------------------- - !> - qsat must be > q_minus to activate evaporation; - !! qsat must be < q_plus to activate accretion - ! ----------------------------------------------------------------------- - - ! ----------------------------------------------------------------------- - !> - rain evaporation (\f$evap\f$) - ! ----------------------------------------------------------------------- - - if (dqv > qvmin .and. qsat > q_minus) then - if (qsat > q_plus) then - dq = qsat - qpz - else - ! ----------------------------------------------------------------------- - ! q_minus < qsat < q_plus - ! dq == dqh if qsat == q_minus - ! ----------------------------------------------------------------------- - dq = 0.25 * (q_minus - qsat) ** 2 / dqh - endif - qden = qr (k) * den (k) - t2 = tin * tin - evap = crevp (1) * t2 * dq * (crevp (2) * sqrt (qden) + crevp (3) * & - exp (0.725 * log (qden))) / (crevp (4) * t2 + crevp (5) * qsat * den (k)) - evap = min (qr (k), dt * evap, dqv / (1. + lcpk (k) * dqsdt)) - ! ----------------------------------------------------------------------- - ! alternative minimum evap in dry environmental air - ! sink = min (qr (k), dim (rh_rain * qsat, qv (k)) / (1. + lcpk (k) * dqsdt)) - ! evap = max (evap, sink) - ! ----------------------------------------------------------------------- - qr (k) = qr (k) - evap - qv (k) = qv (k) + evap - q_liq (k) = q_liq (k) - evap - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) - evap * lhl (k) / cvm (k) - endif - - ! ----------------------------------------------------------------------- - !> - accretion: \f$P_{racc}\f$ - ! ----------------------------------------------------------------------- - - ! if (qr (k) > qrmin .and. ql (k) > 1.e-7 .and. qsat < q_plus) then - if (qr (k) > qrmin .and. ql (k) > 1.e-6 .and. qsat < q_minus) then - sink = dt * denfac (k) * cracw * exp (0.95 * log (qr (k) * den (k))) - sink = sink / (1. + sink) * ql (k) - ql (k) = ql (k) - sink - qr (k) = qr (k) + sink - endif - - endif ! warm - rain - enddo - -end subroutine revap_racc - -! ----------------------------------------------------------------------- -!>\ingroup mod_gfdl_cloud_mp -!> Definition of vertical subgrid variability -!! used for cloud ice and cloud water autoconversion. -! qi -- > ql & ql -- > qr -! edges: qe == qbar + / - dm -!>\section gen_linear GFDL cloud linear_prof General Algorithm -subroutine linear_prof (km, q, dm, z_var, h_var) - - implicit none - - integer, intent (in) :: km - - real, intent (in) :: q (km), h_var - - real, intent (out) :: dm (km) - - logical, intent (in) :: z_var - - real :: dq (km) - - integer :: k - - if (z_var) then - do k = 2, km - dq (k) = 0.5 * (q (k) - q (k - 1)) - enddo - dm (1) = 0. - - ! ----------------------------------------------------------------------- - !> - Use twice the strength of the positive definiteness limiter (Lin et al.(1994) - !! \cite lin_et_al_1994). - ! ----------------------------------------------------------------------- - - do k = 2, km - 1 - dm (k) = 0.5 * min (abs (dq (k) + dq (k + 1)), 0.5 * q (k)) - if (dq (k) * dq (k + 1) <= 0.) then - if (dq (k) > 0.) then ! local max - dm (k) = min (dm (k), dq (k), - dq (k + 1)) - else - dm (k) = 0. - endif - endif - enddo - dm (km) = 0. - - ! ----------------------------------------------------------------------- - !> - Impose the background horizontal variability (\f$h_{var}\f$) that - !! is proportional to the value itself. - ! ----------------------------------------------------------------------- - - do k = 1, km - dm (k) = max (dm (k), qvmin, h_var * q (k)) - enddo - else - do k = 1, km - dm (k) = max (qvmin, h_var * q (k)) - enddo - endif - -end subroutine linear_prof - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!> This subroutine includes cloud ice microphysics processes. -!>\author Shian-Jiann Lin, GFDL -!! -!! This scheme is featured with: -!! - bulk cloud microphysics -!! - processes splitting with some un-split sub-grouping -!! - time implicit (when possible) accretion and autoconversion -!>\section det_icloud GFDL icloud Detailed Algorithm -subroutine icloud (ktop, kbot, tzk, p1, qvk, qlk, qrk, qik, qsk, qgk, dp1, & - den, denfac, vts, vtg, vtr, qak, rh_adj, rh_rain, dts, h_var) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in), dimension (ktop:kbot) :: p1, dp1, den, denfac, vts, vtg, vtr - - real, intent (inout), dimension (ktop:kbot) :: tzk, qvk, qlk, qrk, qik, qsk, qgk, qak - - real, intent (in) :: rh_adj, rh_rain, dts, h_var - - real, dimension (ktop:kbot) :: lcpk, icpk, tcpk, di, lhl, lhi - real, dimension (ktop:kbot) :: cvm, q_liq, q_sol - - real :: rdts, fac_g2v, fac_v2g, fac_i2s, fac_imlt - real :: tz, qv, ql, qr, qi, qs, qg, melt - real :: pracs, psacw, pgacw, psacr, pgacr, pgaci, praci, psaci - real :: pgmlt, psmlt, pgfr, pgaut, psaut, pgsub - real :: tc, tsq, dqs0, qden, qim, qsm - real :: dt5, factor, sink, qi_crt - real :: tmp, qsw, qsi, dqsdt, dq - real :: dtmp, qc, q_plus, q_minus - - integer :: k - - dt5 = 0.5 * dts - - rdts = 1. / dts - - ! ----------------------------------------------------------------------- - !> - Define conversion scalar/factor. - ! ----------------------------------------------------------------------- - - fac_i2s = 1. - exp (- dts / tau_i2s) - fac_g2v = 1. - exp (- dts / tau_g2v) - fac_v2g = 1. - exp (- dts / tau_v2g) - - fac_imlt = 1. - exp (- dt5 / tau_imlt) - - ! ----------------------------------------------------------------------- - !> - Define heat capacity and latend heat coefficient. - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - lhi (k) = li00 + dc_ice * tzk (k) - q_liq (k) = qlk (k) + qrk (k) - q_sol (k) = qik (k) + qsk (k) + qgk (k) - cvm (k) = c_air + qvk (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - icpk (k) = lhi (k) / cvm (k) - enddo - - ! ----------------------------------------------------------------------- - ! sources of cloud ice: pihom, cold rain, and the sat_adj - ! (initiation plus deposition) - ! sources of snow: cold rain, auto conversion + accretion (from cloud ice) - ! sat_adj (deposition; requires pre - existing snow) ; initial snow comes from auto conversion - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - if (tzk (k) > tice .and. qik (k) > qcmin) then - - ! ----------------------------------------------------------------------- - !> - Calculate \f$P_{imlt}\f$: instant melting of cloud ice. - ! ----------------------------------------------------------------------- - - melt = min (qik (k), fac_imlt * (tzk (k) - tice) / icpk (k)) - tmp = min (melt, dim (ql_mlt, qlk (k))) ! max ql amount - qlk (k) = qlk (k) + tmp - qrk (k) = qrk (k) + melt - tmp - qik (k) = qik (k) - melt - q_liq (k) = q_liq (k) + melt - q_sol (k) = q_sol (k) - melt - cvm (k) = c_air + qvk (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tzk (k) = tzk (k) - melt * lhi (k) / cvm (k) - - elseif (tzk (k) < t_wfr .and. qlk (k) > qcmin) then - - ! ----------------------------------------------------------------------- - !> - Calculate \f$P_{ihom}\f$: homogeneous freezing of cloud water into cloud ice. - !! This is the 1st occurance of liquid water freezing in the split MP process. - ! ----------------------------------------------------------------------- - - dtmp = t_wfr - tzk (k) - factor = min (1., dtmp / dt_fr) - sink = min (qlk (k) * factor, dtmp / icpk (k)) - qi_crt = qi_gen * min (qi_lim, 0.1 * (tice - tzk (k))) / den (k) - tmp = min (sink, dim (qi_crt, qik (k))) - qlk (k) = qlk (k) - sink - qsk (k) = qsk (k) + sink - tmp - qik (k) = qik (k) + tmp - q_liq (k) = q_liq (k) - sink - q_sol (k) = q_sol (k) + sink - cvm (k) = c_air + qvk (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tzk (k) = tzk (k) + sink * lhi (k) / cvm (k) - - endif - enddo - - ! ----------------------------------------------------------------------- - !> - Call linear_prof() to calculate vertical subgrid variability of cloud ice. - ! ----------------------------------------------------------------------- - - call linear_prof (kbot - ktop + 1, qik (ktop), di (ktop), z_slope_ice, h_var) - - ! ----------------------------------------------------------------------- - !> - Update capacity heat and latend heat coefficient. - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - lhl (k) = lv00 + d0_vap * tzk (k) - lhi (k) = li00 + dc_ice * tzk (k) - lcpk (k) = lhl (k) / cvm (k) - icpk (k) = lhi (k) / cvm (k) - tcpk (k) = lcpk (k) + icpk (k) - enddo - - do k = ktop, kbot - - ! ----------------------------------------------------------------------- - ! do nothing above p_min - ! ----------------------------------------------------------------------- - - if (p1 (k) < p_min) cycle - - tz = tzk (k) - qv = qvk (k) - ql = qlk (k) - qi = qik (k) - qr = qrk (k) - qs = qsk (k) - qg = qgk (k) - - pgacr = 0. - pgacw = 0. - tc = tz - tice - - if (tc .ge. 0.) then - - ! ----------------------------------------------------------------------- - !> - Melting of snow: - ! ----------------------------------------------------------------------- - - dqs0 = ces0 / p1 (k) - qv - - if (qs > qcmin) then - - ! ----------------------------------------------------------------------- - !> - \f$P_{sacw}\f$: accretion of cloud water by snow - ! only rate is used (for snow melt) since tc > 0. - ! ----------------------------------------------------------------------- - - if (ql > qrmin) then - factor = denfac (k) * csacw * exp (0.8125 * log (qs * den (k))) - psacw = factor / (1. + dts * factor) * ql ! rate - else - psacw = 0. - endif - - ! ----------------------------------------------------------------------- - !> - \f$P_{sacr}\f$: accretion of rain by melted snow - !> - \f$P_{racs}\f$: accretion of snow by rain - ! ----------------------------------------------------------------------- - - if (qr > qrmin) then - psacr = min (acr3d (vts (k), vtr (k), qr, qs, csacr, acco (1, 2), & - den (k)), qr * rdts) - pracs = acr3d (vtr (k), vts (k), qs, qr, cracs, acco (1, 1), den (k)) - else - psacr = 0. - pracs = 0. - endif - - ! ----------------------------------------------------------------------- - !> - Total snow sink: - !! \f$P_{smlt}\f$: snow melt (smlt(); due to rain accretion) - ! ----------------------------------------------------------------------- - - psmlt = max (0., smlt (tc, dqs0, qs * den (k), psacw, psacr, csmlt, & - den (k), denfac (k))) - sink = min (qs, dts * (psmlt + pracs), tc / icpk (k)) - qs = qs - sink - ! sjl, 20170321: - tmp = min (sink, dim (qs_mlt, ql)) ! max ql due to snow melt - ql = ql + tmp - qr = qr + sink - tmp - ! qr = qr + sink - ! sjl, 20170321: - q_liq (k) = q_liq (k) + sink - q_sol (k) = q_sol (k) - sink - cvm (k) = c_air + qv * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz = tz - sink * lhi (k) / cvm (k) - tc = tz - tice - - endif - - ! ----------------------------------------------------------------------- - !> - Update capacity heat and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhi (k) = li00 + dc_ice * tz - icpk (k) = lhi (k) / cvm (k) - - ! ----------------------------------------------------------------------- - !> - Melting of graupel: - ! ----------------------------------------------------------------------- - - if (qg > qcmin .and. tc > 0.) then - - ! ----------------------------------------------------------------------- - !> - \f$P_{gacr}\f$: accretion of rain by graupel - ! ----------------------------------------------------------------------- - - if (qr > qrmin) & - pgacr = min (acr3d (vtg (k), vtr (k), qr, qg, cgacr, acco (1, 3), & - den (k)), rdts * qr) - - ! ----------------------------------------------------------------------- - !> - \f$P_{gacw}\f$: accretion of cloud water by graupel - ! ----------------------------------------------------------------------- - - qden = qg * den (k) - if (ql > qrmin) then - factor = cgacw * qden / sqrt (den (k) * sqrt (sqrt (qden))) - pgacw = factor / (1. + dts * factor) * ql ! rate - endif - - ! ----------------------------------------------------------------------- - !> - \f$P_{gmlt}\f$: graupel melt (gmlt()) - ! ----------------------------------------------------------------------- - - pgmlt = dts * gmlt (tc, dqs0, qden, pgacw, pgacr, cgmlt, den (k)) - pgmlt = min (max (0., pgmlt), qg, tc / icpk (k)) - qg = qg - pgmlt - qr = qr + pgmlt - q_liq (k) = q_liq (k) + pgmlt - q_sol (k) = q_sol (k) - pgmlt - cvm (k) = c_air + qv * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz = tz - pgmlt * lhi (k) / cvm (k) - - endif - - else - - ! ----------------------------------------------------------------------- - !> - Cloud ice processes: - ! ----------------------------------------------------------------------- - - ! ----------------------------------------------------------------------- - !> - \f$P_{saci}\f$: accretion of cloud ice by snow - ! ----------------------------------------------------------------------- - - if (qi > 3.e-7) then ! cloud ice sink terms - - if (qs > 1.e-7) then - ! ----------------------------------------------------------------------- - ! sjl added (following lin eq. 23) the temperature dependency - ! to reduce accretion, use esi = exp (0.05 * tc) as in hong et al 2004 - ! ----------------------------------------------------------------------- - factor = dts * denfac (k) * csaci * exp (0.05 * tc + 0.8125 * log (qs * den (k))) - psaci = factor / (1. + factor) * qi - else - psaci = 0. - endif - - ! ----------------------------------------------------------------------- - !> - \f$P_{saut}\f$: autoconversion: cloud ice \f$\rightarrow\f$ snow. - !!\n similar to Lin et al.(1983) \cite lin_et_al_1983 eq. 21 solved implicitly; - !! threshold from wsm6 scheme, Hong et al. (2004) \cite hong_et_al_2004, - !! eq (13) : qi0_crt ~0.8e-4. - ! ----------------------------------------------------------------------- - if (qi0_crt < 0.) then - qim = - qi0_crt - else - qim = qi0_crt / den (k) - endif - ! ----------------------------------------------------------------------- - ! assuming linear subgrid vertical distribution of cloud ice - ! the mismatch computation following lin et al. 1994, mwr - ! ----------------------------------------------------------------------- - - if (const_vi) then - tmp = fac_i2s - else - tmp = fac_i2s * exp (0.025 * tc) - endif - - di (k) = max (di (k), qrmin) - q_plus = qi + di (k) - if (q_plus > (qim + qrmin)) then - if (qim > (qi - di (k))) then - dq = (0.25 * (q_plus - qim) ** 2) / di (k) - else - dq = qi - qim - endif - psaut = tmp * dq - else - psaut = 0. - endif - ! ----------------------------------------------------------------------- - ! sink is no greater than 75% of qi - ! ----------------------------------------------------------------------- - sink = min (0.75 * qi, psaci + psaut) - qi = qi - sink - qs = qs + sink - - ! ----------------------------------------------------------------------- - !> - \f$P_{gaci}\f$: accretion of cloud ice by graupel - ! ----------------------------------------------------------------------- - - if (qg > 1.e-6) then - ! ----------------------------------------------------------------------- - ! factor = dts * cgaci / sqrt (den (k)) * exp (0.05 * tc + 0.875 * log (qg * den (k))) - ! simplified form: remove temp dependency & set the exponent "0.875" -- > 1 - ! ----------------------------------------------------------------------- - factor = dts * cgaci * sqrt (den (k)) * qg - pgaci = factor / (1. + factor) * qi - qi = qi - pgaci - qg = qg + pgaci - endif - - endif - - ! ----------------------------------------------------------------------- - !> - Cold-rain processes: - ! ----------------------------------------------------------------------- - - ! ----------------------------------------------------------------------- - ! rain to ice, snow, graupel processes: - ! ----------------------------------------------------------------------- - - tc = tz - tice - - if (qr > 1.e-7 .and. tc < 0.) then - - ! ----------------------------------------------------------------------- - ! * sink * terms to qr: psacr + pgfr - ! source terms to qs: psacr - ! source terms to qg: pgfr - ! ----------------------------------------------------------------------- - - ! ----------------------------------------------------------------------- - !> - \f$P_{sacr}\f$: accretion of rain by snow (acr3d()) - ! ----------------------------------------------------------------------- - - if (qs > 1.e-7) then ! if snow exists - psacr = dts * acr3d (vts (k), vtr (k), qr, qs, csacr, acco (1, 2), den (k)) - else - psacr = 0. - endif - - ! ----------------------------------------------------------------------- - !> - \f$P_{gfr}\f$: rain freezing \f$\rightarrow\f$ graupel - ! ----------------------------------------------------------------------- - - pgfr = dts * cgfr (1) / den (k) * (exp (- cgfr (2) * tc) - 1.) * & - exp (1.75 * log (qr * den (k))) - - ! ----------------------------------------------------------------------- - !> - Calculate total sink to \f$q_r\f$ : - !!\n Sink terms to \f$q_r\f$: \f$P_{sacr}+P_{gfr}\f$ - !!\n source term to \f$q_s\f$: \f$P_{sacr}\f$ - !!\n source term to \f$q_g\f$: \f$P_{gfr}\f$ - ! ----------------------------------------------------------------------- - - sink = psacr + pgfr - factor = min (sink, qr, - tc / icpk (k)) / max (sink, qrmin) - - psacr = factor * psacr - pgfr = factor * pgfr - - sink = psacr + pgfr - qr = qr - sink - qs = qs + psacr - qg = qg + pgfr - q_liq (k) = q_liq (k) - sink - q_sol (k) = q_sol (k) + sink - cvm (k) = c_air + qv * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz = tz + sink * lhi (k) / cvm (k) - - endif - - ! ----------------------------------------------------------------------- - !> - Update capacity heat and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhi (k) = li00 + dc_ice * tz - icpk (k) = lhi (k) / cvm (k) - - ! ----------------------------------------------------------------------- - !> - Graupel production terms: - ! ----------------------------------------------------------------------- - - if (qs > 1.e-7) then - - ! ----------------------------------------------------------------------- - !> - accretion: snow \f$\rightarrow\f$ graupel (acr3d()) - ! ----------------------------------------------------------------------- - - if (qg > qrmin) then - sink = dts * acr3d (vtg (k), vts (k), qs, qg, cgacs, acco (1, 4), den (k)) - else - sink = 0. - endif - - ! ----------------------------------------------------------------------- - !> - autoconversion: snow \f$\rightarrow\f$ graupel - ! ----------------------------------------------------------------------- - - qsm = qs0_crt / den (k) - if (qs > qsm) then - factor = dts * 1.e-3 * exp (0.09 * (tz - tice)) - sink = sink + factor / (1. + factor) * (qs - qsm) - endif - sink = min (qs, sink) - qs = qs - sink - qg = qg + sink - - endif ! snow existed - - if (qg > 1.e-7 .and. tz < tice0) then - - ! ----------------------------------------------------------------------- - !> - \f$P_{gacw}\f$: accretion of cloud water by graupel - ! ----------------------------------------------------------------------- - - if (ql > 1.e-6) then - qden = qg * den (k) - factor = dts * cgacw * qden / sqrt (den (k) * sqrt (sqrt (qden))) - pgacw = factor / (1. + factor) * ql - else - pgacw = 0. - endif - - ! ----------------------------------------------------------------------- - !> - \f$P_{gacr}\f$: accretion of rain by graupel (acr3d()) - ! ----------------------------------------------------------------------- - - if (qr > 1.e-6) then - pgacr = min (dts * acr3d (vtg (k), vtr (k), qr, qg, cgacr, acco (1, 3), & - den (k)), qr) - else - pgacr = 0. - endif - - sink = pgacr + pgacw - factor = min (sink, dim (tice, tz) / icpk (k)) / max (sink, qrmin) - pgacr = factor * pgacr - pgacw = factor * pgacw - - sink = pgacr + pgacw - qg = qg + sink - qr = qr - pgacr - ql = ql - pgacw - q_liq (k) = q_liq (k) - sink - q_sol (k) = q_sol (k) + sink - cvm (k) = c_air + qv * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz = tz + sink * lhi (k) / cvm (k) - - endif - - endif - - tzk (k) = tz - qvk (k) = qv - qlk (k) = ql - qik (k) = qi - qrk (k) = qr - qsk (k) = qs - qgk (k) = qg - - enddo - - ! ----------------------------------------------------------------------- - !> - Call subgrid_z_proc() for subgrid cloud microphysics. - ! ----------------------------------------------------------------------- - - call subgrid_z_proc (ktop, kbot, p1, den, denfac, dts, rh_adj, tzk, qvk, & - qlk, qrk, qik, qsk, qgk, qak, h_var, rh_rain) - -end subroutine icloud - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!> This subroutine calculates temperature sentive high vertical resolution processes. -!>\section gen_subz GFDL Cloud subgrid_z_proc General Algorithm -subroutine subgrid_z_proc (ktop, kbot, p1, den, denfac, dts, rh_adj, tz, qv, & - ql, qr, qi, qs, qg, qa, h_var, rh_rain) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in), dimension (ktop:kbot) :: p1, den, denfac - - real, intent (in) :: dts, rh_adj, h_var, rh_rain - - real, intent (inout), dimension (ktop:kbot) :: tz, qv, ql, qr, qi, qs, qg, qa - - real, dimension (ktop:kbot) :: lcpk, icpk, tcpk, tcp3, lhl, lhi - real, dimension (ktop:kbot) :: cvm, q_liq, q_sol, q_cond - - real :: fac_v2l, fac_l2v - - real :: pidep, qi_crt - - ! ----------------------------------------------------------------------- - ! qstar over water may be accurate only down to - 80 deg c with ~10% uncertainty - ! must not be too large to allow psc - ! ----------------------------------------------------------------------- - - real :: rh, rqi, tin, qsw, qsi, qpz, qstar - real :: dqsdt, dwsdt, dq, dq0, factor, tmp - real :: q_plus, q_minus, dt_evap, dt_pisub - real :: evap, sink, tc, pisub, q_adj, dtmp - real :: pssub, pgsub, tsq, qden, fac_g2v, fac_v2g - - integer :: k - - if (fast_sat_adj) then - dt_evap = 0.5 * dts - else - dt_evap = dts - endif - - ! ----------------------------------------------------------------------- - !> - Define conversion scalar/factor. - ! ----------------------------------------------------------------------- - - fac_v2l = 1. - exp (- dt_evap / tau_v2l) - fac_l2v = 1. - exp (- dt_evap / tau_l2v) - - fac_g2v = 1. - exp (- dts / tau_g2v) - fac_v2g = 1. - exp (- dts / tau_v2g) - - ! ----------------------------------------------------------------------- - !> - Define heat capacity and latend heat coefficient. - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - lhl (k) = lv00 + d0_vap * tz (k) - lhi (k) = li00 + dc_ice * tz (k) - q_liq (k) = ql (k) + qr (k) - q_sol (k) = qi (k) + qs (k) + qg (k) - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - lcpk (k) = lhl (k) / cvm (k) - icpk (k) = lhi (k) / cvm (k) - tcpk (k) = lcpk (k) + icpk (k) - tcp3 (k) = lcpk (k) + icpk (k) * min (1., dim (tice, tz (k)) / (tice - t_wfr)) - enddo - - do k = ktop, kbot - - if (p1 (k) < p_min) cycle - - ! ----------------------------------------------------------------------- - !> - Instant deposit all water vapor to cloud ice when temperature is super low. - ! ----------------------------------------------------------------------- - - if (tz (k) < t_min) then - sink = dim (qv (k), 1.e-7) - qv (k) = qv (k) - sink - qi (k) = qi (k) + sink - q_sol (k) = q_sol (k) + sink - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) + sink * (lhl (k) + lhi (k)) / cvm (k) - if (.not. do_qa) qa (k) = qa (k) + 1. ! air fully saturated; 100 % cloud cover - cycle - endif - - ! ----------------------------------------------------------------------- - !> - Update heat capacity and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhl (k) = lv00 + d0_vap * tz (k) - lhi (k) = li00 + dc_ice * tz (k) - lcpk (k) = lhl (k) / cvm (k) - icpk (k) = lhi (k) / cvm (k) - tcpk (k) = lcpk (k) + icpk (k) - tcp3 (k) = lcpk (k) + icpk (k) * min (1., dim (tice, tz (k)) / (tice - t_wfr)) - - ! ----------------------------------------------------------------------- - !> - Instant evaporation/sublimation of all clouds if rh < rh_adj \f$\rightarrow\f$ cloud free. - ! ----------------------------------------------------------------------- - - qpz = qv (k) + ql (k) + qi (k) - tin = tz (k) - (lhl (k) * (ql (k) + qi (k)) + lhi (k) * qi (k)) / (c_air + & - qpz * c_vap + qr (k) * c_liq + (qs (k) + qg (k)) * c_ice) - if (tin > t_sub + 6.) then - rh = qpz / iqs1 (tin, den (k)) - if (rh < rh_adj) then ! qpz / rh_adj < qs - tz (k) = tin - qv (k) = qpz - ql (k) = 0. - qi (k) = 0. - cycle ! cloud free - endif - endif - - ! ----------------------------------------------------------------------- - !> - cloud water \f$\Leftrightarrow\f$ vapor adjustment: - ! ----------------------------------------------------------------------- - - qsw = wqs2 (tz (k), den (k), dwsdt) - dq0 = qsw - qv (k) - if (dq0 > 0.) then - ! SJL 20170703 added ql factor to prevent the situation of high ql and low RH - ! factor = min (1., fac_l2v * sqrt (max (0., ql (k)) / 1.e-5) * 10. * dq0 / qsw) - ! factor = fac_l2v - ! factor = 1 - factor = min (1., fac_l2v * (10. * dq0 / qsw)) ! the rh dependent factor = 1 at 90% - evap = min (ql (k), factor * dq0 / (1. + tcp3 (k) * dwsdt)) - else ! condensate all excess vapor into cloud water - ! ----------------------------------------------------------------------- - ! evap = fac_v2l * dq0 / (1. + tcp3 (k) * dwsdt) - ! sjl, 20161108 - ! ----------------------------------------------------------------------- - evap = dq0 / (1. + tcp3 (k) * dwsdt) - endif - qv (k) = qv (k) + evap - ql (k) = ql (k) - evap - q_liq (k) = q_liq (k) - evap - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) - evap * lhl (k) / cvm (k) - - ! ----------------------------------------------------------------------- - !> - Update heat capacity and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhi (k) = li00 + dc_ice * tz (k) - icpk (k) = lhi (k) / cvm (k) - - ! ----------------------------------------------------------------------- - !> - Enforce complete freezing below \f$-48^oC\f$. - ! ----------------------------------------------------------------------- - - dtmp = t_wfr - tz (k) ! [ - 40, - 48] - if (dtmp > 0. .and. ql (k) > qcmin) then - sink = min (ql (k), ql (k) * dtmp * 0.125, dtmp / icpk (k)) - ql (k) = ql (k) - sink - qi (k) = qi (k) + sink - q_liq (k) = q_liq (k) - sink - q_sol (k) = q_sol (k) + sink - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) + sink * lhi (k) / cvm (k) - endif - - ! ----------------------------------------------------------------------- - !> - Update heat capacity and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhi (k) = li00 + dc_ice * tz (k) - icpk (k) = lhi (k) / cvm (k) - - ! ----------------------------------------------------------------------- - !> - Apply Bigg mechanism. - ! ----------------------------------------------------------------------- - - if (fast_sat_adj) then - dt_pisub = 0.5 * dts - else - dt_pisub = dts - tc = tice - tz (k) - if (ql (k) > qrmin .and. tc > 0.) then - sink = 3.3333e-10 * dts * (exp (0.66 * tc) - 1.) * den (k) * ql (k) * ql (k) - sink = min (ql (k), tc / icpk (k), sink) - ql (k) = ql (k) - sink - qi (k) = qi (k) + sink - q_liq (k) = q_liq (k) - sink - q_sol (k) = q_sol (k) + sink - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) + sink * lhi (k) / cvm (k) - endif ! significant ql existed - endif - - ! ----------------------------------------------------------------------- - !> - Update capacity heat and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhl (k) = lv00 + d0_vap * tz (k) - lhi (k) = li00 + dc_ice * tz (k) - lcpk (k) = lhl (k) / cvm (k) - icpk (k) = lhi (k) / cvm (k) - tcpk (k) = lcpk (k) + icpk (k) - - ! ----------------------------------------------------------------------- - !> - Sublimation/deposition of ice. - ! ----------------------------------------------------------------------- - - if (tz (k) < tice) then - qsi = iqs2 (tz (k), den (k), dqsdt) - dq = qv (k) - qsi - sink = dq / (1. + tcpk (k) * dqsdt) - if (qi (k) > qrmin) then - ! eq 9, hong et al. 2004, mwr - ! for a and b, see dudhia 1989: page 3103 eq (b7) and (b8) - pidep = dt_pisub * dq * 349138.78 * exp (0.875 * log (qi (k) * den (k))) & - / (qsi * den (k) * lat2 / (0.0243 * rvgas * tz (k) ** 2) + 4.42478e4) - else - pidep = 0. - endif - if (dq > 0.) then ! vapor - > ice - tmp = tice - tz (k) - ! 20160912: the following should produce more ice at higher altitude - ! qi_crt = 4.92e-11 * exp (1.33 * log (1.e3 * exp (0.1 * tmp))) / den (k) - qi_crt = qi_gen * min (qi_lim, 0.1 * tmp) / den (k) - sink = min (sink, max (qi_crt - qi (k), pidep), tmp / tcpk (k)) - else ! ice -- > vapor - pidep = pidep * min (1., dim (tz (k), t_sub) * 0.2) - sink = max (pidep, sink, - qi (k)) - endif - qv (k) = qv (k) - sink - qi (k) = qi (k) + sink - q_sol (k) = q_sol (k) + sink - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) + sink * (lhl (k) + lhi (k)) / cvm (k) - endif - - ! ----------------------------------------------------------------------- - !> - Update capacity heat and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhl (k) = lv00 + d0_vap * tz (k) - lhi (k) = li00 + dc_ice * tz (k) - lcpk (k) = lhl (k) / cvm (k) - icpk (k) = lhi (k) / cvm (k) - tcpk (k) = lcpk (k) + icpk (k) - - ! ----------------------------------------------------------------------- - !> - Sublimation/deposition of snow. - ! this process happens for all temp rage - ! ----------------------------------------------------------------------- - - if (qs (k) > qrmin) then - qsi = iqs2 (tz (k), den (k), dqsdt) - qden = qs (k) * den (k) - tmp = exp (0.65625 * log (qden)) - tsq = tz (k) * tz (k) - dq = (qsi - qv (k)) / (1. + tcpk (k) * dqsdt) - pssub = cssub (1) * tsq * (cssub (2) * sqrt (qden) + cssub (3) * tmp * & - sqrt (denfac (k))) / (cssub (4) * tsq + cssub (5) * qsi * den (k)) - pssub = (qsi - qv (k)) * dts * pssub - if (pssub > 0.) then ! qs -- > qv, sublimation - pssub = min (pssub * min (1., dim (tz (k), t_sub) * 0.2), qs (k)) - else - if (tz (k) > tice) then - pssub = 0. ! no deposition - else - pssub = max (pssub, dq, (tz (k) - tice) / tcpk (k)) - endif - endif - qs (k) = qs (k) - pssub - qv (k) = qv (k) + pssub - q_sol (k) = q_sol (k) - pssub - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) - pssub * (lhl (k) + lhi (k)) / cvm (k) - endif - - ! ----------------------------------------------------------------------- - !> - Update capacity heat and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhl (k) = lv00 + d0_vap * tz (k) - lhi (k) = li00 + dc_ice * tz (k) - lcpk (k) = lhl (k) / cvm (k) - icpk (k) = lhi (k) / cvm (k) - tcpk (k) = lcpk (k) + icpk (k) - - ! ----------------------------------------------------------------------- - !> - Simplified 2-way grapuel sublimation-deposition mechanism. - ! ----------------------------------------------------------------------- - - if (qg (k) > qrmin) then - qsi = iqs2 (tz (k), den (k), dqsdt) - dq = (qv (k) - qsi) / (1. + tcpk (k) * dqsdt) - pgsub = (qv (k) / qsi - 1.) * qg (k) - if (pgsub > 0.) then ! deposition - if (tz (k) > tice) then - pgsub = 0. ! no deposition - else - pgsub = min (fac_v2g * pgsub, 0.2 * dq, ql (k) + qr (k), & - (tice - tz (k)) / tcpk (k)) - endif - else ! submilation - pgsub = max (fac_g2v * pgsub, dq) * min (1., dim (tz (k), t_sub) * 0.1) - endif - qg (k) = qg (k) + pgsub - qv (k) = qv (k) - pgsub - q_sol (k) = q_sol (k) + pgsub - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) + pgsub * (lhl (k) + lhi (k)) / cvm (k) - endif - -#ifdef USE_MIN_EVAP - ! ----------------------------------------------------------------------- - !> - Update capacity heat and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhl (k) = lv00 + d0_vap * tz (k) - lcpk (k) = lhl (k) / cvm (k) - - ! ----------------------------------------------------------------------- - !> - Minimum evap of rain in dry environmental air. - ! ----------------------------------------------------------------------- - - if (qr (k) > qcmin) then - qsw = wqs2 (tz (k), den (k), dqsdt) - sink = min (qr (k), dim (rh_rain * qsw, qv (k)) / (1. + lcpk (k) * dqsdt)) - qv (k) = qv (k) + sink - qr (k) = qr (k) - sink - q_liq (k) = q_liq (k) - sink - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) - sink * lhl (k) / cvm (k) - endif -#endif - - ! ----------------------------------------------------------------------- - !> - Update capacity heat and latend heat coefficient. - ! ----------------------------------------------------------------------- - - lhl (k) = lv00 + d0_vap * tz (k) - cvm (k) = c_air + (qv (k) + q_liq (k) + q_sol (k)) * c_vap - lcpk (k) = lhl (k) / cvm (k) - - ! ----------------------------------------------------------------------- - ! compute cloud fraction - ! ----------------------------------------------------------------------- - - ! ----------------------------------------------------------------------- - !> - Combine water species. - ! ----------------------------------------------------------------------- - - if (do_qa) cycle - - if (rad_snow) then - q_sol (k) = qi (k) + qs (k) - else - q_sol (k) = qi (k) - endif - if (rad_rain) then - q_liq (k) = ql (k) + qr (k) - else - q_liq (k) = ql (k) - endif - q_cond (k) = q_liq (k) + q_sol (k) - - qpz = qv (k) + q_cond (k) ! qpz is conserved - - ! ----------------------------------------------------------------------- - !> - Use the "liquid-frozen water temperature" (tin) to compute saturated specific humidity. - ! ----------------------------------------------------------------------- - - tin = tz (k) - (lcpk (k) * q_cond (k) + icpk (k) * q_sol (k)) ! minimum temperature - ! tin = tz (k) - ((lv00 + d0_vap * tz (k)) * q_cond (k) + & - ! (li00 + dc_ice * tz (k)) * q_sol (k)) / (c_air + qpz * c_vap) - - ! ----------------------------------------------------------------------- - ! determine saturated specific humidity - ! ----------------------------------------------------------------------- - - if (tin <= t_wfr) then - ! ice phase: - qstar = iqs1 (tin, den (k)) - elseif (tin >= tice) then - ! liquid phase: - qstar = wqs1 (tin, den (k)) - else - ! mixed phase: - qsi = iqs1 (tin, den (k)) - qsw = wqs1 (tin, den (k)) - if (q_cond (k) > 3.e-6) then - rqi = q_sol (k) / q_cond (k) - else - ! ----------------------------------------------------------------------- - ! mostly liquid water q_cond (k) at initial cloud development stage - ! ----------------------------------------------------------------------- - rqi = (tice - tin) / (tice - t_wfr) - endif - qstar = rqi * qsi + (1. - rqi) * qsw - endif - - ! ----------------------------------------------------------------------- - !> - Compute cloud fraction, assuming subgrid linear distribution in horizontal; - !! this is effectively a smoother for the binary cloud scheme. - ! ----------------------------------------------------------------------- - - if (qpz > qrmin) then - ! partial cloudiness by pdf: - dq = max (qcmin, h_var * qpz) - q_plus = qpz + dq ! cloud free if qstar > q_plus - q_minus = qpz - dq - if (qstar < q_minus) then - qa (k) = qa (k) + 1. ! air fully saturated; 100 % cloud cover - elseif (qstar < q_plus .and. q_cond (k) > qc_crt) then - qa (k) = qa (k) + (q_plus - qstar) / (dq + dq) ! partial cloud cover - ! qa (k) = sqrt (qa (k) + (q_plus - qstar) / (dq + dq)) - endif - endif - - enddo - -end subroutine subgrid_z_proc - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!> This subroutine calculates rain evaporation. -subroutine revap_rac1 (hydrostatic, is, ie, dt, tz, qv, ql, qr, qi, qs, qg, den, hvar) - - implicit none - - logical, intent (in) :: hydrostatic - - integer, intent (in) :: is, ie - - real, intent (in) :: dt ! time step (s) - - real, intent (in), dimension (is:ie) :: den, hvar, qi, qs, qg - - real, intent (inout), dimension (is:ie) :: tz, qv, qr, ql - - real, dimension (is:ie) :: lcp2, denfac, q_liq, q_sol, cvm, lhl - - real :: dqv, qsat, dqsdt, evap, qden, q_plus, q_minus, sink - real :: tin, t2, qpz, dq, dqh - - integer :: i - - ! ----------------------------------------------------------------------- - ! define latend heat coefficient - ! ----------------------------------------------------------------------- - - do i = is, ie - lhl (i) = lv00 + d0_vap * tz (i) - q_liq (i) = ql (i) + qr (i) - q_sol (i) = qi (i) + qs (i) + qg (i) - cvm (i) = c_air + qv (i) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice - lcp2 (i) = lhl (i) / cvm (i) - ! denfac (i) = sqrt (sfcrho / den (i)) - enddo - - do i = is, ie - if (qr (i) > qrmin .and. tz (i) > t_wfr) then - qpz = qv (i) + ql (i) - tin = tz (i) - lcp2 (i) * ql (i) ! presence of clouds suppresses the rain evap - qsat = wqs2 (tin, den (i), dqsdt) - dqh = max (ql (i), hvar (i) * max (qpz, qcmin)) - dqv = qsat - qv (i) - q_minus = qpz - dqh - q_plus = qpz + dqh - - ! ----------------------------------------------------------------------- - ! qsat must be > q_minus to activate evaporation - ! qsat must be < q_plus to activate accretion - ! ----------------------------------------------------------------------- - - ! ----------------------------------------------------------------------- - ! rain evaporation - ! ----------------------------------------------------------------------- - - if (dqv > qvmin .and. qsat > q_minus) then - if (qsat > q_plus) then - dq = qsat - qpz - else - ! q_minus < qsat < q_plus - ! dq == dqh if qsat == q_minus - dq = 0.25 * (q_minus - qsat) ** 2 / dqh - endif - qden = qr (i) * den (i) - t2 = tin * tin - evap = crevp (1) * t2 * dq * (crevp (2) * sqrt (qden) + crevp (3) * exp (0.725 * log (qden))) & - / (crevp (4) * t2 + crevp (5) * qsat * den (i)) - evap = min (qr (i), dt * evap, dqv / (1. + lcp2 (i) * dqsdt)) - qr (i) = qr (i) - evap - qv (i) = qv (i) + evap - q_liq (i) = q_liq (i) - evap - cvm (i) = c_air + qv (i) * c_vap + q_liq (i) * c_liq + q_sol (i) * c_ice - tz (i) = tz (i) - evap * lhl (i) / cvm (i) - endif - - ! ----------------------------------------------------------------------- - ! accretion: pracc - ! ----------------------------------------------------------------------- - - if (qr (i) > qrmin .and. ql (i) > 1.e-8 .and. qsat < q_plus) then - denfac (i) = sqrt (sfcrho / den (i)) - sink = dt * denfac (i) * cracw * exp (0.95 * log (qr (i) * den (i))) - sink = sink / (1. + sink) * ql (i) - ql (i) = ql (i) - sink - qr (i) = qr (i) + sink - endif - endif - enddo - -end subroutine revap_rac1 - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!>@brief The subroutine 'terminal_fall' computes terminal fall speed. -!>@details It considers cloud ice, snow, and graupel's melting during fall. -subroutine terminal_fall (dtm, ktop, kbot, tz, qv, ql, qr, qg, qs, qi, dz, dp, & - den, vtg, vts, vti, r1, g1, s1, i1, m1_sol, w1) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in) :: dtm ! time step (s) - - real, intent (in), dimension (ktop:kbot) :: vtg, vts, vti, den, dp, dz - - real, intent (inout), dimension (ktop:kbot) :: qv, ql, qr, qg, qs, qi, tz, m1_sol, w1 - - real, intent (out) :: r1, g1, s1, i1 - - real, dimension (ktop:kbot + 1) :: ze, zt - - real :: qsat, dqsdt, dt5, evap, dtime - real :: factor, frac - real :: tmp, precip, tc, sink - - real, dimension (ktop:kbot) :: lcpk, icpk, cvm, q_liq, q_sol, lhl, lhi - real, dimension (ktop:kbot) :: m1, dm - - real :: zs = 0. - real :: fac_imlt - - integer :: k, k0, m - - logical :: no_fall - - dt5 = 0.5 * dtm - fac_imlt = 1. - exp (- dt5 / tau_imlt) - - ! ----------------------------------------------------------------------- - ! define heat capacity and latend heat coefficient - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - m1_sol (k) = 0. - lhl (k) = lv00 + d0_vap * tz (k) - lhi (k) = li00 + dc_ice * tz (k) - q_liq (k) = ql (k) + qr (k) - q_sol (k) = qi (k) + qs (k) + qg (k) - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - lcpk (k) = lhl (k) / cvm (k) - icpk (k) = lhi (k) / cvm (k) - enddo - - ! ----------------------------------------------------------------------- - ! find significant melting level - ! ----------------------------------------------------------------------- - - k0 = kbot - do k = ktop, kbot - 1 - if (tz (k) > tice) then - k0 = k - exit - endif - enddo - - ! ----------------------------------------------------------------------- - ! melting of cloud_ice (before fall) : - ! ----------------------------------------------------------------------- - - do k = k0, kbot - tc = tz (k) - tice - if (qi (k) > qcmin .and. tc > 0.) then - sink = min (qi (k), fac_imlt * tc / icpk (k)) - tmp = min (sink, dim (ql_mlt, ql (k))) - ql (k) = ql (k) + tmp - qr (k) = qr (k) + sink - tmp - qi (k) = qi (k) - sink - q_liq (k) = q_liq (k) + sink - q_sol (k) = q_sol (k) - sink - cvm (k) = c_air + qv (k) * c_vap + q_liq (k) * c_liq + q_sol (k) * c_ice - tz (k) = tz (k) - sink * lhi (k) / cvm (k) - tc = tz (k) - tice - endif - enddo - - ! ----------------------------------------------------------------------- - ! turn off melting when cloud microphysics time step is small - ! ----------------------------------------------------------------------- - - if (dtm < 60.) k0 = kbot - - ! sjl, turn off melting of falling cloud ice, snow and graupel - k0 = kbot - ! sjl, turn off melting of falling cloud ice, snow and graupel - - ze (kbot + 1) = zs - do k = kbot, ktop, - 1 - ze (k) = ze (k + 1) - dz (k) ! dz < 0 - enddo - - zt (ktop) = ze (ktop) - - ! ----------------------------------------------------------------------- - ! update capacity heat and latend heat coefficient - ! ----------------------------------------------------------------------- - - do k = k0, kbot - lhi (k) = li00 + dc_ice * tz (k) - icpk (k) = lhi (k) / cvm (k) - enddo - - ! ----------------------------------------------------------------------- - ! melting of falling cloud ice into rain - ! ----------------------------------------------------------------------- - - call check_column (ktop, kbot, qi, no_fall) - - if (vi_fac < 1.e-5 .or. no_fall) then - i1 = 0. - else - - do k = ktop + 1, kbot - zt (k) = ze (k) - dt5 * (vti (k - 1) + vti (k)) - enddo - zt (kbot + 1) = zs - dtm * vti (kbot) - - do k = ktop, kbot - if (zt (k + 1) >= zt (k)) zt (k + 1) = zt (k) - dz_min - enddo - - if (k0 < kbot) then - do k = kbot - 1, k0, - 1 - if (qi (k) > qrmin) then - do m = k + 1, kbot - if (zt (k + 1) >= ze (m)) exit - if (zt (k) < ze (m + 1) .and. tz (m) > tice) then - dtime = min (1.0, (ze (m) - ze (m + 1)) / (max (vr_min, vti (k)) * tau_imlt)) - sink = min (qi (k) * dp (k) / dp (m), dtime * (tz (m) - tice) / icpk (m)) - tmp = min (sink, dim (ql_mlt, ql (m))) - ql (m) = ql (m) + tmp - qr (m) = qr (m) - tmp + sink - tz (m) = tz (m) - sink * icpk (m) - qi (k) = qi (k) - sink * dp (m) / dp (k) - endif - enddo - endif - enddo - endif - - if (do_sedi_w) then - do k = ktop, kbot - dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) - enddo - endif - - if (use_ppm) then - call lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, qi, i1, m1_sol, mono_prof) - else - call implicit_fall (dtm, ktop, kbot, ze, vti, dp, qi, i1, m1_sol) - endif - - if (do_sedi_w) then - w1 (ktop) = (dm (ktop) * w1 (ktop) + m1_sol (ktop) * vti (ktop)) / (dm (ktop) - m1_sol (ktop)) - do k = ktop + 1, kbot - w1 (k) = (dm (k) * w1 (k) - m1_sol (k - 1) * vti (k - 1) + m1_sol (k) * vti (k)) & - / (dm (k) + m1_sol (k - 1) - m1_sol (k)) - enddo - endif - - endif - - ! ----------------------------------------------------------------------- - ! melting of falling snow into rain - ! ----------------------------------------------------------------------- - - r1 = 0. - - call check_column (ktop, kbot, qs, no_fall) - - if (no_fall) then - s1 = 0. - else - - do k = ktop + 1, kbot - zt (k) = ze (k) - dt5 * (vts (k - 1) + vts (k)) - enddo - zt (kbot + 1) = zs - dtm * vts (kbot) - - do k = ktop, kbot - if (zt (k + 1) >= zt (k)) zt (k + 1) = zt (k) - dz_min - enddo - - if (k0 < kbot) then - do k = kbot - 1, k0, - 1 - if (qs (k) > qrmin) then - do m = k + 1, kbot - if (zt (k + 1) >= ze (m)) exit - dtime = min (dtm, (ze (m) - ze (m + 1)) / (vr_min + vts (k))) - if (zt (k) < ze (m + 1) .and. tz (m) > tice) then - dtime = min (1.0, dtime / tau_smlt) - sink = min (qs (k) * dp (k) / dp (m), dtime * (tz (m) - tice) / icpk (m)) - tz (m) = tz (m) - sink * icpk (m) - qs (k) = qs (k) - sink * dp (m) / dp (k) - if (zt (k) < zs) then - r1 = r1 + sink * dp (m) ! precip as rain - else - ! qr source here will fall next time step (therefore, can evap) - qr (m) = qr (m) + sink - endif - endif - if (qs (k) < qrmin) exit - enddo - endif - enddo - endif - - if (do_sedi_w) then - do k = ktop, kbot - dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) - enddo - endif - - if (use_ppm) then - call lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, qs, s1, m1, mono_prof) - else - call implicit_fall (dtm, ktop, kbot, ze, vts, dp, qs, s1, m1) - endif - - do k = ktop, kbot - m1_sol (k) = m1_sol (k) + m1 (k) - enddo - - if (do_sedi_w) then - w1 (ktop) = (dm (ktop) * w1 (ktop) + m1 (ktop) * vts (ktop)) / (dm (ktop) - m1 (ktop)) - do k = ktop + 1, kbot - w1 (k) = (dm (k) * w1 (k) - m1 (k - 1) * vts (k - 1) + m1 (k) * vts (k)) & - / (dm (k) + m1 (k - 1) - m1 (k)) - enddo - endif - - endif - - ! ---------------------------------------------- - ! melting of falling graupel into rain - ! ---------------------------------------------- - - call check_column (ktop, kbot, qg, no_fall) - - if (no_fall) then - g1 = 0. - else - - do k = ktop + 1, kbot - zt (k) = ze (k) - dt5 * (vtg (k - 1) + vtg (k)) - enddo - zt (kbot + 1) = zs - dtm * vtg (kbot) - - do k = ktop, kbot - if (zt (k + 1) >= zt (k)) zt (k + 1) = zt (k) - dz_min - enddo - - if (k0 < kbot) then - do k = kbot - 1, k0, - 1 - if (qg (k) > qrmin) then - do m = k + 1, kbot - if (zt (k + 1) >= ze (m)) exit - dtime = min (dtm, (ze (m) - ze (m + 1)) / vtg (k)) - if (zt (k) < ze (m + 1) .and. tz (m) > tice) then - dtime = min (1., dtime / tau_g2r) - sink = min (qg (k) * dp (k) / dp (m), dtime * (tz (m) - tice) / icpk (m)) - tz (m) = tz (m) - sink * icpk (m) - qg (k) = qg (k) - sink * dp (m) / dp (k) - if (zt (k) < zs) then - r1 = r1 + sink * dp (m) - else - qr (m) = qr (m) + sink - endif - endif - if (qg (k) < qrmin) exit - enddo - endif - enddo - endif - - if (do_sedi_w) then - do k = ktop, kbot - dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) - enddo - endif - - if (use_ppm) then - call lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, qg, g1, m1, mono_prof) - else - call implicit_fall (dtm, ktop, kbot, ze, vtg, dp, qg, g1, m1) - endif - - do k = ktop, kbot - m1_sol (k) = m1_sol (k) + m1 (k) - enddo - - if (do_sedi_w) then - w1 (ktop) = (dm (ktop) * w1 (ktop) + m1 (ktop) * vtg (ktop)) / (dm (ktop) - m1 (ktop)) - do k = ktop + 1, kbot - w1 (k) = (dm (k) * w1 (k) - m1 (k - 1) * vtg (k - 1) + m1 (k) * vtg (k)) & - / (dm (k) + m1 (k - 1) - m1 (k)) - enddo - endif - - endif - -end subroutine terminal_fall - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!>@brief The subroutine 'check_column' checks -!! if the water species is large enough to fall. -subroutine check_column (ktop, kbot, q, no_fall) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in) :: q (ktop:kbot) - - logical, intent (out) :: no_fall - - integer :: k - - no_fall = .true. - - do k = ktop, kbot - if (q (k) > qrmin) then - no_fall = .false. - exit - endif - enddo - -end subroutine check_column - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!>@brief The subroutine computes the time-implicit monotonic -!! fall scheme. -!>@author Shian-Jiann Lin, 2016 -subroutine implicit_fall (dt, ktop, kbot, ze, vt, dp, q, precip, m1) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in) :: dt - - real, intent (in), dimension (ktop:kbot + 1) :: ze - - real, intent (in), dimension (ktop:kbot) :: vt, dp - - real, intent (inout), dimension (ktop:kbot) :: q - - real, intent (out), dimension (ktop:kbot) :: m1 - - real, intent (out) :: precip - - real, dimension (ktop:kbot) :: dz, qm, dd - - integer :: k - - do k = ktop, kbot - dz (k) = ze (k) - ze (k + 1) - dd (k) = dt * vt (k) - q (k) = q (k) * dp (k) - enddo - - ! ----------------------------------------------------------------------- - ! sedimentation: non - vectorizable loop - ! ----------------------------------------------------------------------- - - qm (ktop) = q (ktop) / (dz (ktop) + dd (ktop)) - do k = ktop + 1, kbot - qm (k) = (q (k) + dd (k - 1) * qm (k - 1)) / (dz (k) + dd (k)) - enddo - - ! ----------------------------------------------------------------------- - ! qm is density at this stage - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - qm (k) = qm (k) * dz (k) - enddo - - ! ----------------------------------------------------------------------- - ! output mass fluxes: non - vectorizable loop - ! ----------------------------------------------------------------------- - - m1 (ktop) = q (ktop) - qm (ktop) - do k = ktop + 1, kbot - m1 (k) = m1 (k - 1) + q (k) - qm (k) - enddo - precip = m1 (kbot) - - ! ----------------------------------------------------------------------- - ! update: - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - q (k) = qm (k) / dp (k) - enddo - -end subroutine implicit_fall - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! Lagrangian scheme -!> \author S.J. Lin -subroutine lagrangian_fall_ppm (ktop, kbot, zs, ze, zt, dp, q, precip, m1, mono) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in) :: zs - - logical, intent (in) :: mono - - real, intent (in), dimension (ktop:kbot + 1) :: ze, zt - - real, intent (in), dimension (ktop:kbot) :: dp - - ! m1: flux - real, intent (inout), dimension (ktop:kbot) :: q, m1 - - real, intent (out) :: precip - - real, dimension (ktop:kbot) :: qm, dz - - real :: a4 (4, ktop:kbot) - - real :: pl, pr, delz, esl - - integer :: k, k0, n, m - - real, parameter :: r3 = 1. / 3., r23 = 2. / 3. - - ! ----------------------------------------------------------------------- - ! density: - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - dz (k) = zt (k) - zt (k + 1) ! note: dz is positive - q (k) = q (k) * dp (k) - a4 (1, k) = q (k) / dz (k) - qm (k) = 0. - enddo - - ! ----------------------------------------------------------------------- - ! construct vertical profile with zt as coordinate - ! ----------------------------------------------------------------------- - - call cs_profile (a4 (1, ktop), dz (ktop), kbot - ktop + 1, mono) - - k0 = ktop - do k = ktop, kbot - do n = k0, kbot - if (ze (k) <= zt (n) .and. ze (k) >= zt (n + 1)) then - pl = (zt (n) - ze (k)) / dz (n) - if (zt (n + 1) <= ze (k + 1)) then - ! entire new grid is within the original grid - pr = (zt (n) - ze (k + 1)) / dz (n) - qm (k) = a4 (2, n) + 0.5 * (a4 (4, n) + a4 (3, n) - a4 (2, n)) * (pr + pl) - & - a4 (4, n) * r3 * (pr * (pr + pl) + pl ** 2) - qm (k) = qm (k) * (ze (k) - ze (k + 1)) - k0 = n - goto 555 - else - qm (k) = (ze (k) - zt (n + 1)) * (a4 (2, n) + 0.5 * (a4 (4, n) + & - a4 (3, n) - a4 (2, n)) * (1. + pl) - a4 (4, n) * (r3 * (1. + pl * (1. + pl)))) - if (n < kbot) then - do m = n + 1, kbot - ! locate the bottom edge: ze (k + 1) - if (ze (k + 1) < zt (m + 1)) then - qm (k) = qm (k) + q (m) - else - delz = zt (m) - ze (k + 1) - esl = delz / dz (m) - qm (k) = qm (k) + delz * (a4 (2, m) + 0.5 * esl * & - (a4 (3, m) - a4 (2, m) + a4 (4, m) * (1. - r23 * esl))) - k0 = m - goto 555 - endif - enddo - endif - goto 555 - endif - endif - enddo - 555 continue - enddo - - m1 (ktop) = q (ktop) - qm (ktop) - do k = ktop + 1, kbot - m1 (k) = m1 (k - 1) + q (k) - qm (k) - enddo - precip = m1 (kbot) - - ! convert back to * dry * mixing ratio: - ! dp must be dry air_mass (because moist air mass will be changed due to terminal fall) . - - do k = ktop, kbot - q (k) = qm (k) / dp (k) - enddo - -end subroutine lagrangian_fall_ppm - -!>\ingroup mod_gfdl_cloud_mp -subroutine cs_profile (a4, del, km, do_mono) - - implicit none - - integer, intent (in) :: km ! vertical dimension - - real, intent (in) :: del (km) - - logical, intent (in) :: do_mono - - real, intent (inout) :: a4 (4, km) - - real, parameter :: qp_min = 1.e-6 - - real :: gam (km) - real :: q (km + 1) - real :: d4, bet, a_bot, grat, pmp, lac - real :: pmp_1, lac_1, pmp_2, lac_2 - real :: da1, da2, a6da - - integer :: k - - logical extm (km) - - grat = del (2) / del (1) ! grid ratio - bet = grat * (grat + 0.5) - q (1) = (2. * grat * (grat + 1.) * a4 (1, 1) + a4 (1, 2)) / bet - gam (1) = (1. + grat * (grat + 1.5)) / bet - - do k = 2, km - d4 = del (k - 1) / del (k) - bet = 2. + 2. * d4 - gam (k - 1) - q (k) = (3. * (a4 (1, k - 1) + d4 * a4 (1, k)) - q (k - 1)) / bet - gam (k) = d4 / bet - enddo - - a_bot = 1. + d4 * (d4 + 1.5) - q (km + 1) = (2. * d4 * (d4 + 1.) * a4 (1, km) + a4 (1, km - 1) - a_bot * q (km)) & - / (d4 * (d4 + 0.5) - a_bot * gam (km)) - - do k = km, 1, - 1 - q (k) = q (k) - gam (k) * q (k + 1) - enddo - - ! ----------------------------------------------------------------------- - ! apply constraints - ! ----------------------------------------------------------------------- - - do k = 2, km - gam (k) = a4 (1, k) - a4 (1, k - 1) - enddo - - ! ----------------------------------------------------------------------- - ! apply large - scale constraints to all fields if not local max / min - ! ----------------------------------------------------------------------- - - ! ----------------------------------------------------------------------- - ! top: - ! ----------------------------------------------------------------------- - - q (1) = max (q (1), 0.) - q (2) = min (q (2), max (a4 (1, 1), a4 (1, 2))) - q (2) = max (q (2), min (a4 (1, 1), a4 (1, 2)), 0.) - - ! ----------------------------------------------------------------------- - ! interior: - ! ----------------------------------------------------------------------- - - do k = 3, km - 1 - if (gam (k - 1) * gam (k + 1) > 0.) then - q (k) = min (q (k), max (a4 (1, k - 1), a4 (1, k))) - q (k) = max (q (k), min (a4 (1, k - 1), a4 (1, k))) - else - if (gam (k - 1) > 0.) then - ! there exists a local max - q (k) = max (q (k), min (a4 (1, k - 1), a4 (1, k))) - else - ! there exists a local min - q (k) = min (q (k), max (a4 (1, k - 1), a4 (1, k))) - q (k) = max (q (k), 0.0) - endif - endif - enddo - - ! ----------------------------------------------------------------------- - ! bottom : - ! ----------------------------------------------------------------------- - - q (km) = min (q (km), max (a4 (1, km - 1), a4 (1, km))) - q (km) = max (q (km), min (a4 (1, km - 1), a4 (1, km)), 0.) - ! q (km + 1) = max (q (km + 1), 0.) - - ! ----------------------------------------------------------------------- - ! f (s) = al + s * [ (ar - al) + a6 * (1 - s) ] (0 <= s <= 1) - ! ----------------------------------------------------------------------- - - do k = 1, km - 1 - a4 (2, k) = q (k) - a4 (3, k) = q (k + 1) - enddo - - do k = 2, km - 1 - if (gam (k) * gam (k + 1) > 0.0) then - extm (k) = .false. - else - extm (k) = .true. - endif - enddo - - if (do_mono) then - do k = 3, km - 2 - if (extm (k)) then - ! positive definite constraint only if true local extrema - if (a4 (1, k) < qp_min .or. extm (k - 1) .or. extm (k + 1)) then - a4 (2, k) = a4 (1, k) - a4 (3, k) = a4 (1, k) - endif - else - a4 (4, k) = 6. * a4 (1, k) - 3. * (a4 (2, k) + a4 (3, k)) - if (abs (a4 (4, k)) > abs (a4 (2, k) - a4 (3, k))) then - ! check within the smooth region if subgrid profile is non - monotonic - pmp_1 = a4 (1, k) - 2.0 * gam (k + 1) - lac_1 = pmp_1 + 1.5 * gam (k + 2) - a4 (2, k) = min (max (a4 (2, k), min (a4 (1, k), pmp_1, lac_1)), & - max (a4 (1, k), pmp_1, lac_1)) - pmp_2 = a4 (1, k) + 2.0 * gam (k) - lac_2 = pmp_2 - 1.5 * gam (k - 1) - a4 (3, k) = min (max (a4 (3, k), min (a4 (1, k), pmp_2, lac_2)), & - max (a4 (1, k), pmp_2, lac_2)) - endif - endif - enddo - else - do k = 3, km - 2 - if (extm (k)) then - if (a4 (1, k) < qp_min .or. extm (k - 1) .or. extm (k + 1)) then - a4 (2, k) = a4 (1, k) - a4 (3, k) = a4 (1, k) - endif - endif - enddo - endif - - do k = 1, km - 1 - a4 (4, k) = 6. * a4 (1, k) - 3. * (a4 (2, k) + a4 (3, k)) - enddo - - k = km - 1 - if (extm (k)) then - a4 (2, k) = a4 (1, k) - a4 (3, k) = a4 (1, k) - a4 (4, k) = 0. - else - da1 = a4 (3, k) - a4 (2, k) - da2 = da1 ** 2 - a6da = a4 (4, k) * da1 - if (a6da < - da2) then - a4 (4, k) = 3. * (a4 (2, k) - a4 (1, k)) - a4 (3, k) = a4 (2, k) - a4 (4, k) - elseif (a6da > da2) then - a4 (4, k) = 3. * (a4 (3, k) - a4 (1, k)) - a4 (2, k) = a4 (3, k) - a4 (4, k) - endif - endif - - call cs_limiters (km - 1, a4) - - ! ----------------------------------------------------------------------- - ! bottom layer: - ! ----------------------------------------------------------------------- - - a4 (2, km) = a4 (1, km) - a4 (3, km) = a4 (1, km) - a4 (4, km) = 0. - -end subroutine cs_profile - -!>\ingroup mod_gfdl_cloud_mp -!! This subroutine perform positive definite constraint. -subroutine cs_limiters (km, a4) - - implicit none - - integer, intent (in) :: km - - real, intent (inout) :: a4 (4, km) ! ppm array - - real, parameter :: r12 = 1. / 12. - - integer :: k - - ! ----------------------------------------------------------------------- - ! positive definite constraint - ! ----------------------------------------------------------------------- - - do k = 1, km - if (abs (a4 (3, k) - a4 (2, k)) < - a4 (4, k)) then - if ((a4 (1, k) + 0.25 * (a4 (3, k) - a4 (2, k)) ** 2 / a4 (4, k) + a4 (4, k) * r12) < 0.) then - if (a4 (1, k) < a4 (3, k) .and. a4 (1, k) < a4 (2, k)) then - a4 (3, k) = a4 (1, k) - a4 (2, k) = a4 (1, k) - a4 (4, k) = 0. - elseif (a4 (3, k) > a4 (2, k)) then - a4 (4, k) = 3. * (a4 (2, k) - a4 (1, k)) - a4 (3, k) = a4 (2, k) - a4 (4, k) - else - a4 (4, k) = 3. * (a4 (3, k) - a4 (1, k)) - a4 (2, k) = a4 (3, k) - a4 (4, k) - endif - endif - endif - enddo - -end subroutine cs_limiters - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine calculates vertical fall speed of snow/ice/graupel. -subroutine fall_speed (ktop, kbot, den, qs, qi, qg, ql, tk, vts, vti, vtg) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in), dimension (ktop:kbot) :: den, qs, qi, qg, ql, tk - real, intent (out), dimension (ktop:kbot) :: vts, vti, vtg - - ! fall velocity constants: - - real, parameter :: thi = 1.0e-8 !< cloud ice threshold for terminal fall - real, parameter :: thg = 1.0e-8 - real, parameter :: ths = 1.0e-8 - - ! coefficient for the parameterization of mass weighted fall velocity - ! as a function of temperature and IWC. - ! Table 1 in Deng and Mace (2008) \cite deng_and_mace_2008. - real, parameter :: aa = - 4.14122e-5 - real, parameter :: bb = - 0.00538922 - real, parameter :: cc = - 0.0516344 - real, parameter :: dd = 0.00216078 - real, parameter :: ee = 1.9714 - - ! marshall - palmer constants - - real, parameter :: vcons = 6.6280504 - real, parameter :: vcong = 87.2382675 - real, parameter :: vconh = vcong * sqrt (rhoh / rhog) - real, parameter :: norms = 942477796.076938 - real, parameter :: normg = 5026548245.74367 - real, parameter :: normh = pi * rhoh * rnzh - - real, dimension (ktop:kbot) :: qden, tc, rhof - - real :: vi0 - - integer :: k - - ! ----------------------------------------------------------------------- - ! marshall - palmer formula - ! ----------------------------------------------------------------------- - - ! ----------------------------------------------------------------------- - ! try the local air density -- for global model; the true value could be - ! much smaller than sfcrho over high mountains - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - rhof (k) = sqrt (min (10., sfcrho / den (k))) - enddo - - ! ----------------------------------------------------------------------- - !> - ice: use Deng and Mace (2008) \cite deng_and_mace_2008, which gives smaler - !! fall speed than Heymsfield and Donner (1990) \cite heymsfield_and_donner_1990. - ! ----------------------------------------------------------------------- - - if (const_vi) then - vti (:) = vi_fac - else - ! ----------------------------------------------------------------------- - ! use deng and mace (2008, grl), which gives smaller fall speed than hd90 formula - ! ----------------------------------------------------------------------- - vi0 = 0.01 * vi_fac - do k = ktop, kbot - if (qi (k) < thi) then ! this is needed as the fall - speed maybe problematic for small qi - vti (k) = vf_min - else - tc (k) = tk (k) - tice - vti (k) = (3. + log10 (qi (k) * den (k))) * (tc (k) * (aa * tc (k) + bb) + cc) + dd * tc (k) + ee - vti (k) = vi0 * exp (log_10 * vti (k)) * 0.9 - vti (k) = min (vi_max, max (vf_min, vti (k))) - endif - enddo - endif - - ! ----------------------------------------------------------------------- - !> - snow: - ! ----------------------------------------------------------------------- - - if (const_vs) then - vts (:) = vs_fac ! 1. ifs_2016 - else - do k = ktop, kbot - if (qs (k) < ths) then - vts (k) = vf_min - else - vts (k) = vs_fac * vcons * rhof (k) * exp (0.0625 * log (qs (k) * den (k) / norms)) - vts (k) = min (vs_max, max (vf_min, vts (k))) - endif - enddo - endif - - ! ----------------------------------------------------------------------- - !> - graupel: - ! ----------------------------------------------------------------------- - if (const_vg) then - vtg (:) = vg_fac ! 2. - else - if (do_hail) then - do k = ktop, kbot - if (qg (k) < thg) then - vtg (k) = vf_min - else - vtg (k) = vg_fac * vconh * rhof (k) * sqrt (sqrt (sqrt (qg (k) * den (k) / normh))) - vtg (k) = min (vg_max, max (vf_min, vtg (k))) - endif - enddo - else - do k = ktop, kbot - if (qg (k) < thg) then - vtg (k) = vf_min - else - vtg (k) = vg_fac * vcong * rhof (k) * sqrt (sqrt (sqrt (qg (k) * den (k) / normg))) - vtg (k) = min (vg_max, max (vf_min, vtg (k))) - endif - enddo - endif - endif - -end subroutine fall_speed - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine sets up gfdl cloud microphysics parameters. -subroutine setupm - - implicit none - - real :: gcon, cd, scm3, pisq, act (8) - real :: vdifu, tcond - real :: visk - real :: ch2o, hltf - real :: hlts, hltc, ri50 - - real, parameter :: gam263 = 1.456943, gam275 = 1.608355, gam290 = 1.827363, & - gam325 = 2.54925, gam350 = 3.323363, gam380 = 4.694155, & - gam425 = 8.285063, gam450 = 11.631769, gam480 = 17.837789, & - gam625 = 184.860962, gam680 = 496.604067 - - ! intercept parameters - -! real, parameter :: rnzr = 8.0e6 ! lin83 -! real, parameter :: rnzs = 3.0e6 ! lin83 -! real, parameter :: rnzg = 4.0e6 ! rh84 - - ! density parameters - -! real, parameter :: rhos = 0.1e3 !< lin83 (snow density; 1 / 10 of water) -! real, parameter :: rhog = 0.4e3 !< rh84 (graupel density) - real, parameter :: acc (3) = (/ 5.0, 2.0, 0.5 /) - - real den_rc - - integer :: i, k - - pie = 4. * atan (1.0) - - ! s. klein's formular (eq 16) from am2 - - fac_rc = (4. / 3.) * pie * rhor * rthresh ** 3 - - if (prog_ccn) then - ! if (master) write (*, *) 'prog_ccn option is .t.' - else - den_rc = fac_rc * ccn_o * 1.e6 - ! if (master) write (*, *) 'mp: for ccn_o = ', ccn_o, 'ql_rc = ', den_rc - den_rc = fac_rc * ccn_l * 1.e6 - ! if (master) write (*, *) 'mp: for ccn_l = ', ccn_l, 'ql_rc = ', den_rc - endif - - vdifu = 2.11e-5 - tcond = 2.36e-2 - - visk = 1.259e-5 - hlts = 2.8336e6 - hltc = 2.5e6 - hltf = 3.336e5 - - ch2o = 4.1855e3 - ri50 = 1.e-4 - - pisq = pie * pie - scm3 = (visk / vdifu) ** (1. / 3.) - - cracs = pisq * rnzr * rnzs * rhos - csacr = pisq * rnzr * rnzs * rhor - if (do_hail) then - cgacr = pisq * rnzr * rnzh * rhor - cgacs = pisq * rnzh * rnzs * rhos - else - cgacr = pisq * rnzr * rnzg * rhor - cgacs = pisq * rnzg * rnzs * rhos - endif - cgacs = cgacs * c_pgacs - - ! act: 1 - 2:racs (s - r) ; 3 - 4:sacr (r - s) ; - ! 5 - 6:gacr (r - g) ; 7 - 8:gacs (s - g) - - act (1) = pie * rnzs * rhos - act (2) = pie * rnzr * rhor - if (do_hail) then - act (6) = pie * rnzh * rhoh - else - act (6) = pie * rnzg * rhog - endif - act (3) = act (2) - act (4) = act (1) - act (5) = act (2) - act (7) = act (1) - act (8) = act (6) - - do i = 1, 3 - do k = 1, 4 - acco (i, k) = acc (i) / (act (2 * k - 1) ** ((7 - i) * 0.25) * act (2 * k) ** (i * 0.25)) - enddo - enddo - - gcon = 40.74 * sqrt (sfcrho) ! 44.628 - - csacw = pie * rnzs * clin * gam325 / (4. * act (1) ** 0.8125) - ! decreasing csacw to reduce cloud water --- > snow - - craci = pie * rnzr * alin * gam380 / (4. * act (2) ** 0.95) - csaci = csacw * c_psaci - - if (do_hail) then - cgacw = pie * rnzh * gam350 * gcon / (4. * act (6) ** 0.875) - else - cgacw = pie * rnzg * gam350 * gcon / (4. * act (6) ** 0.875) - endif - ! cgaci = cgacw * 0.1 - - ! sjl, may 28, 2012 - cgaci = cgacw * 0.05 - ! sjl, may 28, 2012 - - cracw = craci ! cracw = 3.27206196043822 - cracw = c_cracw * cracw - - ! subl and revp: five constants for three separate processes - - cssub (1) = 2. * pie * vdifu * tcond * rvgas * rnzs - if (do_hail) then - cgsub (1) = 2. * pie * vdifu * tcond * rvgas * rnzh - else - cgsub (1) = 2. * pie * vdifu * tcond * rvgas * rnzg - endif - crevp (1) = 2. * pie * vdifu * tcond * rvgas * rnzr - cssub (2) = 0.78 / sqrt (act (1)) - cgsub (2) = 0.78 / sqrt (act (6)) - crevp (2) = 0.78 / sqrt (act (2)) - cssub (3) = 0.31 * scm3 * gam263 * sqrt (clin / visk) / act (1) ** 0.65625 - cgsub (3) = 0.31 * scm3 * gam275 * sqrt (gcon / visk) / act (6) ** 0.6875 - crevp (3) = 0.31 * scm3 * gam290 * sqrt (alin / visk) / act (2) ** 0.725 - cssub (4) = tcond * rvgas - cssub (5) = hlts ** 2 * vdifu - cgsub (4) = cssub (4) - crevp (4) = cssub (4) - cgsub (5) = cssub (5) - crevp (5) = hltc ** 2 * vdifu - - cgfr (1) = 20.e2 * pisq * rnzr * rhor / act (2) ** 1.75 - cgfr (2) = 0.66 - - ! smlt: five constants (lin et al. 1983) - - csmlt (1) = 2. * pie * tcond * rnzs / hltf - csmlt (2) = 2. * pie * vdifu * rnzs * hltc / hltf - csmlt (3) = cssub (2) - csmlt (4) = cssub (3) - csmlt (5) = ch2o / hltf - - ! gmlt: five constants - - if (do_hail) then - cgmlt (1) = 2. * pie * tcond * rnzh / hltf - cgmlt (2) = 2. * pie * vdifu * rnzh * hltc / hltf - else - cgmlt (1) = 2. * pie * tcond * rnzg / hltf - cgmlt (2) = 2. * pie * vdifu * rnzg * hltc / hltf - endif - cgmlt (3) = cgsub (2) - cgmlt (4) = cgsub (3) - cgmlt (5) = ch2o / hltf - - es0 = 6.107799961e2 ! ~6.1 mb - ces0 = eps * es0 - -end subroutine setupm - -! ======================================================================= -! initialization of gfdl cloud microphysics -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine 'gfdl_cloud_microphys_init' initializes the GFDL -!! cloud microphysics. -subroutine gfdl_cloud_microphys_mod_init (me, master, nlunit, input_nml_file, logunit, & - fn_nml, errmsg, errflg) - - implicit none - - integer, intent (in) :: me - integer, intent (in) :: master - integer, intent (in) :: nlunit - integer, intent (in) :: logunit - - character (len = 64), intent (in) :: fn_nml - character (len = *), intent (in) :: input_nml_file(:) - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - integer :: ios - logical :: exists - - ! integer, intent (in) :: id, jd, kd - ! integer, intent (in) :: axes (4) - ! type (time_type), intent (in) :: time - - ! integer :: unit, io, ierr, k, logunit - ! logical :: flag - ! real :: tmp, q1, q2 - - ! master = (mpp_pe () .eq.mpp_root_pe ()) - - ! Initialize CCPP error-handling - errflg = 0 - errmsg = '' - -#ifdef INTERNAL_FILE_NML - read (input_nml_file, nml = gfdl_cloud_microphysics_nml) -#else - inquire (file = trim (fn_nml), exist = exists) - if (.not. exists) then - write (6, *) 'gfdl - mp :: namelist file: ', trim (fn_nml), ' does not exist' - errflg = 1 - errmsg = 'ERROR(gfdl_cloud_microphys_mod_init): namelist file '//trim (fn_nml)//' does not exist' - return - else - open (unit = nlunit, file = fn_nml, action = 'read' , status = 'old', iostat = ios) - endif - rewind (nlunit) - read (nlunit, nml = gfdl_cloud_microphysics_nml) - close (nlunit) -#endif - - ! write version number and namelist to log file - if (me == master) then - write (logunit, *) " ================================================================== " - write (logunit, *) "gfdl_cloud_microphys_mod" - write (logunit, nml = gfdl_cloud_microphysics_nml) - endif - - if (do_setup) then - call setup_con - call setupm - do_setup = .false. - endif - - log_10 = log (10.) - - tice0 = tice - 0.01 - t_wfr = tice - 40.0 ! supercooled water can exist down to - 48 c, which is the "absolute" - - ! if (master) write (logunit, nml = gfdl_cloud_microphys_nml) - ! - ! id_vtr = register_diag_field (mod_name, 'vt_r', axes (1:3), time, & - ! 'rain fall speed', 'm / s', missing_value = missing_value) - ! id_vts = register_diag_field (mod_name, 'vt_s', axes (1:3), time, & - ! 'snow fall speed', 'm / s', missing_value = missing_value) - ! id_vtg = register_diag_field (mod_name, 'vt_g', axes (1:3), time, & - ! 'graupel fall speed', 'm / s', missing_value = missing_value) - ! id_vti = register_diag_field (mod_name, 'vt_i', axes (1:3), time, & - ! 'ice fall speed', 'm / s', missing_value = missing_value) - - ! id_droplets = register_diag_field (mod_name, 'droplets', axes (1:3), time, & - ! 'droplet number concentration', '# / m3', missing_value = missing_value) - ! id_rh = register_diag_field (mod_name, 'rh_lin', axes (1:2), time, & - ! 'relative humidity', 'n / a', missing_value = missing_value) - - ! id_rain = register_diag_field (mod_name, 'rain_lin', axes (1:2), time, & - ! 'rain_lin', 'mm / day', missing_value = missing_value) - ! id_snow = register_diag_field (mod_name, 'snow_lin', axes (1:2), time, & - ! 'snow_lin', 'mm / day', missing_value = missing_value) - ! id_graupel = register_diag_field (mod_name, 'graupel_lin', axes (1:2), time, & - ! 'graupel_lin', 'mm / day', missing_value = missing_value) - ! id_ice = register_diag_field (mod_name, 'ice_lin', axes (1:2), time, & - ! 'ice_lin', 'mm / day', missing_value = missing_value) - ! id_prec = register_diag_field (mod_name, 'prec_lin', axes (1:2), time, & - ! 'prec_lin', 'mm / day', missing_value = missing_value) - - ! if (master) write (*, *) 'prec_lin diagnostics initialized.', id_prec - - ! id_cond = register_diag_field (mod_name, 'cond_lin', axes (1:2), time, & - ! 'total condensate', 'kg / m ** 2', missing_value = missing_value) - ! id_var = register_diag_field (mod_name, 'var_lin', axes (1:2), time, & - ! 'subgrid variance', 'n / a', missing_value = missing_value) - - ! call qsmith_init - - ! testing the water vapor tables - - ! if (mp_debug .and. master) then - ! write (*, *) 'testing water vapor tables in gfdl_cloud_microphys' - ! tmp = tice - 90. - ! do k = 1, 25 - ! q1 = wqsat_moist (tmp, 0., 1.e5) - ! q2 = qs1d_m (tmp, 0., 1.e5) - ! write (*, *) nint (tmp - tice), q1, q2, 'dq = ', q1 - q2 - ! tmp = tmp + 5. - ! enddo - ! endif - - ! if (master) write (*, *) 'gfdl_cloud_micrphys diagnostics initialized.' - - module_is_initialized = .true. - -!+---+-----------------------------------------------------------------+ -!..Set these variables needed for computing radar reflectivity. These -!.. get used within radar_init to create other variables used in the -!.. radar module. - - xam_r = pi*rhor/6. - xbm_r = 3. - xmu_r = 0. - xam_s = pi*rhos/6. - xbm_s = 3. - xmu_s = 0. - xam_g = pi*rhog/6. - xbm_g = 3. - xmu_g = 0. - - call radar_init - -end subroutine gfdl_cloud_microphys_mod_init - -! ======================================================================= -! end of gfdl cloud microphysics -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine 'gfdl_cloud_microphys_init' terminates the GFDL -!! cloud microphysics. -subroutine gfdl_cloud_microphys_mod_end() - - implicit none - - deallocate (table) - deallocate (table2) - deallocate (table3) - deallocate (tablew) - deallocate (des) - deallocate (des2) - deallocate (des3) - deallocate (desw) - - tables_are_initialized = .false. - -end subroutine gfdl_cloud_microphys_mod_end - -! ======================================================================= -! qsmith table initialization -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine 'setup_con' sets up constants and calls 'qsmith_init'. -subroutine setup_con - - implicit none - - ! master = (mpp_pe () .eq.mpp_root_pe ()) - - rgrav = 1. / grav - - if (.not. qsmith_tables_initialized) call qsmith_init - - qsmith_tables_initialized = .true. - -end subroutine setup_con - -! ======================================================================= -!>\ingroup gfdlmp -!>@brief The function is an accretion function (Lin et al.(1983) -!! \cite lin_et_al_1983 ) -! ======================================================================= - -real function acr3d (v1, v2, q1, q2, c, cac, rho) - - implicit none - - real, intent (in) :: v1, v2, c, rho - real, intent (in) :: q1, q2 ! mixing ratio!!! - real, intent (in) :: cac (3) - - real :: t1, s1, s2 - - ! integer :: k - ! - ! real :: a - ! - ! a = 0.0 - ! do k = 1, 3 - ! a = a + cac (k) * ((q1 * rho) ** ((7 - k) * 0.25) * (q2 * rho) ** (k * 0.25)) - ! enddo - ! acr3d = c * abs (v1 - v2) * a / rho - - ! optimized - - t1 = sqrt (q1 * rho) - s1 = sqrt (q2 * rho) - s2 = sqrt (s1) ! s1 = s2 ** 2 - acr3d = c * abs (v1 - v2) * q1 * s2 * (cac (1) * t1 + cac (2) * sqrt (t1) * s2 + cac (3) * s1) - -end function acr3d - -! ======================================================================= -!>\ingroup gfdlmp -!>@brief Melting of snow function (Lin et al.(1983) \cite lin_et_al_1983) -!! note: psacw and psacr must be calc before smlt is called -! ======================================================================= - -real function smlt (tc, dqs, qsrho, psacw, psacr, c, rho, rhofac) - - implicit none - - real, intent (in) :: tc, dqs, qsrho, psacw, psacr, c (5), rho, rhofac - - smlt = (c (1) * tc / rho - c (2) * dqs) * (c (3) * sqrt (qsrho) + & - c (4) * qsrho ** 0.65625 * sqrt (rhofac)) + c (5) * tc * (psacw + psacr) - -end function smlt - -! ======================================================================= -!>@brief Melting of graupel function (Eq.(47) in Lin et al. 1983 \cite lin_et_al_1983) -!!\n note: \f$P_{gacw}\f$ and \f$P_{gacr}\f$ must be calculated before gmlt is called. -! ======================================================================= - -real function gmlt (tc, dqs, qgrho, pgacw, pgacr, c, rho) - - implicit none - - real, intent (in) :: tc, dqs, qgrho, pgacw, pgacr, c (5), rho - - gmlt = (c (1) * tc / rho - c (2) * dqs) * (c (3) * sqrt (qgrho) + & - c (4) * qgrho ** 0.6875 / rho ** 0.25) + c (5) * tc * (pgacw + pgacr) - -end function gmlt - -! ======================================================================= -! initialization -! prepare saturation water vapor pressure tables -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!>@brief The subroutine 'qsmith_init' initializes lookup tables for saturation -!! water vapor pressure for the following utility routines that are designed -!! to return qs consistent with the assumptions in FV3. -!>@details The calculations are highly accurate values based on the Clausius-Clapeyron -!! equation. -! ======================================================================= -subroutine qsmith_init - - implicit none - - integer, parameter :: length = 2621 - - integer :: i - - if (.not. tables_are_initialized) then - - ! master = (mpp_pe () .eq. mpp_root_pe ()) - ! if (master) print *, ' gfdl mp: initializing qs tables' - - ! debug code - ! print *, mpp_pe (), allocated (table), allocated (table2), & - ! allocated (table3), allocated (tablew), allocated (des), & - ! allocated (des2), allocated (des3), allocated (desw) - ! end debug code - - ! generate es table (dt = 0.1 deg. c) - - allocate (table (length)) - allocate (table2 (length)) - allocate (table3 (length)) - allocate (tablew (length)) - allocate (des (length)) - allocate (des2 (length)) - allocate (des3 (length)) - allocate (desw (length)) - - call qs_table (length) - call qs_table2 (length) - call qs_table3 (length) - call qs_tablew (length) - - do i = 1, length - 1 - des (i) = max (0., table (i + 1) - table (i)) - des2 (i) = max (0., table2 (i + 1) - table2 (i)) - des3 (i) = max (0., table3 (i + 1) - table3 (i)) - desw (i) = max (0., tablew (i + 1) - tablew (i)) - enddo - des (length) = des (length - 1) - des2 (length) = des2 (length - 1) - des3 (length) = des3 (length - 1) - desw (length) = desw (length - 1) - - tables_are_initialized = .true. - - endif - -end subroutine qsmith_init - -! ======================================================================= -! compute the saturated specific humidity for table ii -!>\ingroup mod_gfdl_cloud_mp -!>@brief The function 'wqs1' returns the saturation vapor pressure over pure -!! liquid water for a given temperature and air density. -real 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, intent (in) :: ta, den - - real :: es, ap1, tmin - - integer :: it - - tmin = table_ice - 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 - -! ======================================================================= -! compute the gradient of saturated specific humidity for table ii -!>@brief The function 'wqs2' returns the saturation vapor pressure over pure -!! liquid water for a given temperature and air density, as well as the -!! analytic dqs/dT: rate of change of saturation vapor pressure WRT temperature. -! ======================================================================= - -real 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, intent (in) :: ta, den - - real, intent (out) :: dqdt - - real :: es, ap1, tmin - - integer :: it - - tmin = table_ice - 160. - - if (.not. tables_are_initialized) call qsmith_init - - 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 - -! ======================================================================= -! compute wet buld temperature -!>@brief The function 'wet_bulb' uses 'wqs2' to compute the wet-bulb temperature -!! from the mixing ratio and the temperature. -! ======================================================================= - -real function wet_bulb (q, t, den) - - implicit none - - real, intent (in) :: t, q, den - - real :: qs, tp, dqdt - - wet_bulb = t - qs = wqs2 (wet_bulb, den, dqdt) - tp = 0.5 * (qs - q) / (1. + lcp * dqdt) * lcp - wet_bulb = wet_bulb - tp - - ! tp is negative if super - saturated - if (tp > 0.01) then - qs = wqs2 (wet_bulb, den, dqdt) - tp = (qs - q) / (1. + lcp * dqdt) * lcp - wet_bulb = wet_bulb - tp - endif - -end function wet_bulb - -! ======================================================================= -!>@brief The function 'iqs1' computes the saturated specific humidity -!! for table iii -! ======================================================================= - -real 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, intent (in) :: ta, den - - real :: es, ap1, tmin - - integer :: it - - tmin = table_ice - 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 - -! ======================================================================= -!>@brief The function 'iqs2' computes the gradient of saturated specific -!! humidity for table iii -! ======================================================================= - -real 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, intent (in) :: ta, den - - real, intent (out) :: dqdt - - real :: es, ap1, tmin - - integer :: it - - tmin = table_ice - 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 - dqdt = 10. * (des2 (it) + (ap1 - it) * (des2 (it + 1) - des2 (it))) / (rvgas * ta * den) - -end function iqs2 - -! ======================================================================= -!>@brief The function 'qs1d_moist' computes the gradient of saturated -!! specific humidity for table iii. -! ======================================================================= - -real function qs1d_moist (ta, qv, pa, dqdt) - - implicit none - - real, intent (in) :: ta, pa, qv - - real, intent (out) :: dqdt - - real :: es, ap1, tmin, eps10 - - integer :: it - - tmin = table_ice - 160. - eps10 = 10. * eps - ap1 = 10. * dim (ta, tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es = table2 (it) + (ap1 - it) * des2 (it) - qs1d_moist = eps * es * (1. + zvir * qv) / pa - it = ap1 - 0.5 - dqdt = eps10 * (des2 (it) + (ap1 - it) * (des2 (it + 1) - des2 (it))) * (1. + zvir * qv) / pa - -end function qs1d_moist - -! ======================================================================= -! compute the gradient of saturated specific humidity for table ii -!>@brief The function 'wqsat2_moist' computes the saturated specific humidity -!! for pure liquid water , as well as des/dT. -! ======================================================================= - -real function wqsat2_moist (ta, qv, pa, dqdt) - - implicit none - - real, intent (in) :: ta, pa, qv - - real, intent (out) :: dqdt - - real :: es, ap1, tmin, eps10 - - integer :: it - - tmin = table_ice - 160. - eps10 = 10. * eps - ap1 = 10. * dim (ta, tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es = tablew (it) + (ap1 - it) * desw (it) - wqsat2_moist = eps * es * (1. + zvir * qv) / pa - it = ap1 - 0.5 - dqdt = eps10 * (desw (it) + (ap1 - it) * (desw (it + 1) - desw (it))) * (1. + zvir * qv) / pa - -end function wqsat2_moist - -! ======================================================================= -! compute the saturated specific humidity for table ii -!>@brief The function 'wqsat_moist' computes the saturated specific humidity -!! for pure liquid water. -! ======================================================================= - -real function wqsat_moist (ta, qv, pa) - - implicit none - - real, intent (in) :: ta, pa, qv - - real :: es, ap1, tmin - - integer :: it - - tmin = table_ice - 160. - ap1 = 10. * dim (ta, tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es = tablew (it) + (ap1 - it) * desw (it) - wqsat_moist = eps * es * (1. + zvir * qv) / pa - -end function wqsat_moist - -! ======================================================================= -!>@brief The function 'qs1d_m' computes the saturated specific humidity -!! for table iii -! ======================================================================= - -real function qs1d_m (ta, qv, pa) - - implicit none - - real, intent (in) :: ta, pa, qv - - real :: es, ap1, tmin - - integer :: it - - tmin = table_ice - 160. - ap1 = 10. * dim (ta, tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es = table2 (it) + (ap1 - it) * des2 (it) - qs1d_m = eps * es * (1. + zvir * qv) / pa - -end function qs1d_m - -! ======================================================================= -!>@brief The function 'd_sat' computes the difference in saturation -!! vapor * density * between water and ice -! ======================================================================= - -real function d_sat (ta, den) - - implicit none - - real, intent (in) :: ta, den - - real :: es_w, es_i, ap1, tmin - - integer :: it - - tmin = table_ice - 160. - ap1 = 10. * dim (ta, tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es_w = tablew (it) + (ap1 - it) * desw (it) - es_i = table2 (it) + (ap1 - it) * des2 (it) - d_sat = dim (es_w, es_i) / (rvgas * ta * den) ! take positive difference - -end function d_sat - -! ======================================================================= -!>@brief The function 'esw_table' computes the saturated water vapor -!! pressure for table ii -! ======================================================================= - -real function esw_table (ta) - - implicit none - - real, intent (in) :: ta - - real :: ap1, tmin - - integer :: it - - tmin = table_ice - 160. - ap1 = 10. * dim (ta, tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - esw_table = tablew (it) + (ap1 - it) * desw (it) - -end function esw_table - -! ======================================================================= -!>@brief The function 'es2_table' computes the saturated water -!! vapor pressure for table iii -! ======================================================================= - -real function es2_table (ta) - - implicit none - - real, intent (in) :: ta - - real :: ap1, tmin - - integer :: it - - tmin = table_ice - 160. - ap1 = 10. * dim (ta, tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es2_table = table2 (it) + (ap1 - it) * des2 (it) - -end function es2_table - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine 'esw_table1d' computes the saturated water vapor -!! pressure for table ii. -subroutine esw_table1d (ta, es, n) - - implicit none - - integer, intent (in) :: n - - real, intent (in) :: ta (n) - - real, intent (out) :: es (n) - - real :: ap1, tmin - - integer :: i, it - - tmin = table_ice - 160. - - do i = 1, n - ap1 = 10. * dim (ta (i), tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es (i) = tablew (it) + (ap1 - it) * desw (it) - enddo - -end subroutine esw_table1d - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine 'es3_table1d' computes the saturated water vapor -!! pressure for table iii. -subroutine es2_table1d (ta, es, n) - - implicit none - - integer, intent (in) :: n - - real, intent (in) :: ta (n) - - real, intent (out) :: es (n) - - real :: ap1, tmin - - integer :: i, it - - tmin = table_ice - 160. - - do i = 1, n - ap1 = 10. * dim (ta (i), tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es (i) = table2 (it) + (ap1 - it) * des2 (it) - enddo - -end subroutine es2_table1d - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine 'es3_table1d' computes the saturated water vapor -!! pressure for table iv. -subroutine es3_table1d (ta, es, n) - - implicit none - - integer, intent (in) :: n - - real, intent (in) :: ta (n) - - real, intent (out) :: es (n) - - real :: ap1, tmin - - integer :: i, it - - tmin = table_ice - 160. - - do i = 1, n - ap1 = 10. * dim (ta (i), tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es (i) = table3 (it) + (ap1 - it) * des3 (it) - enddo - -end subroutine es3_table1d - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! saturation water vapor pressure table ii -! 1 - phase table -subroutine qs_tablew (n) - - implicit none - - integer, intent (in) :: n - - real :: delt = 0.1 - real :: tmin, tem, fac0, fac1, fac2 - - integer :: i - - tmin = table_ice - 160. - - ! ----------------------------------------------------------------------- - ! compute es over water - ! ----------------------------------------------------------------------- - - do i = 1, n - tem = tmin + delt * real (i - 1) - fac0 = (tem - t_ice) / (tem * t_ice) - fac1 = fac0 * lv0 - fac2 = (dc_vap * log (tem / t_ice) + fac1) / rvgas - tablew (i) = e00 * exp (fac2) - enddo - -end subroutine qs_tablew - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!>@brief saturation water vapor pressure table iii -! 2 - phase table -subroutine qs_table2 (n) - - implicit none - - integer, intent (in) :: n - - real :: delt = 0.1 - real :: tmin, tem0, tem1, fac0, fac1, fac2 - - integer :: i, i0, i1 - - tmin = table_ice - 160. - - do i = 1, n - tem0 = tmin + delt * real (i - 1) - fac0 = (tem0 - t_ice) / (tem0 * t_ice) - if (i <= 1600) then - ! ----------------------------------------------------------------------- - ! compute es over ice between - 160 deg c and 0 deg c. - ! ----------------------------------------------------------------------- - fac1 = fac0 * li2 - fac2 = (d2ice * log (tem0 / t_ice) + fac1) / rvgas - else - ! ----------------------------------------------------------------------- - ! compute es over water between 0 deg c and 102 deg c. - ! ----------------------------------------------------------------------- - fac1 = fac0 * lv0 - fac2 = (dc_vap * log (tem0 / t_ice) + 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 - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! saturation water vapor pressure table iv -! 2 - phase table with " - 2 c" as the transition point -subroutine qs_table3 (n) - - implicit none - - integer, intent (in) :: n - - real :: delt = 0.1 - real :: esbasw, tbasw, esbasi, tmin, tem, aa, b, c, d, e - real :: tem0, tem1 - - integer :: i, i0, i1 - - esbasw = 1013246.0 - tbasw = table_ice + 100. - esbasi = 6107.1 - tmin = table_ice - 160. - - do i = 1, n - tem = tmin + delt * real (i - 1) - ! if (i <= 1600) then - if (i <= 1580) then ! change to - 2 c - ! ----------------------------------------------------------------------- - ! compute es over ice between - 160 deg c and 0 deg c. - ! see smithsonian meteorological tables page 350. - ! ----------------------------------------------------------------------- - aa = - 9.09718 * (table_ice / tem - 1.) - b = - 3.56654 * alog10 (table_ice / tem) - c = 0.876793 * (1. - tem / table_ice) - e = alog10 (esbasi) - table3 (i) = 0.1 * 10 ** (aa + b + c + e) - else - ! ----------------------------------------------------------------------- - ! compute es over water between - 2 deg c and 102 deg c. - ! see smithsonian meteorological tables page 350. - ! ----------------------------------------------------------------------- - aa = - 7.90298 * (tbasw / tem - 1.) - b = 5.02808 * alog10 (tbasw / tem) - c = - 1.3816e-7 * (10 ** ((1. - tem / tbasw) * 11.344) - 1.) - d = 8.1328e-3 * (10 ** ((tbasw / tem - 1.) * (- 3.49149)) - 1.) - e = alog10 (esbasw) - table3 (i) = 0.1 * 10 ** (aa + b + c + d + e) - endif - enddo - - ! ----------------------------------------------------------------------- - ! smoother around - 2 deg c - ! ----------------------------------------------------------------------- - - i0 = 1580 - i1 = 1581 - tem0 = 0.25 * (table3 (i0 - 1) + 2. * table (i0) + table3 (i0 + 1)) - tem1 = 0.25 * (table3 (i1 - 1) + 2. * table (i1) + table3 (i1 + 1)) - table3 (i0) = tem0 - table3 (i1) = tem1 - -end subroutine qs_table3 - -! ======================================================================= -! compute the saturated specific humidity for table -! note: this routine is based on "moist" mixing ratio -!>\ingroup mod_gfdl_cloud_mp -!! The function 'qs_blend' computes the saturated specific humidity -!! with a blend of water and ice depending on the temperature. -real function qs_blend (t, p, q) - - implicit none - - real, intent (in) :: t, p, q - - real :: es, ap1, tmin - - integer :: it - - tmin = table_ice - 160. - ap1 = 10. * dim (t, tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es = table (it) + (ap1 - it) * des (it) - qs_blend = eps * es * (1. + zvir * q) / p - -end function qs_blend - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!! saturation water vapor pressure table i -! 3 - phase table -subroutine qs_table (n) - - implicit none - - integer, intent (in) :: n - - real :: delt = 0.1 - real :: tmin, tem, esh20 - real :: wice, wh2o, fac0, fac1, fac2 - real :: esupc (200) - - integer :: i - - tmin = table_ice - 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 - t_ice) / (tem * t_ice) - fac1 = fac0 * li2 - fac2 = (d2ice * log (tem / t_ice) + 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 - t_ice) / (tem * t_ice) - fac1 = fac0 * lv0 - fac2 = (dc_vap * log (tem / t_ice) + 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 * (table_ice - tem) - wh2o = 0.05 * (tem - 253.16) - table (i + 1400) = wice * table (i + 1400) + wh2o * esupc (i) - enddo - -end subroutine qs_table - -! ======================================================================= -! compute the saturated specific humidity and the gradient of saturated specific humidity -! input t in deg k, p in pa; p = rho rdry tv, moist pressure -!>\ingroup mod_gfdl_cloud_mp -!! The function 'qsmith' computes the saturated specific humidity -!! with a blend of water and ice depending on the temperature in 3D. -!@details It als oincludes the option for computing des/dT. -subroutine qsmith (im, km, ks, t, p, q, qs, dqdt) - - implicit none - - integer, intent (in) :: im, km, ks - - real, intent (in), dimension (im, km) :: t, p, q - - real, intent (out), dimension (im, km) :: qs - - real, intent (out), dimension (im, km), optional :: dqdt - - real :: eps10, ap1, tmin - - real, dimension (im, km) :: es - - integer :: i, k, it - - tmin = table_ice - 160. - eps10 = 10. * eps - - if (.not. tables_are_initialized) then - call qsmith_init - endif - - do k = ks, km - do i = 1, im - ap1 = 10. * dim (t (i, k), tmin) + 1. - ap1 = min (2621., ap1) - it = ap1 - es (i, k) = table (it) + (ap1 - it) * des (it) - qs (i, k) = eps * es (i, k) * (1. + zvir * q (i, k)) / p (i, k) - enddo - enddo - - if (present (dqdt)) then - do k = ks, km - do i = 1, im - ap1 = 10. * dim (t (i, k), tmin) + 1. - ap1 = min (2621., ap1) - 0.5 - it = ap1 - dqdt (i, k) = eps10 * (des (it) + (ap1 - it) * (des (it + 1) - des (it))) * (1. + zvir * q (i, k)) / p (i, k) - enddo - enddo - endif - -end subroutine qsmith - -! ======================================================================= -!>\ingroup mod_gfdl_cloud_mp -!>@brief The subroutine 'neg_adj' fixes negative water species. -!>@details This is designed for 6-class micro-physics schemes. -subroutine neg_adj (ktop, kbot, pt, dp, qv, ql, qr, qi, qs, qg) - - implicit none - - integer, intent (in) :: ktop, kbot - - real, intent (in), dimension (ktop:kbot) :: dp - - real, intent (inout), dimension (ktop:kbot) :: pt, qv, ql, qr, qi, qs, qg - - real, dimension (ktop:kbot) :: lcpk, icpk - - real :: dq, cvm - - integer :: k - - ! ----------------------------------------------------------------------- - ! define heat capacity and latent heat coefficient - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - cvm = c_air + qv (k) * c_vap + (qr (k) + ql (k)) * c_liq + (qi (k) + qs (k) + qg (k)) * c_ice - lcpk (k) = (lv00 + d0_vap * pt (k)) / cvm - icpk (k) = (li00 + dc_ice * pt (k)) / cvm - enddo - - do k = ktop, kbot - - ! ----------------------------------------------------------------------- - ! ice phase: - ! ----------------------------------------------------------------------- - - ! if cloud ice < 0, borrow from snow - if (qi (k) < 0.) then - qs (k) = qs (k) + qi (k) - qi (k) = 0. - endif - ! if snow < 0, borrow from graupel - if (qs (k) < 0.) then - qg (k) = qg (k) + qs (k) - qs (k) = 0. - endif - ! if graupel < 0, borrow from rain - if (qg (k) < 0.) then - qr (k) = qr (k) + qg (k) - pt (k) = pt (k) - qg (k) * icpk (k) ! heating - qg (k) = 0. - endif - - ! ----------------------------------------------------------------------- - ! liquid phase: - ! ----------------------------------------------------------------------- - - ! if rain < 0, borrow from cloud water - if (qr (k) < 0.) then - ql (k) = ql (k) + qr (k) - qr (k) = 0. - endif - ! if cloud water < 0, borrow from water vapor - if (ql (k) < 0.) then - qv (k) = qv (k) + ql (k) - pt (k) = pt (k) - ql (k) * lcpk (k) ! heating - ql (k) = 0. - endif - - enddo - - ! ----------------------------------------------------------------------- - ! fix water vapor; borrow from below - ! ----------------------------------------------------------------------- - - do k = ktop, kbot - 1 - if (qv (k) < 0.) then - qv (k + 1) = qv (k + 1) + qv (k) * dp (k) / dp (k + 1) - qv (k) = 0. - endif - enddo - - ! ----------------------------------------------------------------------- - ! bottom layer; borrow from above - ! ----------------------------------------------------------------------- - - if (qv (kbot) < 0. .and. qv (kbot - 1) > 0.) then - dq = min (- qv (kbot) * dp (kbot), qv (kbot - 1) * dp (kbot - 1)) - qv (kbot - 1) = qv (kbot - 1) - dq / dp (kbot - 1) - qv (kbot) = qv (kbot) + dq / dp (kbot) - endif - -end subroutine neg_adj - -! ======================================================================= -! compute global sum -!>@brief quick local sum algorithm -! ======================================================================= - -!real function g_sum (p, ifirst, ilast, jfirst, jlast, area, mode) -! -! use mpp_mod, only: mpp_sum -! -! implicit none -! -! integer, intent (in) :: ifirst, ilast, jfirst, jlast -! integer, intent (in) :: mode ! if == 1 divided by area -! -! real, intent (in), dimension (ifirst:ilast, jfirst:jlast) :: p, area -! -! integer :: i, j -! -! real :: gsum -! -! if (global_area < 0.) then -! global_area = 0. -! do j = jfirst, jlast -! do i = ifirst, ilast -! global_area = global_area + area (i, j) -! enddo -! enddo -! call mpp_sum (global_area) -! endif -! -! gsum = 0. -! do j = jfirst, jlast -! do i = ifirst, ilast -! gsum = gsum + p (i, j) * area (i, j) -! enddo -! enddo -! call mpp_sum (gsum) -! -! if (mode == 1) then -! g_sum = gsum / global_area -! else -! g_sum = gsum -! endif -! -!end function g_sum - -! ========================================================================== -!>\ingroup mod_gfdl_cloud_mp -!! The subroutine 'interpolate_z' interpolates to a prescribed height. -subroutine interpolate_z (is, ie, js, je, km, zl, hgt, a3, a2) - - implicit none - - integer, intent (in) :: is, ie, js, je, km - - real, intent (in), dimension (is:ie, js:je, km) :: a3 - - real, intent (in), dimension (is:ie, js:je, km + 1) :: hgt ! hgt (k) > hgt (k + 1) - - real, intent (in) :: zl - - real, intent (out), dimension (is:ie, js:je) :: a2 - - real, dimension (km) :: zm !< middle layer height - - integer :: i, j, k - - !$omp parallel do default (none) shared (is, ie, js, je, km, hgt, zl, a2, a3) private (zm) - - do j = js, je - do i = is, ie - do k = 1, km - zm (k) = 0.5 * (hgt (i, j, k) + hgt (i, j, k + 1)) - enddo - if (zl >= zm (1)) then - a2 (i, j) = a3 (i, j, 1) - elseif (zl <= zm (km)) then - a2 (i, j) = a3 (i, j, km) - else - do k = 1, km - 1 - if (zl <= zm (k) .and. zl >= zm (k + 1)) then - a2 (i, j) = a3 (i, j, k) + (a3 (i, j, k + 1) - a3 (i, j, k)) * (zm (k) - zl) / (zm (k) - zm (k + 1)) - exit - endif - enddo - endif - enddo - enddo - -end subroutine interpolate_z - -! ======================================================================= -!> \ingroup mod_gfdl_cloud_mp -!! The subroutine 'cloud_diagnosis' diagnoses the radius of cloud -!! species. -!>\author Linjiong Zhoum, Shian-Jiann Lin -! ======================================================================= -subroutine cloud_diagnosis (is, ie, ks, ke, den, delp, lsm, qmw, qmi, qmr, qms, qmg, t, & - rew, rei, rer, res, reg) - - implicit none - - integer, intent (in) :: is, ie, ks, ke - integer, intent (in), dimension (is:ie) :: lsm ! land sea mask, 0: ocean, 1: land, 2: sea ice - - real, intent (in), dimension (is:ie, ks:ke) :: den, delp, t - real, intent (in), dimension (is:ie, ks:ke) :: qmw, qmi, qmr, qms, qmg !< units: kg / kg - - real, intent (out), dimension (is:ie, ks:ke) :: rew, rei, rer, res, reg !< units: micron - - real, dimension (is:ie, ks:ke) :: qcw, qci, qcr, qcs, qcg !< units: g / m^2 - - integer :: i, k - - real :: lambdar, lambdas, lambdag - real :: dpg, rei_fac, mask, ccn, bw - real, parameter :: rho_0 = 50.e-3 - - real :: rhow = 1.0e3, rhor = 1.0e3, rhos = 1.0e2, rhog = 4.0e2 - real :: n0r = 8.0e6, n0s = 3.0e6, n0g = 4.0e6 - real :: alphar = 0.8, alphas = 0.25, alphag = 0.5 - real :: gammar = 17.837789, gammas = 8.2850630, gammag = 11.631769 - real :: qmin = 1.0e-12, beta = 1.22, qmin1 = 9.e-6 - - do k = ks, ke - do i = is, ie - - dpg = abs (delp (i, k)) / grav - mask = min (max (real(lsm (i)), 0.0), 2.0) - - ! ----------------------------------------------------------------------- - ! cloud water (Martin et al., 1994) - ! ----------------------------------------------------------------------- - - ccn = 0.80 * (- 1.15e-3 * (ccn_o ** 2) + 0.963 * ccn_o + 5.30) * abs (mask - 1.0) + & - 0.67 * (- 2.10e-4 * (ccn_l ** 2) + 0.568 * ccn_l - 27.9) * (1.0 - abs (mask - 1.0)) - - if (qmw (i, k) .gt. qmin) then - qcw (i, k) = dpg * qmw (i, k) * 1.0e3 - rew (i, k) = exp (1.0 / 3.0 * log ((3.0 * den (i, k) * qmw (i, k)) / (4.0 * pi * rhow * ccn))) * 1.0e4 - rew (i, k) = max (rewmin, min (rewmax, rew (i, k))) - else - qcw (i, k) = 0.0 - rew (i, k) = rewmin - endif - - if (reiflag .eq. 1) then - - ! ----------------------------------------------------------------------- - ! cloud ice (Heymsfield and Mcfarquhar, 1996) - ! ----------------------------------------------------------------------- - - if (qmi (i, k) .gt. qmin1) then - qci (i, k) = dpg * qmi (i, k) * 1.0e3 - rei_fac = log (1.0e3 * qmi (i, k) * den (i, k)) - if (t (i, k) - tice .lt. - 50) then - rei (i, k) = beta / 9.917 * exp (0.109 * rei_fac) * 1.0e3 - elseif (t (i, k) - tice .lt. - 40) then - rei (i, k) = beta / 9.337 * exp (0.080 * rei_fac) * 1.0e3 - elseif (t (i, k) - tice .lt. - 30) then - rei (i, k) = beta / 9.208 * exp (0.055 * rei_fac) * 1.0e3 - else - rei (i, k) = beta / 9.387 * exp (0.031 * rei_fac) * 1.0e3 - endif - rei (i, k) = max (reimin, min (reimax, rei (i, k))) - else - qci (i, k) = 0.0 - rei (i, k) = reimin - endif - - endif - - if (reiflag .eq. 2) then - - ! ----------------------------------------------------------------------- - ! cloud ice (Wyser, 1998) - ! ----------------------------------------------------------------------- - - if (qmi (i, k) .gt. qmin1) then - qci (i, k) = dpg * qmi (i, k) * 1.0e3 - bw = - 2. + 1.e-3 * log10 (den (i, k) * qmi (i, k) / rho_0) * max (0.0, tice - t (i, k)) ** 1.5 - rei (i, k) = 377.4 + bw * (203.3 + bw * (37.91 + 2.3696 * bw)) - rei (i, k) = max (reimin, min (reimax, rei (i, k))) - else - qci (i, k) = 0.0 - rei (i, k) = reimin - endif - - endif - - ! ----------------------------------------------------------------------- - ! rain (Lin et al., 1983) - ! ----------------------------------------------------------------------- - - if (qmr (i, k) .gt. qmin) then - qcr (i, k) = dpg * qmr (i, k) * 1.0e3 - lambdar = exp (0.25 * log (pi * rhor * n0r / qmr (i, k) / den (i, k))) - rer (i, k) = 0.5 * exp (log (gammar / 6) / alphar) / lambdar * 1.0e6 - rer (i, k) = max (rermin, min (rermax, rer (i, k))) - else - qcr (i, k) = 0.0 - rer (i, k) = rermin - endif - - ! ----------------------------------------------------------------------- - ! snow (Lin et al., 1983) - ! ----------------------------------------------------------------------- - - if (qms (i, k) .gt. qmin1) then - qcs (i, k) = dpg * qms (i, k) * 1.0e3 - lambdas = exp (0.25 * log (pi * rhos * n0s / qms (i, k) / den (i, k))) - res (i, k) = 0.5 * exp (log (gammas / 6) / alphas) / lambdas * 1.0e6 - res (i, k) = max (resmin, min (resmax, res (i, k))) - else - qcs (i, k) = 0.0 - res (i, k) = resmin - endif - - ! ----------------------------------------------------------------------- - ! graupel (Lin et al., 1983) - ! ----------------------------------------------------------------------- - - if (qmg (i, k) .gt. qmin) then - qcg (i, k) = dpg * qmg (i, k) * 1.0e3 - lambdag = exp (0.25 * log (pi * rhog * n0g / qmg (i, k) / den (i, k))) - reg (i, k) = 0.5 * exp (log (gammag / 6) / alphag) / lambdag * 1.0e6 - reg (i, k) = max (regmin, min (regmax, reg (i, k))) - else - qcg (i, k) = 0.0 - reg (i, k) = regmin - endif - - enddo - enddo - -end subroutine cloud_diagnosis - -!+---+-----------------------------------------------------------------+ -!>\ingroup mod_gfdl_cloud_mp -!! This subroutine calculates radar reflectivity. - subroutine refl10cm_gfdl (qv1d, qr1d, qs1d, qg1d, & - t1d, p1d, dBZ, kts, kte, ii, jj, melti) - - IMPLICIT NONE - -!..Sub arguments - INTEGER, INTENT(IN):: kts, kte, ii,jj - REAL, DIMENSION(kts:kte), INTENT(IN):: & - qv1d, qr1d, qs1d, qg1d, t1d, p1d - REAL, DIMENSION(kts:kte), INTENT(INOUT):: dBZ - -!..Local variables - REAL, DIMENSION(kts:kte):: temp, pres, qv, rho - REAL, DIMENSION(kts:kte):: rr, rs, rg -! REAL:: temp_C - - DOUBLE PRECISION, DIMENSION(kts:kte):: ilamr, ilams, ilamg - DOUBLE PRECISION, DIMENSION(kts:kte):: N0_r, N0_s, N0_g - DOUBLE PRECISION:: lamr, lams, lamg - LOGICAL, DIMENSION(kts:kte):: L_qr, L_qs, L_qg - - REAL, DIMENSION(kts:kte):: ze_rain, ze_snow, ze_graupel - DOUBLE PRECISION:: fmelt_s, fmelt_g - - INTEGER:: i, k, k_0, kbot, n - LOGICAL, INTENT(IN):: melti - DOUBLE PRECISION:: cback, x, eta, f_d -!+---+ - - do k = kts, kte - dBZ(k) = -35.0 - enddo - -!+---+-----------------------------------------------------------------+ -!..Put column of data into local arrays. -!+---+-----------------------------------------------------------------+ - do k = kts, kte - temp(k) = t1d(k) -! temp_C = min(-0.001, temp(K)-273.15) - qv(k) = MAX(1.E-10, qv1d(k)) - pres(k) = p1d(k) - rho(k) = 0.622*pres(k)/(rdgas*temp(k)*(qv(k)+0.622)) - - if (qr1d(k) .gt. 1.E-9) then - rr(k) = qr1d(k)*rho(k) - N0_r(k) = n0r - lamr = (xam_r*xcrg(3)*N0_r(k)/rr(k))**(1./xcre(1)) - ilamr(k) = 1./lamr - L_qr(k) = .true. - else - rr(k) = 1.E-12 - L_qr(k) = .false. - endif - - if (qs1d(k) .gt. 1.E-9) then - rs(k) = qs1d(k)*rho(k) - N0_s(k) = n0s - lams = (xam_s*xcsg(3)*N0_s(k)/rs(k))**(1./xcse(1)) - ilams(k) = 1./lams - L_qs(k) = .true. - else - rs(k) = 1.E-12 - L_qs(k) = .false. - endif - - if (qg1d(k) .gt. 1.E-9) then - rg(k) = qg1d(k)*rho(k) - N0_g(k) = n0g - lamg = (xam_g*xcgg(3)*N0_g(k)/rg(k))**(1./xcge(1)) - ilamg(k) = 1./lamg - L_qg(k) = .true. - else - rg(k) = 1.E-12 - L_qg(k) = .false. - endif - enddo - -!+---+-----------------------------------------------------------------+ -!..Locate K-level of start of melting (k_0 is level above). -!+---+-----------------------------------------------------------------+ - k_0 = kts - K_LOOP:do k = kte-1, kts, -1 - if ( melti .and. (temp(k).gt.273.15) .and. L_qr(k) & - .and. (L_qs(k+1).or.L_qg(k+1)) ) then - k_0 = MAX(k+1, k_0) - EXIT K_LOOP - endif - enddo K_LOOP -!+---+-----------------------------------------------------------------+ -!..Assume Rayleigh approximation at 10 cm wavelength. Rain (all temps) -!.. and non-water-coated snow and graupel when below freezing are -!.. simple. Integrations of m(D)*m(D)*N(D)*dD. -!+---+-----------------------------------------------------------------+ - do k = kts, kte - ze_rain(k) = 1.e-22 - ze_snow(k) = 1.e-22 - ze_graupel(k) = 1.e-22 - if (L_qr(k)) ze_rain(k) = N0_r(k)*xcrg(4)*ilamr(k)**xcre(4) - if (L_qs(k)) ze_snow(k) = (0.176/0.93) * (6.0/PI)*(6.0/PI) & - * (xam_s/900.0)*(xam_s/900.0) & - * N0_s(k)*xcsg(4)*ilams(k)**xcse(4) - if (L_qg(k)) ze_graupel(k) = (0.176/0.93) * (6.0/PI)*(6.0/PI) & - * (xam_g/900.0)*(xam_g/900.0) & - * N0_g(k)*xcgg(4)*ilamg(k)**xcge(4) - enddo - - -!+---+-----------------------------------------------------------------+ -!..Special case of melting ice (snow/graupel) particles. Assume the -!.. ice is surrounded by the liquid water. Fraction of meltwater is -!.. extremely simple based on amount found above the melting level. -!.. Uses code from Uli Blahak (rayleigh_soak_wetgraupel and supporting -!.. routines). -!+---+-----------------------------------------------------------------+ - - if (melti .and. k_0.ge.kts+1) then - do k = k_0-1, kts, -1 - -!..Reflectivity contributed by melting snow - if (L_qs(k) .and. L_qs(k_0) ) then - fmelt_s = MAX(0.005d0, MIN(1.0d0-rs(k)/rs(k_0), 0.99d0)) - eta = 0.d0 - lams = 1./ilams(k) - do n = 1, nrbins - x = xam_s * xxDs(n)**xbm_s - call rayleigh_soak_wetgraupel (x,DBLE(xocms),DBLE(xobms), & - fmelt_s, melt_outside_s, m_w_0, m_i_0, lamda_radar, & - CBACK, mixingrulestring_s, matrixstring_s, & - inclusionstring_s, hoststring_s, & - hostmatrixstring_s, hostinclusionstring_s) - f_d = N0_s(k)*xxDs(n)**xmu_s * DEXP(-lams*xxDs(n)) - eta = eta + f_d * CBACK * simpson(n) * xdts(n) - enddo - ze_snow(k) = SNGL(lamda4 / (pi5 * K_w) * eta) - endif - - -!..Reflectivity contributed by melting graupel - - if (L_qg(k) .and. L_qg(k_0) ) then - fmelt_g = MAX(0.005d0, MIN(1.0d0-rg(k)/rg(k_0), 0.99d0)) - eta = 0.d0 - lamg = 1./ilamg(k) - do n = 1, nrbins - x = xam_g * xxDg(n)**xbm_g - call rayleigh_soak_wetgraupel (x,DBLE(xocmg),DBLE(xobmg), & - fmelt_g, melt_outside_g, m_w_0, m_i_0, lamda_radar, & - CBACK, mixingrulestring_g, matrixstring_g, & - inclusionstring_g, hoststring_g, & - hostmatrixstring_g, hostinclusionstring_g) - f_d = N0_g(k)*xxDg(n)**xmu_g * DEXP(-lamg*xxDg(n)) - eta = eta + f_d * CBACK * simpson(n) * xdtg(n) - enddo - ze_graupel(k) = SNGL(lamda4 / (pi5 * K_w) * eta) - endif - - enddo - endif - - do k = kte, kts, -1 - dBZ(k) = 10.*log10((ze_rain(k)+ze_snow(k)+ze_graupel(k))*1.d18) - enddo - - - end subroutine refl10cm_gfdl -!+---+-----------------------------------------------------------------+ - -end module gfdl_cloud_microphys_mod From 57655a6d18d68fafa45364f5428648873cb62186 Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Mon, 29 Jan 2024 16:49:36 +0000 Subject: [PATCH 03/10] make a change in CMakeLists.txt corresponging to the moving of GFLDMP into a subdir v1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee708d4c4..04efd890d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,8 +108,8 @@ set(SCHEMES_OPENMP_OFF ${LOCAL_CURRENT_SOURCE_DIR}/physics/Radiation/RRTMGP/rte- # List of files that need to be compiled with different precision set(SCHEMES_DYNAMICS) -if(${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL/fv_sat_adj.F90 IN_LIST SCHEMES) - list(APPEND SCHEMES_DYNAMICS ${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL/fv_sat_adj.F90) +if(${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL/v1/fv_sat_adj.F90 IN_LIST SCHEMES) + list(APPEND SCHEMES_DYNAMICS ${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL/v1/fv_sat_adj.F90) endif() # Remove files that need to be compiled with different precision From ec416f71de00d7c22fe1c2365f7408d91d916af7 Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Thu, 1 Feb 2024 15:38:06 +0000 Subject: [PATCH 04/10] removed GFDL directory but added GFDL_2019_v1 for GFDLMP v1 and moved the associated files --- physics/MP/{GFDL/v1 => GFDL_2019_v1}/fv_sat_adj.F90 | 0 physics/MP/{GFDL/v1 => GFDL_2019_v1}/fv_sat_adj.meta | 4 ++-- physics/MP/{GFDL/v1 => GFDL_2019_v1}/gfdl_cloud_microphys.F90 | 0 .../MP/{GFDL/v1 => GFDL_2019_v1}/gfdl_cloud_microphys.meta | 4 ++-- .../{GFDL/v1 => GFDL_2019_v1}/module_gfdl_cloud_microphys.F90 | 0 physics/MP/{GFDL => }/GFDL_parse_tracers.F90 | 0 physics/MP/{GFDL => }/multi_gases.F90 | 0 7 files changed, 4 insertions(+), 4 deletions(-) rename physics/MP/{GFDL/v1 => GFDL_2019_v1}/fv_sat_adj.F90 (100%) rename physics/MP/{GFDL/v1 => GFDL_2019_v1}/fv_sat_adj.meta (99%) rename physics/MP/{GFDL/v1 => GFDL_2019_v1}/gfdl_cloud_microphys.F90 (100%) rename physics/MP/{GFDL/v1 => GFDL_2019_v1}/gfdl_cloud_microphys.meta (99%) rename physics/MP/{GFDL/v1 => GFDL_2019_v1}/module_gfdl_cloud_microphys.F90 (100%) rename physics/MP/{GFDL => }/GFDL_parse_tracers.F90 (100%) rename physics/MP/{GFDL => }/multi_gases.F90 (100%) diff --git a/physics/MP/GFDL/v1/fv_sat_adj.F90 b/physics/MP/GFDL_2019_v1/fv_sat_adj.F90 similarity index 100% rename from physics/MP/GFDL/v1/fv_sat_adj.F90 rename to physics/MP/GFDL_2019_v1/fv_sat_adj.F90 diff --git a/physics/MP/GFDL/v1/fv_sat_adj.meta b/physics/MP/GFDL_2019_v1/fv_sat_adj.meta similarity index 99% rename from physics/MP/GFDL/v1/fv_sat_adj.meta rename to physics/MP/GFDL_2019_v1/fv_sat_adj.meta index c79eb6a25..e94c7320d 100644 --- a/physics/MP/GFDL/v1/fv_sat_adj.meta +++ b/physics/MP/GFDL_2019_v1/fv_sat_adj.meta @@ -1,9 +1,9 @@ [ccpp-table-properties] name = fv_sat_adj type = scheme - dependencies = ../../../hooks/machine.F,../../../hooks/physcons.F90 + dependencies = ../../hooks/machine.F,../../hooks/physcons.F90 dependencies = module_gfdl_cloud_microphys.F90,../multi_gases.F90 - dependencies = ../../module_mp_radar.F90 + dependencies = ../module_mp_radar.F90 ######################################################################## [ccpp-arg-table] diff --git a/physics/MP/GFDL/v1/gfdl_cloud_microphys.F90 b/physics/MP/GFDL_2019_v1/gfdl_cloud_microphys.F90 similarity index 100% rename from physics/MP/GFDL/v1/gfdl_cloud_microphys.F90 rename to physics/MP/GFDL_2019_v1/gfdl_cloud_microphys.F90 diff --git a/physics/MP/GFDL/v1/gfdl_cloud_microphys.meta b/physics/MP/GFDL_2019_v1/gfdl_cloud_microphys.meta similarity index 99% rename from physics/MP/GFDL/v1/gfdl_cloud_microphys.meta rename to physics/MP/GFDL_2019_v1/gfdl_cloud_microphys.meta index 236d81ed3..719a340e5 100644 --- a/physics/MP/GFDL/v1/gfdl_cloud_microphys.meta +++ b/physics/MP/GFDL_2019_v1/gfdl_cloud_microphys.meta @@ -1,8 +1,8 @@ [ccpp-table-properties] name = gfdl_cloud_microphys type = scheme - dependencies = ../../../hooks/machine.F - dependencies = ../../module_mp_radar.F90 + dependencies = ../../hooks/machine.F + dependencies = ../module_mp_radar.F90 dependencies = module_gfdl_cloud_microphys.F90 ######################################################################## diff --git a/physics/MP/GFDL/v1/module_gfdl_cloud_microphys.F90 b/physics/MP/GFDL_2019_v1/module_gfdl_cloud_microphys.F90 similarity index 100% rename from physics/MP/GFDL/v1/module_gfdl_cloud_microphys.F90 rename to physics/MP/GFDL_2019_v1/module_gfdl_cloud_microphys.F90 diff --git a/physics/MP/GFDL/GFDL_parse_tracers.F90 b/physics/MP/GFDL_parse_tracers.F90 similarity index 100% rename from physics/MP/GFDL/GFDL_parse_tracers.F90 rename to physics/MP/GFDL_parse_tracers.F90 diff --git a/physics/MP/GFDL/multi_gases.F90 b/physics/MP/multi_gases.F90 similarity index 100% rename from physics/MP/GFDL/multi_gases.F90 rename to physics/MP/multi_gases.F90 From 4026f1a43e1b28fa2eb09e322a9be9a5766f7e10 Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Thu, 1 Feb 2024 15:40:36 +0000 Subject: [PATCH 05/10] re-organized GFDLMP v1 and add v3 --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04efd890d..54647d0e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,8 +108,12 @@ set(SCHEMES_OPENMP_OFF ${LOCAL_CURRENT_SOURCE_DIR}/physics/Radiation/RRTMGP/rte- # List of files that need to be compiled with different precision set(SCHEMES_DYNAMICS) -if(${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL/v1/fv_sat_adj.F90 IN_LIST SCHEMES) - list(APPEND SCHEMES_DYNAMICS ${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL/v1/fv_sat_adj.F90) +if(${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL_2019_v1/fv_sat_adj.F90 IN_LIST SCHEMES) + list(APPEND SCHEMES_DYNAMICS ${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL_2019_v1/fv_sat_adj.F90) +endif() + +if(${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL_2022_v3/fv_sat_adj_v3.F90 IN_LIST SCHEMES) + list(APPEND SCHEMES_DYNAMICS ${LOCAL_CURRENT_SOURCE_DIR}/physics/MP/GFDL_2022_v3/fv_sat_adj_v3.F90) endif() # Remove files that need to be compiled with different precision From 23ef3b402263f2ebb23c050a0da202672a2377e4 Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Thu, 1 Feb 2024 15:58:50 +0000 Subject: [PATCH 06/10] add GFDLMP v3 --- .../UFS_SCM_NEPTUNE/GFS_MP_generic_post.F90 | 19 +- .../UFS_SCM_NEPTUNE/GFS_MP_generic_post.meta | 7 + .../GFS_PBL_generic_common.F90 | 4 +- .../UFS_SCM_NEPTUNE/GFS_PBL_generic_post.F90 | 9 +- .../UFS_SCM_NEPTUNE/GFS_PBL_generic_post.meta | 7 + .../UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.F90 | 10 +- .../UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.meta | 7 + .../UFS_SCM_NEPTUNE/GFS_debug.F90 | 3 +- .../UFS_SCM_NEPTUNE/GFS_rrtmg_pre.F90 | 11 +- .../UFS_SCM_NEPTUNE/GFS_rrtmg_pre.meta | 7 + .../UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.F90 | 8 +- .../UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.meta | 7 + .../UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.F90 | 7 +- .../UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.meta | 7 + .../GFS_suite_interstitial_3.F90 | 7 +- .../GFS_suite_interstitial_3.meta | 7 + .../GFS_suite_interstitial_4.F90 | 20 +- .../GFS_suite_interstitial_4.meta | 9 +- .../maximum_hourly_diagnostics.F90 | 8 +- .../maximum_hourly_diagnostics.meta | 7 + .../UFS_SCM_NEPTUNE/sgscloud_radpre.F90 | 5 +- .../UFS_SCM_NEPTUNE/sgscloud_radpre.meta | 7 + physics/MP/GFDL_2022_v3/fv_sat_adj_v3.F90 | 1441 +++ physics/MP/GFDL_2022_v3/fv_sat_adj_v3.meta | 440 + physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 | 484 ++ physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.meta | 519 ++ .../MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 | 7717 +++++++++++++++++ physics/PBL/MYNN_EDMF/mynnedmf_wrapper.F90 | 9 +- physics/PBL/MYNN_EDMF/mynnedmf_wrapper.meta | 7 + physics/Radiation/radiation_clouds.f | 18 +- physics/SFC_Models/Land/RUC/lsm_ruc.F90 | 12 +- physics/SFC_Models/Land/RUC/lsm_ruc.meta | 7 + 32 files changed, 10779 insertions(+), 58 deletions(-) create mode 100644 physics/MP/GFDL_2022_v3/fv_sat_adj_v3.F90 create mode 100644 physics/MP/GFDL_2022_v3/fv_sat_adj_v3.meta create mode 100644 physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 create mode 100644 physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.meta create mode 100644 physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.F90 index d9d30fb90..3aee0a28a 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.F90 @@ -19,7 +19,8 @@ module GFS_MP_generic_post !> \section gfs_mp_gen GFS MP Generic Post General Algorithm !> @{ subroutine GFS_MP_generic_post_run( & - im, levs, kdt, nrcm, nncl, ntcw, ntrac, imp_physics, imp_physics_gfdl, imp_physics_thompson, imp_physics_nssl, & + im, levs, kdt, nrcm, nncl, ntcw, ntrac, imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3, & + imp_physics_thompson, imp_physics_nssl, & imp_physics_mg, imp_physics_fer_hires, cal_pre, cplflx, cplchm, cpllnd, progsigma, con_g, rhowater, rainmin, dtf, & frain, rainc, rain1, rann, xlat, xlon, gt0, gq0, prsl, prsi, phii, tsfc, ice, phil, htop, refl_10cm, & imfshalcnv,imfshalcnv_gf,imfdeepcnv,imfdeepcnv_gf,imfdeepcnv_samf, con_t0c, snow, graupel, save_t, save_q, & @@ -37,7 +38,8 @@ subroutine GFS_MP_generic_post_run( implicit none integer, intent(in) :: im, levs, kdt, nrcm, nncl, ntcw, ntrac, num_dfi_radar, index_of_process_dfi_radar - integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_thompson, imp_physics_mg, imp_physics_fer_hires + integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3 + integer, intent(in) :: imp_physics_thompson, imp_physics_mg, imp_physics_fer_hires integer, intent(in) :: imp_physics_nssl, iopt_lake_clm, iopt_lake, lkm logical, intent(in) :: cal_pre, lssav, ldiag3d, qdiag3d, cplflx, cplchm, cpllnd, progsigma, exticeden integer, intent(in) :: index_of_temperature,index_of_process_mp,use_lake_model(:) @@ -182,7 +184,8 @@ subroutine GFS_MP_generic_post_run( endif ! compute surface snowfall, graupel/sleet, freezing rain and precip ice density - if (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_thompson .or. imp_physics == imp_physics_nssl ) then + if (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3 & + .or. imp_physics == imp_physics_thompson .or. imp_physics == imp_physics_nssl) then do i = 1, im if (gt0(i,1) .le. 273) then frzr(i) = frzr(i) + rain0(i) @@ -251,7 +254,7 @@ subroutine GFS_MP_generic_post_run( ! GFS_physics_driver is written, Diag%{graupel,ice,snow} are on the ! physics timestep, while Diag%{rain,rainc} and all totprecip etc ! are on the dynamics timestep. Confusing, but works if frain=1. *DH - if (imp_physics == imp_physics_gfdl) then + if (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then tprcp = max(zero, rain) ! clu: rain -> tprcp !graupel = frain*graupel0 !ice = frain*ice0 @@ -306,7 +309,8 @@ subroutine GFS_MP_generic_post_run( ! ! HCHUANG: use new precipitation type to decide snow flag for LSM snow accumulation - if (imp_physics /= imp_physics_gfdl .and. imp_physics /= imp_physics_thompson .and. imp_physics /= imp_physics_nssl) then + if (imp_physics /= imp_physics_gfdl .and. imp_physics /= imp_physics_gfdl_v3 & + .and. imp_physics /= imp_physics_thompson .and. imp_physics /= imp_physics_nssl) then do i=1,im tprcp(i) = max(zero, rain(i) ) if(doms(i) > zero .or. domip(i) > zero) then @@ -393,8 +397,9 @@ subroutine GFS_MP_generic_post_run( !! and convective rainfall from the cumulus scheme if the surface temperature is below !! \f$0^oC\f$. - if (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_thompson .or. & - imp_physics == imp_physics_nssl ) then + if (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3 & + .or. imp_physics == imp_physics_thompson & + .or. imp_physics == imp_physics_nssl ) then ! determine convective rain/snow by surface temperature ! determine large-scale rain/snow by rain/snow coming out directly from MP diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.meta index 7f67aa925..be5023b5f 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.meta @@ -79,6 +79,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_common.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_common.F90 index 5f09f5347..8a6ddeef5 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_common.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_common.F90 @@ -14,6 +14,7 @@ module GFS_PBL_generic_common subroutine set_aerosol_tracer_index(imp_physics, imp_physics_wsm6, & imp_physics_thompson, ltaerosol,mraerosol, & imp_physics_mg, ntgl, imp_physics_gfdl, & + imp_physics_gfdl_v3, & imp_physics_zhao_carr, imp_physics_nssl,& nssl_hail_on, nssl_ccn_on, kk, & errmsg, errflg) @@ -22,6 +23,7 @@ subroutine set_aerosol_tracer_index(imp_physics, imp_physics_wsm6, & integer, intent(in ) :: imp_physics, imp_physics_wsm6, & imp_physics_thompson, & imp_physics_mg, ntgl, imp_physics_gfdl, & + imp_physics_gfdl_v3, & imp_physics_zhao_carr,imp_physics_nssl logical, intent(in ) :: ltaerosol, mraerosol, nssl_hail_on, nssl_ccn_on integer, intent(out) :: kk @@ -50,7 +52,7 @@ subroutine set_aerosol_tracer_index(imp_physics, imp_physics_wsm6, & else kk = 10 endif - elseif (imp_physics == imp_physics_gfdl) then + elseif (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then ! GFDL MP kk = 7 elseif (imp_physics == imp_physics_zhao_carr) then diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.F90 index a4e5f172a..bb50160bc 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.F90 @@ -11,8 +11,8 @@ module GFS_PBL_generic_post subroutine GFS_PBL_generic_post_run (im, levs, nvdiff, ntrac, & ntqv, ntcw, ntiw, ntrw, ntsw, ntlnc, ntinc, ntrnc, ntsnc, ntgnc, ntwa, ntia, ntgl, ntoz, ntke, ntkev,nqrimef, & trans_aero, ntchs, ntchm, ntccn, nthl, nthnc, ntgv, nthv, ntrz, ntgz, nthz, & - imp_physics, imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6, imp_physics_zhao_carr, imp_physics_mg, & - imp_physics_fer_hires, imp_physics_nssl, nssl_ccn_on, ltaerosol, mraerosol, nssl_hail_on, nssl_3moment, & + imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3, imp_physics_thompson, imp_physics_wsm6, imp_physics_zhao_carr, & + imp_physics_mg, imp_physics_fer_hires, imp_physics_nssl, nssl_ccn_on, ltaerosol, mraerosol, nssl_hail_on, nssl_3moment,& cplflx, cplaqm, cplchm, lssav, flag_for_pbl_generic_tend, ldiag3d, lsidea, hybedmf, do_shoc, satmedmf, & shinhong, do_ysu, dvdftra, dusfc1, dvsfc1, dtsfc1, dqsfc1, dtf, dudt, dvdt, dtdt, htrsw, htrlw, xmu, & dqdt, dusfc_cpl, dvsfc_cpl, dtsfc_cpl, dtend, dtidx, index_of_temperature, index_of_x_wind, index_of_y_wind, & @@ -32,7 +32,7 @@ subroutine GFS_PBL_generic_post_run (im, levs, nvdiff, ntrac, integer, intent(in) :: ntqv, ntcw, ntiw, ntrw, ntsw, ntlnc, ntinc, ntrnc, ntsnc, ntgnc, ntwa, ntia, ntgl, ntoz, ntke, ntkev, nqrimef integer, intent(in) :: ntccn, nthl, nthnc, ntgv, nthv, ntrz, ntgz, nthz logical, intent(in) :: trans_aero - integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6 + integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3, imp_physics_thompson, imp_physics_wsm6 integer, intent(in) :: imp_physics_zhao_carr, imp_physics_mg, imp_physics_fer_hires integer, intent(in) :: imp_physics_nssl logical, intent(in) :: nssl_ccn_on, nssl_hail_on, nssl_3moment @@ -106,6 +106,7 @@ subroutine GFS_PBL_generic_post_run (im, levs, nvdiff, ntrac, call set_aerosol_tracer_index(imp_physics, imp_physics_wsm6, & imp_physics_thompson, ltaerosol,mraerosol, & imp_physics_mg, ntgl, imp_physics_gfdl, & + imp_physics_gfdl_v3, & imp_physics_zhao_carr, imp_physics_nssl,& nssl_hail_on, nssl_ccn_on, kk, & errmsg, errflg) @@ -229,7 +230,7 @@ subroutine GFS_PBL_generic_post_run (im, levs, nvdiff, ntrac, enddo enddo endif - elseif (imp_physics == imp_physics_gfdl) then ! GFDL MP + elseif (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then ! GFDL MP do k=1,levs do i=1,im dqdt(i,k,ntqv) = dvdftra(i,k,1) diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.meta index d49a885c5..a4901e9f9 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.meta @@ -246,6 +246,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.F90 index d8ed0f8fc..d56a4b35c 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.F90 @@ -12,8 +12,8 @@ module GFS_PBL_generic_pre subroutine GFS_PBL_generic_pre_run (im, levs, nvdiff, ntrac, rtg_ozone_index, & ntqv, ntcw, ntiw, ntrw, ntsw, ntlnc, ntinc, ntrnc, ntsnc, ntgnc, & ntwa, ntia, ntgl, ntoz, ntke, ntkev, nqrimef, trans_aero, ntchs, ntchm, & - ntccn, nthl, nthnc, ntgv, nthv, ntrz, ntgz, nthz, & - imp_physics, imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6, & + ntccn, nthl, nthnc, ntgv, nthv, ntrz, ntgz, nthz, imp_physics, & + imp_physics_gfdl, imp_physics_gfdl_v3, imp_physics_thompson, imp_physics_wsm6, & imp_physics_zhao_carr, imp_physics_mg, imp_physics_fer_hires, imp_physics_nssl, & ltaerosol, mraerosol, nssl_ccn_on, nssl_hail_on, nssl_3moment, & hybedmf, do_shoc, satmedmf, qgrs, vdftra, save_u, save_v, save_t, save_q, & @@ -31,7 +31,8 @@ subroutine GFS_PBL_generic_pre_run (im, levs, nvdiff, ntrac, rtg_ozone_index, integer, intent(in) :: ntwa, ntia, ntgl, ntoz, ntke, ntkev, nqrimef,ntchs, ntchm integer, intent(in) :: ntccn, nthl, nthnc, ntgv, nthv, ntrz, ntgz, nthz logical, intent(in) :: trans_aero, ldiag3d, qdiag3d, lssav - integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6 + integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3 + integer, intent(in) :: imp_physics_thompson, imp_physics_wsm6 integer, intent(in) :: imp_physics_zhao_carr, imp_physics_mg, imp_physics_fer_hires logical, intent(in) :: ltaerosol, hybedmf, do_shoc, satmedmf, flag_for_pbl_generic_tend, mraerosol integer, intent(in) :: imp_physics_nssl @@ -177,7 +178,7 @@ subroutine GFS_PBL_generic_pre_run (im, levs, nvdiff, ntrac, rtg_ozone_index, enddo rtg_ozone_index = 10 endif - elseif (imp_physics == imp_physics_gfdl) then + elseif (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then ! GFDL MP do k=1,levs do i=1,im @@ -275,6 +276,7 @@ subroutine GFS_PBL_generic_pre_run (im, levs, nvdiff, ntrac, rtg_ozone_index, call set_aerosol_tracer_index(imp_physics, imp_physics_wsm6, & imp_physics_thompson, ltaerosol,mraerosol, & imp_physics_mg, ntgl, imp_physics_gfdl, & + imp_physics_gfdl_v3, & imp_physics_zhao_carr, imp_physics_nssl,& nssl_hail_on, nssl_ccn_on, kk, & errmsg, errflg) diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.meta index 7a8e72bba..b403a9eb5 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.meta @@ -252,6 +252,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_debug.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_debug.F90 index ed26b795f..6dcdf3873 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_debug.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_debug.F90 @@ -1392,7 +1392,8 @@ subroutine GFS_interstitialtoscreen_run (Model, Statein, Stateout, Sfcprop, Coup call print_var(mpirank, omprank, blkno, Grid%xlat_d, Grid%xlon_d, 'Interstitial%clxss ', Interstitial%clxss ) end if ! GFDL and Thompson MP - if (Model%imp_physics == Model%imp_physics_gfdl .or. Model%imp_physics == Model%imp_physics_thompson .or. Model%imp_physics == Model%imp_physics_nssl) then + if (Model%imp_physics == Model%imp_physics_gfdl .or. Model%imp_physics == Model%imp_physics_gfdl_v3 & + .or. Model%imp_physics == Model%imp_physics_thompson .or. Model%imp_physics == Model%imp_physics_nssl) then call print_var(mpirank, omprank, blkno, Grid%xlat_d, Grid%xlon_d, 'Interstitial%graupelmp ', Interstitial%graupelmp ) call print_var(mpirank, omprank, blkno, Grid%xlat_d, Grid%xlon_d, 'Interstitial%icemp ', Interstitial%icemp ) call print_var(mpirank, omprank, blkno, Grid%xlat_d, Grid%xlon_d, 'Interstitial%rainmp ', Interstitial%rainmp ) diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.F90 index 5da5c86fb..c3a2f4fbd 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.F90 @@ -26,7 +26,8 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& ntdu1, ntdu2, ntdu3, ntdu4, ntdu5, ntss1, ntss2, & ntss3, ntss4, ntss5, ntsu, ntbcb, ntbcl, ntocb, ntocl, ntchm, & imp_physics,imp_physics_nssl, nssl_ccn_on, nssl_invertccn, & - imp_physics_thompson, imp_physics_gfdl, imp_physics_zhao_carr, & + imp_physics_thompson, imp_physics_gfdl, imp_physics_gfdl_v3, & + imp_physics_zhao_carr, & imp_physics_zhao_carr_pdf, imp_physics_mg, imp_physics_wsm6, & imp_physics_fer_hires, iovr, iovr_rand, iovr_maxrand, iovr_max, & iovr_dcorr, iovr_exp, iovr_exprand, idcor, idcor_con, idcor_hogan, & @@ -99,6 +100,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& kdt, imp_physics, & imp_physics_thompson, & imp_physics_gfdl, & + imp_physics_gfdl_v3, & imp_physics_zhao_carr, & imp_physics_zhao_carr_pdf, & imp_physics_mg, imp_physics_wsm6, & @@ -778,7 +780,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& enddo enddo enddo - if (imp_physics == imp_physics_gfdl ) then + if (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then if (.not. lgfdlmprad) then @@ -822,7 +824,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& enddo enddo endif - elseif (imp_physics == imp_physics_gfdl) then ! GFDL MP + elseif (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then ! GFDL MP if ((imfdeepcnv==imfdeepcnv_gf .or. imfdeepcnv==imfdeepcnv_c3) .and. kdt>1) then do k=1,lm k1 = k + kd @@ -975,7 +977,8 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& & deltaq, sup, dcorr_con, me, icloud, kdt, & & ntrac, ntcw, ntiw, ntrw, ntsw, ntgl, ntclamt, & & imp_physics, imp_physics_nssl, imp_physics_fer_hires, & - & imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6, & + & imp_physics_gfdl, imp_physics_gfdl_v3, & + & imp_physics_thompson, imp_physics_wsm6, & & imp_physics_zhao_carr, imp_physics_zhao_carr_pdf, & & imp_physics_mg, iovr, iovr_rand, iovr_maxrand, iovr_max, & & iovr_dcorr, iovr_exp, iovr_exprand, idcor, idcor_con, & diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.meta index 43802298b..b371dd90c 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.meta @@ -469,6 +469,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_zhao_carr] standard_name = identifier_for_zhao_carr_microphysics_scheme long_name = choice of Zhao-Carr microphysics scheme diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.F90 index 79ae1559a..8cc1ee239 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.F90 @@ -45,7 +45,8 @@ module GFS_rrtmgp_cloud_mp subroutine GFS_rrtmgp_cloud_mp_run(nCol, nLev, nTracers, ncnd, i_cldliq, i_cldice, & i_cldrain, i_cldsnow, i_cldgrpl, i_cldtot, i_cldliq_nc, i_cldice_nc, i_twa, kdt, & imfdeepcnv, imfdeepcnv_gf, imfdeepcnv_samf, doSWrad, doLWrad, effr_in, lmfshal, & - ltaerosol,mraerosol, icloud, imp_physics, imp_physics_thompson, imp_physics_gfdl, & + ltaerosol,mraerosol, icloud, imp_physics, imp_physics_thompson, & + imp_physics_gfdl, imp_physics_gfdl_v3, & lgfdlmprad, do_mynnedmf, uni_cld, lmfdeep2, p_lev, p_lay, t_lay, qs_lay, q_lay, & relhum, lsmask, xlon, xlat, dx, tv_lay, effrin_cldliq, effrin_cldice, & effrin_cldrain, effrin_cldsnow, tracer, cnv_mixratio, cld_cnv_frac, qci_conv, & @@ -79,7 +80,8 @@ subroutine GFS_rrtmgp_cloud_mp_run(nCol, nLev, nTracers, ncnd, i_cldliq, i_cldic kdt, & ! Current forecast iteration imp_physics, & ! Choice of microphysics scheme imp_physics_thompson, & ! Choice of Thompson - imp_physics_gfdl, & ! Choice of GFDL + imp_physics_gfdl, & ! Choice of GFDL v1 + imp_physics_gfdl_v3, & ! Choice of GFDL v3 icloud ! Control for cloud are fraction option logical, intent(in) :: & doSWrad, & ! Call SW radiation? @@ -179,7 +181,7 @@ subroutine GFS_rrtmgp_cloud_mp_run(nCol, nLev, nTracers, ncnd, i_cldliq, i_cldic ! GFDL Microphysics ! ("Implicit" SGS cloud-coupling to the radiation) ! ################################################################################### - if (imp_physics == imp_physics_gfdl) then + if (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then ! GFDL-Lin if (.not. lgfdlmprad) then errflg = 1 diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.meta index f67259b87..2c9637a36 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.meta @@ -157,6 +157,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [do_mynnedmf] standard_name = flag_for_mellor_yamada_nakanishi_niino_pbl_scheme long_name = flag to activate MYNN-EDMF diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.F90 index 9f2b2a9f9..97889a3bf 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.F90 @@ -36,7 +36,8 @@ module GFS_rrtmgp_setup !! \htmlinclude GFS_rrtmgp_setup_init.html !! subroutine GFS_rrtmgp_setup_init(do_RRTMGP, imp_physics, imp_physics_fer_hires, & - imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6, imp_physics_zhao_carr, & + imp_physics_gfdl, imp_physics_gfdl_v3, & + imp_physics_thompson, imp_physics_wsm6, imp_physics_zhao_carr, & imp_physics_zhao_carr_pdf, imp_physics_mg, si, levr, ictm, isol, ico2, iaer, & ntcw, ntoz, iovr, isubc_sw, isubc_lw, lalw1bd, idate, & me, aeros_file, iaermdl, iaerflg, con_pi, con_t0c, con_c, con_boltz, con_plnk, & @@ -45,10 +46,12 @@ subroutine GFS_rrtmgp_setup_init(do_RRTMGP, imp_physics, imp_physics_fer_hires, ! Inputs logical, intent(in) :: do_RRTMGP +!rsun imp_physics... can be removed integer, intent(in) :: & imp_physics, & ! Flag for MP scheme imp_physics_fer_hires, & ! Flag for fer-hires scheme - imp_physics_gfdl, & ! Flag for gfdl scheme + imp_physics_gfdl, & ! Flag for gfdl scheme v1 + imp_physics_gfdl_v3, & ! Flag for gfdl scheme v3 imp_physics_thompson, & ! Flag for thompsonscheme imp_physics_wsm6, & ! Flag for wsm6 scheme imp_physics_zhao_carr, & ! Flag for zhao-carr scheme diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.meta index fecb716ed..42ccd7f1e 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.meta @@ -38,6 +38,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.F90 index 5ca20ffc1..e703c7dec 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.F90 @@ -18,7 +18,8 @@ subroutine GFS_suite_interstitial_3_run (otsptflag, & xlon, xlat, gt0, gq0, sigmain,sigmaout,qmicro, & imp_physics, imp_physics_mg, & imp_physics_zhao_carr, imp_physics_zhao_carr_pdf, & - imp_physics_gfdl, imp_physics_thompson, dtidx, ntlnc, & + imp_physics_gfdl, imp_physics_gfdl_v3, & + imp_physics_thompson, dtidx, ntlnc, & imp_physics_wsm6, imp_physics_fer_hires, prsi, ntinc, & imp_physics_nssl, & prsl, prslk, rhcbot,rhcpbl, rhctop, rhcmax, islmsk, & @@ -34,7 +35,7 @@ subroutine GFS_suite_interstitial_3_run (otsptflag, & logical, intent(in) :: otsptflag(:)! on/off switch for tracer transport (size ntrac) integer, intent(in ) :: im, levs, nn, ntrac, ntcw, ntiw, ntclamt, ntrw, ntsw,& ntrnc, ntsnc, ntgl, ntgnc, imp_physics, imp_physics_mg, imp_physics_zhao_carr, imp_physics_zhao_carr_pdf, & - imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6,imp_physics_fer_hires, & + imp_physics_gfdl, imp_physics_gfdl_v3, imp_physics_thompson, imp_physics_wsm6,imp_physics_fer_hires, & imp_physics_nssl, me, index_of_process_conv_trans integer, intent(in ), dimension(:) :: islmsk, kpbl, kinver logical, intent(in ) :: cscnv, satmedmf, trans_trac, do_shoc, ltaerosol, ras, progsigma @@ -185,7 +186,7 @@ subroutine GFS_suite_interstitial_3_run (otsptflag, & clw(i,k,1) = gq0(i,k,ntcw) enddo enddo - elseif (imp_physics == imp_physics_gfdl) then + elseif (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then clw(1:im,:,1) = gq0(1:im,:,ntcw) elseif (imp_physics == imp_physics_thompson) then do k=1,levs diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.meta index 22f57e354..fdef11d3b 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.meta @@ -295,6 +295,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.F90 index cbabb991b..6f6bd235e 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.F90 @@ -8,9 +8,9 @@ module GFS_suite_interstitial_4 !> \section arg_table_GFS_suite_interstitial_4_run Argument Table !! \htmlinclude GFS_suite_interstitial_4_run.html !! - subroutine GFS_suite_interstitial_4_run (im, levs, ltaerosol, tracers_total, ntrac, ntcw, ntiw, ntclamt, & - ntrw, ntsw, ntrnc, ntsnc, ntgl, ntgnc, ntlnc, ntinc, ntccn, nn, imp_physics, imp_physics_gfdl, imp_physics_thompson, & - imp_physics_nssl, nssl_invertccn, nssl_ccn_on, & + subroutine GFS_suite_interstitial_4_run (im, levs, ltaerosol, tracers_total, ntrac, ntcw, ntiw, ntclamt, & + ntrw, ntsw, ntrnc, ntsnc, ntgl, ntgnc, ntlnc, ntinc, ntccn, nn, imp_physics, imp_physics_gfdl, & + imp_physics_gfdl_v3, imp_physics_thompson, imp_physics_nssl, nssl_invertccn, nssl_ccn_on, & imp_physics_zhao_carr, imp_physics_zhao_carr_pdf, convert_dry_rho, dtf, save_qc, save_qi, con_pi, dtidx, dtend,& index_of_process_conv_trans, gq0, clw, prsl, save_tcp, con_rd, con_eps, nssl_cccn, nwfa, spechum, ldiag3d, & qdiag3d, save_lnc, save_inc, ntk, ntke, otsptflag, errmsg, errflg) @@ -24,8 +24,8 @@ subroutine GFS_suite_interstitial_4_run (im, levs, ltaerosol, tracers_total, ntr logical, intent(in) :: otsptflag(:)! on/off switch for tracer transport by updraft and integer, intent(in ) :: im, levs, tracers_total, ntrac, ntcw, ntiw, ntclamt, ntrw, & - ntsw, ntrnc, ntsnc, ntgl, ntgnc, ntlnc, ntinc, ntccn, nn, imp_physics, imp_physics_gfdl, imp_physics_thompson, & - imp_physics_zhao_carr, imp_physics_zhao_carr_pdf, imp_physics_nssl + ntsw, ntrnc, ntsnc, ntgl, ntgnc, ntlnc, ntinc, ntccn, nn, imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3, & + imp_physics_thompson, imp_physics_zhao_carr, imp_physics_zhao_carr_pdf, imp_physics_nssl logical, intent(in) :: ltaerosol, convert_dry_rho logical, intent(in) :: nssl_ccn_on, nssl_invertccn @@ -89,9 +89,10 @@ subroutine GFS_suite_interstitial_4_run (im, levs, ltaerosol, tracers_total, ntr endif endif if(ntcw>0) then - if (imp_physics == imp_physics_zhao_carr .or. & + if (imp_physics == imp_physics_zhao_carr .or. & imp_physics == imp_physics_zhao_carr_pdf .or. & - imp_physics == imp_physics_gfdl) then + imp_physics == imp_physics_gfdl .or. & + imp_physics == imp_physics_gfdl_v3 ) then idtend=dtidx(100+ntcw,index_of_process_conv_trans) if(idtend>=1) then dtend(:,:,idtend) = dtend(:,:,idtend) + clw(:,:,1)+clw(:,:,2) - gq0(:,:,ntcw) @@ -150,7 +151,8 @@ subroutine GFS_suite_interstitial_4_run (im, levs, ltaerosol, tracers_total, ntr ! for microphysics if (imp_physics == imp_physics_zhao_carr .or. & imp_physics == imp_physics_zhao_carr_pdf .or. & - imp_physics == imp_physics_gfdl) then + imp_physics == imp_physics_gfdl .or. & + imp_physics == imp_physics_gfdl_v3 ) then gq0(1:im,:,ntcw) = clw(1:im,:,1) + clw(1:im,:,2) elseif (ntiw > 0) then @@ -290,4 +292,4 @@ subroutine GFS_suite_interstitial_4_run (im, levs, ltaerosol, tracers_total, ntr end subroutine GFS_suite_interstitial_4_run - end module GFS_suite_interstitial_4 \ No newline at end of file + end module GFS_suite_interstitial_4 diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.meta index c0df52f1a..0726918fd 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.meta @@ -150,6 +150,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme @@ -390,4 +397,4 @@ units = 1 dimensions = () type = integer - intent = out \ No newline at end of file + intent = out diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.F90 index cd1016053..721cbfc42 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.F90 @@ -23,7 +23,8 @@ module maximum_hourly_diagnostics !! #endif subroutine maximum_hourly_diagnostics_run(im, levs, reset, lradar, imp_physics, & - imp_physics_gfdl, imp_physics_thompson, & + imp_physics_gfdl, imp_physics_gfdl_v3, & + imp_physics_thompson, & imp_physics_fer_hires, imp_physics_nssl, & con_g, phil, & gt0, refl_10cm, refdmax, refdmax263k, u10m, v10m, & @@ -36,8 +37,8 @@ subroutine maximum_hourly_diagnostics_run(im, levs, reset, lradar, imp_physics, ! Interface variables integer, intent(in) :: im, levs, kdt logical, intent(in) :: reset, lradar, lightning_threat - integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_thompson, imp_physics_fer_hires, & - imp_physics_nssl + integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3, & + imp_physics_thompson, imp_physics_fer_hires, imp_physics_nssl real(kind_phys), intent(in ) :: con_g real(kind_phys), intent(in ) :: con_rd real(kind_phys), intent(in ) :: phil(:,:) @@ -84,6 +85,7 @@ subroutine maximum_hourly_diagnostics_run(im, levs, reset, lradar, imp_physics, !Calculate hourly max 1-km agl and -10C reflectivity if (lradar .and. (imp_physics == imp_physics_gfdl .or. & + imp_physics == imp_physics_gfdl_v3 .or. & imp_physics == imp_physics_thompson .or. & imp_physics == imp_physics_fer_hires .or. & imp_physics == imp_physics_nssl )) then diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.meta index 0c2d1bcbe..a42ac8be6 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.meta @@ -49,6 +49,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.F90 b/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.F90 index 936393d5b..83721fa2b 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.F90 +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.F90 @@ -55,6 +55,7 @@ subroutine sgscloud_radpre_run( & nlay, plyr, xlat, dz,de_lgth, & cldsa,mtopa,mbota, & imp_physics, imp_physics_gfdl,& + imp_physics_gfdl_v3, & imp_physics_fa, & iovr, & errmsg, errflg ) @@ -75,7 +76,7 @@ subroutine sgscloud_radpre_run( & real(kind=kind_phys) :: gfac integer, intent(in) :: im, levs, imfdeepcnv, imfdeepcnv_gf, & & nlay, imfdeepcnv_sas, imfdeepcnv_c3, imp_physics, & - & imp_physics_gfdl, imp_physics_fa + & imp_physics_gfdl, imp_physics_gfdl_v3, imp_physics_fa logical, intent(in) :: flag_init, flag_restart, do_mynnedmf real(kind=kind_phys), dimension(:,:), intent(inout) :: qc, qi @@ -237,7 +238,7 @@ subroutine sgscloud_radpre_run( & enddo enddo - elseif (imp_physics /= imp_physics_gfdl) then + elseif (imp_physics /= imp_physics_gfdl .and. imp_physics /= imp_physics_gfdl_v3) then ! Non-MYNN cloud fraction AND non-GFDL microphysics, since both ! have their own cloud fractions. In this case, we resort to diff --git a/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.meta b/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.meta index a9635efa5..b3bf83ae0 100644 --- a/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.meta +++ b/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.meta @@ -468,6 +468,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_fa] standard_name = identifier_for_fer_hires_microphysics_scheme long_name = choice of Ferrier-Aligo microphysics scheme diff --git a/physics/MP/GFDL_2022_v3/fv_sat_adj_v3.F90 b/physics/MP/GFDL_2022_v3/fv_sat_adj_v3.F90 new file mode 100644 index 000000000..16d7bbefd --- /dev/null +++ b/physics/MP/GFDL_2022_v3/fv_sat_adj_v3.F90 @@ -0,0 +1,1441 @@ +!>\file fv_sat_adj_v3.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_v3 +! Modules Included: +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +!
Module NameFunctions Included
constants_modrvgas, rdgas, grav, hlv, hlf, cp_air
fv_arrays_mod r_grid
fv_mp_modis_master
module_gfdl_cld_mpql_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
+ ! 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 module_gfdl_cld_mp, only: ql_gen, qi0_max, ql_mlt, ql0_max, qi_lim, qs_mlt + use module_gfdl_cld_mp, only: icloud_f, t_sub, cld_min + use module_gfdl_cld_mp, only: tau_r2g, tau_smlt, tau_i2s, tau_v2l, tau_l2v, tau_imlt, tau_l2r + use module_gfdl_cld_mp, only: rad_rain, rad_snow, rad_graupel, dw_ocean, dw_land +#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_v3_init, fv_sat_adj_v3_run, fv_sat_adj_v3_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_v3_init' initializes lookup tables for the saturation mixing ratio. +!! \section arg_table_fv_sat_adj_v3_init Argument Table +!! \htmlinclude fv_sat_adj_v3_init.html +!! +subroutine fv_sat_adj_v3_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_v3_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_v3 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_v3_init + +!\ingroup fast_sat_adj +!>\brief The subroutine 'fv_sat_adj_v3_finalize' deallocates lookup tables for the saturation mixing ratio. +!! \section arg_table_fv_sat_adj_v3_finalize Argument Table +!! \htmlinclude fv_sat_adj_v3_finalize.html +!! +subroutine fv_sat_adj_v3_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_v3_finalize + +!>\defgroup fast_sat_adj GFDL In-Core Fast Saturation Adjustment Module +!> @{ +!! The subroutine 'fv_sat_adj_v3' 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_v3' 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_v3_run Argument Table +!! \htmlinclude fv_sat_adj_v3_run.html +!! +subroutine fv_sat_adj_v3_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_v3_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_v3_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_v3_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 + !real(kind=kind_dyn) :: qi_gen, sat_adj0 + real :: qi_gen, sat_adj0 + 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 + sat_adj0 = 0.9 ! !< adjustment factor (0: no, 1: full) during fast_sat_adj + + ! ----------------------------------------------------------------------- + ! wrf / wsm6 scheme: qi_gen = 4.92e-11 * (1.e3 * exp (0.1 * tmp)) ** 1.33 + ! optimized: qi_gen = 4.92e-11 * exp (1.33 * log (1.e3 * exp (0.1 * tmp))) + ! qi_gen ~ 4.808e-7 at 0 c; 1.818e-6 at - 10 c, 9.82679e-5 at - 40c + ! the following value is constructed such that qc_crt = 0 at zero c and @ - 10c matches + ! wrf / wsm6 ice initiation scheme; qi_crt = qi_gen * min (qi_lim, 0.1 * tmp) / den + ! ----------------------------------------------------------------------- + + qi_gen = 1.82e-6 !< max cloud ice generation during remapping step + + ! ----------------------------------------------------------------------- + !> - 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_gen = 4.92e-11 * exp (1.33 * log (1.e3 * exp (0.1 * tmp ))) + 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 + + 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) + + ! ----------------------------------------------------------------------- + ! 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_v3_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_v3 +!> @} diff --git a/physics/MP/GFDL_2022_v3/fv_sat_adj_v3.meta b/physics/MP/GFDL_2022_v3/fv_sat_adj_v3.meta new file mode 100644 index 000000000..9380b49a4 --- /dev/null +++ b/physics/MP/GFDL_2022_v3/fv_sat_adj_v3.meta @@ -0,0 +1,440 @@ +[ccpp-table-properties] + name = fv_sat_adj_v3 + type = scheme + dependencies = ../../hooks/machine.F,../../hooks/physcons.F90 + dependencies = module_gfdl_cld_mp.F90,../multi_gases.F90 + +######################################################################## +[ccpp-arg-table] + name = fv_sat_adj_v3_init + type = scheme +[do_sat_adj] + standard_name = flag_for_saturation_adjustment_for_microphysics_in_dynamics + long_name = flag for saturation adjustment for microphysics in dynamics + units = none + dimensions = () + type = logical + intent = in +[kmp] + standard_name = top_layer_index_for_fast_physics + long_name = top_layer_inder_for_gfdl_mp + units = index + dimensions = () + type = integer + intent = in +[nwat] + standard_name = number_of_water_species + long_name = number of water species + units = count + dimensions = () + type = integer + intent = in +[ngas] + standard_name = number_of_gases_for_multi_gases_physics + long_name = number of gases for multi gases physics + units = count + dimensions = () + type = integer + intent = in +[rilist] + standard_name = gas_constants_for_multi_gases_physics + long_name = gas constants for multi gases physics + units = J kg-1 K-1 + dimensions = (0:number_of_gases_for_multi_gases_physics) + type = real + kind = kind_dyn + intent = in +[cpilist] + standard_name = specific_heat_capacities_for_multi_gases_physics + long_name = specific heat capacities for multi gases physics + units = J kg-1 K-1 + dimensions = (0:number_of_gases_for_multi_gases_physics) + type = real + kind = kind_dyn + intent = in +[mpirank] + standard_name = mpi_rank_for_fast_physics + long_name = current MPI-rank for fast physics schemes + units = index + dimensions = () + type = integer + intent = in +[mpiroot] + standard_name = mpi_root_for_fast_physics + long_name = master MPI-rank for fast physics schemes + units = index + dimensions = () + type = integer + intent = in +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = fv_sat_adj_v3_finalize + type = scheme +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = fv_sat_adj_v3_run + type = scheme +[mdt] + standard_name = time_step_for_remapping_for_fast_physics + long_name = remapping time step for fast physics + units = s + dimensions = () + type = real + kind = kind_dyn + intent = in +[zvir] + standard_name = ratio_of_vapor_to_dry_air_gas_constants_minus_one_default_kind + long_name = zvir=rv/rd-1.0 + units = none + dimensions = () + type = real + kind = kind_dyn + intent = in +[is] + standard_name = starting_x_direction_index + long_name = starting X direction index + units = count + dimensions = () + type = integer + intent = in +[ie] + standard_name = ending_x_direction_index + long_name = ending X direction index + units = count + dimensions = () + type = integer + intent = in +[isd] + standard_name = starting_x_direction_index_domain + long_name = starting X direction index for domain + units = count + dimensions = () + type = integer + intent = in +[ied] + standard_name = ending_x_direction_index_domain + long_name = ending X direction index for domain + units = count + dimensions = () + type = integer + intent = in +[kmp] + standard_name = top_layer_index_for_fast_physics + long_name = top layer index for GFDL mp + units = index + dimensions = () + type = integer + intent = in +[km] + standard_name = vertical_dimension_for_fast_physics + long_name = number of vertical levels + units = count + dimensions = () + type = integer + intent = in +[kmdelz] + standard_name = vertical_dimension_for_thickness_at_Lagrangian_surface + long_name = vertical dimension for thickness at Lagrangian surface + units = count + dimensions = () + type = integer + intent = in +[js] + standard_name = starting_y_direction_index + long_name = starting Y direction index + units = count + dimensions = () + type = integer + intent = in +[je] + standard_name = ending_y_direction_index + long_name = ending Y direction index + units = count + dimensions = () + type = integer + intent = in +[jsd] + standard_name = starting_y_direction_index_domain + long_name = starting X direction index for domain + units = count + dimensions = () + type = integer + intent = in +[jed] + standard_name = ending_y_direction_index_domain + long_name = ending X direction index for domain + units = count + dimensions = () + type = integer + intent = in +[ng] + standard_name = number_of_ghost_zones + long_name = number of ghost zones defined in fv_mp + units = count + dimensions = () + type = integer + intent = in +[hydrostatic] + standard_name = flag_for_hydrostatic_solver_for_fast_physics + long_name = flag for use the hydrostatic or nonhydrostatic solver + units = flag + dimensions = () + type = logical + intent = in +[fast_mp_consv] + standard_name = flag_for_fast_microphysics_energy_conservation + long_name = flag for fast microphysics energy conservation + units = flag + dimensions = () + type = logical + intent = in +[te0_2d] + standard_name = atmosphere_energy_content_in_column + long_name = atmosphere total energy in columns + units = J m-2 + dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index) + type = real + kind = kind_dyn + intent = inout +[te0] + standard_name = atmosphere_energy_content_at_Lagrangian_surface + long_name = atmosphere total energy at Lagrangian surface + units = J m-2 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = out +[ngas] + standard_name = number_of_gases_for_multi_gases_physics + long_name = number of gases for multi gases physics + units = count + dimensions = () + type = integer + intent = in +[qvi] + standard_name = gas_tracers_for_multi_gas_physics_at_Lagrangian_surface + long_name = gas tracers for multi gas physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics,1:number_of_gases_for_multi_gases_physics) + type = real + kind = kind_dyn + intent = inout +[qv] + standard_name = water_vapor_specific_humidity_at_Lagrangian_surface + long_name = water vapor specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[ql] + standard_name = cloud_liquid_water_specific_humidity_at_Lagrangian_surface + long_name = cloud liquid water specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[qi] + standard_name = cloud_ice_specific_humidity_at_Lagrangian_surface + long_name = cloud ice specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[qr] + standard_name = cloud_rain_specific_humidity_at_Lagrangian_surface + long_name = cloud rain specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[qs] + standard_name = cloud_snow_specific_humidity_at_Lagrangian_surface + long_name = cloud snow specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[qg] + standard_name = cloud_graupel_specific_humidity_at_Lagrangian_surface + long_name = cloud graupel specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[hs] + standard_name = surface_geopotential_at_Lagrangian_surface + long_name = surface geopotential at Lagrangian surface + units = m2 s-2 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain) + type = real + kind = kind_dyn + intent = in +[peln] + standard_name = log_pressure_at_Lagrangian_surface + long_name = logarithm of pressure at Lagrangian surface + units = Pa + dimensions = (starting_x_direction_index:ending_x_direction_index,1:vertical_dimension_for_fast_physics_plus_one,starting_y_direction_index:ending_y_direction_index) + type = real + kind = kind_dyn + intent = in +[delz] + standard_name = thickness_at_Lagrangian_surface + long_name = thickness at Lagrangian_surface + units = m + dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_thickness_at_Lagrangian_surface) + type = real + kind = kind_dyn + intent = in +[delp] + standard_name = pressure_thickness_at_Lagrangian_surface + long_name = pressure thickness at Lagrangian surface + units = Pa + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = in +[pt] + standard_name = virtual_temperature_at_Lagrangian_surface + long_name = virtual temperature at Lagrangian surface + units = K + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[pkz] + standard_name = finite_volume_mean_edge_pressure_raised_to_the_power_of_kappa + long_name = finite-volume mean edge pressure in Pa raised to the power of kappa + units = 1 + dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[q_con] + standard_name = cloud_condensed_water_specific_humidity_at_Lagrangian_surface + long_name = cloud condensed water specific humidity updated by fast physics at Lagrangian surface + units = kg kg-1 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_condensed_water_at_Lagrangian_surface) + type = real + kind = kind_dyn + intent = inout +[akap] + standard_name = kappa_dry_for_fast_physics + long_name = modified kappa for dry air, fast physics + units = none + dimensions = () + type = real + kind = kind_dyn + intent = in +[cappa] + standard_name = cappa_moist_gas_constant_at_Lagrangian_surface + long_name = cappa(i,j,k) = rdgas / ( rdgas + cvm(i)/(1.+r_vir*q(i,j,k,sphum)) ) + units = none + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_cappa_at_Lagrangian_surface) + type = real + kind = kind_dyn + intent = inout +[area] + standard_name = cell_area_for_fast_physics + long_name = area of the grid cell for fast physics + units = m2 + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain) + type = real + kind = kind_grid + intent = in +[dtdt] + standard_name = tendency_of_air_temperature_at_Lagrangian_surface + long_name = air temperature tendency due to fast physics at Lagrangian surface + units = K s-1 + dimensions = (starting_x_direction_index:ending_x_direction_index,starting_y_direction_index:ending_y_direction_index,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = inout +[out_dt] + standard_name = flag_for_tendency_of_air_temperature_at_Lagrangian_surface + long_name = flag for calculating tendency of air temperature due to fast physics + units = flag + dimensions = () + type = logical + intent = in +[last_step] + standard_name = flag_for_the_last_step_of_k_split_remapping + long_name = flag for the last step of k-split remapping + units = flag + dimensions = () + type = logical + intent = in +[do_qa] + standard_name = flag_for_inline_cloud_fraction_calculation + long_name = flag for the inline cloud fraction calculation + units = flag + dimensions = () + type = logical + intent = in +[qa] + standard_name = cloud_fraction_at_Lagrangian_surface + long_name = cloud fraction at Lagrangian surface + units = none + dimensions = (starting_x_direction_index_domain:ending_x_direction_index_domain,starting_y_direction_index_domain:ending_y_direction_index_domain,1:vertical_dimension_for_fast_physics) + type = real + kind = kind_dyn + intent = out +[nthreads] + standard_name = omp_threads_for_fast_physics + long_name = number of OpenMP threads available for fast physics schemes + units = count + dimensions = () + type = integer + intent = in +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out diff --git a/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 b/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 new file mode 100644 index 000000000..b5911b193 --- /dev/null +++ b/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 @@ -0,0 +1,484 @@ +!> \file gfdl_cld_mp_v3.F90 +!! This file contains the CCPP entry point for the column GFDL cloud microphysics version 3 ( Chen and Lin (2013) +!! \cite chen_and_lin_2013 ). +module gfdl_cld_mp_v3 + + use module_gfdl_cld_mp, only: module_gfdl_cld_mp_init, & + module_gfdl_cld_mp_driver, & + module_gfdl_cld_mp_end, & + rad_ref, cld_eff_rad + + implicit none + + private + + public gfdl_cld_mp_v3_run, gfdl_cld_mp_v3_init, gfdl_cld_mp_v3_finalize + + logical :: is_initialized = .false. + +contains + +! ----------------------------------------------------------------------- +! CCPP entry points for gfdl cloud microphysics +! ----------------------------------------------------------------------- + +!>\brief The subroutine initializes the GFDL +!! cloud microphysics. +!! +!> \section arg_table_gfdl_cld_mp_v3_init Argument Table +!! \htmlinclude gfdl_cld_mp_v3_init.html +!! + + subroutine gfdl_cld_mp_v3_init (me, master, nlunit, input_nml_file, logunit, & + fn_nml, imp_physics, imp_physics_gfdl_v3, do_shoc, & + hydrostatic, errmsg, errflg) + + implicit none + + integer, intent (in) :: me + integer, intent (in) :: master + integer, intent (in) :: nlunit + integer, intent (in) :: logunit + character(len=*), intent (in) :: fn_nml + character(len=*), intent (in) :: input_nml_file(:) + integer, intent( in) :: imp_physics + integer, intent( in) :: imp_physics_gfdl_v3 + logical, intent( in) :: do_shoc + logical, intent( in) :: hydrostatic + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + if (is_initialized) return + + if (imp_physics/=imp_physics_gfdl_v3) then + write(errmsg,'(*(a))') 'Namelist option for microphysics does not match choice in suite definition file' + errflg = 1 + return + end if + + if (do_shoc) then + write(errmsg,'(*(a))') 'SHOC is not currently compatible with GFDL MP v3' + errflg = 1 + return + endif + + call module_gfdl_cld_mp_init(me, master, nlunit, input_nml_file, logunit, fn_nml, hydrostatic, errmsg, errflg) + + is_initialized = .true. + + end subroutine gfdl_cld_mp_v3_init + + +! ======================================================================= +!>\brief The subroutine 'gfdl_cld_mp_v3_finalize' terminates the GFDL +!! cloud microphysics. +!! +!! \section arg_table_gfdl_cld_mp_v3_finalize Argument Table +!! \htmlinclude gfdl_cld_mp_v3_finalize.html +!! + subroutine gfdl_cld_mp_v3_finalize(errmsg, errflg) + + implicit none + + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + if (.not.is_initialized) return + + call module_gfdl_cld_mp_end() + + is_initialized = .false. + + end subroutine gfdl_cld_mp_v3_finalize + +!>\defgroup gfdlmp GFDL Cloud Microphysics Module +!! This is cloud microphysics package for GFDL global cloud resolving model. +!! The algorithms are originally derived from Lin et al. (1983) \cite lin_et_al_1983. +!! Most of the key elements have been simplified/improved. This code at this stage +!! bears little to no similarity to the original Lin MP. +!! Therefore, it is best to be called GFDL microphysics (GFDL MP) . +!! +!>\brief The module contains the GFDL cloud +!! microphysics (Chen and Lin (2013) \cite chen_and_lin_2013 ). +!> The module is paired with \ref fast_sat_adj, which performs the "fast" +!! processes. +!! +!>\brief The subroutine executes the full GFDL cloud microphysics. +!! \section arg_table_gfdl_cld_mp_v3_run Argument Table +!! \htmlinclude gfdl_cld_mp_v3_run.html +!! + subroutine gfdl_cld_mp_v3_run( & + imp_physics, imp_physics_gfdl_v3, fast_mp_consv, & + levs, im, rainmin, con_g, con_fvirt, con_rd, con_eps, garea, slmsk, snowd, & + gq0, gq0_ntcw, gq0_ntrw, gq0_ntiw, gq0_ntsw, gq0_ntgl, gq0_ntclamt, aerfld, & + gt0, gu0, gv0, vvl, prsl, phii, del, & + rain0, ice0, snow0, graupel0, prcp0, sr, oro, & + dtp, hydrostatic, lradar, refl_10cm, & + reset, effr_in, rew, rei, rer, res, reg, & + cplchm, pfi_lsan, pfl_lsan, errmsg, errflg) + + use machine, only: kind_phys, kind_dyn + + implicit none + + ! DH* TODO: CLEANUP, all of these should be coming in through the argument list + ! parameters + real(kind=kind_phys), parameter :: one = 1.0d0 + real(kind=kind_phys), parameter :: con_p001= 0.001d0 + real(kind=kind_phys), parameter :: con_day = 86400.d0 + !real(kind=kind_phys), parameter :: rainmin = 1.0d-13 + ! *DH + + ! interface variables + integer, intent(in ) :: imp_physics + integer, intent(in ) :: imp_physics_gfdl_v3 + integer, intent(in ) :: levs, im + real(kind=kind_phys), intent(in ) :: con_g, con_fvirt, con_rd, con_eps, rainmin + real(kind=kind_phys), intent(in ), dimension(:) :: garea, slmsk, snowd, oro + real(kind=kind_phys), intent(inout), dimension(:,:) :: gq0, gq0_ntcw, gq0_ntrw, gq0_ntiw, & + gq0_ntsw, gq0_ntgl, gq0_ntclamt + real(kind_phys), intent(in ), dimension(:,:,:) :: aerfld + real(kind=kind_phys), intent(inout), dimension(:,:) :: gt0, gu0, gv0 + real(kind=kind_phys), intent(in ), dimension(:,:) :: vvl, prsl, del + real(kind=kind_phys), intent(in ), dimension(:,:) :: phii + + ! rain/snow/ice/graupel/precip amounts, fraction of frozen precip + !real(kind_phys), dimension(:) :: water0 + real(kind_phys), intent(out ), dimension(:) :: rain0 + real(kind_phys), intent(out ), dimension(:) :: snow0 + real(kind_phys), intent(out ), dimension(:) :: ice0 + real(kind_phys), intent(out ), dimension(:) :: graupel0 + real(kind_phys), intent(out ), dimension(:) :: prcp0 + real(kind_phys), intent(out ), dimension(:) :: sr + + real(kind_phys), intent(in) :: dtp ! physics time step + logical, intent (in) :: hydrostatic, fast_mp_consv + + logical, intent (in) :: lradar + real(kind=kind_phys), intent(inout), dimension(:,:) :: refl_10cm + logical, intent (in) :: reset, effr_in !rsun reset could be removed + real(kind=kind_phys), intent(inout), dimension(:,:) :: rew, rei, rer, res, reg + logical, intent (in) :: cplchm + ! ice and liquid water 3d precipitation fluxes - only allocated if cplchm is .true. + real(kind=kind_phys), intent(inout), dimension(:,:) :: pfi_lsan, pfl_lsan + + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! local variables + integer :: iis, iie, jjs, jje, kks, kke, kbot, ktop + integer :: i, k, kk + real(kind=kind_phys), dimension(1:im,1:levs) :: delp, dz, uin, vin, pt, qv1, ql1, qi1, qr1, qs1, qg1, & + qa1, qnl, qni, pt_dt, qa_dt, u_dt, v_dt, w, qv_dt, ql_dt,& + qr_dt, qi_dt, qs_dt, qg_dt, p123, refl + real(kind=kind_phys), dimension(1:im,1:levs) :: q_con, cappa !for inline MP option + real(kind=kind_phys), dimension(1:im,1,1:levs) :: pfils, pflls + real(kind=kind_phys), dimension(1:im,1,1:levs) :: adj_vmr, te + real(kind=kind_phys), dimension(1:im,1:levs) :: prefluxw, prefluxr, prefluxi, prefluxs, prefluxg + real(kind=kind_phys), dimension(1:im) :: dte, hs + !real(kind=kind_phys), dimension(:,:), allocatable :: den + real(kind=kind_phys), dimension(1:im) :: water0 + real(kind=kind_phys) :: onebg + real(kind=kind_phys) :: tem + logical last_step, do_inline_mp + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + iis = 1 + iie = im + jjs = 1 + jje = 1 + kks = 1 + kke = levs + ! flipping of vertical direction + ktop = 1 + kbot = levs + + onebg = one/con_g + + do k = 1, levs + kk = levs-k+1 + do i = 1, im + qv_dt(i,k) = 0.0 + ql_dt(i,k) = 0.0 + qr_dt(i,k) = 0.0 + qi_dt(i,k) = 0.0 + qs_dt(i,k) = 0.0 + qg_dt(i,k) = 0.0 + qa_dt(i,k) = 0.0 + pt_dt(i,k) = 0.0 + u_dt(i,k) = 0.0 + v_dt(i,k) = 0.0 + qnl(i,k) = aerfld(i,kk,11) ! sulfate + pfils(i,1,k) = 0.0 + pflls(i,1,k) = 0.0 +!rsun intitialize pfluxi etc take a look at the SHield driver + prefluxw(i,k) =0.0 + prefluxi(i,k) =0.0 + prefluxr(i,k) =0.0 + prefluxs(i,k) =0.0 + prefluxg(i,k) =0.0 + + ! flip vertical (k) coordinate top =1 + qv1(i,k) = gq0(i,kk) + ql1(i,k) = gq0_ntcw(i,kk) + qr1(i,k) = gq0_ntrw(i,kk) + qi1(i,k) = gq0_ntiw(i,kk) + qs1(i,k) = gq0_ntsw(i,kk) + qg1(i,k) = gq0_ntgl(i,kk) + qa1(i,k) = gq0_ntclamt(i,kk) + pt(i,k) = gt0(i,kk) +!rsun WW defined here is differnce from what is used in SHiELD (https://github.com/NOAA-GFDL/SHiELD_physics/blob/main/GFS_layer/GFS_physics_driver.F90) + w(i,k) = -vvl(i,kk) * (one+con_fvirt * gq0(i,kk)) & + * gt0(i,kk) / prsl(i,kk) * (con_rd*onebg) + uin(i,k) = gu0(i,kk) + vin(i,k) = gv0(i,kk) + delp(i,k) = del(i,kk) + dz(i,k) = (phii(i,kk)-phii(i,kk+1))*onebg + p123(i,k) = prsl(i,kk) + !tem = con_eps*prsl(i,kk)/(con_rd*gt0(i,kk)*(gq0(i,kk)+con_eps)) + !if(tem <0.0) then + ! write(errmsg,'(*(a))') 'Negative air density associated with GFDL MP v3' + ! errflg = 1 + ! return + !endif + !qni(i,k) = 10./tem + qni(i,k) = 10. +!rsun debug +! if(i == 1) then +! write(*,*) 'T, qnl, qni:',k,p123(i,k),pt(i,k),qnl(i,k), qni(i,k) +! endif + +!rsun for inline option + q_con(i,k) = 0.0 + cappa(i,k) = 0.0 + enddo + enddo + + ! reset precipitation amounts to zero + water0 = 0 + rain0 = 0 + ice0 = 0 + snow0 = 0 + graupel0 = 0 + +! if(imp_physics == imp_physics_gfdl) then +! +! call gfdl_cloud_microphys_mod_driver(iis, iie, jjs, jje, kks, kke, ktop, kbot, & +! qv1, ql1, qr1, qi1, qs1, qg1, qa1, qnl, qv_dt, ql_dt, qr_dt, qi_dt, & +! qs_dt, qg_dt, qa_dt, pt_dt, pt, w, uin, vin, u_dt, v_dt, dz, delp, & +! garea, dtp, frland, rain0, snow0, ice0, graupel0, hydrostatic, & +! phys_hydrostatic, p123, lradar, refl, reset, pfils, pflls) +! +! else if (imp_physics == imp_physics_gfdl_v3) then + if(imp_physics == imp_physics_gfdl_v3) then + +!rsun attention to flipping (same as v1 driver: need to be from top to bottom : 1,km) +!rsun : variables defined in shield +! need to pass water out +! hs = Sfcprop%oro(:) * con_g +! gsize = sqrt(Grid%area(:)) +! w (:,k) = -Statein%vvl(:,levs-k+1)*con_rd*Stateout%gt0(:,levs-k+1) & +! & /Statein%prsl(:,levs-k+1)/con_g +! delp (:,k) = del(:,levs-k+1) +! dz (:,k) = (Statein%phii(:,levs-k+1)-Statein%phii(:,levs-k+2))/con_g +! +! turn off the or remove the inline option +! define consv_te a logical variable as input only +! define adj_vmr output only + + !fast_mp_consv = .false. + !last_step = .true. + last_step = .false. + do_inline_mp = .false. + hs = oro(:) * con_g + + call module_gfdl_cld_mp_driver( qv1, ql1, qr1, qi1, qs1, qg1, qa1, qnl, qni, pt, w,& + uin, vin, dz, delp, garea, dtp, hs, water0, rain0, & + ice0, snow0, graupel0, hydrostatic, iis, iie, kks, kke, q_con, cappa, & + fast_mp_consv, adj_vmr, te, dte, prefluxw, prefluxr, prefluxi, prefluxs, & + prefluxg, last_step, do_inline_mp ) + + !if(lradar) refl = -20.0 !call rad_ref or call refl10cm_gfdl from GFDLMP V1 + +!make sure the unit of water0, rain0, ice0, snow0, graupel0, are the same as in V1 mm/day? +! find how to define them in module_gfdl_cloud_microphys.F90 +! need to add call refl calculation to calulate refl call rad_ref +! +! rsun check to make sure the variables going out of the routine +! the following list of variables can be calcualted here +! (no need for the following variables (the variables are updated in the gfdl_cld_mp_mod_driver) +! pt_dt, qa_dt, u_dt, v_dt, qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt +! take a look how qnl and qi1 are initialized + + else + write(errmsg,'(*(a))') 'Invalid imp_physics option for GFDL MP v3' + errflg = 1 + return + endif + tem = dtp*con_p001/con_day + + ! fix negative values + do i = 1, im + !rain0(i) = max(con_d00, rain0(i)) + !snow0(i) = max(con_d00, snow0(i)) + !ice0(i) = max(con_d00, ice0(i)) + !graupel0(i) = max(con_d00, graupel0(i)) + if(water0(i)*tem < rainmin) then + water0(i) = 0.0 + endif + if(rain0(i)*tem < rainmin) then + rain0(i) = 0.0 + endif + if(ice0(i)*tem < rainmin) then + ice0(i) = 0.0 + endif + if(snow0(i)*tem < rainmin) then + snow0(i) = 0.0 + endif + if(graupel0(i)*tem < rainmin) then + graupel0(i) = 0.0 + endif + enddo + + ! calculate fraction of frozen precipitation using unscaled + ! values of rain0, ice0, snow0, graupel0 (for bit-for-bit) + do i=1,im + prcp0(i) = (rain0(i)+snow0(i)+ice0(i)+graupel0(i)) * tem + if ( prcp0(i) > rainmin ) then + sr(i) = (snow0(i) + ice0(i) + graupel0(i)) & + / (rain0(i) + snow0(i) + ice0(i) + graupel0(i)) + else + sr(i) = 0.0 + endif + enddo + + ! convert rain0, ice0, snow0, graupel0 from mm per day to m per physics timestep + water0 = water0*tem + rain0 = rain0*tem + ice0 = ice0*tem + snow0 = snow0*tem + graupel0 = graupel0*tem + +!rsun: move this after the call of the each driver + + ! flip vertical coordinate back + do k=1,levs + kk = levs-k+1 + do i=1,im + +!rsun add update the following fields only for v1 +! if (imp_physics == imp_physics_gfdl) then +! + ! gq0(i,k) = qv1(i,kk) + qv_dt(i,kk) * dtp + ! gq0_ntcw(i,k) = ql1(i,kk) + ql_dt(i,kk) * dtp + ! gq0_ntrw(i,k) = qr1(i,kk) + qr_dt(i,kk) * dtp + ! gq0_ntiw(i,k) = qi1(i,kk) + qi_dt(i,kk) * dtp + ! gq0_ntsw(i,k) = qs1(i,kk) + qs_dt(i,kk) * dtp + ! gq0_ntgl(i,k) = qg1(i,kk) + qg_dt(i,kk) * dtp + ! gq0_ntclamt(i,k) = qa1(i,kk) + qa_dt(i,kk) * dtp + ! gt0(i,k) = gt0(i,k) + pt_dt(i,kk) * dtp + ! gu0(i,k) = gu0(i,k) + u_dt(i,kk) * dtp + ! gv0(i,k) = gv0(i,k) + v_dt(i,kk) * dtp + ! refl_10cm(i,k) = refl(i,kk) + !else if(imp_physics == imp_physics_gfdl_v3) then + if (imp_physics == imp_physics_gfdl_v3) then + gq0(i,k) = qv1(i,kk) + gq0_ntcw(i,k) = ql1(i,kk) + gq0_ntrw(i,k) = qr1(i,kk) + gq0_ntiw(i,k) = qi1(i,kk) + gq0_ntsw(i,k) = qs1(i,kk) + gq0_ntgl(i,k) = qg1(i,kk) + gq0_ntclamt(i,k) = qa1(i,kk) + gt0(i,k) = pt(i,kk) ! rsun double check this + gu0(i,k) = uin(i,kk) + gv0(i,k) = vin(i,kk) + refl_10cm(i,k) = refl(i,kk) + else + write(errmsg,'(*(a))') 'Invalid imp_physics option for GFDL MP v3' + errflg = 1 + return + endif + enddo + enddo + + ! output ice and liquid water 3d precipitation fluxes if requested + if (cplchm) then + do k=1,levs + kk = levs-k+1 + do i=1,im + !if(imp_physics==imp_physics_gfdl) then + ! pfi_lsan(i,k) = pfils(i,1,kk) !rsun this need special attention to have the same variable in v3 + ! pfl_lsan(i,k) = pflls(i,1,kk) + !else if (imp_physics==imp_physics_gfdl_v3) then + if (imp_physics==imp_physics_gfdl_v3) then + +!rsun make sure prefluxw is the same as pfils + + pfi_lsan(i,k) = prefluxi (i,kk) + prefluxs (i,kk) + prefluxg (i,kk)! rsun: use the same unit as pfils + pfl_lsan(i,k) = prefluxr (i,kk) ! rsun + else + write(errmsg,'(*(a))') 'Invalid imp_physics option for GFDL MP v3' + errflg = 1 + return + endif + enddo + enddo + endif + + if(effr_in) then + !allocate(den(1:im,1:levs)) + !do k=1,levs + ! do i=1,im + ! den(i,k)=con_eps*prsl(i,k)/(con_rd*gt0(i,k)*(gq0(i,k)+con_eps)) + ! enddo + !enddo + !call cloud_diagnosis (1, im, 1, levs, den(1:im,1:levs), & + ! del(1:im,1:levs), islmsk(1:im), & + ! gq0_ntcw(1:im,1:levs), gq0_ntiw(1:im,1:levs), & + ! gq0_ntrw(1:im,1:levs), & + ! gq0_ntsw(1:im,1:levs) + gq0_ntgl(1:im,1:levs), & + ! gq0_ntgl(1:im,1:levs)*0.0, gt0(1:im,1:levs), & + ! rew(1:im,1:levs), rei(1:im,1:levs), rer(1:im,1:levs),& + ! res(1:im,1:levs), reg(1:im,1:levs)) + !deallocate(den) + call cld_eff_rad (1, im, 1, levs, slmsk(1:im), & + prsl(1:im,1:levs), del(1:im,1:levs), & + gt0(1:im,1:levs), gq0(1:im,1:levs), & + gq0_ntcw(1:im,1:levs), gq0_ntiw(1:im,1:levs), & + gq0_ntrw(1:im,1:levs), gq0_ntsw(1:im,1:levs), & + gq0_ntgl(1:im,1:levs), gq0_ntclamt(1:im,1:levs), & + rew(1:im,1:levs), rei(1:im,1:levs), rer(1:im,1:levs),& + res(1:im,1:levs), reg(1:im,1:levs),snowd(1:im)) + endif + + if(lradar) then + ! need peln, zvir; print and check + ! need to use qv1 etc (top 1 and bottom 127) + ! make sure the consistency between peln, zvir and qv1 etc + call rad_ref (1, im, 1, 1, qv1(1:im,1:levs), qr1(1:im,1:levs), & + qs1(1:im,1:levs),qg1(1:im,1:levs),pt(1:im,1:levs), & + delp(1:im,1:levs), dz(1:im,1:levs), refl(1:im,1:levs), levs, hydrostatic, & + do_inline_mp, 1) + + do k=1,levs + kk = levs-k+1 + do i=1,im + refl_10cm(i,k) = max(-35.,refl(i,kk)) + enddo + enddo + endif + + end subroutine gfdl_cld_mp_v3_run + +end module gfdl_cld_mp_v3 diff --git a/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.meta b/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.meta new file mode 100644 index 000000000..2fdf630c5 --- /dev/null +++ b/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.meta @@ -0,0 +1,519 @@ +[ccpp-table-properties] + name = gfdl_cld_mp_v3 + type = scheme + dependencies = ../../hooks/machine.F + dependencies = module_gfdl_cld_mp.F90 + +######################################################################## +[ccpp-arg-table] + name = gfdl_cld_mp_v3_init + type = scheme +[me] + standard_name = mpi_rank + long_name = MPI rank of current process + units = index + dimensions = () + type = integer + intent = in +[master] + standard_name = mpi_root + long_name = MPI rank of master process + units = index + dimensions = () + type = integer + intent = in +[nlunit] + standard_name = iounit_of_namelist + long_name = fortran unit number for opening nameliust file + units = none + dimensions = () + type = integer + intent = in +[input_nml_file] + standard_name = filename_of_internal_namelist + long_name = character string to store full namelist contents + units = none + dimensions = (number_of_lines_in_internal_namelist) + type = character + kind = len=* + intent = in +[logunit] + standard_name = iounit_of_log + long_name = fortran unit number for writing logfile + units = none + dimensions = () + type = integer + intent = in +[fn_nml] + standard_name = filename_of_namelist + long_name = namelist filename + units = none + dimensions = () + type = character + kind = len=* + intent = in +[imp_physics] + standard_name = control_for_microphysics_scheme + long_name = choice of microphysics scheme + units = flag + dimensions = () + type = integer + intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in +[do_shoc] + standard_name = flag_for_shoc + long_name = flag to indicate use of SHOC + units = flag + dimensions = () + type = logical + intent = in +[hydrostatic] + standard_name = flag_for_hydrostatic_solver + long_name = flag indicating hydrostatic solver + units = flag + dimensions = () + type = logical + intent = in +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = gfdl_cld_mp_v3_finalize + type = scheme +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = gfdl_cld_mp_v3_run + type = scheme +[imp_physics] + standard_name = control_for_microphysics_scheme + long_name = choice of microphysics scheme + units = flag + dimensions = () + type = integer + intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics scheme + units = flag + dimensions = () + type = integer + intent = in +[fast_mp_consv] + standard_name = flag_for_fast_microphysics_energy_conservation + long_name = flag for fast microphysics energy conservation + units = flag + dimensions = () + type = logical + intent = in +[levs] + standard_name = vertical_layer_dimension + long_name = number of vertical levels + units = count + dimensions = () + type = integer + intent = in +[im] + standard_name = horizontal_loop_extent + long_name = horizontal loop extent + units = count + dimensions = () + type = integer + intent = in +[rainmin] + standard_name = lwe_thickness_of_minimum_rain_amount + long_name = minimum rain amount + units = m + dimensions = () + type = real + kind = kind_phys + intent = in +[con_g] + standard_name = gravitational_acceleration + long_name = gravitational acceleration + units = m s-2 + dimensions = () + type = real + kind = kind_phys + intent = in +[con_fvirt] + standard_name = ratio_of_vapor_to_dry_air_gas_constants_minus_one + long_name = rv/rd - 1 (rv = ideal gas constant for water vapor) + units = none + dimensions = () + type = real + kind = kind_phys + intent = in +[con_rd] + standard_name = gas_constant_of_dry_air + long_name = ideal gas constant for dry air + units = J kg-1 K-1 + dimensions = () + type = real + kind = kind_phys + intent = in +[con_eps] + standard_name = ratio_of_dry_air_to_water_vapor_gas_constants + long_name = rd/rv + units = none + dimensions = () + type = real + kind = kind_phys + intent = in +[garea] + standard_name = cell_area + long_name = area of grid cell + units = m2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = in +[slmsk] + standard_name = area_type + long_name = landmask: sea/land/ice=0/1/2 + units = flag + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = in +[snowd] + standard_name = lwe_surface_snow + long_name = water equivalent snow depth + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = in +[gq0] + standard_name = specific_humidity_of_new_state + long_name = water vapor specific humidity updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntcw] + standard_name = cloud_liquid_water_mixing_ratio_of_new_state + long_name = cloud condensed water mixing ratio updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntrw] + standard_name = rain_mixing_ratio_of_new_state + long_name = moist mixing ratio of rain updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntiw] + standard_name = cloud_ice_mixing_ratio_of_new_state + long_name = moist mixing ratio of cloud ice updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntsw] + standard_name = snow_mixing_ratio_of_new_state + long_name = moist mixing ratio of snow updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntgl] + standard_name = graupel_mixing_ratio_of_new_state + long_name = moist ratio of mass of graupel to mass of dry air plus vapor (without condensates) updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gq0_ntclamt] + standard_name = cloud_area_fraction_in_atmosphere_layer_of_new_state + long_name = cloud fraction updated by physics + units = frac + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[aerfld] + standard_name = mass_mixing_ratio_of_aerosol_from_gocart_or_merra2 + long_name = mass mixing ratio of aerosol from gocart or merra2 + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension,number_of_aerosol_tracers_MG) + type = real + kind = kind_phys + intent = in +[gt0] + standard_name = air_temperature_of_new_state + long_name = air temperature updated by physics + units = K + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gu0] + standard_name = x_wind_of_new_state + long_name = zonal wind updated by physics + units = m s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[gv0] + standard_name = y_wind_of_new_state + long_name = meridional wind updated by physics + units = m s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[vvl] + standard_name = lagrangian_tendency_of_air_pressure + long_name = layer mean vertical velocity + units = Pa s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[prsl] + standard_name = air_pressure + long_name = mean layer pressure + units = Pa + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[phii] + standard_name = geopotential_at_interface + long_name = geopotential at model layer interfaces + units = m2 s-2 + dimensions = (horizontal_loop_extent,vertical_interface_dimension) + type = real + kind = kind_phys + intent = in +[del] + standard_name = air_pressure_difference_between_midlayers + long_name = air pressure difference between mid-layers + units = Pa + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[rain0] + standard_name = lwe_thickness_of_explicit_rain_amount + long_name = explicit rain on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[ice0] + standard_name = lwe_thickness_of_ice_amount + long_name = ice fall on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[snow0] + standard_name = lwe_thickness_of_snow_amount + long_name = snow fall on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[graupel0] + standard_name = lwe_thickness_of_graupel_amount + long_name = graupel fall on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[prcp0] + standard_name = lwe_thickness_of_explicit_precipitation_amount + long_name = explicit precipitation (rain, ice, snow, graupel) on physics timestep + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[sr] + standard_name = ratio_of_snowfall_to_rainfall + long_name = snow ratio: ratio of snow to total precipitation + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = out +[oro] + standard_name = height_above_mean_sea_level + long_name = height_above_mean_sea_level + units = m + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = inout +[dtp] + standard_name = timestep_for_physics + long_name = physics timestep + units = s + dimensions = () + type = real + kind = kind_phys + intent = in +[hydrostatic] + standard_name = flag_for_hydrostatic_solver + long_name = flag indicating hydrostatic solver + units = flag + dimensions = () + type = logical + intent = in +[lradar] + standard_name = flag_for_radar_reflectivity + long_name = flag for radar reflectivity + units = flag + dimensions = () + type = logical + intent = in +[refl_10cm] + standard_name = radar_reflectivity_10cm + long_name = instantaneous refl_10cm + units = dBZ + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[reset] + standard_name = flag_reset_maximum_hourly_fields + long_name = flag for resetting maximum hourly fields + units = flag + dimensions = () + type = logical + intent = in +[effr_in] + standard_name = flag_for_cloud_effective_radii + long_name = flag for cloud effective radii calculations in GFDL microphysics + units = flag + dimensions = () + type = logical + intent = in +[rew] + standard_name = effective_radius_of_stratiform_cloud_liquid_water_particle + long_name = eff. radius of cloud liquid water particle in micrometer + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[rei] + standard_name = effective_radius_of_stratiform_cloud_ice_particle + long_name = eff. radius of cloud ice water particle in micrometer + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[rer] + standard_name = effective_radius_of_stratiform_cloud_rain_particle + long_name = effective radius of cloud rain particle in micrometers + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[res] + standard_name = effective_radius_of_stratiform_cloud_snow_particle + long_name = effective radius of cloud snow particle in micrometers + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[reg] + standard_name = effective_radius_of_stratiform_cloud_graupel_particle + long_name = eff. radius of cloud graupel particle in micrometer + units = um + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[cplchm] + standard_name = flag_for_chemistry_coupling + long_name = flag controlling cplchm collection (default off) + units = flag + dimensions = () + type = logical + intent = in +[pfi_lsan] + standard_name = ice_flux_due_to_large_scale_precipitation + long_name = instantaneous 3D flux of ice from nonconvective precipitation + units = kg m-2 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[pfl_lsan] + standard_name = liquid_flux_due_to_large_scale_precipitation + long_name = instantaneous 3D flux of liquid water from nonconvective precipitation + units = kg m-2 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out diff --git a/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 b/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 new file mode 100644 index 000000000..37fbd7cee --- /dev/null +++ b/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 @@ -0,0 +1,7717 @@ +!>\file module_gfdl_cld_mp.F90 +!! This file contains the entity of GFDL MP scheme Version 3. + +!*********************************************************************** +!* GNU Lesser General Public License +!* +!* This file is part of the FV3 dynamical core. +!* +!* The FV3 dynamical core is free software: you can 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 FV3 dynamical core is distributed in the hope that it will be +!* useful, but WITHOUT ANY WARRANTY; 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 FV3 dynamical core. +!* If not, see . +!*********************************************************************** + +! ======================================================================= +! GFDL Cloud Microphysics Package (GFDL MP) Version 3 +! The algorithms are originally derived from Lin et al. (1983). +! Most of the key elements have been simplified / improved. +! This code at this stage bears little to no similarity to the original Lin MP in ZETAC. +! Developers: Linjiong Zhou and the GFDL FV3 Team +! References: +! Version 0: Chen and Lin (2011 doi: 10.1029/2011GL047629, 2013 doi: 10.1175/JCLI-D-12-00061.1) +! Version 1: Zhou et al. (2019 doi: 10.1175/BAMS-D-17-0246.1) +! Version 2: Harris et al. (2020 doi: 10.1029/2020MS002223), Zhou et al. (2022 doi: 10.25923/pz3c-8b96) +! Version 3: Zhou et al. (2022 doi: 10.1029/2021MS002971) +! ======================================================================= + +module module_gfdl_cld_mp + + implicit none + + private + + ! ----------------------------------------------------------------------- + ! interface functions + ! ----------------------------------------------------------------------- + + interface wqs + procedure wes_t + procedure wqs_trho + procedure wqs_ptqv + end interface wqs + + interface mqs + procedure mes_t + procedure mqs_trho + procedure mqs_ptqv + end interface mqs + + interface iqs + procedure ies_t + procedure iqs_trho + procedure iqs_ptqv + end interface iqs + + interface mhc + procedure mhc3 + procedure mhc4 + procedure mhc6 + end interface mhc + + interface wet_bulb + procedure wet_bulb_dry + procedure wet_bulb_moist + end interface wet_bulb + + ! ----------------------------------------------------------------------- + ! public subroutines, functions, and variables + ! ----------------------------------------------------------------------- + + public :: module_gfdl_cld_mp_init + public :: module_gfdl_cld_mp_driver + public :: module_gfdl_cld_mp_end + public :: cld_sat_adj, cld_eff_rad, rad_ref + public :: qs_init, wqs, mqs, mqs3d + public :: c_liq, c_ice, rhow, wet_bulb + public :: cv_air, cv_vap, mtetw + public :: hlv, hlf, tice + + ! ----------------------------------------------------------------------- + ! precision definition + ! ----------------------------------------------------------------------- + + integer, parameter :: r8 = 8 ! double precision + + ! ----------------------------------------------------------------------- + ! initialization conditions + ! ----------------------------------------------------------------------- + + logical :: tables_are_initialized = .false. ! initialize satuation tables + + ! ----------------------------------------------------------------------- + ! physics constants + ! ----------------------------------------------------------------------- + + real, parameter :: grav = 9.80665 ! acceleration due to gravity (m/s^2), ref: IFS + + real, parameter :: rgrav = 1.0 / grav ! inversion of gravity acceleration (s^2/m) + + real, parameter :: pi = 4.0 * atan (1.0) ! ratio of circle circumference to diameter + + real, parameter :: boltzmann = 1.38064852e-23 ! boltzmann constant (J/K) + real, parameter :: avogadro = 6.02214076e23 ! avogadro number (1/mol) + real, parameter :: runiver = avogadro * boltzmann ! 8.314459727525675, universal gas constant (J/K/mol) + real, parameter :: mmd = 2.89644e-2 ! dry air molar mass (kg/mol), ref: IFS + real, parameter :: mmv = 1.80153e-2 ! water vapor molar mass (kg/mol), ref: IFS + + real, parameter :: rdgas = 287.05 ! gas constant for dry air (J/kg/K): ref: GFDL, GFS + real, parameter :: rvgas = 461.50 ! gas constant for water vapor (J/kg/K): ref: GFDL, GFS + !real, parameter :: rdgas = runiver / mmd ! 287.0578961596192, gas constant for dry air (J/kg/K) + !real, parameter :: rvgas = runiver / mmv ! 461.52213549181386, gas constant for water vapor (J/kg/K) + + real, parameter :: zvir = rvgas / rdgas - 1. ! 0.6077667316114637 + real, parameter :: eps = rdgas / rvgas ! 0.6219934994582882 + real, parameter :: epsm1 = rdgas / rvgas - 1. ! -0.3780065005417118 + + real, parameter :: tice = 273.15 ! freezing temperature (K): ref: GFDL, GFS + !real, parameter :: tice = 273.16 ! freezing temperature (K), ref: IFS + + real, parameter :: cp_air = 1004.6 ! heat capacity of dry air at constant pressure (J/kg/K): ref: GFDL, GFS + real, parameter :: cv_air = cp_air - rdgas ! 717.55, heat capacity of dry air at constant volume (J/kg/K): ref: GFDL, GFS + !real, parameter :: cp_air = 7. / 2. * rdgas ! 1004.7026365586671, heat capacity of dry air at constant pressure (J/kg/K) + !real, parameter :: cv_air = 5. / 2. * rdgas ! 717.644740399048, heat capacity of dry air at constant volume (J/kg/K) + real, parameter :: cp_vap = 4.0 * rvgas ! 1846.0885419672554, heat capacity of water vapor at constnat pressure (J/kg/K) + real, parameter :: cv_vap = 3.0 * rvgas ! 1384.5664064754415, heat capacity of water vapor at constant volume (J/kg/K) + + real, parameter :: c_ice = 2.106e3 ! heat capacity of ice at 0 deg C (J/kg/K), ref: IFS + real, parameter :: c_liq = 4.218e3 ! heat capacity of water at 0 deg C (J/kg/K), ref: IFS + + real, parameter :: dc_vap = cp_vap - c_liq ! - 2371.9114580327446, isobaric heating / cooling (J/kg/K) + real, parameter :: dc_ice = c_liq - c_ice ! 2112.0, isobaric heating / colling (J/kg/K) + real, parameter :: d2_ice = cp_vap - c_ice ! - 259.9114580327446, isobaric heating / cooling (J/kg/K) + + real, parameter :: hlv = 2.5e6 ! latent heat of evaporation at 0 deg C (J/kg): ref: GFDL, GFS + real, parameter :: hlf = 3.3358e5 ! latent heat of fusion at 0 deg C (J/kg): ref: GFDL, GFS + !real, parameter :: hlv = 2.5008e6 ! latent heat of evaporation at 0 deg C (J/kg), ref: IFS + !real, parameter :: hlf = 3.345e5 ! latent heat of fusion at 0 deg C (J/kg), ref: IFS + + real, parameter :: visd = 1.717e-5 ! dynamics viscosity of air at 0 deg C and 1000 hPa (Mason, 1971) (kg/m/s) + real, parameter :: visk = 1.35e-5 ! kinematic viscosity of air at 0 deg C and 1000 hPa (Mason, 1971) (m^2/s) + real, parameter :: vdifu = 2.25e-5 ! diffusivity of water vapor in air at 0 deg C and 1000 hPa (Mason, 1971) (m^2/s) + real, parameter :: tcond = 2.40e-2 ! thermal conductivity of air at 0 deg C and 1000 hPa (Mason, 1971) (J/m/s/K) + + real, parameter :: rho0 = 1.0 ! reference air density (kg/m^3), ref: IFS + real, parameter :: cdg = 3.15121 ! drag coefficient of graupel (Locatelli and Hobbs, 1974) + real, parameter :: cdh = 0.5 ! drag coefficient of hail (Heymsfield and Wright, 2014) + + real (kind = r8), parameter :: lv0 = hlv - dc_vap * tice ! 3148711.3338762247, evaporation latent heat coeff. at 0 deg K (J/kg) + real (kind = r8), parameter :: li0 = hlf - dc_ice * tice ! - 242413.92000000004, fussion latent heat coeff. at 0 deg K (J/kg) + real (kind = r8), parameter :: li2 = lv0 + li0 ! 2906297.413876225, sublimation latent heat coeff. at 0 deg K (J/kg) + + real (kind = r8), parameter :: e00 = 611.21 ! saturation vapor pressure at 0 deg C (Pa), ref: IFS + + ! ----------------------------------------------------------------------- + ! predefined parameters + ! ----------------------------------------------------------------------- + + integer, parameter :: length = 2621 ! length of the saturation table + + real, parameter :: qcmin = 1.0e-15 ! min value for cloud condensates (kg/kg) + real, parameter :: qfmin = 1.0e-8 ! min value for sedimentation (kg/kg) + + real, parameter :: dz_min = 1.0e-2 ! used for correcting flipped height (m) + + real, parameter :: rhow = 1.0e3 ! density of cloud water (kg/m^3) + real, parameter :: rhoi = 9.17e2 ! density of cloud ice (kg/m^3) + real, parameter :: rhor = 1.0e3 ! density of rain (Lin et al. 1983) (kg/m^3) + real, parameter :: rhos = 1.0e2 ! density of snow (Lin et al. 1983) (kg/m^3) + real, parameter :: rhog = 4.0e2 ! density of graupel (Rutledge and Hobbs 1984) (kg/m^3) + real, parameter :: rhoh = 9.17e2 ! density of hail (Lin et al. 1983) (kg/m^3) + + real, parameter :: dt_fr = 8.0 ! t_wfr - dt_fr: minimum temperature water can exist (Moore and Molinero 2011) + + real (kind = r8), parameter :: one_r8 = 1.0 ! constant 1 + + ! ----------------------------------------------------------------------- + ! namelist parameters + ! ----------------------------------------------------------------------- + + integer :: ntimes = 1 ! cloud microphysics sub cycles + + integer :: nconds = 1 ! condensation sub cycles + + integer :: cfflag = 1 ! cloud fraction scheme + ! 1: GFDL cloud scheme + ! 2: Xu and Randall (1996) + ! 3: Park et al. (2016) + ! 4: Gultepe and Isaac (2007) + + integer :: icloud_f = 0 ! GFDL cloud scheme + ! 0: subgrid variability based scheme + ! 1: same as 0, but for old fvgfs implementation + ! 2: binary cloud scheme + ! 3: extension of 0 + + integer :: irain_f = 0 ! cloud water to rain auto conversion scheme + ! 0: subgrid variability based scheme + ! 1: no subgrid varaibility + + integer :: inflag = 1 ! ice nucleation scheme + ! 1: Hong et al. (2004) + ! 2: Meyers et al. (1992) + ! 3: Meyers et al. (1992) + ! 4: Cooper (1986) + ! 5: Fletcher (1962) + + integer :: igflag = 3 ! ice generation scheme + ! 1: WSM6 + ! 2: WSM6 with 0 at 0 C + ! 3: WSM6 with 0 at 0 C and fixed value at - 10 C + ! 4: combination of 1 and 3 + + integer :: ifflag = 1 ! ice fall scheme + ! 1: Deng and Mace (2008) + ! 2: Heymsfield and Donner (1990) + + integer :: rewflag = 1 ! cloud water effective radius scheme + ! 1: Martin et al. (1994) + ! 2: Martin et al. (1994), GFDL revision + ! 3: Kiehl et al. (1994) + ! 4: effective radius + + integer :: reiflag = 5 ! cloud ice effective radius scheme + ! 1: Heymsfield and Mcfarquhar (1996) + ! 2: Donner et al. (1997) + ! 3: Fu (2007) + ! 4: Kristjansson et al. (2000) + ! 5: Wyser (1998) + ! 6: Sun and Rikus (1999), Sun (2001) + ! 7: effective radius + + integer :: rerflag = 1 ! rain effective radius scheme + ! 1: effective radius + + integer :: resflag = 1 ! snow effective radius scheme + ! 1: effective radius + + integer :: regflag = 1 ! graupel effective radius scheme + ! 1: effective radius + + integer :: radr_flag = 1 ! radar reflectivity for rain + ! 1: Mark Stoelinga (2005) + ! 2: Smith et al. (1975), Tong and Xue (2005) + ! 3: Marshall-Palmer formula (https://en.wikipedia.org/wiki/DBZ_(meteorology)) + + integer :: rads_flag = 1 ! radar reflectivity for snow + ! 1: Mark Stoelinga (2005) + ! 2: Smith et al. (1975), Tong and Xue (2005) + ! 3: Marshall-Palmer formula (https://en.wikipedia.org/wiki/DBZ_(meteorology)) + + integer :: radg_flag = 1 ! radar reflectivity for graupel + ! 1: Mark Stoelinga (2005) + ! 2: Smith et al. (1975), Tong and Xue (2005) + ! 3: Marshall-Palmer formula (https://en.wikipedia.org/wiki/DBZ_(meteorology)) + + integer :: sedflag = 1 ! sedimentation scheme + ! 1: implicit scheme + ! 2: explicit scheme + ! 3: lagrangian scheme + ! 4: combined implicit and lagrangian scheme + + integer :: vdiffflag = 1 ! wind difference scheme in accretion + ! 1: Wisner et al. (1972) + ! 2: Mizuno (1990) + ! 3: Murakami (1990) + + logical :: do_sedi_uv = .true. ! transport of horizontal momentum in sedimentation + logical :: do_sedi_w = .true. ! transport of vertical momentum in sedimentation + logical :: do_sedi_heat = .true. ! transport of heat in sedimentation + logical :: do_sedi_melt = .true. ! melt cloud ice, snow, and graupel during sedimentation + + logical :: do_qa = .true. ! do inline cloud fraction + logical :: rad_snow = .true. ! include snow in cloud fraciton calculation + logical :: rad_graupel = .true. ! include graupel in cloud fraction calculation + logical :: rad_rain = .true. ! include rain in cloud fraction calculation + logical :: do_cld_adj = .false. ! do cloud fraction adjustment + + logical :: z_slope_liq = .true. ! use linear mono slope for autocconversions + logical :: z_slope_ice = .true. ! use linear mono slope for autocconversions + + logical :: use_rhc_cevap = .false. ! cap of rh for cloud water evaporation + logical :: use_rhc_revap = .false. ! cap of rh for rain evaporation + + logical :: const_vw = .false. ! if .ture., the constants are specified by v * _fac + logical :: const_vi = .false. ! if .ture., the constants are specified by v * _fac + logical :: const_vs = .false. ! if .ture., the constants are specified by v * _fac + logical :: const_vg = .false. ! if .ture., the constants are specified by v * _fac + logical :: const_vr = .false. ! if .ture., the constants are specified by v * _fac + + logical :: liq_ice_combine = .false. ! combine all liquid water, combine all solid water + logical :: snow_grauple_combine = .true. ! combine snow and graupel + + logical :: prog_ccn = .false. ! do prognostic ccn (Yi Ming's method) + + logical :: fix_negative = .true. ! fix negative water species + + logical :: do_evap_timescale = .true. ! whether to apply a timescale to evaporation + logical :: do_cond_timescale = .false. ! whether to apply a timescale to condensation + + logical :: do_hail = .false. ! use hail parameters instead of graupel + + logical :: consv_checker = .false. ! turn on energy and water conservation checker + + logical :: do_warm_rain_mp = .false. ! do warm rain cloud microphysics only + + logical :: do_wbf = .false. ! do Wegener Bergeron Findeisen process + + logical :: do_psd_water_fall = .false. ! calculate cloud water terminal velocity based on PSD + logical :: do_psd_ice_fall = .false. ! calculate cloud ice terminal velocity based on PSD + + logical :: do_psd_water_num = .false. ! calculate cloud water number concentration based on PSD + logical :: do_psd_ice_num = .false. ! calculate cloud ice number concentration based on PSD + + logical :: do_new_acc_water = .false. ! perform the new accretion for cloud water + logical :: do_new_acc_ice = .false. ! perform the new accretion for cloud ice + + logical :: cp_heating = .false. ! update temperature based on constant pressure + + logical :: delay_cond_evap = .false. ! do condensation evaporation only at the last time step + + logical :: do_subgrid_proc = .true. ! do temperature sentive high vertical resolution processes + + logical :: fast_fr_mlt = .true. ! do freezing and melting in fast microphysics + logical :: fast_dep_sub = .true. ! do deposition and sublimation in fast microphysics + + real :: mp_time = 150.0 ! maximum microphysics time step (s) + + real :: n0w_sig = 1.1 ! intercept parameter (significand) of cloud water (Lin et al. 1983) (1/m^4) (Martin et al. 1994) + !real :: n0w_sig = 1.4 ! intercept parameter (significand) of cloud water (Lin et al. 1983) (1/m^4) (Martin et al. 1994) + real :: n0i_sig = 1.3 ! intercept parameter (significand) of cloud ice (Lin et al. 1983) (1/m^4) (McFarquhar et al. 2015) + !real :: n0i_sig = 9.4 ! intercept parameter (significand) of cloud ice (Lin et al. 1983) (1/m^4) (McFarquhar et al. 2015) + real :: n0r_sig = 8.0 ! intercept parameter (significand) of rain (Lin et al. 1983) (1/m^4) (Marshall and Palmer 1948) + real :: n0s_sig = 3.0 ! intercept parameter (significand) of snow (Lin et al. 1983) (1/m^4) (Gunn and Marshall 1958) + real :: n0g_sig = 4.0 ! intercept parameter (significand) of graupel (Rutledge and Hobbs 1984) (1/m^4) (Houze et al. 1979) + real :: n0h_sig = 4.0 ! intercept parameter (significand) of hail (Lin et al. 1983) (1/m^4) (Federer and Waldvogel 1975) + + real :: n0w_exp = 41 ! intercept parameter (exponent) of cloud water (Lin et al. 1983) (1/m^4) (Martin et al. 1994) + !real :: n0w_exp = 91 ! intercept parameter (exponent) of cloud water (Lin et al. 1983) (1/m^4) (Martin et al. 1994) + real :: n0i_exp = 18 ! intercept parameter (exponent) of cloud ice (Lin et al. 1983) (1/m^4) (McFarquhar et al. 2015) + !real :: n0i_exp = 17 ! intercept parameter (exponent) of cloud ice (Lin et al. 1983) (1/m^4) (McFarquhar et al. 2015) + real :: n0r_exp = 6 ! intercept parameter (exponent) of rain (Lin et al. 1983) (1/m^4) (Marshall and Palmer 1948) + real :: n0s_exp = 6 ! intercept parameter (exponent) of snow (Lin et al. 1983) (1/m^4) (Gunn and Marshall 1958) + real :: n0g_exp = 6 ! intercept parameter (exponent) of graupel (Rutledge and Hobbs 1984) (1/m^4) (Houze et al. 1979) + real :: n0h_exp = 4 ! intercept parameter (exponent) of hail (Lin et al. 1983) (1/m^4) (Federer and Waldvogel 1975) + + real :: muw = 6.0 ! shape parameter of cloud water in Gamma distribution (Martin et al. 1994) + !real :: muw = 16.0 ! shape parameter of cloud water in Gamma distribution (Martin et al. 1994) + real :: mui = 3.35 ! shape parameter of cloud ice in Gamma distribution (McFarquhar et al. 2015) + !real :: mui = 3.54 ! shape parameter of cloud ice in Gamma distribution (McFarquhar et al. 2015) + real :: mur = 1.0 ! shape parameter of rain in Gamma distribution (Marshall and Palmer 1948) + real :: mus = 1.0 ! shape parameter of snow in Gamma distribution (Gunn and Marshall 1958) + real :: mug = 1.0 ! shape parameter of graupel in Gamma distribution (Houze et al. 1979) + real :: muh = 1.0 ! shape parameter of hail in Gamma distribution (Federer and Waldvogel 1975) + + real :: alinw = 3.e7 ! "a" in Lin et al. (1983) for cloud water (Ikawa and Saito 1990) + real :: alini = 7.e2 ! "a" in Lin et al. (1983) for cloud ice (Ikawa and Saita 1990) + real :: alinr = 842.0 ! "a" in Lin et al. (1983) for rain (Liu and Orville 1969) + real :: alins = 4.8 ! "a" in Lin et al. (1983) for snow (straka 2009) + real :: aling = 1.0 ! "a" in Lin et al. (1983), similar to a, but for graupel (Pruppacher and Klett 2010) + real :: alinh = 1.0 ! "a" in Lin et al. (1983), similar to a, but for hail (Pruppacher and Klett 2010) + + real :: blinw = 2.0 ! "b" in Lin et al. (1983) for cloud water (Ikawa and Saito 1990) + real :: blini = 1.0 ! "b" in Lin et al. (1983) for cloud ice (Ikawa and Saita 1990) + real :: blinr = 0.8 ! "b" in Lin et al. (1983) for rain (Liu and Orville 1969) + real :: blins = 0.25 ! "b" in Lin et al. (1983) for snow (straka 2009) + real :: bling = 0.5 ! "b" in Lin et al. (1983), similar to b, but for graupel (Pruppacher and Klett 2010) + real :: blinh = 0.5 ! "b" in Lin et al. (1983), similar to b, but for hail (Pruppacher and Klett 2010) + + real :: tice_mlt = 273.16 ! can set ice melting temperature to 268 based on observation (Kay et al. 2016) (K) + + real :: t_min = 178.0 ! minimum temperature to freeze - dry all water vapor (K) + real :: t_sub = 184.0 ! minimum temperature for sublimation of cloud ice (K) + + real :: rh_inc = 0.25 ! rh increment for complete evaporation of cloud water and cloud ice + real :: rh_inr = 0.25 ! rh increment for minimum evaporation of rain + real :: rh_ins = 0.25 ! rh increment for sublimation of snow + + real :: tau_r2g = 900.0 ! rain freezing to graupel time scale (s) + real :: tau_i2s = 1000.0 ! cloud ice to snow autoconversion time scale (s) + real :: tau_l2r = 900.0 ! cloud water to rain autoconversion time scale (s) + real :: tau_v2l = 150.0 ! water vapor to cloud water condensation time scale (s) + real :: tau_l2v = 300.0 ! cloud water to water vapor evaporation time scale (s) + real :: tau_revp = 0.0 ! rain evaporation time scale (s) + !rsun real :: tau_imlt = 1200.0 ! cloud ice melting time scale (s) ! ori in v3 + real :: tau_imlt = 600.0 ! cloud ice melting time scale (s) ! 600.0 is the origin in v1 + real :: tau_smlt = 900.0 ! snow melting time scale (s) + real :: tau_gmlt = 600.0 ! graupel melting time scale (s) + real :: tau_wbf = 300.0 ! graupel melting time scale (s) + + real :: dw_land = 0.20 ! base value for subgrid deviation / variability over land + real :: dw_ocean = 0.10 ! base value for subgrid deviation / variability over ocean + + real :: ccn_o = 90.0 ! ccn over ocean (1/cm^3) + real :: ccn_l = 270.0 ! ccn over land (1/cm^3) + !real :: ccn_o = 66.0 ! ccn over ocean (1/cm^3) + !real :: ccn_l = 159.0 ! ccn over land (1/cm^3) + + !real :: rthresh = 10.0e-6 ! critical cloud drop radius (micron) for autoconversion + real :: rthresh = 20.0e-6 ! critical cloud drop radius (micron) for autoconversion + + real :: cld_min = 0.05 ! minimum cloud fraction + + real :: qi_lim = 1.0 ! cloud ice limiter (0: no, 1: full, >1: extra) to prevent large ice build up + + real :: ql_mlt = 2.0e-3 ! maximum cloud water allowed from melted cloud ice (kg/kg) + real :: qs_mlt = 1.0e-6 ! maximum cloud water allowed from melted snow (kg/kg) + + real :: ql_gen = 1.0e-3 ! maximum cloud water generation during remapping step (kg/kg) + + real :: ql0_max = 2.0e-3 ! maximum cloud water value (autoconverted to rain) (kg/kg) + real :: qi0_max = 1.0e-4 ! maximum cloud ice value (autoconverted to snow) (kg/m^3) + + real :: qi0_crt = 1.0e-4 ! cloud ice to snow autoconversion threshold (kg/m^3) + real :: qs0_crt = 1.0e-3 ! snow to graupel autoconversion threshold (0.6e-3 in Purdue Lin scheme) (kg/m^3) + + real :: c_paut = 0.55 ! cloud water to rain autoconversion efficiency + real :: c_psacw = 1.0 ! cloud water to snow accretion efficiency + real :: c_psaci = 0.05 ! cloud ice to snow accretion efficiency (was 0.1 in ZETAC) + real :: c_pracw = 0.8 ! cloud water to rain accretion efficiency + real :: c_praci = 1.0 ! cloud ice to rain accretion efficiency + real :: c_pgacw = 1.0 ! cloud water to graupel accretion efficiency + real :: c_pgaci = 0.05 ! cloud ice to graupel accretion efficiency (was 0.1 in ZETAC) + real :: c_pracs = 1.0 ! snow to rain accretion efficiency + real :: c_psacr = 1.0 ! rain to snow accretion efficiency + real :: c_pgacr = 1.0 ! rain to graupel accretion efficiency + real :: c_pgacs = 0.01 ! snow to graupel accretion efficiency (was 0.1 in ZETAC) + + real :: is_fac = 0.2 ! cloud ice sublimation temperature factor + real :: ss_fac = 0.2 ! snow sublimation temperature factor + real :: gs_fac = 0.2 ! graupel sublimation temperature factor + + real :: rh_fac_evap = 10.0 ! cloud water evaporation relative humidity factor + real :: rh_fac_cond = 10.0 ! cloud water condensation relative humidity factor + + real :: sed_fac = 1.0 ! coefficient for sedimentation fall, scale from 1.0 (implicit) to 0.0 (lagrangian) + + real :: vw_fac = 1.0 + real :: vi_fac = 1.0 ! IFS: if const_vi: 1 / 3 + real :: vs_fac = 1.0 ! IFS: if const_vs: 1. + real :: vg_fac = 1.0 ! IFS: if const_vg: 2. + real :: vr_fac = 1.0 ! IFS: if const_vr: 4. + + real :: vw_max = 0.01 ! maximum fall speed for cloud water (m/s) + real :: vi_max = 0.5 ! maximum fall speed for cloud ice (m/s) + real :: vs_max = 5.0 ! maximum fall speed for snow (m/s) + real :: vg_max = 8.0 ! maximum fall speed for graupel (m/s) + real :: vr_max = 12.0 ! maximum fall speed for rain (m/s) + + real :: xr_a = 0.25 ! p value in Xu and Randall (1996) + real :: xr_b = 100.0 ! alpha_0 value in Xu and Randall (1996) + real :: xr_c = 0.49 ! gamma value in Xu and Randall (1996) + + real :: te_err = 1.e-5 ! 64bit: 1.e-14, 32bit: 1.e-7; turn off to save computer time + real :: tw_err = 1.e-8 ! 64bit: 1.e-14, 32bit: 1.e-7; turn off to save computer time + + real :: rh_thres = 0.75 ! minimum relative humidity for cloud fraction + real :: rhc_cevap = 0.85 ! maximum relative humidity for cloud water evaporation + real :: rhc_revap = 0.85 ! maximum relative humidity for rain evaporation + + real :: f_dq_p = 1.0 ! cloud fraction adjustment for supersaturation + real :: f_dq_m = 1.0 ! cloud fraction adjustment for undersaturation + + real :: fi2s_fac = 1.0 ! maximum sink of cloud ice to form snow: 0-1 + real :: fi2g_fac = 1.0 ! maximum sink of cloud ice to form graupel: 0-1 + real :: fs2g_fac = 1.0 ! maximum sink of snow to form graupel: 0-1 + + real :: beta = 1.22 ! defined in Heymsfield and Mcfarquhar (1996) + + real :: rewmin = 5.0, rewmax = 15.0 ! minimum and maximum effective radius for cloud water (micron) + real :: reimin = 10.0, reimax = 150.0 ! minimum and maximum effective radius for cloud ice (micron) + real :: rermin = 15.0, rermax = 10000.0 ! minimum and maximum effective radius for rain (micron) + real :: resmin = 150.0, resmax = 10000.0 ! minimum and maximum effective radius for snow (micron) + real :: regmin = 150.0, regmax = 10000.0 ! minimum and maximum effective radius for graupel + !real :: rewmax = 15.0, rermin = 15.0 ! Kokhanovsky (2004) + + real :: rewfac = 1.0 ! this is a tuning parameter to compromise the inconsistency between + ! GFDL MP's PSD and cloud water radiative property's PSD assumption. + ! after the cloud water radiative property's PSD is rebuilt, + ! this parameter should be 1.0. + real :: reifac = 1.0 ! this is a tuning parameter to compromise the inconsistency between + ! GFDL MP's PSD and cloud ice radiative property's PSD assumption. + ! after the cloud ice radiative property's PSD is rebuilt, + ! this parameter should be 1.0. + + ! ----------------------------------------------------------------------- + ! local shared variables + ! ----------------------------------------------------------------------- + + real :: acco (3, 10), acc (20) + real :: cracs, csacr, cgacr, cgacs, csacw, craci, csaci, cgacw, cgaci, cracw + real :: cssub (5), cgsub (5), crevp (5), cgfr (2), csmlt (4), cgmlt (4) + + real :: t_wfr, fac_rc, c_air, c_vap, d0_vap + + real (kind = r8) :: lv00, li00, li20, cpaut + real (kind = r8) :: d1_vap, d1_ice, c1_vap, c1_liq, c1_ice + real (kind = r8) :: normw, normr, normi, norms, normg, normh + real (kind = r8) :: expow, expor, expoi, expos, expog, expoh + real (kind = r8) :: pcaw, pcar, pcai, pcas, pcag, pcah + real (kind = r8) :: pcbw, pcbr, pcbi, pcbs, pcbg, pcbh + real (kind = r8) :: edaw, edar, edai, edas, edag, edah + real (kind = r8) :: edbw, edbr, edbi, edbs, edbg, edbh + real (kind = r8) :: oeaw, oear, oeai, oeas, oeag, oeah + real (kind = r8) :: oebw, oebr, oebi, oebs, oebg, oebh + real (kind = r8) :: rraw, rrar, rrai, rras, rrag, rrah + real (kind = r8) :: rrbw, rrbr, rrbi, rrbs, rrbg, rrbh + real (kind = r8) :: tvaw, tvar, tvai, tvas, tvag, tvah + real (kind = r8) :: tvbw, tvbr, tvbi, tvbs, tvbg, tvbh + + real, allocatable :: table0 (:), table1 (:), table2 (:), table3 (:), table4 (:) + real, allocatable :: des0 (:), des1 (:), des2 (:), des3 (:), des4 (:) + + ! ----------------------------------------------------------------------- + ! namelist + ! ----------------------------------------------------------------------- + + namelist / gfdl_mp_nml / & + t_min, t_sub, tau_r2g, tau_smlt, tau_gmlt, dw_land, dw_ocean, vw_fac, vi_fac, & + vr_fac, vs_fac, vg_fac, ql_mlt, do_qa, fix_negative, vw_max, vi_max, vs_max, & + vg_max, vr_max, qs_mlt, qs0_crt, ql0_max, qi0_max, qi0_crt, ifflag, & + rh_inc, rh_ins, rh_inr, const_vw, const_vi, const_vs, const_vg, const_vr, rthresh, & + ccn_l, ccn_o, igflag, c_paut, tau_imlt, tau_v2l, tau_l2v, tau_i2s, & + tau_l2r, qi_lim, ql_gen, do_hail, inflag, c_psacw, c_psaci, c_pracs, & + c_psacr, c_pgacr, c_pgacs, c_pgacw, c_pgaci, z_slope_liq, z_slope_ice, & + prog_ccn, c_pracw, c_praci, rad_snow, rad_graupel, rad_rain, cld_min, & + sedflag, sed_fac, do_sedi_uv, do_sedi_w, do_sedi_heat, icloud_f, & + irain_f, xr_a, xr_b, xr_c, ntimes, tau_revp, tice_mlt, do_cond_timescale, & + mp_time, consv_checker, te_err, tw_err, use_rhc_cevap, use_rhc_revap, tau_wbf, & + do_warm_rain_mp, rh_thres, f_dq_p, f_dq_m, do_cld_adj, rhc_cevap, & + rhc_revap, beta, liq_ice_combine, rewflag, reiflag, rerflag, resflag, & + regflag, rewmin, rewmax, reimin, reimax, rermin, rermax, resmin, & + resmax, regmin, regmax, fs2g_fac, fi2s_fac, fi2g_fac, do_sedi_melt, & + radr_flag, rads_flag, radg_flag, do_wbf, do_psd_water_fall, do_psd_ice_fall, & + n0w_sig, n0i_sig, n0r_sig, n0s_sig, n0g_sig, n0h_sig, n0w_exp, n0i_exp, & + n0r_exp, n0s_exp, n0g_exp, n0h_exp, muw, mui, mur, mus, mug, muh, & + alinw, alini, alinr, alins, aling, alinh, blinw, blini, blinr, blins, bling, blinh, & + do_new_acc_water, do_new_acc_ice, is_fac, ss_fac, gs_fac, rh_fac_evap, rh_fac_cond, & + snow_grauple_combine, do_psd_water_num, do_psd_ice_num, vdiffflag, rewfac, reifac, & + cp_heating, nconds, do_evap_timescale, delay_cond_evap, do_subgrid_proc, & + fast_fr_mlt, fast_dep_sub + + ! fast physics + public & + ql_gen, qi0_max, ql_mlt, ql0_max, qi_lim, qs_mlt, icloud_f, t_sub, & + cld_min, tau_r2g, tau_smlt, tau_i2s, tau_v2l, tau_l2v, tau_imlt, & + tau_l2r, rad_rain, rad_snow, rad_graupel, dw_ocean, dw_land + + +contains + +! ======================================================================= +! GFDL cloud microphysics initialization +! ======================================================================= + +subroutine module_gfdl_cld_mp_init (me, master, nlunit, input_nml_file, logunit, & + fn_nml, hydrostatic, errmsg, errflg) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: me + integer, intent (in) :: master + integer, intent (in) :: nlunit + integer, intent (in) :: logunit + + character (len = 64), intent (in) :: fn_nml + character (len = *), intent (in) :: input_nml_file (:) + logical, intent (in) :: hydrostatic + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: ios + logical :: exists + + ! Initialize CCPP error-handling + errflg = 0 + errmsg = '' + +#ifdef INTERNAL_FILE_NML + read (input_nml_file, nml = gfdl_mp_nml) +#else + inquire (file = trim (fn_nml), exist = exists) + if (.not. exists) then + write (6, *) 'gfdl - mp :: namelist file: ', trim (fn_nml), ' does not exist' + errflg = 1 + errmsg = 'ERROR(module_gfdl_cld_mp_init): namelist file '//trim (fn_nml)//' does not exist' + return + else + open (unit = nlunit, file = fn_nml, action = 'read' , status = 'old', iostat = ios) + endif + rewind (nlunit) + read (nlunit, nml = gfdl_mp_nml) + close (nlunit) +#endif + + ! ----------------------------------------------------------------------- + ! write version number and namelist to log file + ! ----------------------------------------------------------------------- + + write (logunit, *) " ================================================================== " + write (logunit, *) "gfdl_mp_mod" + write (logunit, nml = gfdl_mp_nml) + write (*, nml = gfdl_mp_nml) + + ! ----------------------------------------------------------------------- + ! initialize microphysics variables + ! ----------------------------------------------------------------------- + + if (.not. tables_are_initialized) call qs_init + + call setup_mp + + ! ----------------------------------------------------------------------- + ! define various heat capacities and latent heat coefficients at 0 deg K + ! ----------------------------------------------------------------------- + + call setup_mhc_lhc (hydrostatic) + +end subroutine module_gfdl_cld_mp_init + +! ======================================================================= +! GFDL cloud microphysics driver +! ======================================================================= + +subroutine module_gfdl_cld_mp_driver (qv, ql, qr, qi, qs, qg, qa, qnl, qni, pt, wa, & + ua, va, delz, delp, gsize, dtm, hs, water, rain, ice, snow, graupel, & + hydrostatic, is, ie, ks, ke, q_con, cappa, consv_te, adj_vmr, te, dte, & + prefluxw, prefluxr, prefluxi, prefluxs, prefluxg, last_step, do_inline_mp) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: is, ie, ks, ke + + logical, intent (in) :: hydrostatic, last_step, consv_te, do_inline_mp + + real, intent (in) :: dtm + + real, intent (in), dimension (is:ie) :: hs, gsize + + real, intent (in), dimension (is:ie, ks:ke) :: qnl, qni + + real, intent (inout), dimension (is:ie, ks:ke) :: delp, delz, pt, ua, va, wa, te + real, intent (inout), dimension (is:ie, ks:ke) :: qv, ql, qr, qi, qs, qg, qa + real, intent (inout), dimension (is:ie, ks:ke) :: prefluxw, prefluxr, prefluxi, prefluxs, prefluxg + + real, intent (inout), dimension (is:, ks:) :: q_con, cappa + + real, intent (inout), dimension (is:ie) :: water, rain, ice, snow, graupel + + real, intent (out), dimension (is:ie, ks:ke) :: adj_vmr + + real (kind = r8), intent (out), dimension (is:ie) :: dte + + ! ----------------------------------------------------------------------- + ! major cloud microphysics driver + ! ----------------------------------------------------------------------- + + call mpdrv (hydrostatic, ua, va, wa, delp, pt, qv, ql, qr, qi, qs, qg, qa, & + qnl, qni, delz, is, ie, ks, ke, dtm, water, rain, ice, snow, graupel, & + gsize, hs, q_con, cappa, consv_te, adj_vmr, te, dte, prefluxw, prefluxr, & + prefluxi, prefluxs, prefluxg, last_step, do_inline_mp, .false., .true.) + +end subroutine module_gfdl_cld_mp_driver + +! ======================================================================= +! GFDL cloud microphysics end +! ======================================================================= + +subroutine module_gfdl_cld_mp_end + + implicit none + + ! ----------------------------------------------------------------------- + ! free up memory + ! ----------------------------------------------------------------------- + + deallocate (table0) + deallocate (table1) + deallocate (table2) + deallocate (table3) + deallocate (table4) + deallocate (des0) + deallocate (des1) + deallocate (des2) + deallocate (des3) + deallocate (des4) + + tables_are_initialized = .false. + +end subroutine module_gfdl_cld_mp_end + +! ======================================================================= +! setup cloud microphysics parameters +! ======================================================================= + +subroutine setup_mp + + implicit none + + integer :: i, k + + real :: gcon, hcon, scm3, pisq, act (20), ace (20), occ (3), aone + + ! ----------------------------------------------------------------------- + ! complete freezing temperature + ! ----------------------------------------------------------------------- + + if (do_warm_rain_mp) then + t_wfr = t_min + else + t_wfr = tice - 40.0 + endif + + ! ----------------------------------------------------------------------- + ! cloud water autoconversion, Hong et al. (2004) + ! ----------------------------------------------------------------------- + + fac_rc = (4. / 3.) * pi * rhow * rthresh ** 3 + + aone = 2. / 9. * (3. / 4.) ** (4. / 3.) / pi ** (1. / 3.) + cpaut = c_paut * aone * grav / visd + + ! ----------------------------------------------------------------------- + ! terminal velocities parameters, Lin et al. (1983) + ! ----------------------------------------------------------------------- + + gcon = (4. * grav * rhog / (3. * cdg * rho0)) ** 0.5 + hcon = (4. * grav * rhoh / (3. * cdh * rho0)) ** 0.5 + + ! ----------------------------------------------------------------------- + ! part of the slope parameters + ! ----------------------------------------------------------------------- + + normw = pi * rhow * n0w_sig * gamma (muw + 3) + normi = pi * rhoi * n0i_sig * gamma (mui + 3) + normr = pi * rhor * n0r_sig * gamma (mur + 3) + norms = pi * rhos * n0s_sig * gamma (mus + 3) + normg = pi * rhog * n0g_sig * gamma (mug + 3) + normh = pi * rhoh * n0h_sig * gamma (muh + 3) + + expow = exp (n0w_exp / (muw + 3) * log (10.)) + expoi = exp (n0i_exp / (mui + 3) * log (10.)) + expor = exp (n0r_exp / (mur + 3) * log (10.)) + expos = exp (n0s_exp / (mus + 3) * log (10.)) + expog = exp (n0g_exp / (mug + 3) * log (10.)) + expoh = exp (n0h_exp / (muh + 3) * log (10.)) + + ! ----------------------------------------------------------------------- + ! parameters for particle concentration (pc), effective diameter (ed), + ! optical extinction (oe), radar reflectivity factor (rr), and + ! mass-weighted terminal velocity (tv) + ! ----------------------------------------------------------------------- + + pcaw = exp (3 / (muw + 3) * log (n0w_sig)) * gamma (muw) * exp (3 * n0w_exp / (muw + 3) * log (10.)) + pcai = exp (3 / (mui + 3) * log (n0i_sig)) * gamma (mui) * exp (3 * n0i_exp / (mui + 3) * log (10.)) + pcar = exp (3 / (mur + 3) * log (n0r_sig)) * gamma (mur) * exp (3 * n0r_exp / (mur + 3) * log (10.)) + pcas = exp (3 / (mus + 3) * log (n0s_sig)) * gamma (mus) * exp (3 * n0s_exp / (mus + 3) * log (10.)) + pcag = exp (3 / (mug + 3) * log (n0g_sig)) * gamma (mug) * exp (3 * n0g_exp / (mug + 3) * log (10.)) + pcah = exp (3 / (muh + 3) * log (n0h_sig)) * gamma (muh) * exp (3 * n0h_exp / (muh + 3) * log (10.)) + + pcbw = exp (muw / (muw + 3) * log (pi * rhow * gamma (muw + 3))) + pcbi = exp (mui / (mui + 3) * log (pi * rhoi * gamma (mui + 3))) + pcbr = exp (mur / (mur + 3) * log (pi * rhor * gamma (mur + 3))) + pcbs = exp (mus / (mus + 3) * log (pi * rhos * gamma (mus + 3))) + pcbg = exp (mug / (mug + 3) * log (pi * rhog * gamma (mug + 3))) + pcbh = exp (muh / (muh + 3) * log (pi * rhoh * gamma (muh + 3))) + + edaw = exp (- 1. / (muw + 3) * log (n0w_sig)) * (muw + 2) * exp (- n0w_exp / (muw + 3) * log (10.)) + edai = exp (- 1. / (mui + 3) * log (n0i_sig)) * (mui + 2) * exp (- n0i_exp / (mui + 3) * log (10.)) + edar = exp (- 1. / (mur + 3) * log (n0r_sig)) * (mur + 2) * exp (- n0r_exp / (mur + 3) * log (10.)) + edas = exp (- 1. / (mus + 3) * log (n0s_sig)) * (mus + 2) * exp (- n0s_exp / (mus + 3) * log (10.)) + edag = exp (- 1. / (mug + 3) * log (n0g_sig)) * (mug + 2) * exp (- n0g_exp / (mug + 3) * log (10.)) + edah = exp (- 1. / (muh + 3) * log (n0h_sig)) * (muh + 2) * exp (- n0h_exp / (muh + 3) * log (10.)) + + edbw = exp (1. / (muw + 3) * log (pi * rhow * gamma (muw + 3))) + edbi = exp (1. / (mui + 3) * log (pi * rhoi * gamma (mui + 3))) + edbr = exp (1. / (mur + 3) * log (pi * rhor * gamma (mur + 3))) + edbs = exp (1. / (mus + 3) * log (pi * rhos * gamma (mus + 3))) + edbg = exp (1. / (mug + 3) * log (pi * rhog * gamma (mug + 3))) + edbh = exp (1. / (muh + 3) * log (pi * rhoh * gamma (muh + 3))) + + oeaw = exp (1. / (muw + 3) * log (n0w_sig)) * pi * gamma (muw + 2) * & + exp (n0w_exp / (muw + 3) * log (10.)) + oeai = exp (1. / (mui + 3) * log (n0i_sig)) * pi * gamma (mui + 2) * & + exp (n0i_exp / (mui + 3) * log (10.)) + oear = exp (1. / (mur + 3) * log (n0r_sig)) * pi * gamma (mur + 2) * & + exp (n0r_exp / (mur + 3) * log (10.)) + oeas = exp (1. / (mus + 3) * log (n0s_sig)) * pi * gamma (mus + 2) * & + exp (n0s_exp / (mus + 3) * log (10.)) + oeag = exp (1. / (mug + 3) * log (n0g_sig)) * pi * gamma (mug + 2) * & + exp (n0g_exp / (mug + 3) * log (10.)) + oeah = exp (1. / (muh + 3) * log (n0h_sig)) * pi * gamma (muh + 2) * & + exp (n0h_exp / (muh + 3) * log (10.)) + + oebw = 2 * exp ((muw + 2) / (muw + 3) * log (pi * rhow * gamma (muw + 3))) + oebi = 2 * exp ((mui + 2) / (mui + 3) * log (pi * rhoi * gamma (mui + 3))) + oebr = 2 * exp ((mur + 2) / (mur + 3) * log (pi * rhor * gamma (mur + 3))) + oebs = 2 * exp ((mus + 2) / (mus + 3) * log (pi * rhos * gamma (mus + 3))) + oebg = 2 * exp ((mug + 2) / (mug + 3) * log (pi * rhog * gamma (mug + 3))) + oebh = 2 * exp ((muh + 2) / (muh + 3) * log (pi * rhoh * gamma (muh + 3))) + + rraw = exp (- 3 / (muw + 3) * log (n0w_sig)) * gamma (muw + 6) * & + exp (- 3 * n0w_exp / (muw + 3) * log (10.)) + rrai = exp (- 3 / (mui + 3) * log (n0i_sig)) * gamma (mui + 6) * & + exp (- 3 * n0i_exp / (mui + 3) * log (10.)) + rrar = exp (- 3 / (mur + 3) * log (n0r_sig)) * gamma (mur + 6) * & + exp (- 3 * n0r_exp / (mur + 3) * log (10.)) + rras = exp (- 3 / (mus + 3) * log (n0s_sig)) * gamma (mus + 6) * & + exp (- 3 * n0s_exp / (mus + 3) * log (10.)) + rrag = exp (- 3 / (mug + 3) * log (n0g_sig)) * gamma (mug + 6) * & + exp (- 3 * n0g_exp / (mug + 3) * log (10.)) + rrah = exp (- 3 / (muh + 3) * log (n0h_sig)) * gamma (muh + 6) * & + exp (- 3 * n0h_exp / (muh + 3) * log (10.)) + + rrbw = exp ((muw + 6) / (muw + 3) * log (pi * rhow * gamma (muw + 3))) + rrbi = exp ((mui + 6) / (mui + 3) * log (pi * rhoi * gamma (mui + 3))) + rrbr = exp ((mur + 6) / (mur + 3) * log (pi * rhor * gamma (mur + 3))) + rrbs = exp ((mus + 6) / (mus + 3) * log (pi * rhos * gamma (mus + 3))) + rrbg = exp ((mug + 6) / (mug + 3) * log (pi * rhog * gamma (mug + 3))) + rrbh = exp ((muh + 6) / (muh + 3) * log (pi * rhoh * gamma (muh + 3))) + + tvaw = exp (- blinw / (muw + 3) * log (n0w_sig)) * alinw * gamma (muw + blinw + 3) * & + exp (- blinw * n0w_exp / (muw + 3) * log (10.)) + tvai = exp (- blini / (mui + 3) * log (n0i_sig)) * alini * gamma (mui + blini + 3) * & + exp (- blini * n0i_exp / (mui + 3) * log (10.)) + tvar = exp (- blinr / (mur + 3) * log (n0r_sig)) * alinr * gamma (mur + blinr + 3) * & + exp (- blinr * n0r_exp / (mur + 3) * log (10.)) + tvas = exp (- blins / (mus + 3) * log (n0s_sig)) * alins * gamma (mus + blins + 3) * & + exp (- blins * n0s_exp / (mus + 3) * log (10.)) + tvag = exp (- bling / (mug + 3) * log (n0g_sig)) * aling * gamma (mug + bling + 3) * & + exp (- bling * n0g_exp / (mug + 3) * log (10.)) * gcon + tvah = exp (- blinh / (muh + 3) * log (n0h_sig)) * alinh * gamma (muh + blinh + 3) * & + exp (- blinh * n0h_exp / (muh + 3) * log (10.)) * hcon + + tvbw = exp (blinw / (muw + 3) * log (pi * rhow * gamma (muw + 3))) * gamma (muw + 3) + tvbi = exp (blini / (mui + 3) * log (pi * rhoi * gamma (mui + 3))) * gamma (mui + 3) + tvbr = exp (blinr / (mur + 3) * log (pi * rhor * gamma (mur + 3))) * gamma (mur + 3) + tvbs = exp (blins / (mus + 3) * log (pi * rhos * gamma (mus + 3))) * gamma (mus + 3) + tvbg = exp (bling / (mug + 3) * log (pi * rhog * gamma (mug + 3))) * gamma (mug + 3) + tvbh = exp (blinh / (muh + 3) * log (pi * rhoh * gamma (muh + 3))) * gamma (muh + 3) + + ! ----------------------------------------------------------------------- + ! Schmidt number, Sc ** (1 / 3) in Lin et al. (1983) + ! ----------------------------------------------------------------------- + + scm3 = exp (1. / 3. * log (visk / vdifu)) + + pisq = pi * pi + + ! ----------------------------------------------------------------------- + ! accretion between cloud water, cloud ice, rain, snow, and graupel or hail, Lin et al. (1983) + ! ----------------------------------------------------------------------- + + cracw = pi * n0r_sig * alinr * gamma (2 + mur + blinr) / & + (4. * exp ((2 + mur + blinr) / (mur + 3) * log (normr))) * & + exp ((1 - blinr) * log (expor)) + craci = pi * n0r_sig * alinr * gamma (2 + mur + blinr) / & + (4. * exp ((2 + mur + blinr) / (mur + 3) * log (normr))) * & + exp ((1 - blinr) * log (expor)) + csacw = pi * n0s_sig * alins * gamma (2 + mus + blins) / & + (4. * exp ((2 + mus + blins) / (mus + 3) * log (norms))) * & + exp ((1 - blins) * log (expos)) + csaci = pi * n0s_sig * alins * gamma (2 + mus + blins) / & + (4. * exp ((2 + mus + blins) / (mus + 3) * log (norms))) * & + exp ((1 - blins) * log (expos)) + if (do_hail) then + cgacw = pi * n0h_sig * alinh * gamma (2 + muh + blinh) * hcon / & + (4. * exp ((2 + muh + blinh) / (muh + 3) * log (normh))) * & + exp ((1 - blinh) * log (expoh)) + cgaci = pi * n0h_sig * alinh * gamma (2 + muh + blinh) * hcon / & + (4. * exp ((2 + muh + blinh) / (muh + 3) * log (normh))) * & + exp ((1 - blinh) * log (expoh)) + else + cgacw = pi * n0g_sig * aling * gamma (2 + mug + bling) * gcon / & + (4. * exp ((2 + mug + bling) / (mug + 3) * log (normg))) * & + exp ((1 - bling) * log (expog)) + cgaci = pi * n0g_sig * aling * gamma (2 + mug + bling) * gcon / & + (4. * exp ((2 + mug + bling) / (mug + 3) * log (normg))) * & + exp ((1 - bling) * log (expog)) + endif + + if (do_new_acc_water) then + + cracw = pisq * n0r_sig * n0w_sig * rhow / 24. + csacw = pisq * n0s_sig * n0w_sig * rhow / 24. + if (do_hail) then + cgacw = pisq * n0h_sig * n0w_sig * rhow / 24. + else + cgacw = pisq * n0g_sig * n0w_sig * rhow / 24. + endif + + endif + + if (do_new_acc_ice) then + + craci = pisq * n0r_sig * n0i_sig * rhoi / 24. + csaci = pisq * n0s_sig * n0i_sig * rhoi / 24. + if (do_hail) then + cgaci = pisq * n0h_sig * n0i_sig * rhoi / 24. + else + cgaci = pisq * n0g_sig * n0i_sig * rhoi / 24. + endif + + endif + + cracw = cracw * c_pracw + craci = craci * c_praci + csacw = csacw * c_psacw + csaci = csaci * c_psaci + cgacw = cgacw * c_pgacw + cgaci = cgaci * c_pgaci + + ! ----------------------------------------------------------------------- + ! accretion between cloud water, cloud ice, rain, snow, and graupel or hail, Lin et al. (1983) + ! ----------------------------------------------------------------------- + + cracs = pisq * n0r_sig * n0s_sig * rhos / 24. + csacr = pisq * n0s_sig * n0r_sig * rhor / 24. + if (do_hail) then + cgacr = pisq * n0h_sig * n0r_sig * rhor / 24. + cgacs = pisq * n0h_sig * n0s_sig * rhos / 24. + else + cgacr = pisq * n0g_sig * n0r_sig * rhor / 24. + cgacs = pisq * n0g_sig * n0s_sig * rhos / 24. + endif + + cracs = cracs * c_pracs + csacr = csacr * c_psacr + cgacr = cgacr * c_pgacr + cgacs = cgacs * c_pgacs + + ! act / ace / acc: + ! 1 - 2: racs (s - r) + ! 3 - 4: sacr (r - s) + ! 5 - 6: gacr (r - g) + ! 7 - 8: gacs (s - g) + ! 9 - 10: racw (w - r) + ! 11 - 12: raci (i - r) + ! 13 - 14: sacw (w - s) + ! 15 - 16: saci (i - s) + ! 17 - 18: sacw (w - g) + ! 19 - 20: saci (i - g) + + act (1) = norms + act (2) = normr + act (3) = act (2) + act (4) = act (1) + act (5) = act (2) + if (do_hail) then + act (6) = normh + else + act (6) = normg + endif + act (7) = act (1) + act (8) = act (6) + act (9) = normw + act (10) = act (2) + act (11) = normi + act (12) = act (2) + act (13) = act (9) + act (14) = act (1) + act (15) = act (11) + act (16) = act (1) + act (17) = act (9) + act (18) = act (6) + act (19) = act (11) + act (20) = act (6) + + ace (1) = expos + ace (2) = expor + ace (3) = ace (2) + ace (4) = ace (1) + ace (5) = ace (2) + if (do_hail) then + ace (6) = expoh + else + ace (6) = expog + endif + ace (7) = ace (1) + ace (8) = ace (6) + ace (9) = expow + ace (10) = ace (2) + ace (11) = expoi + ace (12) = ace (2) + ace (13) = ace (9) + ace (14) = ace (1) + ace (15) = ace (11) + ace (16) = ace (1) + ace (17) = ace (9) + ace (18) = ace (6) + ace (19) = ace (11) + ace (20) = ace (6) + + acc (1) = mus + acc (2) = mur + acc (3) = acc (2) + acc (4) = acc (1) + acc (5) = acc (2) + if (do_hail) then + acc (6) = muh + else + acc (6) = mug + endif + acc (7) = acc (1) + acc (8) = acc (6) + acc (9) = muw + acc (10) = acc (2) + acc (11) = mui + acc (12) = acc (2) + acc (13) = acc (9) + acc (14) = acc (1) + acc (15) = acc (11) + acc (16) = acc (1) + acc (17) = acc (9) + acc (18) = acc (6) + acc (19) = acc (11) + acc (20) = acc (6) + + occ (1) = 1. + occ (2) = 2. + occ (3) = 1. + + do i = 1, 3 + do k = 1, 10 + acco (i, k) = occ (i) * gamma (6 + acc (2 * k - 1) - i) * gamma (acc (2 * k) + i - 1) / & + (exp ((6 + acc (2 * k - 1) - i) / (acc (2 * k - 1) + 3) * log (act (2 * k - 1))) * & + exp ((acc (2 * k) + i - 1) / (acc (2 * k) + 3) * log (act (2 * k)))) * & + exp ((i - 3) * log (ace (2 * k - 1))) * exp ((4 - i) * log (ace (2 * k))) + enddo + enddo + + ! ----------------------------------------------------------------------- + ! rain evaporation, snow sublimation, and graupel or hail sublimation, Lin et al. (1983) + ! ----------------------------------------------------------------------- + + crevp (1) = 2. * pi * vdifu * tcond * rvgas * n0r_sig * gamma (1 + mur) / & + exp ((1 + mur) / (mur + 3) * log (normr)) * exp (2.0 * log (expor)) + crevp (2) = 0.78 + crevp (3) = 0.31 * scm3 * sqrt (alinr / visk) * gamma ((3 + 2 * mur + blinr) / 2) / & + exp ((3 + 2 * mur + blinr) / (mur + 3) / 2 * log (normr)) * & + exp ((1 + mur) / (mur + 3) * log (normr)) / gamma (1 + mur) * & + exp ((- 1 - blinr) / 2. * log (expor)) + crevp (4) = tcond * rvgas + crevp (5) = vdifu + + cssub (1) = 2. * pi * vdifu * tcond * rvgas * n0s_sig * gamma (1 + mus) / & + exp ((1 + mus) / (mus + 3) * log (norms)) * exp (2.0 * log (expos)) + cssub (2) = 0.78 + cssub (3) = 0.31 * scm3 * sqrt (alins / visk) * gamma ((3 + 2 * mus + blins) / 2) / & + exp ((3 + 2 * mus + blins) / (mus + 3) / 2 * log (norms)) * & + exp ((1 + mus) / (mus + 3) * log (norms)) / gamma (1 + mus) * & + exp ((- 1 - blins) / 2. * log (expos)) + cssub (4) = tcond * rvgas + cssub (5) = vdifu + + if (do_hail) then + cgsub (1) = 2. * pi * vdifu * tcond * rvgas * n0h_sig * gamma (1 + muh) / & + exp ((1 + muh) / (muh + 3) * log (normh)) * exp (2.0 * log (expoh)) + cgsub (2) = 0.78 + cgsub (3) = 0.31 * scm3 * sqrt (alinh * hcon / visk) * gamma ((3 + 2 * muh + blinh) / 2) / & + exp (1. / (muh + 3) * (3 + 2 * muh + blinh) / 2 * log (normh)) * & + exp (1. / (muh + 3) * (1 + muh) * log (normh)) / gamma (1 + muh) * & + exp ((- 1 - blinh) / 2. * log (expoh)) + else + cgsub (1) = 2. * pi * vdifu * tcond * rvgas * n0g_sig * gamma (1 + mug) / & + exp ((1 + mug) / (mug + 3) * log (normg)) * exp (2.0 * log (expog)) + cgsub (2) = 0.78 + cgsub (3) = 0.31 * scm3 * sqrt (aling * gcon / visk) * gamma ((3 + 2 * mug + bling) / 2) / & + exp ((3 + 2 * mug + bling) / (mug + 3) / 2 * log (normg)) * & + exp ((1 + mug) / (mug + 3) * log (normg)) / gamma (1 + mug) * & + exp ((- 1 - bling) / 2. * log (expog)) + endif + cgsub (4) = tcond * rvgas + cgsub (5) = vdifu + + ! ----------------------------------------------------------------------- + ! snow melting, Lin et al. (1983) + ! ----------------------------------------------------------------------- + + csmlt (1) = 2. * pi * tcond * n0s_sig * gamma (1 + mus) / & + exp ((1 + mus) / (mus + 3) * log (norms)) * exp (2.0 * log (expos)) + csmlt (2) = 2. * pi * vdifu * n0s_sig * gamma (1 + mus) / & + exp ((1 + mus) / (mus + 3) * log (norms)) * exp (2.0 * log (expos)) + csmlt (3) = cssub (2) + csmlt (4) = cssub (3) + + ! ----------------------------------------------------------------------- + ! graupel or hail melting, Lin et al. (1983) + ! ----------------------------------------------------------------------- + + if (do_hail) then + cgmlt (1) = 2. * pi * tcond * n0h_sig * gamma (1 + muh) / & + exp ((1 + muh) / (muh + 3) * log (normh)) * exp (2.0 * log (expoh)) + cgmlt (2) = 2. * pi * vdifu * n0h_sig * gamma (1 + muh) / & + exp ((1 + muh) / (muh + 3) * log (normh)) * exp (2.0 * log (expoh)) + else + cgmlt (1) = 2. * pi * tcond * n0g_sig * gamma (1 + mug) / & + exp ((1 + mug) / (mug + 3) * log (normg)) * exp (2.0 * log (expog)) + cgmlt (2) = 2. * pi * vdifu * n0g_sig * gamma (1 + mug) / & + exp ((1 + mug) / (mug + 3) * log (normg)) * exp (2.0 * log (expog)) + endif + cgmlt (3) = cgsub (2) + cgmlt (4) = cgsub (3) + + ! ----------------------------------------------------------------------- + ! rain freezing, Lin et al. (1983) + ! ----------------------------------------------------------------------- + + cgfr (1) = 1.e2 / 36 * pisq * n0r_sig * rhor * gamma (6 + mur) / & + exp ((6 + mur) / (mur + 3) * log (normr)) * exp (- 3.0 * log (expor)) + cgfr (2) = 0.66 + +end subroutine setup_mp + +! ======================================================================= +! define various heat capacities and latent heat coefficients at 0 deg K +! ======================================================================= + +subroutine setup_mhc_lhc (hydrostatic) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + logical, intent (in) :: hydrostatic + + if (hydrostatic) then + c_air = cp_air + c_vap = cp_vap + do_sedi_w = .false. + else + c_air = cv_air + c_vap = cv_vap + endif + d0_vap = c_vap - c_liq + + ! scaled constants (to reduce float point errors for 32-bit) + + d1_vap = d0_vap / c_air + d1_ice = dc_ice / c_air + + lv00 = (hlv - d0_vap * tice) / c_air + li00 = (hlf - dc_ice * tice) / c_air + li20 = lv00 + li00 + + c1_vap = c_vap / c_air + c1_liq = c_liq / c_air + c1_ice = c_ice / c_air + +end subroutine setup_mhc_lhc + +! ======================================================================= +! major cloud microphysics driver +! ======================================================================= + +subroutine mpdrv (hydrostatic, ua, va, wa, delp, pt, qv, ql, qr, qi, qs, qg, & + qa, qnl, qni, delz, is, ie, ks, ke, dtm, water, rain, ice, snow, graupel, & + gsize, hs, q_con, cappa, consv_te, adj_vmr, te, dte, prefluxw, prefluxr, & + prefluxi, prefluxs, prefluxg, last_step, do_inline_mp, do_mp_fast, do_mp_full) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: is, ie, ks, ke + + logical, intent (in) :: hydrostatic, last_step, consv_te, do_inline_mp + logical, intent (in) :: do_mp_fast, do_mp_full + + real, intent (in) :: dtm + + real, intent (in), dimension (is:ie) :: gsize, hs + + real, intent (in), dimension (is:ie, ks:ke) :: qnl, qni + + real, intent (inout), dimension (is:ie, ks:ke) :: delp, delz, pt, ua, va, wa + real, intent (inout), dimension (is:ie, ks:ke) :: qv, ql, qr, qi, qs, qg, qa + real, intent (inout), dimension (is:ie, ks:ke) :: prefluxw, prefluxr, prefluxi, prefluxs, prefluxg + + real, intent (inout), dimension (is:, ks:) :: q_con, cappa + + real, intent (inout), dimension (is:ie) :: water, rain, ice, snow, graupel + + real, intent (out), dimension (is:ie, ks:ke) :: te, adj_vmr + + real (kind = r8), intent (out), dimension (is:ie) :: dte + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: i, k + + real :: rh_adj, rh_rain, ccn0, cin0, cond, q1, q2 + real :: convt, dts, q_cond, t_lnd, t_ocn, h_var, tmp, nl, ni + + real, dimension (ks:ke) :: q_liq, q_sol, dp, dz, dp0 + real, dimension (ks:ke) :: qvz, qlz, qrz, qiz, qsz, qgz, qaz + real, dimension (ks:ke) :: den, pz, denfac, ccn, cin + real, dimension (ks:ke) :: u, v, w + + real, dimension (is:ie, ks:ke) :: pcw, edw, oew, rrw, tvw + real, dimension (is:ie, ks:ke) :: pci, edi, oei, rri, tvi + real, dimension (is:ie, ks:ke) :: pcr, edr, oer, rrr, tvr + real, dimension (is:ie, ks:ke) :: pcs, eds, oes, rrs, tvs + real, dimension (is:ie, ks:ke) :: pcg, edg, oeg, rrg, tvg + + real, dimension (is:ie) :: condensation, deposition + real, dimension (is:ie) :: evaporation, sublimation + + real (kind = r8) :: con_r8, c8, cp8 + + real (kind = r8), dimension (is:ie, ks:ke) :: te_beg_d, te_end_d, tw_beg_d, tw_end_d + real (kind = r8), dimension (is:ie, ks:ke) :: te_beg_m, te_end_m, tw_beg_m, tw_end_m + + real (kind = r8), dimension (is:ie) :: te_b_beg_d, te_b_end_d, tw_b_beg_d, tw_b_end_d, te_loss + real (kind = r8), dimension (is:ie) :: te_b_beg_m, te_b_end_m, tw_b_beg_m, tw_b_end_m + + real (kind = r8), dimension (ks:ke) :: tz, tzuv, tzw + + ! ----------------------------------------------------------------------- + ! time steps + ! ----------------------------------------------------------------------- + + ntimes = max (ntimes, int (dtm / min (dtm, mp_time))) + dts = dtm / real (ntimes) + + ! ----------------------------------------------------------------------- + ! initialization of total energy difference and condensation diag + ! ----------------------------------------------------------------------- + + dte = 0.0 + cond = 0.0 + adj_vmr = 1.0 + + condensation = 0.0 + deposition = 0.0 + evaporation = 0.0 + sublimation = 0.0 + + ! ----------------------------------------------------------------------- + ! unit convert to mm/day + ! ----------------------------------------------------------------------- + + convt = 86400. * rgrav / dts + + do i = is, ie + + ! ----------------------------------------------------------------------- + ! conversion of temperature + ! ----------------------------------------------------------------------- + + if (do_inline_mp) then + do k = ks, ke + q_cond = ql (i, k) + qr (i, k) + qi (i, k) + qs (i, k) + qg (i, k) + tz (k) = pt (i, k) / ((1. + zvir * qv (i, k)) * (1. - q_cond)) + enddo + else + do k = ks, ke + tz (k) = pt (i, k) + enddo + endif + + ! ----------------------------------------------------------------------- + ! calculate base total energy + ! ----------------------------------------------------------------------- + + if (consv_te) then + if (hydrostatic) then + do k = ks, ke + te (i, k) = - c_air * tz (k) * delp (i, k) + enddo + else + do k = ks, ke + te (i, k) = - mte (qv (i, k), ql (i, k), qr (i, k), qi (i, k), & + qs (i, k), qg (i, k), tz (k), delp (i, k), .true.) * grav + enddo + endif + endif + + ! ----------------------------------------------------------------------- + ! total energy checker + ! ----------------------------------------------------------------------- + + if (consv_checker) then + call mtetw (ks, ke, qv (i, :), ql (i, :), qr (i, :), qi (i, :), & + qs (i, :), qg (i, :), tz, ua (i, :), va (i, :), wa (i, :), & + delp (i, :), dte (i), 0.0, water (i), rain (i), ice (i), & + snow (i), graupel (i), 0.0, 0.0, dtm, te_beg_m (i, :), & + tw_beg_m (i, :), te_b_beg_m (i), tw_b_beg_m (i), .true., hydrostatic) + endif + + do k = ks, ke + + ! ----------------------------------------------------------------------- + ! convert specific ratios to mass mixing ratios + ! ----------------------------------------------------------------------- + + qvz (k) = qv (i, k) + qlz (k) = ql (i, k) + qrz (k) = qr (i, k) + qiz (k) = qi (i, k) + qsz (k) = qs (i, k) + qgz (k) = qg (i, k) + qaz (k) = qa (i, k) + + if (do_inline_mp) then + q_cond = qlz (k) + qrz (k) + qiz (k) + qsz (k) + qgz (k) + con_r8 = one_r8 - (qvz (k) + q_cond) + else + con_r8 = one_r8 - qvz (k) + endif + + dp0 (k) = delp (i, k) + dp (k) = delp (i, k) * con_r8 + con_r8 = one_r8 / con_r8 + qvz (k) = qvz (k) * con_r8 + qlz (k) = qlz (k) * con_r8 + qrz (k) = qrz (k) * con_r8 + qiz (k) = qiz (k) * con_r8 + qsz (k) = qsz (k) * con_r8 + qgz (k) = qgz (k) * con_r8 + + ! ----------------------------------------------------------------------- + ! dry air density and layer-mean pressure thickness + ! ----------------------------------------------------------------------- + + dz (k) = delz (i, k) + den (k) = - dp (k) / (grav * dz (k)) + pz (k) = den (k) * rdgas * tz (k) + + ! ----------------------------------------------------------------------- + ! for sedi_momentum transport + ! ----------------------------------------------------------------------- + + u (k) = ua (i, k) + v (k) = va (i, k) + if (.not. hydrostatic) then + w (k) = wa (i, k) + endif + + enddo + +!rsun ke is sufface + + do k = ks, ke + denfac (k) = sqrt (den (ke) / den (k)) + enddo + + ! ----------------------------------------------------------------------- + ! total energy checker + ! ----------------------------------------------------------------------- + + if (consv_checker) then + call mtetw (ks, ke, qvz, qlz, qrz, qiz, qsz, qgz, tz, u, v, w, & + dp, dte (i), 0.0, water (i), rain (i), ice (i), snow (i), & + graupel (i), 0.0, 0.0, dtm, te_beg_d (i, :), tw_beg_d (i, :), & + te_b_beg_d (i), tw_b_beg_d (i), .false., hydrostatic) + endif + + ! ----------------------------------------------------------------------- + ! cloud condensation nuclei (CCN), cloud ice nuclei (CIN) + ! ----------------------------------------------------------------------- + + if (prog_ccn) then + do k = ks, ke + ! boucher and lohmann (1995) + nl = min (1., abs (hs (i)) / (10. * grav)) * & + (10. ** 2.24 * (qnl (i, k) * den (k) * 1.e9) ** 0.257) + & + (1. - min (1., abs (hs (i)) / (10. * grav))) * & + (10. ** 2.06 * (qnl (i, k) * den (k) * 1.e9) ** 0.48) + ni = qni (i, k) + ccn (k) = max (10.0, nl) * 1.e6 + cin (k) = max (10.0, ni) * 1.e6 + ccn (k) = ccn (k) / den (k) + cin (k) = cin (k) / den (k) + enddo + else + ccn0 = (ccn_l * min (1., abs (hs (i)) / (10. * grav)) + & + ccn_o * (1. - min (1., abs (hs (i)) / (10. * grav)))) * 1.e6 + cin0 = 0.0 + do k = ks, ke + ccn (k) = ccn0 / den (k) + cin (k) = cin0 / den (k) + enddo + endif + + ! ----------------------------------------------------------------------- + ! subgrid deviation in horizontal direction + ! default area dependent form: use dx ~ 100 km as the base + ! ----------------------------------------------------------------------- + + t_lnd = dw_land * sqrt (gsize (i) / 1.e5) + t_ocn = dw_ocean * sqrt (gsize (i) / 1.e5) + tmp = min (1., abs (hs (i)) / (10. * grav)) + h_var = t_lnd * tmp + t_ocn * (1. - tmp) + h_var = min (0.20, max (0.01, h_var)) + + ! ----------------------------------------------------------------------- + ! relative humidity thresholds + ! ----------------------------------------------------------------------- + + rh_adj = 1. - h_var - rh_inc + rh_rain = max (0.35, rh_adj - rh_inr) + + ! ----------------------------------------------------------------------- + ! fix negative water species from outside + ! ----------------------------------------------------------------------- + + if (fix_negative) & + call neg_adj (ks, ke, tz, dp, qvz, qlz, qrz, qiz, qsz, qgz, cond) + + condensation (i) = condensation (i) + cond * convt * ntimes + + ! ----------------------------------------------------------------------- + ! fast microphysics loop + ! ----------------------------------------------------------------------- + + if (do_mp_fast) then + + call mp_fast (ks, ke, tz, qvz, qlz, qrz, qiz, qsz, qgz, dtm, dp, den, & + ccn, cin, condensation (i), deposition (i), evaporation (i), & + sublimation (i), denfac, convt, last_step) + + endif + + ! ----------------------------------------------------------------------- + ! full microphysics loop + ! ----------------------------------------------------------------------- + + if (do_mp_full) then + + call mp_full (ks, ke, ntimes, tz, qvz, qlz, qrz, qiz, qsz, qgz, dp, dz, & + u, v, w, den, denfac, ccn, cin, dts, rh_adj, rh_rain, h_var, dte (i), & + water (i), rain (i), ice (i), snow (i), graupel (i), prefluxw (i, :), & + prefluxr (i, :), prefluxi (i, :), prefluxs (i, :), prefluxg (i, :), & + condensation (i), deposition (i), evaporation (i), sublimation (i), & + convt, last_step) + + endif + + ! ----------------------------------------------------------------------- + ! cloud fraction diagnostic + ! ----------------------------------------------------------------------- + + if (do_qa .and. last_step) then + call cloud_fraction (ks, ke, pz, den, qvz, qlz, qrz, qiz, qsz, qgz, qaz, & + tz, h_var, gsize (i)) + endif + + ! ======================================================================= + ! calculation of particle concentration (pc), effective diameter (ed), + ! optical extinction (oe), radar reflectivity factor (rr), and + ! mass-weighted terminal velocity (tv) + ! ======================================================================= + + pcw (i, :) = 0.0 + edw (i, :) = 0.0 + oew (i, :) = 0.0 + rrw (i, :) = 0.0 + tvw (i, :) = 0.0 + pci (i, :) = 0.0 + edi (i, :) = 0.0 + oei (i, :) = 0.0 + rri (i, :) = 0.0 + tvi (i, :) = 0.0 + pcr (i, :) = 0.0 + edr (i, :) = 0.0 + oer (i, :) = 0.0 + rrr (i, :) = 0.0 + tvr (i, :) = 0.0 + pcs (i, :) = 0.0 + eds (i, :) = 0.0 + oes (i, :) = 0.0 + rrs (i, :) = 0.0 + tvs (i, :) = 0.0 + pcg (i, :) = 0.0 + edg (i, :) = 0.0 + oeg (i, :) = 0.0 + rrg (i, :) = 0.0 + tvg (i, :) = 0.0 + + do k = ks, ke + if (qlz (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qlz (k), den (k), blinw, muw, pcaw, pcbw, pcw (i, k), & + edaw, edbw, edw (i, k), oeaw, oebw, oew (i, k), rraw, rrbw, rrw (i, k), & + tvaw, tvbw, tvw (i, k)) + endif + if (qiz (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qiz (k), den (k), blini, mui, pcai, pcbi, pci (i, k), & + edai, edbi, edi (i, k), oeai, oebi, oei (i, k), rrai, rrbi, rri (i, k), & + tvai, tvbi, tvi (i, k)) + endif + if (qrz (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qrz (k), den (k), blinr, mur, pcar, pcbr, pcr (i, k), & + edar, edbr, edr (i, k), oear, oebr, oer (i, k), rrar, rrbr, rrr (i, k), & + tvar, tvbr, tvr (i, k)) + endif + if (qsz (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qsz (k), den (k), blins, mus, pcas, pcbs, pcs (i, k), & + edas, edbs, eds (i, k), oeas, oebs, oes (i, k), rras, rrbs, rrs (i, k), & + tvas, tvbs, tvs (i, k)) + endif + if (do_hail) then + if (qgz (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qgz (k), den (k), blinh, muh, pcah, pcbh, pcg (i, k), & + edah, edbh, edg (i, k), oeah, oebh, oeg (i, k), rrah, rrbh, rrg (i, k), & + tvah, tvbh, tvg (i, k)) + endif + else + if (qgz (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qgz (k), den (k), bling, mug, pcag, pcbg, pcg (i, k), & + edag, edbg, edg (i, k), oeag, oebg, oeg (i, k), rrag, rrbg, rrg (i, k), & + tvag, tvbg, tvg (i, k)) + endif + endif + enddo + + ! ----------------------------------------------------------------------- + ! momentum transportation during sedimentation + ! update temperature before delp and q update + ! ----------------------------------------------------------------------- + + if (do_sedi_uv) then + do k = ks, ke + c8 = mhc (qvz (k), qlz (k), qrz (k), qiz (k), qsz (k), qgz (k)) * c_air + tzuv (k) = 0.5 * (ua (i, k) ** 2 + va (i, k) ** 2 - (u (k) ** 2 + v (k) ** 2)) / c8 + tz (k) = tz (k) + tzuv (k) + enddo + endif + + if (do_sedi_w) then + do k = ks, ke + c8 = mhc (qvz (k), qlz (k), qrz (k), qiz (k), qsz (k), qgz (k)) * c_air + tzw (k) = 0.5 * (wa (i, k) ** 2 - w (k) ** 2) / c8 + tz (k) = tz (k) + tzw (k) + enddo + endif + + ! ----------------------------------------------------------------------- + ! total energy checker + ! ----------------------------------------------------------------------- + + if (consv_checker) then + call mtetw (ks, ke, qvz, qlz, qrz, qiz, qsz, qgz, tz, u, v, w, & + dp, dte (i), 0.0, water (i), rain (i), ice (i), snow (i), & + graupel (i), 0.0, 0.0, dtm, te_end_d (i, :), tw_end_d (i, :), & + te_b_end_d (i), tw_b_end_d (i), .false., hydrostatic, te_loss (i)) + endif + + do k = ks, ke + + ! ----------------------------------------------------------------------- + ! convert mass mixing ratios back to specific ratios + ! ----------------------------------------------------------------------- + + if (do_inline_mp) then + q_cond = qlz (k) + qrz (k) + qiz (k) + qsz (k) + qgz (k) + con_r8 = one_r8 + qvz (k) + q_cond + else + con_r8 = one_r8 + qvz (k) + endif + + delp (i, k) = dp (k) * con_r8 + con_r8 = one_r8 / con_r8 + qvz (k) = qvz (k) * con_r8 + qlz (k) = qlz (k) * con_r8 + qrz (k) = qrz (k) * con_r8 + qiz (k) = qiz (k) * con_r8 + qsz (k) = qsz (k) * con_r8 + qgz (k) = qgz (k) * con_r8 + + q1 = qv (i, k) + ql (i, k) + qr (i, k) + qi (i, k) + qs (i, k) + qg (i, k) + q2 = qvz (k) + qlz (k) + qrz (k) + qiz (k) + qsz (k) + qgz (k) + adj_vmr (i, k) = ((one_r8 - q1) / (one_r8 - q2)) / (one_r8 + q2 - q1) + + qv (i, k) = qvz (k) + ql (i, k) = qlz (k) + qr (i, k) = qrz (k) + qi (i, k) = qiz (k) + qs (i, k) = qsz (k) + qg (i, k) = qgz (k) + qa (i, k) = qaz (k) + +!rsun + !if(qaz(k) > 0.0) print*,'qa(i,k):',i,k, qaz(k) + + + ! ----------------------------------------------------------------------- + ! calculate some more variables needed outside + ! ----------------------------------------------------------------------- + + q_liq (k) = qlz (k) + qrz (k) + q_sol (k) = qiz (k) + qsz (k) + qgz (k) + q_cond = q_liq (k) + q_sol (k) + con_r8 = one_r8 - (qvz (k) + q_cond) + c8 = mhc (con_r8, qvz (k), q_liq (k), q_sol (k)) * c_air + +#ifdef USE_COND + q_con (i, k) = q_cond +#endif +#ifdef MOIST_CAPPA + tmp = rdgas * (1. + zvir * qvz (k)) + cappa (i, k) = tmp / (tmp + c8) +#endif + + enddo + + ! ----------------------------------------------------------------------- + ! momentum transportation during sedimentation + ! update temperature after delp and q update + ! ----------------------------------------------------------------------- + + if (do_sedi_uv) then + do k = ks, ke + tz (k) = tz (k) - tzuv (k) + q_liq (k) = qlz (k) + qrz (k) + q_sol (k) = qiz (k) + qsz (k) + qgz (k) + q_cond = q_liq (k) + q_sol (k) + con_r8 = one_r8 - (qvz (k) + q_cond) + c8 = mhc (con_r8, qvz (k), q_liq (k), q_sol (k)) * c_air + tzuv (k) = (0.5 * (ua (i, k) ** 2 + va (i, k) ** 2) * dp0 (k) - & + 0.5 * (u (k) ** 2 + v (k) ** 2) * delp (i, k)) / c8 / delp (i, k) + tz (k) = tz (k) + tzuv (k) + enddo + do k = ks, ke + ua (i, k) = u (k) + va (i, k) = v (k) + enddo + endif + + if (do_sedi_w) then + do k = ks, ke + tz (k) = tz (k) - tzw (k) + q_liq (k) = qlz (k) + qrz (k) + q_sol (k) = qiz (k) + qsz (k) + qgz (k) + q_cond = q_liq (k) + q_sol (k) + con_r8 = one_r8 - (qvz (k) + q_cond) + c8 = mhc (con_r8, qvz (k), q_liq (k), q_sol (k)) * c_air + tzw (k) = (0.5 * (wa (i, k) ** 2) * dp0 (k) - & + 0.5 * (w (k) ** 2) * delp (i, k)) / c8 / delp (i, k) + tz (k) = tz (k) + tzw (k) + enddo + do k = ks, ke + wa (i, k) = w (k) + enddo + endif + + ! ----------------------------------------------------------------------- + ! total energy checker + ! ----------------------------------------------------------------------- + + if (consv_checker) then + call mtetw (ks, ke, qv (i, :), ql (i, :), qr (i, :), qi (i, :), & + qs (i, :), qg (i, :), tz, ua (i, :), va (i, :), wa (i, :), & + delp (i, :), dte (i), 0.0, water (i), rain (i), ice (i), & + snow (i), graupel (i), 0.0, 0.0, dtm, te_end_m (i, :), & + tw_end_m (i, :), te_b_end_m (i), tw_b_end_m (i), .true., hydrostatic) + endif + + ! ----------------------------------------------------------------------- + ! calculate total energy loss or gain + ! ----------------------------------------------------------------------- + + if (consv_te) then + if (hydrostatic) then + do k = ks, ke + te (i, k) = te (i, k) + c_air * tz (k) * delp (i, k) + enddo + else + do k = ks, ke + te (i, k) = te (i, k) + mte (qv (i, k), ql (i, k), qr (i, k), qi (i, k), & + qs (i, k), qg (i, k), tz (k), delp (i, k), .true.) * grav + enddo + endif + endif + + ! ----------------------------------------------------------------------- + ! conversion of temperature + ! ----------------------------------------------------------------------- + + if (do_inline_mp) then + do k = ks, ke + q_cond = qlz (k) + qrz (k) + qiz (k) + qsz (k) + qgz (k) + if (cp_heating) then + con_r8 = one_r8 - (qvz (k) + q_cond) + c8 = mhc (con_r8, qvz (k), q_liq (k), q_sol (k)) * c_air + cp8 = con_r8 * cp_air + qvz (k) * cp_vap + q_liq (k) * c_liq + q_sol (k) * c_ice + delz (i, k) = delz (i, k) / pt (i, k) + pt (i, k) = pt (i, k) + (tz (k) * ((1. + zvir * qvz (k)) * (1. - q_cond)) - pt (i, k)) * c8 / cp8 + delz (i, k) = delz (i, k) * pt (i, k) + else + pt (i, k) = tz (k) * ((1. + zvir * qvz (k)) * (1. - q_cond)) + endif + enddo + else + do k = ks, ke + q_liq (k) = qlz (k) + qrz (k) + q_sol (k) = qiz (k) + qsz (k) + qgz (k) + q_cond = q_liq (k) + q_sol (k) + con_r8 = one_r8 - (qvz (k) + q_cond) + c8 = mhc (con_r8, qvz (k), q_liq (k), q_sol (k)) * c_air + pt (i, k) = pt (i, k) + (tz (k) - pt (i, k)) * c8 / cp_air + enddo + endif + + ! ----------------------------------------------------------------------- + ! total energy checker + ! ----------------------------------------------------------------------- + + if (consv_checker) then + if (abs (sum (te_end_d (i, :)) + te_b_end_d (i) - sum (te_beg_d (i, :)) - te_b_beg_d (i)) / & + (sum (te_beg_d (i, :)) + te_b_beg_d (i)) .gt. te_err) then + print*, "GFDL-MP-DRY TE: ", & + !(sum (te_beg_d (i, :)) + te_b_beg_d (i)), & + !(sum (te_end_d (i, :)) + te_b_end_d (i)), & + (sum (te_end_d (i, :)) + te_b_end_d (i) - sum (te_beg_d (i, :)) - te_b_beg_d (i)) / & + (sum (te_beg_d (i, :)) + te_b_beg_d (i)) + endif + if (abs (sum (tw_end_d (i, :)) + tw_b_end_d (i) - sum (tw_beg_d (i, :)) - tw_b_beg_d (i)) / & + (sum (tw_beg_d (i, :)) + tw_b_beg_d (i)) .gt. tw_err) then + print*, "GFDL-MP-DRY TW: ", & + !(sum (tw_beg_d (i, :)) + tw_b_beg_d (i)), & + !(sum (tw_end_d (i, :)) + tw_b_end_d (i)), & + (sum (tw_end_d (i, :)) + tw_b_end_d (i) - sum (tw_beg_d (i, :)) - tw_b_beg_d (i)) / & + (sum (tw_beg_d (i, :)) + tw_b_beg_d (i)) + endif + !print*, "GFDL MP TE DRY LOSS (%) : ", te_loss (i) / (sum (te_beg_d (i, :)) + te_b_beg_d (i)) * 100.0 + if (abs (sum (te_end_m (i, :)) + te_b_end_m (i) - sum (te_beg_m (i, :)) - te_b_beg_m (i)) / & + (sum (te_beg_m (i, :)) + te_b_beg_m (i)) .gt. te_err) then + print*, "GFDL-MP-WET TE: ", & + !(sum (te_beg_m (i, :)) + te_b_beg_m (i)), & + !(sum (te_end_m (i, :)) + te_b_end_m (i)), & + (sum (te_end_m (i, :)) + te_b_end_m (i) - sum (te_beg_m (i, :)) - te_b_beg_m (i)) / & + (sum (te_beg_m (i, :)) + te_b_beg_m (i)) + endif + if (abs (sum (tw_end_m (i, :)) + tw_b_end_m (i) - sum (tw_beg_m (i, :)) - tw_b_beg_m (i)) / & + (sum (tw_beg_m (i, :)) + tw_b_beg_m (i)) .gt. tw_err) then + print*, "GFDL-MP-WET TW: ", & + !(sum (tw_beg_m (i, :)) + tw_b_beg_m (i)), & + !(sum (tw_end_m (i, :)) + tw_b_end_m (i)), & + (sum (tw_end_m (i, :)) + tw_b_end_m (i) - sum (tw_beg_m (i, :)) - tw_b_beg_m (i)) / & + (sum (tw_beg_m (i, :)) + tw_b_beg_m (i)) + endif + !print*, "GFDL MP TE WET LOSS (%) : ", te_loss_0 (i) / (sum (te_beg_m (i, :)) + te_b_beg_m (i)) * 100.0 + endif + + enddo ! i loop + +end subroutine mpdrv + +! ======================================================================= +! fix negative water species +! ======================================================================= + +subroutine neg_adj (ks, ke, tz, dp, qv, ql, qr, qi, qs, qg, cond) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in), dimension (ks:ke) :: dp + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real, intent (out) :: cond + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: dq, sink + + real, dimension (ks:ke) :: q_liq, q_sol, lcpk, icpk, tcpk, tcp3 + + real (kind = r8), dimension (ks:ke) :: cvm, te8 + + ! ----------------------------------------------------------------------- + ! initialization + ! ----------------------------------------------------------------------- + + cond = 0 + + ! ----------------------------------------------------------------------- + ! calculate moist heat capacity and latent heat coefficients + ! ----------------------------------------------------------------------- + + call cal_mhc_lhc (ks, ke, qv, ql, qr, qi, qs, qg, q_liq, q_sol, cvm, te8, tz, & + lcpk, icpk, tcpk, tcp3) + + do k = ks, ke + + ! ----------------------------------------------------------------------- + ! fix negative solid-phase hydrometeors + ! ----------------------------------------------------------------------- + + ! if cloud ice < 0, borrow from snow + if (qi (k) .lt. 0.) then + sink = min (- qi (k), max (0., qs (k))) + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., 0., sink, - sink, 0.) + endif + + ! if snow < 0, borrow from graupel + if (qs (k) .lt. 0.) then + sink = min (- qs (k), max (0., qg (k))) + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., 0., 0., sink, - sink) + endif + + ! if graupel < 0, borrow from rain + if (qg (k) .lt. 0.) then + sink = min (- qg (k), max (0., qr (k))) + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., - sink, 0., 0., sink, te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + endif + + ! ----------------------------------------------------------------------- + ! fix negative liquid-phase hydrometeors + ! ----------------------------------------------------------------------- + + ! if rain < 0, borrow from cloud water + if (qr (k) .lt. 0.) then + sink = min (- qr (k), max (0., ql (k))) + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, sink, 0., 0., 0.) + endif + + ! if cloud water < 0, borrow from water vapor + if (ql (k) .lt. 0.) then + sink = min (- ql (k), max (0., qv (k))) + cond = cond + sink * dp (k) + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + - sink, sink, 0., 0., 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + endif + + enddo + + ! ----------------------------------------------------------------------- + ! fix negative water vapor + ! ----------------------------------------------------------------------- + + ! if water vapor < 0, borrow water vapor from below + do k = ks, ke - 1 + if (qv (k) .lt. 0.) then + qv (k + 1) = qv (k + 1) + qv (k) * dp (k) / dp (k + 1) + qv (k) = 0. + endif + enddo + + ! if water vapor < 0, borrow water vapor from above + if (qv (ke) .lt. 0. .and. qv (ke - 1) .gt. 0.) then + dq = min (- qv (ke) * dp (ke), qv (ke - 1) * dp (ke - 1)) + qv (ke - 1) = qv (ke - 1) - dq / dp (ke - 1) + qv (ke) = qv (ke) + dq / dp (ke) + endif + +end subroutine neg_adj + +! ======================================================================= +! full microphysics loop +! ======================================================================= + +subroutine mp_full (ks, ke, ntimes, tz, qv, ql, qr, qi, qs, qg, dp, dz, u, v, w, & + den, denfac, ccn, cin, dts, rh_adj, rh_rain, h_var, dte, water, rain, ice, & + snow, graupel, prefluxw, prefluxr, prefluxi, prefluxs, prefluxg, & + condensation, deposition, evaporation, sublimation, convt, last_step) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + logical, intent (in) :: last_step + + integer, intent (in) :: ks, ke, ntimes + + real, intent (in) :: dts, rh_adj, rh_rain, h_var, convt + + real, intent (in), dimension (ks:ke) :: dp, dz, den, denfac + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, u, v, w, ccn, cin + real, intent (inout), dimension (ks:ke) :: prefluxw, prefluxr, prefluxi, prefluxs, prefluxg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + real, intent (inout) :: water, rain, ice, snow, graupel + real, intent (inout) :: condensation, deposition + real, intent (inout) :: evaporation, sublimation + + real (kind = r8), intent (inout) :: dte + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: n + + real :: w1, r1, i1, s1, g1, cond, dep, reevap, sub + + real, dimension (ks:ke) :: vtw, vtr, vti, vts, vtg, pfw, pfr, pfi, pfs, pfg + + do n = 1, ntimes + + ! ----------------------------------------------------------------------- + ! sedimentation of cloud ice, snow, graupel or hail, and rain + ! ----------------------------------------------------------------------- + + call sedimentation (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, & + dz, dp, vtw, vtr, vti, vts, vtg, w1, r1, i1, s1, g1, pfw, pfr, pfi, pfs, pfg, & + u, v, w, den, denfac, dte) + + water = water + w1 * convt + rain = rain + r1 * convt + ice = ice + i1 * convt + snow = snow + s1 * convt + graupel = graupel + g1 * convt + + !prefluxw = prefluxw + pfw * convt + !prefluxr = prefluxr + pfr * convt + !prefluxi = prefluxi + pfi * convt + !prefluxs = prefluxs + pfs * convt + !prefluxg = prefluxg + pfg * convt + prefluxw = prefluxw + pfw + prefluxr = prefluxr + pfr + prefluxi = prefluxi + pfi + prefluxs = prefluxs + pfs + prefluxg = prefluxg + pfg + + ! ----------------------------------------------------------------------- + ! warm rain cloud microphysics + ! ----------------------------------------------------------------------- + + call warm_rain (dts, ks, ke, dp, dz, tz, qv, ql, qr, qi, qs, qg, & + den, denfac, vtw, vtr, ccn, rh_rain, h_var, reevap) + + evaporation = evaporation + reevap * convt + + ! ----------------------------------------------------------------------- + ! ice cloud microphysics + ! ----------------------------------------------------------------------- + + call ice_cloud (ks, ke, tz, qv, ql, qr, qi, qs, qg, den, & + denfac, vtw, vtr, vti, vts, vtg, dts, h_var) + + if (do_subgrid_proc) then + + ! ----------------------------------------------------------------------- + ! temperature sentive high vertical resolution processes + ! ----------------------------------------------------------------------- + + call subgrid_z_proc (ks, ke, den, denfac, dts, rh_adj, tz, qv, ql, & + qr, qi, qs, qg, dp, ccn, cin, cond, dep, reevap, sub, last_step) + + condensation = condensation + cond * convt + deposition = deposition + dep * convt + evaporation = evaporation + reevap * convt + sublimation = sublimation + sub * convt + + endif + + enddo + +end subroutine mp_full + +! ======================================================================= +! fast microphysics loop +! ======================================================================= + +subroutine mp_fast (ks, ke, tz, qv, ql, qr, qi, qs, qg, dtm, dp, den, & + ccn, cin, condensation, deposition, evaporation, sublimation, & + denfac, convt, last_step) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + logical, intent (in) :: last_step + + integer, intent (in) :: ks, ke + + real, intent (in) :: dtm, convt + + real, intent (in), dimension (ks:ke) :: dp, den, denfac + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, ccn, cin + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + real, intent (inout) :: condensation, deposition + real, intent (inout) :: evaporation, sublimation + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + logical :: cond_evap + + integer :: n + + real :: cond, dep, reevap, sub + + real, dimension (ks:ke) :: q_liq, q_sol, lcpk, icpk, tcpk, tcp3 + + real (kind = r8), dimension (ks:ke) :: cvm, te8 + + ! ----------------------------------------------------------------------- + ! initialization + ! ----------------------------------------------------------------------- + + cond = 0 + dep = 0 + reevap = 0 + sub = 0 + + ! ----------------------------------------------------------------------- + ! calculate heat capacities and latent heat coefficients + ! ----------------------------------------------------------------------- + + call cal_mhc_lhc (ks, ke, qv, ql, qr, qi, qs, qg, q_liq, q_sol, cvm, te8, tz, & + lcpk, icpk, tcpk, tcp3) + + if (.not. do_warm_rain_mp .and. fast_fr_mlt) then + + ! ----------------------------------------------------------------------- + ! cloud ice melting to form cloud water and rain + ! ----------------------------------------------------------------------- + + call pimlt (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, cvm, te8, & + lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! enforce complete freezing below t_wfr + ! ----------------------------------------------------------------------- + + call pcomp (ks, ke, qv, ql, qr, qi, qs, qg, tz, cvm, te8, & + lcpk, icpk, tcpk, tcp3) + + endif + + ! ----------------------------------------------------------------------- + ! cloud water condensation and evaporation + ! ----------------------------------------------------------------------- + + if (delay_cond_evap) then + cond_evap = last_step + else + cond_evap = .true. + endif + + if (cond_evap) then + do n = 1, nconds + call pcond_pevap (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3, cond, reevap) + enddo + endif + + condensation = condensation + cond * convt + evaporation = evaporation + reevap * convt + + if (.not. do_warm_rain_mp .and. fast_fr_mlt) then + + ! ----------------------------------------------------------------------- + ! cloud water freezing to form cloud ice and snow + ! ----------------------------------------------------------------------- + + call pifr (ks, ke, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! Wegener Bergeron Findeisen process + ! ----------------------------------------------------------------------- + + call pwbf (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! Bigg freezing mechanism + ! ----------------------------------------------------------------------- + + call pbigg (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, ccn, & + lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! rain freezing to form graupel + ! ----------------------------------------------------------------------- + + call pgfr_simp (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, cvm, te8, & + lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! snow melting to form cloud water and rain + ! ----------------------------------------------------------------------- + + call psmlt_simp (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, cvm, te8, & + lcpk, icpk, tcpk, tcp3) + + endif + + ! ----------------------------------------------------------------------- + ! cloud water to rain autoconversion + ! ----------------------------------------------------------------------- + + call praut_simp (ks, ke, dtm, tz, qv, ql, qr, qi, qs, qg) + + if (.not. do_warm_rain_mp .and. fast_dep_sub) then + + ! ----------------------------------------------------------------------- + ! cloud ice deposition and sublimation + ! ----------------------------------------------------------------------- + + call pidep_pisub (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3, cin, dep, sub) + + deposition = deposition + dep * convt + sublimation = sublimation + sub * convt + + ! ----------------------------------------------------------------------- + ! cloud ice to snow autoconversion + ! ----------------------------------------------------------------------- + + call psaut_simp (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, den) + + ! ----------------------------------------------------------------------- + ! snow deposition and sublimation + ! ----------------------------------------------------------------------- + + call psdep_pssub (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + denfac, lcpk, icpk, tcpk, tcp3, dep, sub) + + ! ----------------------------------------------------------------------- + ! graupel deposition and sublimation + ! ----------------------------------------------------------------------- + + call pgdep_pgsub (ks, ke, dtm, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + denfac, lcpk, icpk, tcpk, tcp3, dep, sub) + + endif + +end subroutine mp_fast + +! ======================================================================= +! sedimentation of cloud ice, snow, graupel or hail, and rain +! ======================================================================= + +subroutine sedimentation (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vtw, vtr, vti, vts, vtg, w1, r1, i1, s1, g1, pfw, pfr, pfi, pfs, pfg, & + u, v, w, den, denfac, dte) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: dp, dz, den, denfac + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, u, v, w + + real, intent (out) :: w1, r1, i1, s1, g1 + + real, intent (out), dimension (ks:ke) :: vtw, vtr, vti, vts, vtg, pfw, pfr, pfi, pfs, pfg + + real (kind = r8), intent (inout) :: dte + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real, dimension (ks:ke) :: q_liq, q_sol, lcpk, icpk, tcpk, tcp3 + + real (kind = r8), dimension (ks:ke) :: te8, cvm + + w1 = 0. + r1 = 0. + i1 = 0. + s1 = 0. + g1 = 0. + + vtw = 0. + vtr = 0. + vti = 0. + vts = 0. + vtg = 0. + + pfw = 0. + pfr = 0. + pfi = 0. + pfs = 0. + pfg = 0. + + ! ----------------------------------------------------------------------- + ! calculate heat capacities and latent heat coefficients + ! ----------------------------------------------------------------------- + + call cal_mhc_lhc (ks, ke, qv, ql, qr, qi, qs, qg, q_liq, q_sol, cvm, te8, tz, & + lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! terminal fall and melting of falling cloud ice into rain + ! ----------------------------------------------------------------------- + + if (do_psd_ice_fall) then + call term_rsg (ks, ke, qi, den, denfac, vi_fac, blini, mui, tvai, tvbi, vi_max, const_vi, vti) + else + call term_ice (ks, ke, tz, qi, den, vi_fac, vi_max, const_vi, vti) + endif + + if (do_sedi_melt) then + call sedi_melt (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vti, r1, tau_imlt, icpk, "qi") + endif + + call terminal_fall (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vti, i1, pfi, u, v, w, dte, "qi") + + pfi (ks) = max (0.0, pfi (ks)) + do k = ke, ks + 1, -1 + pfi (k) = max (0.0, pfi (k) - pfi (k - 1)) + enddo + + ! ----------------------------------------------------------------------- + ! terminal fall and melting of falling snow into rain + ! ----------------------------------------------------------------------- + + call term_rsg (ks, ke, qs, den, denfac, vs_fac, blins, mus, tvas, tvbs, vs_max, const_vs, vts) + + if (do_sedi_melt) then + call sedi_melt (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vts, r1, tau_smlt, icpk, "qs") + endif + + call terminal_fall (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vts, s1, pfs, u, v, w, dte, "qs") + + pfs (ks) = max (0.0, pfs (ks)) + do k = ke, ks + 1, -1 + pfs (k) = max (0.0, pfs (k) - pfs (k - 1)) + enddo + + ! ----------------------------------------------------------------------- + ! terminal fall and melting of falling graupel into rain + ! ----------------------------------------------------------------------- + + if (do_hail) then + call term_rsg (ks, ke, qg, den, denfac, vg_fac, blinh, muh, tvah, tvbh, vg_max, const_vg, vtg) + else + call term_rsg (ks, ke, qg, den, denfac, vg_fac, bling, mug, tvag, tvbg, vg_max, const_vg, vtg) + endif + + if (do_sedi_melt) then + call sedi_melt (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vtg, r1, tau_gmlt, icpk, "qg") + endif + + call terminal_fall (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vtg, g1, pfg, u, v, w, dte, "qg") + + pfg (ks) = max (0.0, pfg (ks)) + do k = ke, ks + 1, -1 + pfg (k) = max (0.0, pfg (k) - pfg (k - 1)) + enddo + + ! ----------------------------------------------------------------------- + ! terminal fall of cloud water + ! ----------------------------------------------------------------------- + + if (do_psd_water_fall) then + + call term_rsg (ks, ke, ql, den, denfac, vw_fac, blinw, muw, tvaw, tvbw, vw_max, const_vw, vtw) + + call terminal_fall (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vtw, w1, pfw, u, v, w, dte, "ql") + + pfw (ks) = max (0.0, pfw (ks)) + do k = ke, ks + 1, -1 + pfw (k) = max (0.0, pfw (k) - pfw (k - 1)) + enddo + + endif + + ! ----------------------------------------------------------------------- + ! terminal fall of rain + ! ----------------------------------------------------------------------- + + call term_rsg (ks, ke, qr, den, denfac, vr_fac, blinr, mur, tvar, tvbr, vr_max, const_vr, vtr) + + call terminal_fall (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vtr, r1, pfr, u, v, w, dte, "qr") + + pfr (ks) = max (0.0, pfr (ks)) + do k = ke, ks + 1, -1 + pfr (k) = max (0.0, pfr (k) - pfr (k - 1)) + enddo + +end subroutine sedimentation + +! ======================================================================= +! terminal velocity for cloud ice +! ======================================================================= + +subroutine term_ice (ks, ke, tz, q, den, v_fac, v_max, const_v, vt) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + logical, intent (in) :: const_v + + real, intent (in) :: v_fac, v_max + + real, intent (in), dimension (ks:ke) :: q, den + + real (kind = r8), intent (in), dimension (ks:ke) :: tz + + real, intent (out), dimension (ks:ke) :: vt + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: qden + + real, parameter :: aa = - 4.14122e-5 + real, parameter :: bb = - 0.00538922 + real, parameter :: cc = - 0.0516344 + real, parameter :: dd = 0.00216078 + real, parameter :: ee = 1.9714 + + real, dimension (ks:ke) :: tc + + if (const_v) then + vt (:) = v_fac + else + do k = ks, ke + qden = q (k) * den (k) + if (q (k) .lt. qfmin) then + vt (k) = 0.0 + else + tc (k) = tz (k) - tice + if (ifflag .eq. 1) then + vt (k) = (3. + log10 (qden)) * (tc (k) * (aa * tc (k) + bb) + cc) + & + dd * tc (k) + ee + vt (k) = 0.01 * v_fac * exp (vt (k) * log (10.)) + endif + if (ifflag .eq. 2) & + vt (k) = v_fac * 3.29 * exp (0.16 * log (qden)) + vt (k) = min (v_max, max (0.0, vt (k))) + endif + enddo + endif + +end subroutine term_ice + +! ======================================================================= +! terminal velocity for rain, snow, and graupel, Lin et al. (1983) +! ======================================================================= + +subroutine term_rsg (ks, ke, q, den, denfac, v_fac, blin, mu, tva, tvb, v_max, const_v, vt) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + logical, intent (in) :: const_v + + real, intent (in) :: v_fac, blin, v_max, mu + + real (kind = r8), intent (in) :: tva, tvb + + real, intent (in), dimension (ks:ke) :: q, den, denfac + + real, intent (out), dimension (ks:ke) :: vt + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + if (const_v) then + vt (:) = v_fac + else + do k = ks, ke + if (q (k) .lt. qfmin) then + vt (k) = 0.0 + else + call cal_pc_ed_oe_rr_tv (q (k), den (k), blin, mu, & + tva = tva, tvb = tvb, tv = vt (k)) + vt (k) = v_fac * vt (k) * denfac (k) + vt (k) = min (v_max, max (0.0, vt (k))) + endif + enddo + endif + +end subroutine term_rsg + +! ======================================================================= +! melting during sedimentation +! ======================================================================= + +subroutine sedi_melt (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vt, r1, tau_mlt, icpk, qflag) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts, tau_mlt + + real, intent (in), dimension (ks:ke) :: vt, dp, dz, icpk + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real, intent (inout) :: r1 + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + character (len = 2), intent (in) :: qflag + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k, m + + real :: dtime, sink, zs + + real, dimension (ks:ke) :: q + + real, dimension (ks:ke + 1) :: ze, zt + + real (kind = r8), dimension (ks:ke) :: cvm + + call zezt (ks, ke, dts, zs, dz, vt, ze, zt) + + select case (qflag) + case ("qi") + q = qi + case ("qs") + q = qs + case ("qg") + q = qg + case default + print *, "gfdl_mp: qflag error!" + end select + + ! ----------------------------------------------------------------------- + ! melting to rain + ! ----------------------------------------------------------------------- + + do k = ke - 1, ks, - 1 + if (vt (k) .lt. 1.e-10) cycle + if (q (k) .gt. qcmin) then + do m = k + 1, ke + if (zt (k + 1) .ge. ze (m)) exit + if (zt (k) .lt. ze (m + 1) .and. tz (m) .gt. tice) then + cvm (k) = mhc (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k)) + cvm (m) = mhc (qv (m), ql (m), qr (m), qi (m), qs (m), qg (m)) + dtime = min (dts, (ze (m) - ze (m + 1)) / vt (k)) + dtime = min (1.0, dtime / tau_mlt) + sink = min (q (k) * dp (k) / dp (m), dtime * (tz (m) - tice) / icpk (m)) + q (k) = q (k) - sink * dp (m) / dp (k) + if (zt (k) .lt. zs) then + r1 = r1 + sink * dp (m) + else + qr (m) = qr (m) + sink + endif + select case (qflag) + case ("qi") + qi (k) = q (k) + case ("qs") + qs (k) = q (k) + case ("qg") + qg (k) = q (k) + case default + print *, "gfdl_mp: qflag error!" + end select + tz (k) = (tz (k) * cvm (k) - li00 * sink * dp (m) / dp (k)) / & + mhc (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k)) + tz (m) = (tz (m) * cvm (m)) / & + mhc (qv (m), ql (m), qr (m), qi (m), qs (m), qg (m)) + endif + if (q (k) .lt. qcmin) exit + enddo + endif + enddo + +end subroutine sedi_melt + +! ======================================================================= +! melting during sedimentation +! ======================================================================= + +subroutine terminal_fall (dts, ks, ke, tz, qv, ql, qr, qi, qs, qg, dz, dp, & + vt, x1, m1, u, v, w, dte, qflag) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: vt, dp, dz + + character (len = 2), intent (in) :: qflag + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, u, v, w + + real, intent (inout) :: x1 + + real (kind = r8), intent (inout) :: dte + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + real, intent (out), dimension (ks:ke) :: m1 + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + logical :: no_fall + + real :: zs + + real, dimension (ks:ke) :: dm, q + + real, dimension (ks:ke + 1) :: ze, zt + + real (kind = r8), dimension (ks:ke) :: te1, te2 + + m1 = 0.0 + + call zezt (ks, ke, dts, zs, dz, vt, ze, zt) + + select case (qflag) + case ("ql") + q = ql + case ("qr") + q = qr + case ("qi") + q = qi + case ("qs") + q = qs + case ("qg") + q = qg + case default + print *, "gfdl_mp: qflag error!" + end select + + call check_column (ks, ke, q, no_fall) + + if (no_fall) return + + ! ----------------------------------------------------------------------- + ! momentum transportation during sedimentation + ! ----------------------------------------------------------------------- + + if (do_sedi_w) then + do k = ks, ke + dm (k) = dp (k) * (1. + qv (k) + ql (k) + qr (k) + qi (k) + qs (k) + qg (k)) + enddo + endif + + ! ----------------------------------------------------------------------- + ! energy change during sedimentation + ! ----------------------------------------------------------------------- + + do k = ks, ke + te1 (k) = mte (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), tz (k), dp (k), .false.) + enddo + + ! ----------------------------------------------------------------------- + ! sedimentation + ! ----------------------------------------------------------------------- + + select case (qflag) + case ("ql") + q = ql + case ("qr") + q = qr + case ("qi") + q = qi + case ("qs") + q = qs + case ("qg") + q = qg + case default + print *, "gfdl_mp: qflag error!" + end select + + if (sedflag .eq. 1) & + call implicit_fall (dts, ks, ke, ze, vt, dp, q, x1, m1) + if (sedflag .eq. 2) & + call explicit_fall (dts, ks, ke, ze, vt, dp, q, x1, m1) + if (sedflag .eq. 3) & + call lagrangian_fall (ks, ke, zs, ze, zt, dp, q, x1, m1) + if (sedflag .eq. 4) & + call implicit_lagrangian_fall (dts, ks, ke, zs, ze, zt, vt, dp, q, & + x1, m1, sed_fac) + + select case (qflag) + case ("ql") + ql = q + case ("qr") + qr = q + case ("qi") + qi = q + case ("qs") + qs = q + case ("qg") + qg = q + case default + print *, "gfdl_mp: qflag error!" + end select + + ! ----------------------------------------------------------------------- + ! energy change during sedimentation + ! ----------------------------------------------------------------------- + + do k = ks, ke + te2 (k) = mte (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), tz (k), dp (k), .false.) + enddo + dte = dte + sum (te1) - sum (te2) + + ! ----------------------------------------------------------------------- + ! momentum transportation during sedimentation + ! ----------------------------------------------------------------------- + + if (do_sedi_uv) then + call sedi_uv (ks, ke, m1, dp, u, v) + endif + + if (do_sedi_w) then + call sedi_w (ks, ke, m1, w, vt, dm) + endif + + ! ----------------------------------------------------------------------- + ! energy change during sedimentation heating + ! ----------------------------------------------------------------------- + + do k = ks, ke + te1 (k) = mte (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), tz (k), dp (k), .false.) + enddo + + ! ----------------------------------------------------------------------- + ! heat exchanges during sedimentation + ! ----------------------------------------------------------------------- + + if (do_sedi_heat) then + call sedi_heat (ks, ke, dp, m1, dz, tz, qv, ql, qr, qi, qs, qg, c_ice) + endif + + ! ----------------------------------------------------------------------- + ! energy change during sedimentation heating + ! ----------------------------------------------------------------------- + + do k = ks, ke + te2 (k) = mte (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), tz (k), dp (k), .false.) + enddo + dte = dte + sum (te1) - sum (te2) + +end subroutine terminal_fall + +! ======================================================================= +! calculate ze zt for sedimentation +! ======================================================================= + +subroutine zezt (ks, ke, dts, zs, dz, vt, ze, zt) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: dz, vt + + real, intent (out) :: zs + + real, intent (out), dimension (ks:ke + 1) :: ze, zt + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: dt5 + + dt5 = 0.5 * dts + zs = 0.0 + ze (ke + 1) = zs + do k = ke, ks, - 1 + ze (k) = ze (k + 1) - dz (k) + enddo + zt (ks) = ze (ks) + do k = ks + 1, ke + zt (k) = ze (k) - dt5 * (vt (k - 1) + vt (k)) + enddo + zt (ke + 1) = zs - dts * vt (ke) + do k = ks, ke + if (zt (k + 1) .ge. zt (k)) zt (k + 1) = zt (k) - dz_min + enddo + +end subroutine zezt + +! ======================================================================= +! check if water species is large enough to fall +! ======================================================================= + +subroutine check_column (ks, ke, q, no_fall) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: q (ks:ke) + + logical, intent (out) :: no_fall + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + no_fall = .true. + + do k = ks, ke + if (q (k) .gt. qfmin) then + no_fall = .false. + exit + endif + enddo + +end subroutine check_column + +! ======================================================================= +! warm rain cloud microphysics +! ======================================================================= + +subroutine warm_rain (dts, ks, ke, dp, dz, tz, qv, ql, qr, qi, qs, qg, & + den, denfac, vtw, vtr, ccn, rh_rain, h_var, reevap) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts, rh_rain, h_var + + real, intent (in), dimension (ks:ke) :: dp, dz, den, denfac, vtw, vtr + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, ccn + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + real, intent (out) :: reevap + + ! ----------------------------------------------------------------------- + ! initialization + ! ----------------------------------------------------------------------- + + reevap = 0 + + ! ----------------------------------------------------------------------- + ! rain evaporation to form water vapor + ! ----------------------------------------------------------------------- + + call prevp (ks, ke, dts, tz, qv, ql, qr, qi, qs, qg, den, denfac, rh_rain, h_var, dp, reevap) + + ! ----------------------------------------------------------------------- + ! rain accretion with cloud water + ! ----------------------------------------------------------------------- + + call pracw (ks, ke, dts, tz, qv, ql, qr, qi, qs, qg, den, denfac, vtw, vtr) + + ! ----------------------------------------------------------------------- + ! cloud water to rain autoconversion + ! ----------------------------------------------------------------------- + + call praut (ks, ke, dts, tz, qv, ql, qr, qi, qs, qg, den, ccn, h_var) + +end subroutine warm_rain + +! ======================================================================= +! rain evaporation to form water vapor, Lin et al. (1983) +! ======================================================================= + +subroutine prevp (ks, ke, dts, tz, qv, ql, qr, qi, qs, qg, den, denfac, rh_rain, h_var, dp, reevap) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts, rh_rain, h_var + + real, intent (in), dimension (ks:ke) :: den, denfac, dp + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + real, intent (inout), dimension (ks:ke) :: qv, qr, ql, qi, qs, qg + + real, intent (out) :: reevap + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: dqv, qsat, dqdt, tmp, t2, qden, q_plus, q_minus, sink + real :: qpz, dq, dqh, tin, fac_revp, rh_tem + + real, dimension (ks:ke) :: q_liq, q_sol, lcpk, icpk, tcpk, tcp3 + + real (kind = r8), dimension (ks:ke) :: cvm, te8 + + ! ----------------------------------------------------------------------- + ! initialization + ! ----------------------------------------------------------------------- + + reevap = 0 + + ! ----------------------------------------------------------------------- + ! time-scale factor + ! ----------------------------------------------------------------------- + + fac_revp = 1. + if (tau_revp .gt. 1.e-6) then + fac_revp = 1. - exp (- dts / tau_revp) + endif + + ! ----------------------------------------------------------------------- + ! calculate heat capacities and latent heat coefficients + ! ----------------------------------------------------------------------- + + call cal_mhc_lhc (ks, ke, qv, ql, qr, qi, qs, qg, q_liq, q_sol, cvm, te8, tz, & + lcpk, icpk, tcpk, tcp3) + + do k = ks, ke + + tin = (tz (k) * cvm (k) - lv00 * ql (k)) / mhc (qv (k) + ql (k), qr (k), q_sol (k)) + + ! ----------------------------------------------------------------------- + ! calculate supersaturation and subgrid variability of water + ! ----------------------------------------------------------------------- + + qpz = qv (k) + ql (k) + qsat = wqs (tin, den (k), dqdt) + dqv = qsat - qv (k) + + dqh = max (ql (k), h_var * max (qpz, qcmin)) + dqh = min (dqh, 0.2 * qpz) + q_minus = qpz - dqh + q_plus = qpz + dqh + + ! ----------------------------------------------------------------------- + ! rain evaporation + ! ----------------------------------------------------------------------- + + rh_tem = qpz / qsat + + if (tz (k) .gt. t_wfr .and. qr (k) .gt. qcmin .and. dqv .gt. 0.0 .and. qsat .gt. q_minus) then + + if (qsat .gt. q_plus) then + dq = qsat - qpz + else + dq = 0.25 * (qsat - q_minus) ** 2 / dqh + endif + qden = qr (k) * den (k) + t2 = tin * tin + sink = psub (t2, dq, qden, qsat, crevp, den (k), denfac (k), blinr, mur, lcpk (k), cvm (k)) + sink = min (qr (k), dts * fac_revp * sink, dqv / (1. + lcpk (k) * dqdt)) + if (use_rhc_revap .and. rh_tem .ge. rhc_revap) then + sink = 0.0 + endif + + ! ----------------------------------------------------------------------- + ! alternative minimum evaporation in dry environmental air + ! ----------------------------------------------------------------------- + ! tmp = min (qr (k), dim (rh_rain * qsat, qv (k)) / (1. + lcpk (k) * dqdt)) + ! sink = max (sink, tmp) + + reevap = reevap + sink * dp (k) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + sink, 0., - sink, 0., 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo ! k loop + +end subroutine prevp + +! ======================================================================= +! rain accretion with cloud water, Lin et al. (1983) +! ======================================================================= + +subroutine pracw (ks, ke, dts, tz, qv, ql, qr, qi, qs, qg, den, denfac, vtw, vtr) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, denfac, vtw, vtr + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + real, intent (inout), dimension (ks:ke) :: qv, qr, ql, qi, qs, qg + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: qden, sink + + do k = ks, ke + + if (tz (k) .gt. t_wfr .and. qr (k) .gt. qcmin .and. ql (k) .gt. qcmin) then + + qden = qr (k) * den (k) + if (do_new_acc_water) then + sink = dts * acr3d (vtr (k), vtw (k), ql (k), qr (k), cracw, acco (:, 5), & + acc (9), acc (10), den (k)) + else + sink = dts * acr2d (qden, cracw, denfac (k), blinr, mur) + sink = sink / (1. + sink) * ql (k) + endif + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, sink, 0., 0., 0.) + + endif + + enddo + +end subroutine pracw + +! ======================================================================= +! cloud water to rain autoconversion, Hong et al. (2004) +! ======================================================================= + +subroutine praut (ks, ke, dts, tz, qv, ql, qr, qi, qs, qg, den, ccn, h_var) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts, h_var + + real, intent (in), dimension (ks:ke) :: den + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, ccn + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real, parameter :: so3 = 7.0 / 3.0 + real, parameter :: so1 = - 1.0 / 3.0 + + integer :: k + + real :: sink, dq, qc + + real, dimension (ks:ke) :: dl, c_praut + + if (irain_f .eq. 0) then + + call linear_prof (ke - ks + 1, ql (ks), dl (ks), z_slope_liq, h_var) + + do k = ks, ke + + if (tz (k) .gt. t_wfr .and. ql (k) .gt. qcmin) then + + if (do_psd_water_num) then + call cal_pc_ed_oe_rr_tv (ql (k), den (k), blinw, muw, & + pca = pcaw, pcb = pcbw, pc = ccn (k)) + ccn (k) = ccn (k) / den (k) + endif + + qc = fac_rc * ccn (k) + dl (k) = min (max (qcmin, dl (k)), 0.5 * ql (k)) + dq = 0.5 * (ql (k) + dl (k) - qc) + + if (dq .gt. 0.) then + + c_praut (k) = cpaut * exp (so1 * log (ccn (k) * rhow)) + sink = min (1., dq / dl (k)) * dts * c_praut (k) * den (k) * & + exp (so3 * log (ql (k))) + sink = min (ql (k), sink) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, sink, 0., 0., 0.) + + endif + + endif + + enddo + + endif + + if (irain_f .eq. 1) then + + do k = ks, ke + + if (tz (k) .gt. t_wfr .and. ql (k) .gt. qcmin) then + + if (do_psd_water_num) then + call cal_pc_ed_oe_rr_tv (ql (k), den (k), blinw, muw, & + pca = pcaw, pcb = pcbw, pc = ccn (k)) + ccn (k) = ccn (k) / den (k) + endif + + qc = fac_rc * ccn (k) + dq = ql (k) - qc + + if (dq .gt. 0.) then + + c_praut (k) = cpaut * exp (so1 * log (ccn (k) * rhow)) + sink = min (dq, dts * c_praut (k) * den (k) * exp (so3 * log (ql (k)))) + sink = min (ql (k), sink) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, sink, 0., 0., 0.) + + endif + + endif + + enddo + + endif + +end subroutine praut + +! ======================================================================= +! ice cloud microphysics +! ======================================================================= + +subroutine ice_cloud (ks, ke, tz, qv, ql, qr, qi, qs, qg, den, & + denfac, vtw, vtr, vti, vts, vtg, dts, h_var) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts, h_var + + real, intent (in), dimension (ks:ke) :: den, denfac, vtw, vtr, vti, vts, vtg + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real, dimension (ks:ke) :: di, q_liq, q_sol, lcpk, icpk, tcpk, tcp3 + + real (kind = r8), dimension (ks:ke) :: cvm, te8 + + ! ----------------------------------------------------------------------- + ! calculate heat capacities and latent heat coefficients + ! ----------------------------------------------------------------------- + + call cal_mhc_lhc (ks, ke, qv, ql, qr, qi, qs, qg, q_liq, q_sol, cvm, te8, tz, & + lcpk, icpk, tcpk, tcp3) + + if (.not. do_warm_rain_mp) then + + ! ----------------------------------------------------------------------- + ! cloud ice melting to form cloud water and rain + ! ----------------------------------------------------------------------- + + call pimlt (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! cloud water freezing to form cloud ice and snow + ! ----------------------------------------------------------------------- + + call pifr (ks, ke, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! vertical subgrid variability + ! ----------------------------------------------------------------------- + + call linear_prof (ke - ks + 1, qi, di, z_slope_ice, h_var) + + ! ----------------------------------------------------------------------- + ! snow melting (includes snow accretion with cloud water and rain) to form cloud water and rain + ! ----------------------------------------------------------------------- + + call psmlt (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, denfac, & + vtw, vtr, vts, lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! graupel melting (includes graupel accretion with cloud water and rain) to form rain + ! ----------------------------------------------------------------------- + + call pgmlt (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, denfac, & + vtw, vtr, vtg, lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! snow accretion with cloud ice + ! ----------------------------------------------------------------------- + + call psaci (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den, denfac, vti, vts) + + ! ----------------------------------------------------------------------- + ! cloud ice to snow autoconversion + ! ----------------------------------------------------------------------- + + call psaut (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den, di) + + ! ----------------------------------------------------------------------- + ! graupel accretion with cloud ice + ! ----------------------------------------------------------------------- + + call pgaci (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den, denfac, vti, vtg) + + ! ----------------------------------------------------------------------- + ! snow accretion with rain and rain freezing to form graupel + ! ----------------------------------------------------------------------- + + call psacr_pgfr (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, denfac, & + vtr, vts, lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! graupel accretion with snow + ! ----------------------------------------------------------------------- + + call pgacs (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den, vts, vtg) + + ! ----------------------------------------------------------------------- + ! snow to graupel autoconversion + ! ----------------------------------------------------------------------- + + call pgaut (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den) + + ! ----------------------------------------------------------------------- + ! graupel accretion with cloud water and rain + ! ----------------------------------------------------------------------- + + call pgacw_pgacr (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, denfac, & + vtr, vtg, lcpk, icpk, tcpk, tcp3) + + endif ! do_warm_rain_mp + +end subroutine ice_cloud + +! ======================================================================= +! cloud ice melting to form cloud water and rain, Lin et al. (1983) +! ======================================================================= + +subroutine pimlt (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, tmp, sink, fac_imlt + + fac_imlt = 1. - exp (- dts / tau_imlt) + + do k = ks, ke + + tc = tz (k) - tice_mlt + + if (tc .gt. 0 .and. qi (k) .gt. qcmin) then + + sink = fac_imlt * tc / icpk (k) + sink = min (qi (k), sink) + tmp = min (sink, dim (ql_mlt, ql (k))) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., tmp, sink - tmp, - sink, 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pimlt + +! ======================================================================= +! cloud water freezing to form cloud ice and snow, Lin et al. (1983) +! ======================================================================= + +subroutine pifr (ks, ke, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in), dimension (ks:ke) :: den + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, tmp, sink, qim + + do k = ks, ke + + tc = t_wfr - tz (k) + + if (tc .gt. 0. .and. ql (k) .gt. qcmin) then + + sink = ql (k) * tc / dt_fr + sink = min (ql (k), sink, tc / icpk (k)) + qim = qi0_crt / den (k) + tmp = min (sink, dim (qim, qi (k))) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, 0., tmp, sink - tmp, 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pifr + +! ======================================================================= +! snow melting (includes snow accretion with cloud water and rain) to form cloud water and rain +! Lin et al. (1983) +! ======================================================================= + +subroutine psmlt (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, denfac, & + vtw, vtr, vts, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, denfac, vtw, vtr, vts + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, factor, tmp, sink, qden, dqdt, tin, dq, qsi + real :: psacw, psacr, pracs + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .ge. 0. .and. qs (k) .gt. qcmin) then + + psacw = 0. + qden = qs (k) * den (k) + if (ql (k) .gt. qcmin) then + if (do_new_acc_water) then + psacw = acr3d (vts (k), vtw (k), ql (k), qs (k), csacw, acco (:, 7), & + acc (13), acc (14), den (k)) + else + factor = acr2d (qden, csacw, denfac (k), blins, mus) + psacw = factor / (1. + dts * factor) * ql (k) + endif + endif + + psacr = 0. + pracs = 0. + if (qr (k) .gt. qcmin) then + psacr = min (acr3d (vts (k), vtr (k), qr (k), qs (k), csacr, acco (:, 2), & + acc (3), acc (4), den (k)), qr (k) / dts) + pracs = acr3d (vtr (k), vts (k), qs (k), qr (k), cracs, acco (:, 1), & + acc (1), acc (2), den (k)) + endif + + tin = tz (k) + qsi = iqs (tin, den (k), dqdt) + dq = qsi - qv (k) + sink = max (0., pmlt (tc, dq, qden, psacw, psacr, csmlt, den (k), denfac (k), blins, mus, & + lcpk (k), icpk (k), cvm (k))) + + sink = min (qs (k), (sink + pracs) * dts, tc / icpk (k)) + tmp = min (sink, dim (qs_mlt, ql (k))) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., tmp, sink - tmp, 0., - sink, 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine psmlt + +! ======================================================================= +! graupel melting (includes graupel accretion with cloud water and rain) to form rain +! Lin et al. (1983) +! ======================================================================= + +subroutine pgmlt (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, denfac, & + vtw, vtr, vtg, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, denfac, vtw, vtr, vtg + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, factor, sink, qden, dqdt, tin, dq, qsi + real :: pgacw, pgacr + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .ge. 0. .and. qg (k) .gt. qcmin) then + + pgacw = 0. + qden = qg (k) * den (k) + if (ql (k) .gt. qcmin) then + if (do_new_acc_water) then + pgacw = acr3d (vtg (k), vtw (k), ql (k), qg (k), cgacw, acco (:, 9), & + acc (17), acc (18), den (k)) + else + if (do_hail) then + factor = acr2d (qden, cgacw, denfac (k), blinh, muh) + else + factor = acr2d (qden, cgacw, denfac (k), bling, mug) + endif + pgacw = factor / (1. + dts * factor) * ql (k) + endif + endif + + pgacr = 0. + if (qr (k) .gt. qcmin) then + pgacr = min (acr3d (vtg (k), vtr (k), qr (k), qg (k), cgacr, acco (:, 3), & + acc (5), acc (6), den (k)), qr (k) / dts) + endif + + tin = tz (k) + qsi = iqs (tin, den (k), dqdt) + dq = qsi - qv (k) + if (do_hail) then + sink = max (0., pmlt (tc, dq, qden, pgacw, pgacr, cgmlt, den (k), denfac (k), & + blinh, muh, lcpk (k), icpk (k), cvm (k))) + else + sink = max (0., pmlt (tc, dq, qden, pgacw, pgacr, cgmlt, den (k), denfac (k), & + bling, mug, lcpk (k), icpk (k), cvm (k))) + endif + + sink = min (qg (k), sink * dts, tc / icpk (k)) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., sink, 0., 0., - sink, te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pgmlt + +! ======================================================================= +! snow accretion with cloud ice, Lin et al. (1983) +! ======================================================================= + +subroutine psaci (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den, denfac, vti, vts) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, denfac, vti, vts + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, factor, sink, qden + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .lt. 0. .and. qi (k) .gt. qcmin) then + + sink = 0. + qden = qs (k) * den (k) + if (qs (k) .gt. qcmin) then + if (do_new_acc_ice) then + sink = dts * acr3d (vts (k), vti (k), qi (k), qs (k), csaci, acco (:, 8), & + acc (15), acc (16), den (k)) + else + factor = dts * acr2d (qden, csaci, denfac (k), blins, mus) + sink = factor / (1. + factor) * qi (k) + endif + endif + + sink = min (fi2s_fac * qi (k), sink) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., 0., - sink, sink, 0.) + + endif + + enddo + +end subroutine psaci + +! ======================================================================= +! cloud ice to snow autoconversion, Lin et al. (1983) +! ======================================================================= + +subroutine psaut (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den, di) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, di + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, sink, fac_i2s, q_plus, qim, dq, tmp + + fac_i2s = 1. - exp (- dts / tau_i2s) + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .lt. 0. .and. qi (k) .gt. qcmin) then + + sink = 0. + tmp = fac_i2s * exp (0.025 * tc) + di (k) = max (di (k), qcmin) + q_plus = qi (k) + di (k) + qim = qi0_crt / den (k) + if (q_plus .gt. (qim + qcmin)) then + if (qim .gt. (qi (k) - di (k))) then + dq = (0.25 * (q_plus - qim) ** 2) / di (k) + else + dq = qi (k) - qim + endif + sink = tmp * dq + endif + + sink = min (fi2s_fac * qi (k), sink) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., 0., - sink, sink, 0.) + + endif + + enddo + +end subroutine psaut + +! ======================================================================= +! graupel accretion with cloud ice, Lin et al. (1983) +! ======================================================================= + +subroutine pgaci (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den, denfac, vti, vtg) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, denfac, vti, vtg + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, factor, sink, qden + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .lt. 0. .and. qi (k) .gt. qcmin) then + + sink = 0. + qden = qg (k) * den (k) + if (qg (k) .gt. qcmin) then + if (do_new_acc_ice) then + sink = dts * acr3d (vtg (k), vti (k), qi (k), qg (k), cgaci, acco (:, 10), & + acc (19), acc (20), den (k)) + else + if (do_hail) then + factor = dts * acr2d (qden, cgaci, denfac (k), blinh, muh) + else + factor = dts * acr2d (qden, cgaci, denfac (k), bling, mug) + endif + sink = factor / (1. + factor) * qi (k) + endif + endif + + sink = min (fi2g_fac * qi (k), sink) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., 0., - sink, 0., sink) + + endif + + enddo + +end subroutine pgaci + +! ======================================================================= +! snow accretion with rain and rain freezing to form graupel, Lin et al. (1983) +! ======================================================================= + +subroutine psacr_pgfr (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, denfac, & + vtr, vts, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, denfac, vtr, vts + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, factor, sink + real :: psacr, pgfr + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .lt. 0. .and. qr (k) .gt. qcmin) then + + psacr = 0. + if (qs (k) .gt. qcmin) then + psacr = dts * acr3d (vts (k), vtr (k), qr (k), qs (k), csacr, acco (:, 2), & + acc (3), acc (4), den (k)) + endif + + pgfr = dts * cgfr (1) / den (k) * (exp (- cgfr (2) * tc) - 1.) * & + exp ((6 + mur) / (mur + 3) * log (6 * qr (k) * den (k))) + + sink = psacr + pgfr + factor = min (sink, qr (k), - tc / icpk (k)) / max (sink, qcmin) + psacr = factor * psacr + pgfr = factor * pgfr + + sink = min (qr (k), psacr + pgfr) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., - sink, 0., psacr, pgfr, te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine psacr_pgfr + +! ======================================================================= +! graupel accretion with snow, Lin et al. (1983) +! ======================================================================= + +subroutine pgacs (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den, vts, vtg) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, vts, vtg + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: sink + + do k = ks, ke + + if (tz (k) .lt. tice .and. qs (k) .gt. qcmin .and. qg (k) .gt. qcmin) then + + sink = dts * acr3d (vtg (k), vts (k), qs (k), qg (k), cgacs, acco (:, 4), & + acc (7), acc (8), den (k)) + sink = min (fs2g_fac * qs (k), sink) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., 0., 0., - sink, sink) + + endif + + enddo + +end subroutine pgacs + +! ======================================================================= +! snow to graupel autoconversion, Lin et al. (1983) +! ======================================================================= + +subroutine pgaut (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, factor, sink, qsm + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .lt. 0. .and. qs (k) .gt. qcmin) then + + sink = 0 + qsm = qs0_crt / den (k) + if (qs (k) .gt. qsm) then + factor = dts * 1.e-3 * exp (0.09 * (tz (k) - tice)) + sink = factor / (1. + factor) * (qs (k) - qsm) + endif + + sink = min (fs2g_fac * qs (k), sink) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., 0., 0., - sink, sink) + + endif + + enddo + +end subroutine pgaut + +! ======================================================================= +! graupel accretion with cloud water and rain, Lin et al. (1983) +! ======================================================================= + +subroutine pgacw_pgacr (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, denfac, & + vtr, vtg, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, denfac, vtr, vtg + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, factor, sink, qden + real :: pgacw, pgacr + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .lt. 0. .and. qg (k) .gt. qcmin) then + + pgacw = 0. + if (ql (k) .gt. qcmin) then + qden = qg (k) * den (k) + if (do_hail) then + factor = dts * acr2d (qden, cgacw, denfac (k), blinh, muh) + else + factor = dts * acr2d (qden, cgacw, denfac (k), bling, mug) + endif + pgacw = factor / (1. + factor) * ql (k) + endif + + pgacr = 0. + if (qr (k) .gt. qcmin) then + pgacr = min (dts * acr3d (vtg (k), vtr (k), qr (k), qg (k), cgacr, acco (:, 3), & + acc (5), acc (6), den (k)), qr (k)) + endif + + sink = pgacr + pgacw + factor = min (sink, dim (tice, tz (k)) / icpk (k)) / max (sink, qcmin) + pgacr = factor * pgacr + pgacw = factor * pgacw + + sink = pgacr + pgacw + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - pgacw, - pgacr, 0., 0., sink, te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pgacw_pgacr + +! ======================================================================= +! temperature sentive high vertical resolution processes +! ======================================================================= + +subroutine subgrid_z_proc (ks, ke, den, denfac, dts, rh_adj, tz, qv, ql, qr, & + qi, qs, qg, dp, ccn, cin, cond, dep, reevap, sub, last_step) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + logical, intent (in) :: last_step + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts, rh_adj + + real, intent (in), dimension (ks:ke) :: den, denfac, dp + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, ccn, cin + + real, intent (out) :: cond, dep, reevap, sub + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + logical :: cond_evap + + integer :: n + + real, dimension (ks:ke) :: q_liq, q_sol, q_cond, lcpk, icpk, tcpk, tcp3 + + real (kind = r8), dimension (ks:ke) :: cvm, te8 + + ! ----------------------------------------------------------------------- + ! initialization + ! ----------------------------------------------------------------------- + + cond = 0 + dep = 0 + reevap = 0 + sub = 0 + + ! ----------------------------------------------------------------------- + ! calculate heat capacities and latent heat coefficients + ! ----------------------------------------------------------------------- + + call cal_mhc_lhc (ks, ke, qv, ql, qr, qi, qs, qg, q_liq, q_sol, cvm, te8, tz, & + lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! instant processes (include deposition, evaporation, and sublimation) + ! ----------------------------------------------------------------------- + + if (.not. do_warm_rain_mp) then + + call pinst (ks, ke, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3, rh_adj, dep, sub, reevap) + + endif + + ! ----------------------------------------------------------------------- + ! cloud water condensation and evaporation + ! ----------------------------------------------------------------------- + + if (delay_cond_evap) then + cond_evap = last_step + else + cond_evap = .true. + endif + + if (cond_evap) then + do n = 1, nconds + call pcond_pevap (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3, cond, reevap) + enddo + endif + + if (.not. do_warm_rain_mp) then + + ! ----------------------------------------------------------------------- + ! enforce complete freezing below t_wfr + ! ----------------------------------------------------------------------- + + call pcomp (ks, ke, qv, ql, qr, qi, qs, qg, tz, cvm, te8, lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! Wegener Bergeron Findeisen process + ! ----------------------------------------------------------------------- + + call pwbf (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! Bigg freezing mechanism + ! ----------------------------------------------------------------------- + + call pbigg (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, ccn, lcpk, icpk, tcpk, tcp3) + + ! ----------------------------------------------------------------------- + ! cloud ice deposition and sublimation + ! ----------------------------------------------------------------------- + + call pidep_pisub (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3, cin, dep, sub) + + ! ----------------------------------------------------------------------- + ! snow deposition and sublimation + ! ----------------------------------------------------------------------- + + call psdep_pssub (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + denfac, lcpk, icpk, tcpk, tcp3, dep, sub) + + ! ----------------------------------------------------------------------- + ! graupel deposition and sublimation + ! ----------------------------------------------------------------------- + + call pgdep_pgsub (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + denfac, lcpk, icpk, tcpk, tcp3, dep, sub) + + endif + +end subroutine subgrid_z_proc + +! ======================================================================= +! instant processes (include deposition, evaporation, and sublimation) +! ======================================================================= + +subroutine pinst (ks, ke, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3, rh_adj, dep, sub, reevap) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: rh_adj + + real, intent (in), dimension (ks:ke) :: den, dp + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + real, intent (out) :: dep, reevap, sub + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: sink, tin, qpz, rh, dqdt, tmp, qsi + + do k = ks, ke + + ! ----------------------------------------------------------------------- + ! instant deposit all water vapor to cloud ice when temperature is super low + ! ----------------------------------------------------------------------- + + if (tz (k) .lt. t_min) then + + sink = dim (qv (k), qcmin) + dep = dep + sink * dp (k) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + - sink, 0., 0., sink, 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + ! ----------------------------------------------------------------------- + ! instant evaporation / sublimation of all clouds when rh < rh_adj + ! ----------------------------------------------------------------------- + + qpz = qv (k) + ql (k) + qi (k) + tin = (te8 (k) - lv00 * qpz + li00 * (qs (k) + qg (k))) / & + mhc (qpz, qr (k), qs (k) + qg (k)) + + if (tin .gt. t_sub + 6.) then + + qsi = iqs (tin, den (k), dqdt) + rh = qpz / qsi + if (rh .lt. rh_adj) then + + sink = ql (k) + tmp = qi (k) + + reevap = reevap + sink * dp (k) + sub = sub + tmp * dp (k) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + sink + tmp, - sink, 0., - tmp, 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + endif + + enddo + +end subroutine pinst + +! ======================================================================= +! cloud water condensation and evaporation, Hong and Lim (2006) +! ======================================================================= + +subroutine pcond_pevap (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3, cond, reevap) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, dp + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + real, intent (out) :: cond, reevap + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: sink, tin, qpz, dqdt, qsw, rh_tem, dq, factor, fac_l2v, fac_v2l + + fac_l2v = 1. - exp (- dts / tau_l2v) + fac_v2l = 1. - exp (- dts / tau_v2l) + + do k = ks, ke + + tin = tz (k) + qsw = wqs (tin, den (k), dqdt) + qpz = qv (k) + ql (k) + qi (k) + rh_tem = qpz / qsw + dq = qsw - qv (k) + if (dq .gt. 0.) then + if (do_evap_timescale) then + factor = min (1., fac_l2v * (rh_fac_evap * dq / qsw)) + else + factor = 1. + endif + sink = min (ql (k), factor * dq / (1. + tcp3 (k) * dqdt)) + if (use_rhc_cevap .and. rh_tem .ge. rhc_cevap) then + sink = 0. + endif + reevap = reevap + sink * dp (k) + else + if (do_cond_timescale) then + factor = min (1., fac_v2l * (rh_fac_cond * (- dq) / qsw)) + else + factor = 1. + endif + sink = - min (qv (k), factor * (- dq) / (1. + tcp3 (k) * dqdt)) + cond = cond - sink * dp (k) + endif + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + sink, - sink, 0., 0., 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + enddo + +end subroutine pcond_pevap + +! ======================================================================= +! enforce complete freezing below t_wfr, Lin et al. (1983) +! ======================================================================= + +subroutine pcomp (ks, ke, qv, ql, qr, qi, qs, qg, tz, cvm, te8, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, sink + + do k = ks, ke + + tc = t_wfr - tz (k) + + if (tc .gt. 0. .and. ql (k) .gt. qcmin) then + + sink = ql (k) * tc / dt_fr + sink = min (ql (k), sink, tc / icpk (k)) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, 0., sink, 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pcomp + +! ======================================================================= +! Wegener Bergeron Findeisen process, Storelvmo and Tan (2015) +! ======================================================================= + +subroutine pwbf (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, tin, sink, dqdt, qsw, qsi, qim, tmp, fac_wbf + + if (.not. do_wbf) return + + fac_wbf = 1. - exp (- dts / tau_wbf) + + do k = ks, ke + + tc = tice - tz (k) + + tin = tz (k) + qsw = wqs (tin, den (k), dqdt) + qsi = iqs (tin, den (k), dqdt) + + if (tc .gt. 0. .and. ql (k) .gt. qcmin .and. qi (k) .gt. qcmin .and. & + qv (k) .gt. qsi .and. qv (k) .lt. qsw) then + + sink = min (fac_wbf * ql (k), tc / icpk (k)) + qim = qi0_crt / den (k) + tmp = min (sink, dim (qim, qi (k))) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, 0., tmp, sink - tmp, 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pwbf + +! ======================================================================= +! Bigg freezing mechanism, Bigg (1953) +! ======================================================================= + +subroutine pbigg (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, den, ccn, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, ccn + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: sink, tc + + do k = ks, ke + + tc = tice - tz (k) + + if (tc .gt. 0 .and. ql (k) .gt. qcmin) then + + if (do_psd_water_num) then + call cal_pc_ed_oe_rr_tv (ql (k), den (k), blinw, muw, & + pca = pcaw, pcb = pcbw, pc = ccn (k)) + ccn (k) = ccn (k) / den (k) + endif + + sink = 100. / (rhow * ccn (k)) * dts * (exp (0.66 * tc) - 1.) * ql (k) ** 2 + sink = min (ql (k), sink, tc / icpk (k)) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, 0., sink, 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pbigg + +! ======================================================================= +! cloud ice deposition and sublimation, Hong et al. (2004) +! ======================================================================= + +subroutine pidep_pisub (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + lcpk, icpk, tcpk, tcp3, cin, dep, sub) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, dp + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, cin + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + real, intent (out) :: dep, sub + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: sink, tin, dqdt, qsi, dq, pidep, tmp, tc, qi_gen, qi_crt + + do k = ks, ke + + if (tz (k) .lt. tice) then + + pidep = 0. + tin = tz (k) + qsi = iqs (tin, den (k), dqdt) + dq = qv (k) - qsi + tmp = dq / (1. + tcpk (k) * dqdt) + + if (qi (k) .gt. qcmin) then + +!rsun added for ice number associated with prog_ccn + cin (k) = 5.38e7 * exp (0.75 * log (qi (k) * den (k))) + + if (.not. prog_ccn) then + if (inflag .eq. 1) & + cin (k) = 5.38e7 * exp (0.75 * log (qi (k) * den (k))) + if (inflag .eq. 2) & + cin (k) = exp (- 2.80 + 0.262 * (tice - tz (k))) * 1000.0 + if (inflag .eq. 3) & + cin (k) = exp (- 0.639 + 12.96 * (qv (k) / qsi - 1.0)) * 1000.0 + if (inflag .eq. 4) & + cin (k) = 5.e-3 * exp (0.304 * (tice - tz (k))) * 1000.0 + if (inflag .eq. 5) & + cin (k) = 1.e-5 * exp (0.5 * (tice - tz (k))) * 1000.0 + endif + if (do_psd_ice_num) then + call cal_pc_ed_oe_rr_tv (qi (k), den (k), blini, mui, & + pca = pcai, pcb = pcbi, pc = cin (k)) + cin (k) = cin (k) / den (k) + endif + pidep = dts * dq * 4.0 * 11.9 * exp (0.5 * log (qi (k) * den (k) * cin (k))) / & + (qsi * den (k) * (tcpk (k) * cvm (k)) ** 2 / (tcond * rvgas * tz (k) ** 2) + & + 1. / vdifu) + endif + + if (dq .gt. 0.) then + tc = tice - tz (k) + qi_gen = 4.92e-11 * exp (1.33 * log (1.e3 * exp (0.1 * tc))) + if (igflag .eq. 1) & + qi_crt = qi_gen / den (k) + if (igflag .eq. 2) & + qi_crt = qi_gen * min (qi_lim, 0.1 * tc) / den (k) + if (igflag .eq. 3) & + qi_crt = 1.82e-6 * min (qi_lim, 0.1 * tc) / den (k) + if (igflag .eq. 4) & + qi_crt = max (qi_gen, 1.82e-6) * min (qi_lim, 0.1 * tc) / den (k) + sink = min (tmp, max (qi_crt - qi (k), pidep), tc / tcpk (k)) + dep = dep + sink * dp (k) + else + pidep = pidep * min (1., dim (tz (k), t_sub) * is_fac) + sink = max (pidep, tmp, - qi (k)) + sub = sub - sink * dp (k) + endif + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + - sink, 0., 0., sink, 0., 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pidep_pisub + +! ======================================================================= +! snow deposition and sublimation, Lin et al. (1983) +! ======================================================================= + +subroutine psdep_pssub (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + denfac, lcpk, icpk, tcpk, tcp3, dep, sub) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, dp, denfac + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + real, intent (out) :: dep, sub + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: sink, tin, dqdt, qsi, qden, t2, dq, pssub + + do k = ks, ke + + if (qs (k) .gt. qcmin) then + + tin = tz (k) + qsi = iqs (tin, den (k), dqdt) + qden = qs (k) * den (k) + t2 = tz (k) * tz (k) + dq = qsi - qv (k) + pssub = psub (t2, dq, qden, qsi, cssub, den (k), denfac (k), blins, mus, tcpk (k), cvm (k)) + pssub = dts * pssub + dq = dq / (1. + tcpk (k) * dqdt) + if (pssub .gt. 0.) then + sink = min (pssub * min (1., dim (tz (k), t_sub) * ss_fac), qs (k)) + sub = sub + sink * dp (k) + else + sink = 0. + if (tz (k) .le. tice) then + sink = max (pssub, dq, (tz (k) - tice) / tcpk (k)) + endif + dep = dep - sink * dp (k) + endif + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + sink, 0., 0., 0., - sink, 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine psdep_pssub + +! ======================================================================= +! graupel deposition and sublimation, Lin et al. (1983) +! ======================================================================= + +subroutine pgdep_pgsub (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, den, & + denfac, lcpk, icpk, tcpk, tcp3, dep, sub) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den, dp, denfac + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + real, intent (out) :: dep, sub + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: sink, tin, dqdt, qsi, qden, t2, dq, pgsub + + do k = ks, ke + + if (qg (k) .gt. qcmin) then + + tin = tz (k) + qsi = iqs (tin, den (k), dqdt) + qden = qg (k) * den (k) + t2 = tz (k) * tz (k) + dq = qsi - qv (k) + if (do_hail) then + pgsub = psub (t2, dq, qden, qsi, cgsub, den (k), denfac (k), & + blinh, muh, tcpk (k), cvm (k)) + else + pgsub = psub (t2, dq, qden, qsi, cgsub, den (k), denfac (k), & + bling, mug, tcpk (k), cvm (k)) + endif + pgsub = dts * pgsub + dq = dq / (1. + tcpk (k) * dqdt) + if (pgsub .gt. 0.) then + sink = min (pgsub * min (1., dim (tz (k), t_sub) * gs_fac), qg (k)) + sub = sub + sink * dp (k) + else + sink = 0. + if (tz (k) .le. tice) then + sink = max (pgsub, dq, (tz (k) - tice) / tcpk (k)) + endif + dep = dep - sink * dp (k) + endif + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + sink, 0., 0., 0., 0., - sink, te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pgdep_pgsub + +! ======================================================================= +! cloud fraction diagnostic +! ======================================================================= + +subroutine cloud_fraction (ks, ke, pz, den, qv, ql, qr, qi, qs, qg, qa, tz, h_var, gsize) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: h_var, gsize + + real, intent (in), dimension (ks:ke) :: pz, den + + real (kind = r8), intent (in), dimension (ks:ke) :: tz + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, qa + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: q_plus, q_minus + real :: rh, rqi, tin, qsw, qsi, qpz, qstar, sigma, gam + real :: dqdt, dq, liq, ice + real :: qa10, qa100 + + real, dimension (ks:ke) :: q_liq, q_sol, q_cond, lcpk, icpk, tcpk, tcp3 + + real (kind = r8), dimension (ks:ke) :: cvm, te8 + + ! ----------------------------------------------------------------------- + ! calculate heat capacities and latent heat coefficients + ! ----------------------------------------------------------------------- + + call cal_mhc_lhc (ks, ke, qv, ql, qr, qi, qs, qg, q_liq, q_sol, cvm, te8, tz, & + lcpk, icpk, tcpk, tcp3) + + do k = ks, ke + + ! combine water species + + ice = q_sol (k) + q_sol (k) = qi (k) + if (rad_snow) then + q_sol (k) = qi (k) + qs (k) + if (rad_graupel) then + q_sol (k) = qi (k) + qs (k) + qg (k) + endif + endif + + liq = q_liq (k) + q_liq (k) = ql (k) + if (rad_rain) then + q_liq (k) = ql (k) + qr (k) + endif + + q_cond (k) = q_liq (k) + q_sol (k) + qpz = qv (k) + q_cond (k) + + ! use the "liquid - frozen water temperature" (tin) to compute saturated specific humidity + + ice = ice - q_sol (k) + liq = liq - q_liq (k) + tin = (te8 (k) - lv00 * qpz + li00 * ice) / mhc (qpz, liq, ice) + + ! calculate saturated specific humidity + + if (tin .le. t_wfr) then + qstar = iqs (tin, den (k), dqdt) + elseif (tin .ge. tice) then + qstar = wqs (tin, den (k), dqdt) + else + qsi = iqs (tin, den (k), dqdt) + qsw = wqs (tin, den (k), dqdt) + if (q_cond (k) .gt. qcmin) then + rqi = q_sol (k) / q_cond (k) + else + rqi = (tice - tin) / (tice - t_wfr) + endif + qstar = rqi * qsi + (1. - rqi) * qsw + endif + + ! cloud schemes + + rh = qpz / qstar + + if (cfflag .eq. 1) then + if (rh .gt. rh_thres .and. qpz .gt. qcmin) then + + dq = h_var * qpz + if (do_cld_adj) then + q_plus = qpz + dq * f_dq_p * min (1.0, max (0.0, (pz (k) - 200.e2) / & + (1000.e2 - 200.e2))) + else + q_plus = qpz + dq * f_dq_p + endif + q_minus = qpz - dq * f_dq_m + + if (icloud_f .eq. 2) then + if (qstar .lt. qpz) then + qa (k) = 1. + else + qa (k) = 0. + endif + elseif (icloud_f .eq. 3) then + if (qstar .lt. qpz) then + qa (k) = 1. + else + if (qstar .lt. q_plus) then + qa (k) = (q_plus - qstar) / (dq * f_dq_p) + else + qa (k) = 0. + endif + if (q_cond (k) .gt. qcmin) then + qa (k) = max (cld_min, qa (k)) + endif + qa (k) = min (1., qa (k)) + endif + else + if (qstar .lt. q_minus) then + qa (k) = 1. + else + if (qstar .lt. q_plus) then + if (icloud_f .eq. 0) then + qa (k) = (q_plus - qstar) / (dq * f_dq_p + dq * f_dq_m) + else + qa (k) = (q_plus - qstar) / ((dq * f_dq_p + dq * f_dq_m) * & + (1. - q_cond (k))) + endif + else + qa (k) = 0. + endif + if (q_cond (k) .gt. qcmin) then + qa (k) = max (cld_min, qa (k)) + endif + qa (k) = min (1., qa (k)) + endif + endif + else + qa (k) = 0. + endif + endif + + if (cfflag .eq. 2) then + if (rh .ge. 1.0) then + qa (k) = 1.0 + elseif (rh .gt. rh_thres .and. q_cond (k) .gt. qcmin) then + qa (k) = exp (xr_a * log (rh)) * (1.0 - exp (- xr_b * max (0.0, q_cond (k)) / & + max (1.e-5, exp (xr_c * log (max (1.e-10, 1.0 - rh) * qstar))))) + qa (k) = max (0.0, min (1., qa (k))) + else + qa (k) = 0.0 + endif + endif + + if (cfflag .eq. 3) then + if (q_cond (k) .gt. qcmin) then + qa (k) = 1. / 50. * (5.77 * (100. - gsize / 1000.) * & + exp (1.07 * log (max (qcmin * 1000., q_cond (k) * 1000.))) + & + 4.82 * (gsize / 1000. - 50.) * & + exp (0.94 * log (max (qcmin * 1000., q_cond (k) * 1000.)))) + qa (k) = qa (k) * (0.92 / 0.96 * q_liq (k) / q_cond (k) + & + 1.0 / 0.96 * q_sol (k) / q_cond (k)) + qa (k) = max (0.0, min (1., qa (k))) + else + qa (k) = 0.0 + endif + endif + + if (cfflag .eq. 4) then + sigma = 0.28 + exp (0.49 * log (max (qcmin * 1000., q_cond (k) * 1000.))) + gam = max (0.0, q_cond (k) * 1000.) / sigma + if (gam .lt. 0.18) then + qa10 = 0. + elseif (gam .gt. 2.0) then + qa10 = 1.0 + else + qa10 = - 0.1754 + 0.9811 * gam - 0.2223 * gam ** 2 + 0.0104 * gam ** 3 + qa10 = max (0.0, min (1., qa10)) + endif + if (gam .lt. 0.12) then + qa100 = 0. + elseif (gam .gt. 1.85) then + qa100 = 1.0 + else + qa100 = - 0.0913 + 0.7213 * gam + 0.1060 * gam ** 2 - 0.0946 * gam ** 3 + qa100 = max (0.0, min (1., qa100)) + endif + qa (k) = qa10 + (log10 (gsize / 1000.) - 1) * (qa100 - qa10) + qa (k) = max (0.0, min (1., qa (k))) + endif + + enddo + +end subroutine cloud_fraction + +! ======================================================================= +! piecewise parabolic lagrangian scheme +! this subroutine is the same as map1_q2 in fv_mapz_mod. +! ======================================================================= + +subroutine lagrangian_fall (ks, ke, zs, ze, zt, dp, q, precip, m1) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: zs + + real, intent (in), dimension (ks:ke + 1) :: ze, zt + + real, intent (in), dimension (ks:ke) :: dp + + real, intent (inout), dimension (ks:ke) :: q + + real, intent (inout) :: precip + + real, intent (out), dimension (ks:ke) :: m1 + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k, k0, n, m + + real :: a4 (4, ks:ke), pl, pr, delz, esl + + real, parameter :: r3 = 1. / 3., r23 = 2. / 3. + + real, dimension (ks:ke) :: qm, dz + + ! ----------------------------------------------------------------------- + ! density: + ! ----------------------------------------------------------------------- + + do k = ks, ke + dz (k) = zt (k) - zt (k + 1) + q (k) = q (k) * dp (k) + a4 (1, k) = q (k) / dz (k) + qm (k) = 0. + enddo + + ! ----------------------------------------------------------------------- + ! construct vertical profile with zt as coordinate + ! ----------------------------------------------------------------------- + + call cs_profile (a4 (1, ks), dz (ks), ke - ks + 1) + + k0 = ks + do k = ks, ke + do n = k0, ke + if (ze (k) .le. zt (n) .and. ze (k) .ge. zt (n + 1)) then + pl = (zt (n) - ze (k)) / dz (n) + if (zt (n + 1) .le. ze (k + 1)) then + ! entire new grid is within the original grid + pr = (zt (n) - ze (k + 1)) / dz (n) + qm (k) = a4 (2, n) + 0.5 * (a4 (4, n) + a4 (3, n) - a4 (2, n)) * (pr + pl) - & + a4 (4, n) * r3 * (pr * (pr + pl) + pl ** 2) + qm (k) = qm (k) * (ze (k) - ze (k + 1)) + k0 = n + goto 555 + else + qm (k) = (ze (k) - zt (n + 1)) * (a4 (2, n) + 0.5 * (a4 (4, n) + & + a4 (3, n) - a4 (2, n)) * (1. + pl) - a4 (4, n) * (r3 * (1. + pl * (1. + pl)))) + if (n .lt. ke) then + do m = n + 1, ke + ! locate the bottom edge: ze (k + 1) + if (ze (k + 1) .lt. zt (m + 1)) then + qm (k) = qm (k) + q (m) + else + delz = zt (m) - ze (k + 1) + esl = delz / dz (m) + qm (k) = qm (k) + delz * (a4 (2, m) + 0.5 * esl * & + (a4 (3, m) - a4 (2, m) + a4 (4, m) * (1. - r23 * esl))) + k0 = m + goto 555 + endif + enddo + endif + goto 555 + endif + endif + enddo + 555 continue + enddo + + m1 (ks) = q (ks) - qm (ks) + do k = ks + 1, ke + m1 (k) = m1 (k - 1) + q (k) - qm (k) + enddo + precip = precip + m1 (ke) + + ! ----------------------------------------------------------------------- + ! convert back to * dry * mixing ratio: + ! dp must be dry air_mass (because moist air mass will be changed due to terminal fall) . + ! ----------------------------------------------------------------------- + + do k = ks, ke + q (k) = qm (k) / dp (k) + enddo + +end subroutine lagrangian_fall + +! ======================================================================= +! vertical profile reconstruction +! this subroutine is the same as cs_profile in fv_mapz_mod where iv = 0 and kord = 9 +! ======================================================================= + +subroutine cs_profile (a4, del, km) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: km + + real, intent (in) :: del (km) + + real, intent (inout) :: a4 (4, km) + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + logical :: extm (km) + + real :: gam (km), q (km + 1), d4, bet, a_bot, grat, pmp, lac + real :: pmp_1, lac_1, pmp_2, lac_2, da1, da2, a6da + + grat = del (2) / del (1) ! grid ratio + bet = grat * (grat + 0.5) + q (1) = (2. * grat * (grat + 1.) * a4 (1, 1) + a4 (1, 2)) / bet + gam (1) = (1. + grat * (grat + 1.5)) / bet + + do k = 2, km + d4 = del (k - 1) / del (k) + bet = 2. + 2. * d4 - gam (k - 1) + q (k) = (3. * (a4 (1, k - 1) + d4 * a4 (1, k)) - q (k - 1)) / bet + gam (k) = d4 / bet + enddo + + a_bot = 1. + d4 * (d4 + 1.5) + q (km + 1) = (2. * d4 * (d4 + 1.) * a4 (1, km) + a4 (1, km - 1) - a_bot * q (km)) & + / (d4 * (d4 + 0.5) - a_bot * gam (km)) + + do k = km, 1, - 1 + q (k) = q (k) - gam (k) * q (k + 1) + enddo + + ! ----------------------------------------------------------------------- + ! apply constraints + ! ----------------------------------------------------------------------- + + do k = 2, km + gam (k) = a4 (1, k) - a4 (1, k - 1) + enddo + + ! ----------------------------------------------------------------------- + ! top: + ! ----------------------------------------------------------------------- + + q (1) = max (q (1), 0.) + q (2) = min (q (2), max (a4 (1, 1), a4 (1, 2))) + q (2) = max (q (2), min (a4 (1, 1), a4 (1, 2)), 0.) + + ! ----------------------------------------------------------------------- + ! interior: + ! ----------------------------------------------------------------------- + + do k = 3, km - 1 + if (gam (k - 1) * gam (k + 1) .gt. 0.) then + ! apply large - scale constraints to all fields if not local max / min + q (k) = min (q (k), max (a4 (1, k - 1), a4 (1, k))) + q (k) = max (q (k), min (a4 (1, k - 1), a4 (1, k))) + else + if (gam (k - 1) .gt. 0.) then + ! there exists a local max + q (k) = max (q (k), min (a4 (1, k - 1), a4 (1, k))) + else + ! there exists a local min + q (k) = min (q (k), max (a4 (1, k - 1), a4 (1, k))) + ! positive-definite + q (k) = max (q (k), 0.0) + endif + endif + enddo + + ! ----------------------------------------------------------------------- + ! bottom: + ! ----------------------------------------------------------------------- + + q (km) = min (q (km), max (a4 (1, km - 1), a4 (1, km))) + q (km) = max (q (km), min (a4 (1, km - 1), a4 (1, km)), 0.) + q (km + 1) = max (q (km + 1), 0.) + + do k = 1, km + a4 (2, k) = q (k) + a4 (3, k) = q (k + 1) + enddo + + do k = 1, km + if (k .eq. 1 .or. k .eq. km) then + extm (k) = (a4 (2, k) - a4 (1, k)) * (a4 (3, k) - a4 (1, k)) .gt. 0. + else + extm (k) = gam (k) * gam (k + 1) .lt. 0. + endif + enddo + + ! ----------------------------------------------------------------------- + ! apply constraints + ! f (s) = al + s * [ (ar - al) + a6 * (1 - s) ] (0 <= s <= 1) + ! always use monotonic mapping + ! ----------------------------------------------------------------------- + + ! ----------------------------------------------------------------------- + ! top: + ! ----------------------------------------------------------------------- + + a4 (2, 1) = max (0., a4 (2, 1)) + + ! ----------------------------------------------------------------------- + ! Huynh's 2nd constraint for interior: + ! ----------------------------------------------------------------------- + + do k = 3, km - 2 + if (extm (k)) then + ! positive definite constraint only if true local extrema + if (a4 (1, k) .lt. qcmin .or. extm (k - 1) .or. extm (k + 1)) then + a4 (2, k) = a4 (1, k) + a4 (3, k) = a4 (1, k) + endif + else + a4 (4, k) = 6. * a4 (1, k) - 3. * (a4 (2, k) + a4 (3, k)) + if (abs (a4 (4, k)) .gt. abs (a4 (2, k) - a4 (3, k))) then + ! check within the smooth region if subgrid profile is non - monotonic + pmp_1 = a4 (1, k) - 2.0 * gam (k + 1) + lac_1 = pmp_1 + 1.5 * gam (k + 2) + a4 (2, k) = min (max (a4 (2, k), min (a4 (1, k), pmp_1, lac_1)), & + max (a4 (1, k), pmp_1, lac_1)) + pmp_2 = a4 (1, k) + 2.0 * gam (k) + lac_2 = pmp_2 - 1.5 * gam (k - 1) + a4 (3, k) = min (max (a4 (3, k), min (a4 (1, k), pmp_2, lac_2)), & + max (a4 (1, k), pmp_2, lac_2)) + endif + endif + enddo + + do k = 1, km - 1 + a4 (4, k) = 6. * a4 (1, k) - 3. * (a4 (2, k) + a4 (3, k)) + enddo + + k = km - 1 + if (extm (k)) then + a4 (2, k) = a4 (1, k) + a4 (3, k) = a4 (1, k) + a4 (4, k) = 0. + else + da1 = a4 (3, k) - a4 (2, k) + da2 = da1 ** 2 + a6da = a4 (4, k) * da1 + if (a6da .lt. - da2) then + a4 (4, k) = 3. * (a4 (2, k) - a4 (1, k)) + a4 (3, k) = a4 (2, k) - a4 (4, k) + elseif (a6da .gt. da2) then + a4 (4, k) = 3. * (a4 (3, k) - a4 (1, k)) + a4 (2, k) = a4 (3, k) - a4 (4, k) + endif + endif + + call cs_limiters (km - 1, a4) + + ! ----------------------------------------------------------------------- + ! bottom: + ! ----------------------------------------------------------------------- + + a4 (2, km) = a4 (1, km) + a4 (3, km) = a4 (1, km) + a4 (4, km) = 0. + +end subroutine cs_profile + +! ======================================================================= +! cubic spline (cs) limiters or boundary conditions +! a positive-definite constraint (iv = 0) is applied to tracers in every layer, +! adjusting the top-most and bottom-most interface values to enforce positive. +! this subroutine is the same as cs_limiters in fv_mapz_mod where iv = 0. +! ======================================================================= + +subroutine cs_limiters (km, a4) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: km + + real, intent (inout) :: a4 (4, km) ! ppm array + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real, parameter :: r12 = 1. / 12. + + do k = 1, km + if (a4 (1, k) .le. 0.) then + a4 (2, k) = a4 (1, k) + a4 (3, k) = a4 (1, k) + a4 (4, k) = 0. + else + if (abs (a4 (3, k) - a4 (2, k)) .lt. - a4 (4, k)) then + if ((a4 (1, k) + 0.25 * (a4 (3, k) - a4 (2, k)) ** 2 / a4 (4, k) + & + a4 (4, k) * r12) .lt. 0.) then + ! local minimum is negative + if (a4 (1, k) .lt. a4 (3, k) .and. a4 (1, k) .lt. a4 (2, k)) then + a4 (3, k) = a4 (1, k) + a4 (2, k) = a4 (1, k) + a4 (4, k) = 0. + elseif (a4 (3, k) .gt. a4 (2, k)) then + a4 (4, k) = 3. * (a4 (2, k) - a4 (1, k)) + a4 (3, k) = a4 (2, k) - a4 (4, k) + else + a4 (4, k) = 3. * (a4 (3, k) - a4 (1, k)) + a4 (2, k) = a4 (3, k) - a4 (4, k) + endif + endif + endif + endif + enddo + +end subroutine cs_limiters + +! ======================================================================= +! time-implicit monotonic scheme +! ======================================================================= + +subroutine implicit_fall (dts, ks, ke, ze, vt, dp, q, precip, m1) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke + 1) :: ze + + real, intent (in), dimension (ks:ke) :: vt, dp + + real, intent (inout), dimension (ks:ke) :: q + + real, intent (inout) :: precip + + real, intent (out), dimension (ks:ke) :: m1 + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real, dimension (ks:ke) :: dz, qm, dd + + do k = ks, ke + dz (k) = ze (k) - ze (k + 1) + dd (k) = dts * vt (k) + q (k) = q (k) * dp (k) + enddo + + qm (ks) = q (ks) / (dz (ks) + dd (ks)) + do k = ks + 1, ke + qm (k) = (q (k) + qm (k - 1) * dd (k - 1)) / (dz (k) + dd (k)) + enddo + + do k = ks, ke + qm (k) = qm (k) * dz (k) + enddo + + m1 (ks) = q (ks) - qm (ks) + do k = ks + 1, ke + m1 (k) = m1 (k - 1) + q (k) - qm (k) + enddo + precip = precip + m1 (ke) + + do k = ks, ke + q (k) = qm (k) / dp (k) + enddo + +end subroutine implicit_fall + +! ======================================================================= +! time-explicit monotonic scheme +! ======================================================================= + +subroutine explicit_fall (dts, ks, ke, ze, vt, dp, q, precip, m1) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke + 1) :: ze + + real, intent (in), dimension (ks:ke) :: vt, dp + + real, intent (inout), dimension (ks:ke) :: q + + real, intent (inout) :: precip + + real, intent (out), dimension (ks:ke) :: m1 + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: n, k, nstep + + real, dimension (ks:ke) :: dz, qm, q0, dd + + do k = ks, ke + dz (k) = ze (k) - ze (k + 1) + dd (k) = dts * vt (k) + q0 (k) = q (k) * dp (k) + enddo + + nstep = 1 + int (maxval (dd / dz)) + do k = ks, ke + dd (k) = dd (k) / nstep + q (k) = q0 (k) + enddo + + do n = 1, nstep + qm (ks) = q (ks) - q (ks) * dd (ks) / dz (ks) + do k = ks + 1, ke + qm (k) = q (k) - q (k) * dd (k) / dz (k) + q (k - 1) * dd (k - 1) / dz (k - 1) + enddo + q = qm + enddo + + m1 (ks) = q0 (ks) - qm (ks) + do k = ks + 1, ke + m1 (k) = m1 (k - 1) + q0 (k) - qm (k) + enddo + precip = precip + m1 (ke) + + do k = ks, ke + q (k) = qm (k) / dp (k) + enddo + +end subroutine explicit_fall + +! ======================================================================= +! combine time-implicit monotonic scheme with the piecewise parabolic lagrangian scheme +! ======================================================================= + +subroutine implicit_lagrangian_fall (dts, ks, ke, zs, ze, zt, vt, dp, q, & + precip, flux, sed_fac) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: zs, dts, sed_fac + + real, intent (in), dimension (ks:ke + 1) :: ze, zt + + real, intent (in), dimension (ks:ke) :: vt, dp + + real, intent (inout), dimension (ks:ke) :: q + + real, intent (inout) :: precip + + real, intent (out), dimension (ks:ke) :: flux + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real :: pre0, pre1 + + real, dimension (ks:ke) :: q0, q1, m0, m1 + + q0 = q + pre0 = precip + + call implicit_fall (dts, ks, ke, ze, vt, dp, q0, pre0, m0) + + q1 = q + pre1 = precip + + call lagrangian_fall (ks, ke, zs, ze, zt, dp, q1, pre1, m1) + + q = q0 * sed_fac + q1 * (1.0 - sed_fac) + flux = m0 * sed_fac + m1 * (1.0 - sed_fac) + precip = pre0 * sed_fac + pre1 * (1.0 - sed_fac) + +end subroutine implicit_lagrangian_fall + +! ======================================================================= +! vertical subgrid variability used for cloud ice and cloud water autoconversion +! edges: qe == qbar + / - dm +! ======================================================================= + +subroutine linear_prof (km, q, dm, z_var, h_var) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: km + + logical, intent (in) :: z_var + + real, intent (in) :: q (km), h_var + + real, intent (out) :: dm (km) + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: dq (km) + + if (z_var) then + do k = 2, km + dq (k) = 0.5 * (q (k) - q (k - 1)) + enddo + dm (1) = 0. + ! ----------------------------------------------------------------------- + ! use twice the strength of the positive definiteness limiter (Lin et al. 1994) + ! ----------------------------------------------------------------------- + do k = 2, km - 1 + dm (k) = 0.5 * min (abs (dq (k) + dq (k + 1)), 0.5 * q (k)) + if (dq (k) * dq (k + 1) .le. 0.) then + if (dq (k) .gt. 0.) then + dm (k) = min (dm (k), dq (k), - dq (k + 1)) + else + dm (k) = 0. + endif + endif + enddo + dm (km) = 0. + ! ----------------------------------------------------------------------- + ! impose a presumed background horizontal variability that is proportional to the value itself + ! ----------------------------------------------------------------------- + do k = 1, km + dm (k) = max (dm (k), 0.0, h_var * q (k)) + enddo + else + do k = 1, km + dm (k) = max (0.0, h_var * q (k)) + enddo + endif + +end subroutine linear_prof + +! ======================================================================= +! accretion function, Lin et al. (1983) +! ======================================================================= + +function acr2d (qden, c, denfac, blin, mu) + + implicit none + + real :: acr2d + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: qden, c, denfac, blin, mu + + acr2d = denfac * c * exp ((2 + mu + blin) / (mu + 3) * log (6 * qden)) + +end function acr2d + +! ======================================================================= +! accretion function, Lin et al. (1983) +! ======================================================================= + +function acr3d (v1, v2, q1, q2, c, acco, acc1, acc2, den) + + implicit none + + real :: acr3d + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: v1, v2, c, den, q1, q2, acco (3), acc1, acc2 + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: i + + real :: t1, t2, tmp, vdiff + + t1 = exp (1. / (acc1 + 3) * log (6 * q1 * den)) + t2 = exp (1. / (acc2 + 3) * log (6 * q2 * den)) + + if (vdiffflag .eq. 1) vdiff = abs (v1 - v2) + if (vdiffflag .eq. 2) vdiff = sqrt ((1.20 * v1 - 0.95 * v2) ** 2. + 0.08 * v1 * v2) + if (vdiffflag .eq. 3) vdiff = sqrt ((1.00 * v1 - 1.00 * v2) ** 2. + 0.04 * v1 * v2) + + acr3d = c * vdiff / den + + tmp = 0 + do i = 1, 3 + tmp = tmp + acco (i) * exp ((6 + acc1 - i) * log (t1)) * exp ((acc2 + i - 1) * log (t2)) + enddo + + acr3d = acr3d * tmp + +end function acr3d + +! ======================================================================= +! ventilation coefficient, Lin et al. (1983) +! ======================================================================= + +function vent_coeff (qden, c1, c2, denfac, blin, mu) + + implicit none + + real :: vent_coeff + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: qden, c1, c2, denfac, blin, mu + + vent_coeff = c1 + c2 * exp ((3 + 2 * mu + blin) / (mu + 3) / 2 * log (6 * qden)) * & + sqrt (denfac) / exp ((1 + mu) / (mu + 3) * log (6 * qden)) + +end function vent_coeff + +! ======================================================================= +! sublimation or evaporation function, Lin et al. (1983) +! ======================================================================= + +function psub (t2, dq, qden, qsat, c, den, denfac, blin, mu, cpk, cvm) + + implicit none + + real :: psub + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: t2, dq, qden, qsat, c (5), den, denfac, blin, cpk, mu + + real (kind = r8), intent (in) :: cvm + + psub = c (1) * t2 * dq * exp ((1 + mu) / (mu + 3) * log (6 * qden)) * & + vent_coeff (qden, c (2), c (3), denfac, blin, mu) / & + (c (4) * t2 + c (5) * (cpk * cvm) ** 2 * qsat * den) + +end function psub + +! ======================================================================= +! melting function, Lin et al. (1983) +! ======================================================================= + +function pmlt (tc, dq, qden, pxacw, pxacr, c, den, denfac, blin, mu, lcpk, icpk, cvm) + + implicit none + + real :: pmlt + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tc, dq, qden, pxacw, pxacr, c (4), den, denfac, blin, lcpk, icpk, mu + + real (kind = r8), intent (in) :: cvm + + pmlt = (c (1) / (icpk * cvm) * tc / den - c (2) * lcpk / icpk * dq) * & + exp ((1 + mu) / (mu + 3) * log (6 * qden)) * & + vent_coeff (qden, c (3), c (4), denfac, blin, mu) + & + c_liq / (icpk * cvm) * tc * (pxacw + pxacr) + +end function pmlt + +! ======================================================================= +! sedimentation of horizontal momentum +! ======================================================================= + +subroutine sedi_uv (ks, ke, m1, dp, u, v) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in), dimension (ks:ke) :: m1, dp + + real, intent (inout), dimension (ks:ke) :: u, v + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + do k = ks + 1, ke + u (k) = (dp (k) * u (k) + m1 (k - 1) * u (k - 1)) / (dp (k) + m1 (k - 1)) + v (k) = (dp (k) * v (k) + m1 (k - 1) * v (k - 1)) / (dp (k) + m1 (k - 1)) + enddo + +end subroutine sedi_uv + +! ======================================================================= +! sedimentation of vertical momentum +! ======================================================================= + +subroutine sedi_w (ks, ke, m1, w, vt, dm) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in), dimension (ks:ke) :: m1, vt, dm + + real, intent (inout), dimension (ks:ke) :: w + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + w (ks) = w (ks) + m1 (ks) * vt (ks) / dm (ks) + do k = ks + 1, ke + w (k) = (dm (k) * w (k) + m1 (k - 1) * (w (k - 1) - vt (k - 1)) + m1 (k) * vt (k)) / & + (dm (k) + m1 (k - 1)) + enddo + +end subroutine sedi_w + +! ======================================================================= +! sedimentation of heat +! ======================================================================= + +subroutine sedi_heat (ks, ke, dm, m1, dz, tz, qv, ql, qr, qi, qs, qg, cw) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: cw + + real, intent (in), dimension (ks:ke) :: dm, m1, dz, qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real, dimension (ks:ke) :: dgz, cv0 + + do k = ks + 1, ke + dgz (k) = - 0.5 * grav * (dz (k - 1) + dz (k)) + cv0 (k) = dm (k) * (cv_air + qv (k) * cv_vap + (qr (k) + ql (k)) * c_liq + & + (qi (k) + qs (k) + qg (k)) * c_ice) + cw * (m1 (k) - m1 (k - 1)) + enddo + + do k = ks + 1, ke + tz (k) = (cv0 (k) * tz (k) + m1 (k - 1) * (cw * tz (k - 1) + dgz (k))) / & + (cv0 (k) + cw * m1 (k - 1)) + enddo + +end subroutine sedi_heat + +! ======================================================================= +! fast saturation adjustments +! ======================================================================= + +subroutine cld_sat_adj (dtm, is, ie, ks, ke, hydrostatic, consv_te, & + adj_vmr, te, dte, qv, ql, qr, qi, qs, qg, qa, qnl, qni, hs, delz, & + pt, delp, q_con, cappa, gsize, last_step, do_sat_adj) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: is, ie, ks, ke + + logical, intent (in) :: hydrostatic, last_step, consv_te, do_sat_adj + + real, intent (in) :: dtm + + real, intent (in), dimension (is:ie) :: hs, gsize + + real, intent (in), dimension (is:ie, ks:ke) :: qnl, qni + + real, intent (inout), dimension (is:ie, ks:ke) :: delp, delz, pt, te + real, intent (inout), dimension (is:ie, ks:ke) :: qv, ql, qr, qi, qs, qg, qa + + real, intent (inout), dimension (is:, ks:) :: q_con, cappa + + real, intent (out), dimension (is:ie, ks:ke) :: adj_vmr + + real (kind = r8), intent (out), dimension (is:ie) :: dte + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real, dimension (is:ie, ks:ke) :: ua, va, wa, prefluxw, prefluxr, prefluxi, prefluxs, prefluxg + + real, dimension (is:ie) :: water, rain, ice, snow, graupel + + ! ----------------------------------------------------------------------- + ! initialization + ! ----------------------------------------------------------------------- + + ua = 0.0 + va = 0.0 + wa = 0.0 + + water = 0.0 + rain = 0.0 + ice = 0.0 + snow = 0.0 + graupel = 0.0 + + prefluxw = 0.0 + prefluxr = 0.0 + prefluxi = 0.0 + prefluxs = 0.0 + prefluxg = 0.0 + + ! ----------------------------------------------------------------------- + ! major cloud microphysics driver + ! ----------------------------------------------------------------------- + + call mpdrv (hydrostatic, ua, va, wa, delp, pt, qv, ql, qr, qi, qs, qg, qa, & + qnl, qni, delz, is, ie, ks, ke, dtm, water, rain, ice, snow, graupel, & + gsize, hs, q_con, cappa, consv_te, adj_vmr, te, dte, prefluxw, prefluxr, & + prefluxi, prefluxs, prefluxg, last_step, .false., do_sat_adj, .false.) + +end subroutine cld_sat_adj + +! ======================================================================= +! rain freezing to form graupel, simple version +! ======================================================================= + +subroutine pgfr_simp (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, & + lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, sink, fac_r2g + + fac_r2g = 1. - exp (- dts / tau_r2g) + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .lt. 0. .and. qr (k) .gt. qcmin) then + + sink = (- tc * 0.025) ** 2 * qr (k) + sink = min (qr (k), sink, - fac_r2g * tc / icpk (k)) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., - sink, 0., 0., sink, te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine pgfr_simp + +! ======================================================================= +! snow melting to form cloud water and rain, simple version +! ======================================================================= + +subroutine psmlt_simp (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, cvm, te8, & + lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real (kind = r8), intent (in), dimension (ks:ke) :: te8 + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + real, intent (inout), dimension (ks:ke) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (inout), dimension (ks:ke) :: cvm, tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, tmp, sink, fac_smlt + + fac_smlt = 1. - exp (- dts / tau_smlt) + + do k = ks, ke + + tc = tz (k) - tice + + if (tc .ge. 0. .and. qs (k) .gt. qcmin) then + + sink = (tc * 0.1) ** 2 * qs (k) + sink = min (qs (k), sink, fac_smlt * tc / icpk (k)) + tmp = min (sink, dim (qs_mlt, ql (k))) + + call update_qt (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., tmp, sink - tmp, 0., - sink, 0., te8 (k), cvm (k), tz (k), & + lcpk (k), icpk (k), tcpk (k), tcp3 (k)) + + endif + + enddo + +end subroutine psmlt_simp + +! ======================================================================= +! cloud water to rain autoconversion, simple version +! ======================================================================= + +subroutine praut_simp (ks, ke, dts, tz, qv, ql, qr, qi, qs, qg) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, sink, fac_l2r + + fac_l2r = 1. - exp (- dts / tau_l2r) + + do k = ks, ke + + tc = tz (k) - t_wfr + + if (tc .gt. 0 .and. ql (k) .gt. ql0_max) then + + sink = fac_l2r * (ql (k) - ql0_max) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., - sink, sink, 0., 0., 0.) + + endif + + enddo + +end subroutine praut_simp + +! ======================================================================= +! cloud ice to snow autoconversion, simple version +! ======================================================================= + +subroutine psaut_simp (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, den) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in) :: dts + + real, intent (in), dimension (ks:ke) :: den + + real, intent (inout), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (inout), dimension (ks:ke) :: tz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: tc, sink, fac_i2s, qim + + fac_i2s = 1. - exp (- dts / tau_i2s) + + do k = ks, ke + + tc = tz (k) - tice + + qim = qi0_max / den (k) + + if (tc .lt. 0. .and. qi (k) .gt. qim) then + + sink = fac_i2s * (qi (k) - qim) + + call update_qq (qv (k), ql (k), qr (k), qi (k), qs (k), qg (k), & + 0., 0., 0., - sink, sink, 0.) + + endif + + enddo + +end subroutine psaut_simp + +! ======================================================================= +! cloud radii diagnosis built for gfdl cloud microphysics +! ======================================================================= + +subroutine cld_eff_rad (is, ie, ks, ke, lsm, p, delp, t, qv, qw, qi, qr, qs, qg, qa, & + rew, rei, rer, res, reg, snowd, cnvw, cnvi) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: is, ie, ks, ke + + real, intent (in), dimension (is:ie) :: lsm, snowd + + real, intent (in), dimension (is:ie, ks:ke) :: delp, t, p + real, intent (in), dimension (is:ie, ks:ke) :: qv, qw, qi, qr, qs, qg, qa + + real, intent (in), dimension (is:ie, ks:ke), optional :: cnvw, cnvi + + real, intent (inout), dimension (is:ie, ks:ke) :: rew, rei, rer, res, reg + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: i, k, ind + + real, dimension (is:ie, ks:ke) :: qcw, qci, qcr, qcs, qcg + real, dimension (is:ie, ks:ke) :: qmw, qmr, qmi, qms, qmg + + real :: dpg, rho, ccnw, mask, cor, tc, bw + real :: lambdaw, lambdar, lambdai, lambdas, lambdag, rei_fac + + real :: retab (138) = (/ & + 0.05000, 0.05000, 0.05000, 0.05000, 0.05000, 0.05000, & + 0.05500, 0.06000, 0.07000, 0.08000, 0.09000, 0.10000, & + 0.20000, 0.30000, 0.40000, 0.50000, 0.60000, 0.70000, & + 0.80000, 0.90000, 1.00000, 1.10000, 1.20000, 1.30000, & + 1.40000, 1.50000, 1.60000, 1.80000, 2.00000, 2.20000, & + 2.40000, 2.60000, 2.80000, 3.00000, 3.20000, 3.50000, & + 3.80000, 4.10000, 4.40000, 4.70000, 5.00000, 5.30000, & + 5.60000, 5.92779, 6.26422, 6.61973, 6.99539, 7.39234, & + 7.81177, 8.25496, 8.72323, 9.21800, 9.74075, 10.2930, & + 10.8765, 11.4929, 12.1440, 12.8317, 13.5581, 14.2319, & + 15.0351, 15.8799, 16.7674, 17.6986, 18.6744, 19.6955, & + 20.7623, 21.8757, 23.0364, 24.2452, 25.5034, 26.8125, & + 27.7895, 28.6450, 29.4167, 30.1088, 30.7306, 31.2943, & + 31.8151, 32.3077, 32.7870, 33.2657, 33.7540, 34.2601, & + 34.7892, 35.3442, 35.9255, 36.5316, 37.1602, 37.8078, & + 38.4720, 39.1508, 39.8442, 40.5552, 41.2912, 42.0635, & + 42.8876, 43.7863, 44.7853, 45.9170, 47.2165, 48.7221, & + 50.4710, 52.4980, 54.8315, 57.4898, 60.4785, 63.7898, & + 65.5604, 71.2885, 75.4113, 79.7368, 84.2351, 88.8833, & + 93.6658, 98.5739, 103.603, 108.752, 114.025, 119.424, & + 124.954, 130.630, 136.457, 142.446, 148.608, 154.956, & + 161.503, 168.262, 175.248, 182.473, 189.952, 197.699, & + 205.728, 214.055, 222.694, 231.661, 240.971, 250.639 /) + + qmw = qw + qmi = qi + qmr = qr + qms = qs + qmg = qg + + ! ----------------------------------------------------------------------- + ! merge convective cloud to total cloud + ! ----------------------------------------------------------------------- + + if (present (cnvw)) then + qmw = qmw + cnvw + endif + if (present (cnvi)) then + qmi = qmi + cnvi + endif + + ! ----------------------------------------------------------------------- + ! combine liquid and solid phases + ! ----------------------------------------------------------------------- + + if (liq_ice_combine) then + do i = is, ie + do k = ks, ke + qmw (i, k) = qmw (i, k) + qmr (i, k) + qmr (i, k) = 0.0 + qmi (i, k) = qmi (i, k) + qms (i, k) + qmg (i, k) + qms (i, k) = 0.0 + qmg (i, k) = 0.0 + enddo + enddo + endif + + ! ----------------------------------------------------------------------- + ! combine snow and graupel + ! ----------------------------------------------------------------------- + + if (snow_grauple_combine) then + do i = is, ie + do k = ks, ke + qms (i, k) = qms (i, k) + qmg (i, k) + qmg (i, k) = 0.0 + enddo + enddo + endif + + + !print*,'cld_eff_rad: radius option:',rewflag, reiflag, resflag, rerflag, regflag: 1 2 1 1 1 + !print*,'in cld_eff_rad:ccn_o, ccn_l:',ccn_o, ccn_l + + + do i = is, ie + + do k = ks, ke + + qmw (i, k) = max (qmw (i, k), qcmin) + qmi (i, k) = max (qmi (i, k), qcmin) + qmr (i, k) = max (qmr (i, k), qcmin) + qms (i, k) = max (qms (i, k), qcmin) + qmg (i, k) = max (qmg (i, k), qcmin) + + + mask = min (max (lsm (i), 0.0), 2.0) + + dpg = abs (delp (i, k)) / grav + rho = p (i, k) / (rdgas * t (i, k) * (1. + zvir * qv (i, k))) + + tc = t (i, k) - tice + + if (rewflag .eq. 1) then + + ! ----------------------------------------------------------------------- + ! cloud water (Martin et al. 1994) + ! ----------------------------------------------------------------------- + + if (prog_ccn) then + ! boucher and lohmann (1995) + ccnw = (1.0 - abs (mask - 1.0)) * & + (10. ** 2.24 * (qa (i, k) * rho * 1.e9) ** 0.257) + & + abs (mask - 1.0) * & + (10. ** 2.06 * (qa (i, k) * rho * 1.e9) ** 0.48) + else + ccnw = ccn_o * abs (mask - 1.0) + ccn_l * (1.0 - abs (mask - 1.0)) + endif + + if (qmw (i, k) .gt. qcmin) then + qcw (i, k) = dpg * qmw (i, k) * 1.0e3 + rew (i, k) = exp (1.0 / 3.0 * log ((3.0 * qmw (i, k) * rho) / & + (4.0 * pi * rhow * ccnw))) * 1.0e4 + rew (i, k) = max (rewmin, min (rewmax, rew (i, k))) + else + qcw (i, k) = 0.0 + rew (i, k) = rewmin + endif + + endif + + if (rewflag .eq. 2) then + + ! ----------------------------------------------------------------------- + ! cloud water (Martin et al. 1994, gfdl revision) + ! ----------------------------------------------------------------------- + + if (prog_ccn) then + ! boucher and lohmann (1995) + ccnw = (1.0 - abs (mask - 1.0)) * & + (10. ** 2.24 * (qa (i, k) * rho * 1.e9) ** 0.257) + & + abs (mask - 1.0) * & + (10. ** 2.06 * (qa (i, k) * rho * 1.e9) ** 0.48) + else + ccnw = 1.077 * ccn_o * abs (mask - 1.0) + 1.143 * ccn_l * (1.0 - abs (mask - 1.0)) + endif + + if (qmw (i, k) .gt. qcmin) then + qcw (i, k) = dpg * qmw (i, k) * 1.0e3 + rew (i, k) = exp (1.0 / 3.0 * log ((3.0 * qmw (i, k) * rho) / & + (4.0 * pi * rhow * ccnw))) * 1.0e4 + rew (i, k) = max (rewmin, min (rewmax, rew (i, k))) + else + qcw (i, k) = 0.0 + rew (i, k) = rewmin + endif + + endif + + if (rewflag .eq. 3) then + + ! ----------------------------------------------------------------------- + ! cloud water (Kiehl et al. 1994) + ! ----------------------------------------------------------------------- + + if (qmw (i, k) .gt. qcmin) then + qcw (i, k) = dpg * qmw (i, k) * 1.0e3 + rew (i, k) = 14.0 * abs (mask - 1.0) + & + (8.0 + (14.0 - 8.0) * min (1.0, max (0.0, - tc / 30.0))) * & + (1.0 - abs (mask - 1.0)) + rew (i, k) = rew (i, k) + (14.0 - rew (i, k)) * & + min (1.0, max (0.0, snowd (i) / 1000.0)) ! snowd is in mm + rew (i, k) = max (rewmin, min (rewmax, rew (i, k))) + else + qcw (i, k) = 0.0 + rew (i, k) = rewmin + endif + + endif + + if (rewflag .eq. 4) then + + ! ----------------------------------------------------------------------- + ! cloud water derived from PSD + ! ----------------------------------------------------------------------- + + if (qmw (i, k) .gt. qcmin) then + qcw (i, k) = dpg * qmw (i, k) * 1.0e3 + call cal_pc_ed_oe_rr_tv (qmw (i, k), rho, blinw, muw, & + eda = edaw, edb = edbw, ed = rew (i, k)) + rew (i, k) = rewfac * 0.5 * rew (i, k) * 1.0e6 + rew (i, k) = max (rewmin, min (rewmax, rew (i, k))) + else + qcw (i, k) = 0.0 + rew (i, k) = rewmin + endif + + endif + + if (reiflag .eq. 1) then + + ! ----------------------------------------------------------------------- + ! cloud ice (Heymsfield and Mcfarquhar 1996) + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qcmin) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + rei_fac = log (1.0e3 * qmi (i, k) * rho) + if (tc .lt. - 50) then + rei (i, k) = beta / 9.917 * exp (0.109 * rei_fac) * 1.0e3 + elseif (tc .lt. - 40) then + rei (i, k) = beta / 9.337 * exp (0.080 * rei_fac) * 1.0e3 + elseif (tc .lt. - 30) then + rei (i, k) = beta / 9.208 * exp (0.055 * rei_fac) * 1.0e3 + else + rei (i, k) = beta / 9.387 * exp (0.031 * rei_fac) * 1.0e3 + endif + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + if (reiflag .eq. 2) then + + ! ----------------------------------------------------------------------- + ! cloud ice (Donner et al. 1997) + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qcmin) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + if (tc .le. - 55) then + rei (i, k) = 15.41627 + elseif (tc .le. - 50) then + rei (i, k) = 16.60895 + elseif (tc .le. - 45) then + rei (i, k) = 32.89967 + elseif (tc .le. - 40) then + rei (i, k) = 35.29989 + elseif (tc .le. - 35) then + rei (i, k) = 55.65818 + elseif (tc .le. - 30) then + rei (i, k) = 85.19071 + elseif (tc .le. - 25) then + rei (i, k) = 72.35392 + else + rei (i, k) = 92.46298 + endif + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + if (reiflag .eq. 3) then + + ! ----------------------------------------------------------------------- + ! cloud ice (Fu 2007) + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qcmin) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + rei (i, k) = 47.05 + tc * (0.6624 + 0.001741 * tc) + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + if (reiflag .eq. 4) then + + ! ----------------------------------------------------------------------- + ! cloud ice (Kristjansson et al. 2000) + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qcmin) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + ind = min (max (int (t (i, k) - 136.0), 44), 138 - 1) + cor = t (i, k) - int (t (i, k)) + rei (i, k) = retab (ind) * (1. - cor) + retab (ind + 1) * cor + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + if (reiflag .eq. 5) then + + ! ----------------------------------------------------------------------- + ! cloud ice (Wyser 1998) + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qcmin) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + bw = - 2. + 1.e-3 * log10 (rho * qmi (i, k) / 50.e-3) * & + exp (1.5 * log (max (1.e-10, - tc))) + rei (i, k) = 377.4 + bw * (203.3 + bw * (37.91 + 2.3696 * bw)) + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + if (reiflag .eq. 6) then + + ! ----------------------------------------------------------------------- + ! cloud ice (Sun and Rikus 1999, Sun 2001) + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qcmin) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + rei_fac = log (1.0e3 * qmi (i, k) * rho) + rei (i, k) = 45.8966 * exp (0.2214 * rei_fac) + & + 0.7957 * exp (0.2535 * rei_fac) * (tc + 190.0) + rei (i, k) = (1.2351 + 0.0105 * tc) * rei (i, k) + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + if (reiflag .eq. 7) then + + ! ----------------------------------------------------------------------- + ! cloud ice derived from PSD + ! ----------------------------------------------------------------------- + + if (qmi (i, k) .gt. qcmin) then + qci (i, k) = dpg * qmi (i, k) * 1.0e3 + call cal_pc_ed_oe_rr_tv (qmi (i, k), rho, blini, mui, & + eda = edai, edb = edbi, ed = rei (i, k)) + rei (i, k) = reifac * 0.5 * rei (i, k) * 1.0e6 + rei (i, k) = max (reimin, min (reimax, rei (i, k))) + else + qci (i, k) = 0.0 + rei (i, k) = reimin + endif + + endif + + if (rerflag .eq. 1) then + + ! ----------------------------------------------------------------------- + ! rain derived from PSD + ! ----------------------------------------------------------------------- + + if (qmr (i, k) .gt. qcmin) then + qcr (i, k) = dpg * qmr (i, k) * 1.0e3 + call cal_pc_ed_oe_rr_tv (qmr (i, k), rho, blinr, mur, & + eda = edar, edb = edbr, ed = rer (i, k)) + rer (i, k) = 0.5 * rer (i, k) * 1.0e6 + rer (i, k) = max (rermin, min (rermax, rer (i, k))) + else + qcr (i, k) = 0.0 + rer (i, k) = rermin + endif + + endif + + if (resflag .eq. 1) then + + ! ----------------------------------------------------------------------- + ! snow derived from PSD + ! ----------------------------------------------------------------------- + + if (qms (i, k) .gt. qcmin) then + qcs (i, k) = dpg * qms (i, k) * 1.0e3 + call cal_pc_ed_oe_rr_tv (qms (i, k), rho, blins, mus, & + eda = edas, edb = edbs, ed = res (i, k)) + res (i, k) = 0.5 * res (i, k) * 1.0e6 + res (i, k) = max (resmin, min (resmax, res (i, k))) + else + qcs (i, k) = 0.0 + res (i, k) = resmin + endif + + endif + + if (regflag .eq. 1) then + + ! ----------------------------------------------------------------------- + ! graupel derived from PSD + ! ----------------------------------------------------------------------- + + if (qmg (i, k) .gt. qcmin) then + qcg (i, k) = dpg * qmg (i, k) * 1.0e3 + if (do_hail) then + call cal_pc_ed_oe_rr_tv (qmg (i, k), rho, blinh, muh, & + eda = edah, edb = edbh, ed = reg (i, k)) + else + call cal_pc_ed_oe_rr_tv (qmg (i, k), rho, bling, mug, & + eda = edag, edb = edbg, ed = reg (i, k)) + endif + reg (i, k) = 0.5 * reg (i, k) * 1.0e6 + reg (i, k) = max (regmin, min (regmax, reg (i, k))) + else + qcg (i, k) = 0.0 + reg (i, k) = regmin + endif + + endif + + enddo + + enddo + +end subroutine cld_eff_rad + +! ======================================================================= +! radar reflectivity +! ======================================================================= + +subroutine rad_ref (is, ie, js, je, qv, qr, qs, qg, pt, delp, & + delz, dbz, npz, hydrostatic, do_inline_mp, mp_top) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + logical, intent (in) :: hydrostatic, do_inline_mp + + integer, intent (in) :: is, ie, js, je + integer, intent (in) :: npz, mp_top + !integer, intent (in) :: sphum, liq_wat, ice_wat, rainwat, snowwat, graupel + + !real, intent (in) :: zvir + + real, intent (in), dimension (is:ie, js:je, npz) :: delz + + real, intent (in), dimension (is:ie, js:je, npz) :: pt, delp + + real, intent (in), dimension (is:ie, js:je, npz) :: qv, qr, qs, qg + + !real, intent (in), dimension (is:ie, npz + 1, js:je) :: peln + + !real, intent (out) :: allmax + + !real, intent (out), dimension (is:ie, js:je) :: maxdbz + + real, intent (out), dimension (is:ie, js:je, npz) :: dbz + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: i, j, k + + real, parameter :: alpha = 0.224, mp_const = 200 * exp (1.6 * log (3.6e6)) + + real (kind = r8) :: qden, z_e + real :: fac_r, fac_s, fac_g + real :: allmax + real, dimension (is:ie, js:je) :: maxdbz + + real, dimension (npz) :: den, denfac, qmr, qms, qmg, vtr, vts, vtg + + ! ----------------------------------------------------------------------- + ! return if the microphysics scheme doesn't include rain + ! ----------------------------------------------------------------------- + + !if (rainwat .lt. 1) return + + ! ----------------------------------------------------------------------- + ! initialization + ! ----------------------------------------------------------------------- + + dbz = - 20. + maxdbz = - 20. + allmax = - 20. + + ! ----------------------------------------------------------------------- + ! calculate radar reflectivity + ! ----------------------------------------------------------------------- + + do j = js, je + do i = is, ie + + ! ----------------------------------------------------------------------- + ! air density + ! ----------------------------------------------------------------------- + + do k = 1, npz + ! rsun: find more about this + !if (hydrostatic) then + ! den (k) = delp (i, j, k) / ((peln (i, k + 1, j) - peln (i, k, j)) * & + ! rdgas * pt (i, j, k) * (1. + zvir * qv (i, j, k))) + !else + ! den (k) = - delp (i, j, k) / (grav * delz (i, j, k)) + !endif + + den (k) = - delp (i, j, k) / (grav * delz (i, j, k)) + qmr (k) = max (qcmin, qr (i, j, k)) + qms (k) = max (qcmin, qs (i, j, k)) + qmg (k) = max (qcmin, qg (i, j, k)) + enddo + + do k = 1, npz + denfac (k) = sqrt (den (npz) / den (k)) + enddo + + ! ----------------------------------------------------------------------- + ! fall speed + ! ----------------------------------------------------------------------- + + if (radr_flag .eq. 3) then + call term_rsg (1, npz, qmr, den, denfac, vr_fac, blinr, & + mur, tvar, tvbr, vr_max, const_vr, vtr) + vtr = vtr / rhor + endif + + if (rads_flag .eq. 3) then + call term_rsg (1, npz, qms, den, denfac, vs_fac, blins, & + mus, tvas, tvbs, vs_max, const_vs, vts) + vts = vts / rhos + endif + + if (radg_flag .eq. 3) then + if (do_hail .and. .not. do_inline_mp) then + call term_rsg (1, npz, qmg, den, denfac, vg_fac, blinh, & + muh, tvah, tvbh, vg_max, const_vg, vtg) + vtg = vtg / rhoh + else + call term_rsg (1, npz, qmg, den, denfac, vg_fac, bling, & + mug, tvag, tvbg, vg_max, const_vg, vtg) + vtg = vtg / rhog + endif + endif + + ! ----------------------------------------------------------------------- + ! radar reflectivity + ! ----------------------------------------------------------------------- + + do k = mp_top + 1, npz + z_e = 0. + + !if (rainwat .gt. 0) then + qden = den (k) * qmr (k) + if (qmr (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qmr (k), den (k), blinr, mur, & + rra = rrar, rrb = rrbr, rr = fac_r) + else + fac_r = 0.0 + endif + if (radr_flag .eq. 1 .or. radr_flag .eq. 2) then + z_e = z_e + fac_r * 1.e18 + endif + if (radr_flag .eq. 3) then + z_e = z_e + mp_const * exp (1.6 * log (qden * vtr (k))) + endif + !endif + + !if (snowwat .gt. 0) then + qden = den (k) * qms (k) + if (qms (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qms (k), den (k), blins, mus, & + rra = rras, rrb = rrbs, rr = fac_s) + else + fac_s = 0.0 + endif + if (rads_flag .eq. 1) then + if (pt (i, j, k) .lt. tice) then + z_e = z_e + fac_s * 1.e18 * alpha * (rhos / rhor) ** 2 + else + z_e = z_e + fac_s * 1.e18 * alpha * (rhos / rhor) ** 2 / alpha + endif + endif + if (rads_flag .eq. 2) then + if (pt (i, j, k) .lt. tice) then + z_e = z_e + fac_s * 1.e18 * alpha * (rhos / rhoi) ** 2 + else + z_e = z_e + fac_s * 1.e18 + endif + endif + if (rads_flag .eq. 3) then + z_e = z_e + mp_const * exp (1.6 * log (qden * vts (k))) + endif + !endif + + !if (graupel .gt. 0) then + qden = den (k) * qmg (k) + if (do_hail .and. .not. do_inline_mp) then + if (qmg (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qmg (k), den (k), blinh, muh, & + rra = rrah, rrb = rrbh, rr = fac_g) + else + fac_g = 0.0 + endif + if (radg_flag .eq. 1) then + if (pt (i, j, k) .lt. tice) then + z_e = z_e + fac_g * 1.e18 * alpha * (rhoh / rhor) ** 2 + else + z_e = z_e + fac_g * 1.e18 * alpha * (rhoh / rhor) ** 2 / alpha + endif + endif + if (radg_flag .eq. 2) then + z_e = z_e + fac_g * 1.e18 + endif + else + if (qmg (k) .gt. qcmin) then + call cal_pc_ed_oe_rr_tv (qmg (k), den (k), bling, mug, & + rra = rrag, rrb = rrbg, rr = fac_g) + else + fac_g = 0.0 + endif + if (radg_flag .eq. 1) then + if (pt (i, j, k) .lt. tice) then + z_e = z_e + fac_g * 1.e18 * alpha * (rhog / rhor) ** 2 + else + z_e = z_e + fac_g * 1.e18 * alpha * (rhog / rhor) ** 2 / alpha + endif + endif + if (radg_flag .eq. 2) then + z_e = z_e + fac_g * 1.e18 + endif + endif + if (radg_flag .eq. 3) then + z_e = z_e + mp_const * exp (1.6 * log (qden * vtg (k))) + endif + !endif + + dbz (i, j, k) = 10. * log10 (max (0.01, z_e)) + enddo + + do k = mp_top + 1, npz + maxdbz (i, j) = max (dbz (i, j, k), maxdbz (i, j)) + enddo + + allmax = max (maxdbz (i, j), allmax) + + enddo + enddo + +end subroutine rad_ref + +! ======================================================================= +! moist heat capacity, 3 input variables +! ======================================================================= + +function mhc3 (qv, q_liq, q_sol) + + implicit none + + real (kind = r8) :: mhc3 + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: qv, q_liq, q_sol + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + mhc3 = one_r8 + qv * c1_vap + q_liq * c1_liq + q_sol * c1_ice + +end function mhc3 + +! ======================================================================= +! moist heat capacity, 4 input variables +! ======================================================================= + +function mhc4 (qd, qv, q_liq, q_sol) + + implicit none + + real (kind = r8) :: mhc4 + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: qv, q_liq, q_sol + + real (kind = r8), intent (in) :: qd + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + mhc4 = qd + qv * c1_vap + q_liq * c1_liq + q_sol * c1_ice + +end function mhc4 + +! ======================================================================= +! moist heat capacity, 6 input variables +! ======================================================================= + +function mhc6 (qv, ql, qr, qi, qs, qg) + + implicit none + + real (kind = r8) :: mhc6 + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: qv, ql, qr, qi, qs, qg + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real :: q_liq, q_sol + + q_liq = ql + qr + q_sol = qi + qs + qg + mhc6 = mhc (qv, q_liq, q_sol) + +end function mhc6 + +! ======================================================================= +! moist total energy +! ======================================================================= + +function mte (qv, ql, qr, qi, qs, qg, tk, dp, moist_q) + + implicit none + + real (kind = r8) :: mte + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + logical, intent (in) :: moist_q + + real, intent (in) :: qv, ql, qr, qi, qs, qg, dp + + real (kind = r8), intent (in) :: tk + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real :: q_liq, q_sol, q_cond + + real (kind = r8) :: cvm, con_r8 + + q_liq = ql + qr + q_sol = qi + qs + qg + q_cond = q_liq + q_sol + con_r8 = one_r8 - (qv + q_cond) + if (moist_q) then + cvm = mhc (con_r8, qv, q_liq, q_sol) + else + cvm = mhc (qv, q_liq, q_sol) + endif + mte = rgrav * cvm * c_air * tk * dp + +end function mte + +! ======================================================================= +! moist total energy and total water +! ======================================================================= + +subroutine mtetw (ks, ke, qv, ql, qr, qi, qs, qg, tz, ua, va, wa, delp, & + dte, vapor, water, rain, ice, snow, graupel, sen, stress, dts, & + te, tw, te_b, tw_b, moist_q, hydrostatic, te_loss) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + logical, intent (in) :: moist_q, hydrostatic + + real, intent (in) :: vapor, water, rain, ice, snow, graupel, dts, sen, stress + + real, intent (in), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg, ua, va, wa, delp + + real (kind = r8), intent (in) :: dte + + real (kind = r8), intent (in), dimension (ks:ke) :: tz + + real (kind = r8), intent (out) :: te_b, tw_b + + real (kind = r8), intent (out), optional :: te_loss + + real (kind = r8), intent (out), dimension (ks:ke) :: te, tw + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + real :: q_cond + + real (kind = r8) :: con_r8 + + real, dimension (ks:ke) :: q_liq, q_sol + + real (kind = r8), dimension (ks:ke) :: cvm + + do k = ks, ke + q_liq (k) = ql (k) + qr (k) + q_sol (k) = qi (k) + qs (k) + qg (k) + q_cond = q_liq (k) + q_sol (k) + con_r8 = one_r8 - (qv (k) + q_cond) + if (moist_q) then + cvm (k) = mhc (con_r8, qv (k), q_liq (k), q_sol (k)) + else + cvm (k) = mhc (qv (k), q_liq (k), q_sol (k)) + endif + te (k) = (cvm (k) * tz (k) + lv00 * qv (k) - li00 * q_sol (k)) * c_air + if (hydrostatic) then + te (k) = te (k) + 0.5 * (ua (k) ** 2 + va (k) ** 2) + else + te (k) = te (k) + 0.5 * (ua (k) ** 2 + va (k) ** 2 + wa (k) ** 2) + endif + te (k) = rgrav * te (k) * delp (k) + tw (k) = rgrav * (qv (k) + q_cond) * delp (k) + enddo + te_b = (dte + (lv00 * c_air * vapor - li00 * c_air * (ice + snow + graupel)) * dts / 86400 + sen * dts + stress * dts) + tw_b = (vapor + water + rain + ice + snow + graupel) * dts / 86400 + + if (present (te_loss)) then + ! total energy change due to sedimentation and its heating + te_loss = dte + endif + +end subroutine mtetw + +! ======================================================================= +! calculate heat capacities and latent heat coefficients +! ======================================================================= + +subroutine cal_mhc_lhc (ks, ke, qv, ql, qr, qi, qs, qg, q_liq, q_sol, & + cvm, te8, tz, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: ks, ke + + real, intent (in), dimension (ks:ke) :: qv, ql, qr, qi, qs, qg + + real (kind = r8), intent (in), dimension (ks:ke) :: tz + + real, intent (out), dimension (ks:ke) :: q_liq, q_sol, lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (out), dimension (ks:ke) :: cvm, te8 + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: k + + do k = ks, ke + q_liq (k) = ql (k) + qr (k) + q_sol (k) = qi (k) + qs (k) + qg (k) + cvm (k) = mhc (qv (k), q_liq (k), q_sol (k)) + te8 (k) = cvm (k) * tz (k) + lv00 * qv (k) - li00 * q_sol (k) + lcpk (k) = (lv00 + d1_vap * tz (k)) / cvm (k) + icpk (k) = (li00 + d1_ice * tz (k)) / cvm (k) + tcpk (k) = (li20 + (d1_vap + d1_ice) * tz (k)) / cvm (k) + tcp3 (k) = lcpk (k) + icpk (k) * min (1., dim (tice, tz (k)) / (tice - t_wfr)) + enddo + +end subroutine cal_mhc_lhc + +! ======================================================================= +! update hydrometeors +! ======================================================================= + +subroutine update_qq (qv, ql, qr, qi, qs, qg, dqv, dql, dqr, dqi, dqs, dqg) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: dqv, dql, dqr, dqi, dqs, dqg + + real, intent (inout) :: qv, ql, qr, qi, qs, qg + + qv = qv + dqv + ql = ql + dql + qr = qr + dqr + qi = qi + dqi + qs = qs + dqs + qg = qg + dqg + +end subroutine update_qq + +! ======================================================================= +! update hydrometeors and temperature +! ======================================================================= + +subroutine update_qt (qv, ql, qr, qi, qs, qg, dqv, dql, dqr, dqi, dqs, dqg, te8, & + cvm, tk, lcpk, icpk, tcpk, tcp3) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: dqv, dql, dqr, dqi, dqs, dqg + + real (kind = r8), intent (in) :: te8 + + real, intent (inout) :: qv, ql, qr, qi, qs, qg + + real, intent (out) :: lcpk, icpk, tcpk, tcp3 + + real (kind = r8), intent (out) :: cvm, tk + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + qv = qv + dqv + ql = ql + dql + qr = qr + dqr + qi = qi + dqi + qs = qs + dqs + qg = qg + dqg + + cvm = mhc (qv, ql, qr, qi, qs, qg) + tk = (te8 - lv00 * qv + li00 * (qi + qs + qg)) / cvm + + lcpk = (lv00 + d1_vap * tk) / cvm + icpk = (li00 + d1_ice * tk) / cvm + tcpk = (li20 + (d1_vap + d1_ice) * tk) / cvm + tcp3 = lcpk + icpk * min (1., dim (tice, tk) / (tice - t_wfr)) + +end subroutine update_qt + +! ======================================================================= +! calculation of particle concentration (pc), effective diameter (ed), +! optical extinction (oe), radar reflectivity factor (rr), and +! mass-weighted terminal velocity (tv) +! ======================================================================= + +subroutine cal_pc_ed_oe_rr_tv (q, den, blin, mu, pca, pcb, pc, eda, edb, ed, & + oea, oeb, oe, rra, rrb, rr, tva, tvb, tv) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: blin, mu + + real, intent (in) :: q, den + + real (kind = r8), intent (in), optional :: pca, pcb, eda, edb, oea, oeb, rra, rrb, tva, tvb + + real, intent (out), optional :: pc, ed, oe, rr, tv + + if (present (pca) .and. present (pcb) .and. present (pc)) then + pc = pca / pcb * exp (mu / (mu + 3) * log (6 * den * q)) + endif + if (present (eda) .and. present (edb) .and. present (ed)) then + ed = eda / edb * exp (1. / (mu + 3) * log (6 * den * q)) + endif + if (present (oea) .and. present (oeb) .and. present (oe)) then + oe = oea / oeb * exp ((mu + 2) / (mu + 3) * log (6 * den * q)) + endif + if (present (rra) .and. present (rrb) .and. present (rr)) then + rr = rra / rrb * exp ((mu + 6) / (mu + 3) * log (6 * den * q)) + endif + if (present (tva) .and. present (tvb) .and. present (tv)) then + tv = tva / tvb * exp (blin / (mu + 3) * log (6 * den * q)) + endif + +end subroutine cal_pc_ed_oe_rr_tv + +! ======================================================================= +! prepare saturation water vapor pressure tables +! ======================================================================= + +subroutine qs_init + + implicit none + + integer :: i + + if (.not. tables_are_initialized) then + + allocate (table0 (length)) + allocate (table1 (length)) + allocate (table2 (length)) + allocate (table3 (length)) + allocate (table4 (length)) + + allocate (des0 (length)) + allocate (des1 (length)) + allocate (des2 (length)) + allocate (des3 (length)) + allocate (des4 (length)) + + call qs_table0 (length) + call qs_table1 (length) + call qs_table2 (length) + call qs_table3 (length) + call qs_table4 (length) + + do i = 1, length - 1 + des0 (i) = max (0., table0 (i + 1) - table0 (i)) + des1 (i) = max (0., table1 (i + 1) - table1 (i)) + des2 (i) = max (0., table2 (i + 1) - table2 (i)) + des3 (i) = max (0., table3 (i + 1) - table3 (i)) + des4 (i) = max (0., table4 (i + 1) - table4 (i)) + enddo + des0 (length) = des0 (length - 1) + des1 (length) = des1 (length - 1) + des2 (length) = des2 (length - 1) + des3 (length) = des3 (length - 1) + des4 (length) = des4 (length - 1) + + tables_are_initialized = .true. + + endif + +end subroutine qs_init + +! ======================================================================= +! saturation water vapor pressure table, core function +! ======================================================================= + +subroutine qs_table_core (n, n_blend, do_smith_table, table) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: n, n_blend + + logical, intent (in) :: do_smith_table + + real, intent (out), dimension (n) :: table + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: i + integer, parameter :: n_min = 1600 + + real (kind = r8) :: delt = 0.1 + real (kind = r8) :: tmin, tem, esh + real (kind = r8) :: wice, wh2o, fac0, fac1, fac2 + real (kind = r8) :: esbasw, tbasw, esbasi, a, b, c, d, e + real (kind = r8) :: esupc (n_blend) + + esbasw = 1013246.0 + tbasw = tice + 100. + esbasi = 6107.1 + tmin = tice - n_min * delt + + ! ----------------------------------------------------------------------- + ! compute es over ice between - (n_min * delt) deg C and 0 deg C + ! ----------------------------------------------------------------------- + + if (do_smith_table) then + do i = 1, n_min + tem = tmin + delt * real (i - 1) + a = - 9.09718 * (tice / tem - 1.) + b = - 3.56654 * log10 (tice / tem) + c = 0.876793 * (1. - tem / tice) + e = log10 (esbasi) + table (i) = 0.1 * exp ((a + b + c + e) * log (10.)) + enddo + else + do i = 1, n_min + tem = tmin + delt * real (i - 1) + fac0 = (tem - tice) / (tem * tice) + fac1 = fac0 * li2 + fac2 = (d2_ice * log (tem / tice) + fac1) / rvgas + table (i) = e00 * exp (fac2) + enddo + endif + + ! ----------------------------------------------------------------------- + ! compute es over water between - (n_blend * delt) deg C and [ (n - n_min - 1) * delt] deg C + ! ----------------------------------------------------------------------- + + if (do_smith_table) then + do i = 1, n - n_min + n_blend + tem = tice + delt * (real (i - 1) - n_blend) + a = - 7.90298 * (tbasw / tem - 1.) + b = 5.02808 * log10 (tbasw / tem) + c = - 1.3816e-7 * (exp ((1. - tem / tbasw) * 11.344 * log (10.)) - 1.) + d = 8.1328e-3 * (exp ((tbasw / tem - 1.) * (- 3.49149) * log (10.)) - 1.) + e = log10 (esbasw) + esh = 0.1 * exp ((a + b + c + d + e) * log (10.)) + if (i .le. n_blend) then + esupc (i) = esh + else + table (i + n_min - n_blend) = esh + endif + enddo + else + do i = 1, n - n_min + n_blend + tem = tice + delt * (real (i - 1) - n_blend) + fac0 = (tem - tice) / (tem * tice) + fac1 = fac0 * lv0 + fac2 = (dc_vap * log (tem / tice) + fac1) / rvgas + esh = e00 * exp (fac2) + if (i .le. n_blend) then + esupc (i) = esh + else + table (i + n_min - n_blend) = esh + endif + enddo + endif + + ! ----------------------------------------------------------------------- + ! derive blended es over ice and supercooled water between - (n_blend * delt) deg C and 0 deg C + ! ----------------------------------------------------------------------- + + do i = 1, n_blend + tem = tice + delt * (real (i - 1) - n_blend) + wice = 1.0 / (delt * n_blend) * (tice - tem) + wh2o = 1.0 / (delt * n_blend) * (tem - tice + delt * n_blend) + table (i + n_min - n_blend) = wice * table (i + n_min - n_blend) + wh2o * esupc (i) + enddo + +end subroutine qs_table_core + +! ======================================================================= +! saturation water vapor pressure table 0, water only +! useful for idealized experiments +! it can also be used in warm rain microphyscis only +! ======================================================================= + +subroutine qs_table0 (n) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: n + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: i + + real (kind = r8) :: delt = 0.1 + real (kind = r8) :: tmin, tem, fac0, fac1, fac2 + + tmin = tice - 160. + + ! ----------------------------------------------------------------------- + ! compute es over water only + ! ----------------------------------------------------------------------- + + 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 + table0 (i) = e00 * exp (fac2) + enddo + +end subroutine qs_table0 + +! ======================================================================= +! saturation water vapor pressure table 1, water and ice +! blended between -20 deg C and 0 deg C +! the most realistic saturation water vapor pressure for the full temperature range +! ======================================================================= + +subroutine qs_table1 (n) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: n + + call qs_table_core (n, 200, .false., table1) + +end subroutine qs_table1 + +! ======================================================================= +! saturation water vapor pressure table 2, water and ice +! same as table 1, but the blending is replaced with smoothing around 0 deg C +! it is not designed for mixed-phase cloud microphysics +! used for ice microphysics (< 0 deg C) or warm rain microphysics (> 0 deg C) +! ======================================================================= + +subroutine qs_table2 (n) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: n + + call qs_table_core (n, 0, .false., table2) + +end subroutine qs_table2 + +! ======================================================================= +! saturation water vapor pressure table 3, water and ice +! blended between -20 deg C and 0 deg C +! the same as table 1, but from smithsonian meteorological tables page 350 +! ======================================================================= + +subroutine qs_table3 (n) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: n + + call qs_table_core (n, 200, .true., table3) + +end subroutine qs_table3 + +! ======================================================================= +! saturation water vapor pressure table 4, water and ice +! same as table 3, but the blending is replaced with smoothing around 0 deg C +! the same as table 2, but from smithsonian meteorological tables page 350 +! ======================================================================= + +subroutine qs_table4 (n) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: n + + call qs_table_core (n, 0, .true., table4) + +end subroutine qs_table4 + +! ======================================================================= +! compute the saturated water pressure, core function +! ======================================================================= + +function es_core (length, tk, table, des) + + implicit none + + real :: es_core + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: length + + real, intent (in) :: tk + + real, intent (in), dimension (length) :: table, des + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: it + + real :: ap1, tmin + + if (.not. tables_are_initialized) call qs_init + + tmin = tice - 160. + ap1 = 10. * dim (tk, tmin) + 1. + ap1 = min (2621., ap1) + it = ap1 + es_core = table (it) + (ap1 - it) * des (it) + +end function es_core + +! ======================================================================= +! compute the saturated specific humidity, core function +! ======================================================================= + +function qs_core (length, tk, den, dqdt, table, des) + + implicit none + + real :: qs_core + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: length + + real, intent (in) :: tk, den + + real, intent (in), dimension (length) :: table, des + + real, intent (out) :: dqdt + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: it + + real :: ap1, tmin + + tmin = tice - 160. + ap1 = 10. * dim (tk, tmin) + 1. + ap1 = min (2621., ap1) + qs_core = es_core (length, tk, table, des) / (rvgas * tk * den) + it = ap1 - 0.5 + dqdt = 10. * (des (it) + (ap1 - it) * (des (it + 1) - des (it))) / (rvgas * tk * den) + +end function qs_core + +! ======================================================================= +! compute the saturated water pressure based on table 0, water only +! useful for idealized experiments +! it can also be used in warm rain microphyscis only +! ======================================================================= + +function wes_t (tk) + + implicit none + + real :: wes_t + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk + + wes_t = es_core (length, tk, table0, des0) + +end function wes_t + +! ======================================================================= +! compute the saturated water pressure based on table 1, water and ice +! the most realistic saturation water vapor pressure for the full temperature range +! ======================================================================= + +function mes_t (tk) + + implicit none + + real :: mes_t + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk + + mes_t = es_core (length, tk, table1, des1) + +end function mes_t + +! ======================================================================= +! compute the saturated water pressure based on table 2, water and ice +! it is not designed for mixed-phase cloud microphysics +! used for ice microphysics (< 0 deg C) or warm rain microphysics (> 0 deg C) +! ======================================================================= + +function ies_t (tk) + + implicit none + + real :: ies_t + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk + + ies_t = es_core (length, tk, table2, des2) + +end function ies_t + +! ======================================================================= +! compute the saturated specific humidity based on table 0, water only +! useful for idealized experiments +! it can also be used in warm rain microphyscis only +! ======================================================================= + +function wqs_trho (tk, den, dqdt) + + implicit none + + real :: wqs_trho + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk, den + + real, intent (out) :: dqdt + + wqs_trho = qs_core (length, tk, den, dqdt, table0, des0) + +end function wqs_trho + +! ======================================================================= +! compute the saturated specific humidity based on table 1, water and ice +! the most realistic saturation water vapor pressure for the full temperature range +! ======================================================================= + +function mqs_trho (tk, den, dqdt) + + implicit none + + real :: mqs_trho + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk, den + + real, intent (out) :: dqdt + + mqs_trho = qs_core (length, tk, den, dqdt, table1, des1) + +end function mqs_trho + +! ======================================================================= +! compute the saturated specific humidity based on table 2, water and ice +! it is not designed for mixed-phase cloud microphysics +! used for ice microphysics (< 0 deg C) or warm rain microphysics (> 0 deg C) +! ======================================================================= + +function iqs_trho (tk, den, dqdt) + + implicit none + + real :: iqs_trho + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk, den + + real, intent (out) :: dqdt + + iqs_trho = qs_core (length, tk, den, dqdt, table2, des2) + +end function iqs_trho + +! ======================================================================= +! compute the saturated specific humidity based on table 0, water only +! useful for idealized experiments +! it can also be used in warm rain microphyscis only +! ======================================================================= + +function wqs_ptqv (tk, pa, qv, dqdt) + + implicit none + + real :: wqs_ptqv + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk, pa, qv + + real, intent (out) :: dqdt + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real :: den + + den = pa / (rdgas * tk * (1. + zvir * qv)) + + wqs_ptqv = wqs (tk, den, dqdt) + +end function wqs_ptqv + +! ======================================================================= +! compute the saturated specific humidity based on table 1, water and ice +! the most realistic saturation water vapor pressure for the full temperature range +! ======================================================================= + +function mqs_ptqv (tk, pa, qv, dqdt) + + implicit none + + real :: mqs_ptqv + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk, pa, qv + + real, intent (out) :: dqdt + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real :: den + + den = pa / (rdgas * tk * (1. + zvir * qv)) + + mqs_ptqv = mqs (tk, den, dqdt) + +end function mqs_ptqv + +! ======================================================================= +! compute the saturated specific humidity based on table 2, water and ice +! it is not designed for mixed-phase cloud microphysics +! used for ice microphysics (< 0 deg C) or warm rain microphysics (> 0 deg C) +! ======================================================================= + +function iqs_ptqv (tk, pa, qv, dqdt) + + implicit none + + real :: iqs_ptqv + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: tk, pa, qv + + real, intent (out) :: dqdt + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real :: den + + den = pa / (rdgas * tk * (1. + zvir * qv)) + + iqs_ptqv = iqs (tk, den, dqdt) + +end function iqs_ptqv + +! ======================================================================= +! compute the saturated specific humidity based on table 1, water and ice +! the most realistic saturation water vapor pressure for the full temperature range +! it is the 3d version of "mqs" +! ======================================================================= + +subroutine mqs3d (im, km, ks, tk, pa, qv, qs, dqdt) + + implicit none + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + integer, intent (in) :: im, km, ks + + real, intent (in), dimension (im, ks:km) :: tk, pa, qv + + real, intent (out), dimension (im, ks:km) :: qs + + real, intent (out), dimension (im, ks:km), optional :: dqdt + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + integer :: i, k + + real :: dqdt0 + + if (present (dqdt)) then + do k = ks, km + do i = 1, im + qs (i, k) = mqs (tk (i, k), pa (i, k), qv (i, k), dqdt (i, k)) + enddo + enddo + else + do k = ks, km + do i = 1, im + qs (i, k) = mqs (tk (i, k), pa (i, k), qv (i, k), dqdt0) + enddo + enddo + endif + +end subroutine mqs3d + +! ======================================================================= +! compute wet buld temperature, core function +! Knox et al. (2017) +! ======================================================================= + +function wet_bulb_core (qv, tk, den, lcp) + + implicit none + + real :: wet_bulb_core + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: qv, tk, den, lcp + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + logical :: do_adjust = .false. + + real :: factor = 1. / 3. + real :: qsat, tp, dqdt + + wet_bulb_core = tk + qsat = wqs (wet_bulb_core, den, dqdt) + tp = factor * (qsat - qv) / (1. + lcp * dqdt) * lcp + wet_bulb_core = wet_bulb_core - tp + + if (do_adjust .and. tp .gt. 0.0) then + qsat = wqs (wet_bulb_core, den, dqdt) + tp = (qsat - qv) / (1. + lcp * dqdt) * lcp + wet_bulb_core = wet_bulb_core - tp + endif + +end function wet_bulb_core + +! ======================================================================= +! compute wet buld temperature, dry air case +! ======================================================================= + +function wet_bulb_dry (qv, tk, den) + + implicit none + + real :: wet_bulb_dry + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: qv, tk, den + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real :: lcp + + lcp = hlv / cp_air + + wet_bulb_dry = wet_bulb_core (qv, tk, den, lcp) + +end function wet_bulb_dry + +! ======================================================================= +! compute wet buld temperature, moist air case +! ======================================================================= + +function wet_bulb_moist (qv, ql, qi, qr, qs, qg, tk, den) + + implicit none + + real :: wet_bulb_moist + + ! ----------------------------------------------------------------------- + ! input / output arguments + ! ----------------------------------------------------------------------- + + real, intent (in) :: qv, ql, qi, qr, qs, qg, tk, den + + ! ----------------------------------------------------------------------- + ! local variables + ! ----------------------------------------------------------------------- + + real :: lcp, q_liq, q_sol + + real (kind = r8) :: cvm + + q_liq = ql + qr + q_sol = qi + qs + qg + cvm = mhc (qv, q_liq, q_sol) + lcp = (lv00 + d1_vap * tk) / cvm + + wet_bulb_moist = wet_bulb_core (qv, tk, den, lcp) + +end function wet_bulb_moist + +end module module_gfdl_cld_mp diff --git a/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.F90 b/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.F90 index 487753027..3c2fe85cd 100644 --- a/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.F90 +++ b/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.F90 @@ -153,7 +153,7 @@ SUBROUTINE mynnedmf_wrapper_run( & & bl_mynn_cloudmix, bl_mynn_mixqt, & & bl_mynn_output, bl_mynn_closure, & & icloud_bl, do_mynnsfclay, & - & imp_physics, imp_physics_gfdl, & + & imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3,& & imp_physics_thompson, imp_physics_wsm6, & & imp_physics_fa, & & chem3d, frp, mix_chem, rrfs_sd, enh_mix, & @@ -204,7 +204,8 @@ SUBROUTINE mynnedmf_wrapper_run( & & bl_mynn_mixqt, & & bl_mynn_output, & & imp_physics, imp_physics_wsm6, & - & imp_physics_thompson, imp_physics_gfdl, & + & imp_physics_thompson, & + & imp_physics_gfdl, imp_physics_gfdl_v3, & & imp_physics_nssl, imp_physics_fa, & & spp_pbl, & & tke_budget @@ -487,7 +488,7 @@ SUBROUTINE mynnedmf_wrapper_run( & enddo enddo endif - elseif (imp_physics == imp_physics_gfdl) then + elseif (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then ! GFDL MP FLAG_QI = .true. FLAG_QNI= .false. @@ -927,7 +928,7 @@ SUBROUTINE mynnedmf_wrapper_run( & enddo enddo - elseif (imp_physics == imp_physics_gfdl) then + elseif (imp_physics == imp_physics_gfdl .or. imp_physics == imp_physics_gfdl_v3) then ! GFDL MP do k=1,levs do i=1,im diff --git a/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.meta b/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.meta index 00589dfe5..a4dad3d86 100644 --- a/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.meta +++ b/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.meta @@ -1348,6 +1348,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme diff --git a/physics/Radiation/radiation_clouds.f b/physics/Radiation/radiation_clouds.f index 111be4019..9a04ee118 100644 --- a/physics/Radiation/radiation_clouds.f +++ b/physics/Radiation/radiation_clouds.f @@ -27,7 +27,8 @@ ! deltaq, sup, me, icloud, kdt, ! ! ntrac, ntcw, ntiw, ntrw, ntsw, ntgl, ntclamt, ! ! imp_physics, imp_physics_nssl, imp_physics_fer_hires, ! -! imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6, ! +! imp_physics_gfdl, imp_physics_gfdl_v3, ! +! imp_physics_thompson, imp_physics_wsm6, ! ! imp_physics_zhao_carr, imp_physics_zhao_carr_pdf, ! ! imp_physics_mg, iovr, iovr_rand, iovr_maxrand, iovr_max, ! ! iovr_dcorr, iovr_exp, iovr_exprand, idcor, idcor_con, ! @@ -307,6 +308,8 @@ subroutine cld_init & print *,' --- zhao/carr/sundqvist + pdf cloud' elseif (imp_physics == 11) then print *,' --- GFDL Lin cloud microphysics' + elseif (imp_physics == 13) then + print *,' --- GFDL Lin cloud microphysics V3' elseif (imp_physics == 8) then print *,' --- Thompson cloud microphysics' elseif (imp_physics == 6) then @@ -342,7 +345,8 @@ subroutine radiation_clouds_prop & & deltaq, sup, dcorr_con, me, icloud, kdt, & & ntrac, ntcw, ntiw, ntrw, ntsw, ntgl, ntclamt, & & imp_physics, imp_physics_nssl, imp_physics_fer_hires, & - & imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6, & + & imp_physics_gfdl, imp_physics_gfdl_v3, & + & imp_physics_thompson, imp_physics_wsm6, & & imp_physics_zhao_carr, imp_physics_zhao_carr_pdf, & & imp_physics_mg, iovr, iovr_rand, iovr_maxrand, iovr_max, & & iovr_dcorr, iovr_exp, iovr_exprand, idcor, idcor_con, & @@ -432,6 +436,7 @@ subroutine radiation_clouds_prop & ! imp_physics_nssl : NSSL microphysics ! ! imp_physics_fer_hires : Ferrier-Aligo microphysics scheme ! ! imp_physics_gfdl : GFDL microphysics scheme ! +! imp_physics_gfdl_v3 : GFDL microphysics scheme v3 ! ! imp_physics_thompson : Thompson microphysics scheme ! ! imp_physics_wsm6 : WSMG microphysics scheme ! ! imp_physics_zhao_carr : Zhao-Carr microphysics scheme ! @@ -517,6 +522,7 @@ subroutine radiation_clouds_prop & & imp_physics_nssl, ! Flag for NSSL scheme & imp_physics_fer_hires, ! Flag for fer-hires scheme & imp_physics_gfdl, ! Flag for gfdl scheme + & imp_physics_gfdl_v3, ! Flag for gfdl scheme v3 & imp_physics_thompson, ! Flag for thompsonscheme & imp_physics_wsm6, ! Flag for wsm6 scheme & imp_physics_zhao_carr, ! Flag for zhao-carr scheme @@ -655,10 +661,11 @@ subroutine radiation_clouds_prop & & cld_reice,cld_rwp, cld_rerain,cld_swp, & & cld_resnow) - elseif (imp_physics == imp_physics_gfdl) then ! GFDL cloud scheme + elseif (imp_physics == imp_physics_gfdl .or. & + & imp_physics == imp_physics_gfdl_v3) then ! GFDL cloud scheme if (.not. lgfdlmprad) then - call progcld_gfdl_lin (plyr, plvl, tlyr, tvly, qlyr, & ! --- inputs + call progcld_gfdl_lin (plyr, plvl, tlyr, tvly, qlyr, & ! --- inputs & qstl, rhly, ccnd(1:IX,1:NLAY,1), cnvw, cnvc, & & xlat, xlon, slmsk, cldcov, dz, delp, & & IX, NLAY, NLP1, dzlay, & @@ -666,6 +673,9 @@ subroutine radiation_clouds_prop & & cld_frac, cld_lwp, cld_reliq, cld_iwp, & ! --- outputs & cld_reice,cld_rwp, cld_rerain,cld_swp, & & cld_resnow) +! +! rsun add an option for gfdlmp when do_sat_adj = .false. and do_qa =.false. +! else call progclduni (plyr, plvl, tlyr, tvly, ccnd, ncndl, xlat, & ! --- inputs diff --git a/physics/SFC_Models/Land/RUC/lsm_ruc.F90 b/physics/SFC_Models/Land/RUC/lsm_ruc.F90 index ba1b1b4e9..e850630f5 100644 --- a/physics/SFC_Models/Land/RUC/lsm_ruc.F90 +++ b/physics/SFC_Models/Land/RUC/lsm_ruc.F90 @@ -324,8 +324,8 @@ end subroutine lsm_ruc_finalize !>\section gen_lsmruc RUC LSM General Algorithm subroutine lsm_ruc_run & ! inputs & ( iter, me, master, delt, kdt, im, nlev, lsm_ruc, lsm, & - & imp_physics, imp_physics_gfdl, imp_physics_thompson, & - & imp_physics_nssl, do_mynnsfclay, & + & imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3, & + & imp_physics_thompson, imp_physics_nssl, do_mynnsfclay, & & exticeden, lsoil_ruc, lsoil, mosaic_lu, mosaic_soil, & & isncond_opt, isncovr_opt, nlcat, nscat, & & rdlai, xlat_d, xlon_d, & @@ -377,8 +377,8 @@ subroutine lsm_ruc_run & ! inputs integer, intent(in) :: mosaic_lu, mosaic_soil, isncond_opt, isncovr_opt integer, intent(in) :: nlcat, nscat integer, intent(in) :: lsm_ruc, lsm - integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_thompson, & - imp_physics_nssl + integer, intent(in) :: imp_physics, imp_physics_gfdl, imp_physics_gfdl_v3,& + imp_physics_thompson, imp_physics_nssl real (kind_phys), dimension(:), intent(in) :: xlat_d, xlon_d real (kind_phys), dimension(:), intent(in) :: oro, sigma @@ -800,8 +800,8 @@ subroutine lsm_ruc_run & ! inputs ! Set flag for mixed phase precipitation depending on microphysics scheme. ! For GFDL and Thompson, srflag is fraction of frozen precip for convective+explicit precip. - if (imp_physics==imp_physics_gfdl .or. imp_physics==imp_physics_thompson .or. & - imp_physics == imp_physics_nssl) then + if (imp_physics==imp_physics_gfdl .or. imp_physics==imp_physics_gfdl_v3 .or. & + imp_physics==imp_physics_thompson .or. imp_physics == imp_physics_nssl) then frpcpn = .true. else frpcpn = .false. diff --git a/physics/SFC_Models/Land/RUC/lsm_ruc.meta b/physics/SFC_Models/Land/RUC/lsm_ruc.meta index bc4d358e3..9f332e276 100644 --- a/physics/SFC_Models/Land/RUC/lsm_ruc.meta +++ b/physics/SFC_Models/Land/RUC/lsm_ruc.meta @@ -614,6 +614,13 @@ dimensions = () type = integer intent = in +[imp_physics_gfdl_v3] + standard_name = identifier_for_gfdl_microphysics_v3_scheme + long_name = choice of GFDL microphysics v3 scheme + units = flag + dimensions = () + type = integer + intent = in [imp_physics_thompson] standard_name = identifier_for_thompson_microphysics_scheme long_name = choice of Thompson microphysics scheme From 26ac3ddf4423334ae2ffe65e24a513ccea6fe187 Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Fri, 2 Feb 2024 16:47:25 +0000 Subject: [PATCH 07/10] remove comment and previous tests --- physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 b/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 index 37fbd7cee..6a5c8e4e7 100644 --- a/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 +++ b/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 @@ -4459,10 +4459,6 @@ subroutine pidep_pisub (ks, ke, dts, qv, ql, qr, qi, qs, qg, tz, dp, cvm, te8, d tmp = dq / (1. + tcpk (k) * dqdt) if (qi (k) .gt. qcmin) then - -!rsun added for ice number associated with prog_ccn - cin (k) = 5.38e7 * exp (0.75 * log (qi (k) * den (k))) - if (.not. prog_ccn) then if (inflag .eq. 1) & cin (k) = 5.38e7 * exp (0.75 * log (qi (k) * den (k))) From deeb2cf606d2c0094d28dde42b541953aafacce6 Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Wed, 7 Feb 2024 21:18:36 +0000 Subject: [PATCH 08/10] remove previous comments --- physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 | 104 +-------------------- 1 file changed, 5 insertions(+), 99 deletions(-) diff --git a/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 b/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 index b5911b193..09b3f6cac 100644 --- a/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 +++ b/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 @@ -164,7 +164,7 @@ subroutine gfdl_cld_mp_v3_run( logical, intent (in) :: lradar real(kind=kind_phys), intent(inout), dimension(:,:) :: refl_10cm - logical, intent (in) :: reset, effr_in !rsun reset could be removed + logical, intent (in) :: reset, effr_in real(kind=kind_phys), intent(inout), dimension(:,:) :: rew, rei, rer, res, reg logical, intent (in) :: cplchm ! ice and liquid water 3d precipitation fluxes - only allocated if cplchm is .true. @@ -222,7 +222,6 @@ subroutine gfdl_cld_mp_v3_run( qnl(i,k) = aerfld(i,kk,11) ! sulfate pfils(i,1,k) = 0.0 pflls(i,1,k) = 0.0 -!rsun intitialize pfluxi etc take a look at the SHield driver prefluxw(i,k) =0.0 prefluxi(i,k) =0.0 prefluxr(i,k) =0.0 @@ -238,7 +237,6 @@ subroutine gfdl_cld_mp_v3_run( qg1(i,k) = gq0_ntgl(i,kk) qa1(i,k) = gq0_ntclamt(i,kk) pt(i,k) = gt0(i,kk) -!rsun WW defined here is differnce from what is used in SHiELD (https://github.com/NOAA-GFDL/SHiELD_physics/blob/main/GFS_layer/GFS_physics_driver.F90) w(i,k) = -vvl(i,kk) * (one+con_fvirt * gq0(i,kk)) & * gt0(i,kk) / prsl(i,kk) * (con_rd*onebg) uin(i,k) = gu0(i,kk) @@ -246,20 +244,7 @@ subroutine gfdl_cld_mp_v3_run( delp(i,k) = del(i,kk) dz(i,k) = (phii(i,kk)-phii(i,kk+1))*onebg p123(i,k) = prsl(i,kk) - !tem = con_eps*prsl(i,kk)/(con_rd*gt0(i,kk)*(gq0(i,kk)+con_eps)) - !if(tem <0.0) then - ! write(errmsg,'(*(a))') 'Negative air density associated with GFDL MP v3' - ! errflg = 1 - ! return - !endif - !qni(i,k) = 10./tem qni(i,k) = 10. -!rsun debug -! if(i == 1) then -! write(*,*) 'T, qnl, qni:',k,p123(i,k),pt(i,k),qnl(i,k), qni(i,k) -! endif - -!rsun for inline option q_con(i,k) = 0.0 cappa(i,k) = 0.0 enddo @@ -272,33 +257,8 @@ subroutine gfdl_cld_mp_v3_run( snow0 = 0 graupel0 = 0 -! if(imp_physics == imp_physics_gfdl) then -! -! call gfdl_cloud_microphys_mod_driver(iis, iie, jjs, jje, kks, kke, ktop, kbot, & -! qv1, ql1, qr1, qi1, qs1, qg1, qa1, qnl, qv_dt, ql_dt, qr_dt, qi_dt, & -! qs_dt, qg_dt, qa_dt, pt_dt, pt, w, uin, vin, u_dt, v_dt, dz, delp, & -! garea, dtp, frland, rain0, snow0, ice0, graupel0, hydrostatic, & -! phys_hydrostatic, p123, lradar, refl, reset, pfils, pflls) -! -! else if (imp_physics == imp_physics_gfdl_v3) then if(imp_physics == imp_physics_gfdl_v3) then - -!rsun attention to flipping (same as v1 driver: need to be from top to bottom : 1,km) -!rsun : variables defined in shield -! need to pass water out -! hs = Sfcprop%oro(:) * con_g -! gsize = sqrt(Grid%area(:)) -! w (:,k) = -Statein%vvl(:,levs-k+1)*con_rd*Stateout%gt0(:,levs-k+1) & -! & /Statein%prsl(:,levs-k+1)/con_g -! delp (:,k) = del(:,levs-k+1) -! dz (:,k) = (Statein%phii(:,levs-k+1)-Statein%phii(:,levs-k+2))/con_g -! -! turn off the or remove the inline option -! define consv_te a logical variable as input only -! define adj_vmr output only - - !fast_mp_consv = .false. - !last_step = .true. + last_step = .false. do_inline_mp = .false. hs = oro(:) * con_g @@ -309,18 +269,6 @@ subroutine gfdl_cld_mp_v3_run( fast_mp_consv, adj_vmr, te, dte, prefluxw, prefluxr, prefluxi, prefluxs, & prefluxg, last_step, do_inline_mp ) - !if(lradar) refl = -20.0 !call rad_ref or call refl10cm_gfdl from GFDLMP V1 - -!make sure the unit of water0, rain0, ice0, snow0, graupel0, are the same as in V1 mm/day? -! find how to define them in module_gfdl_cloud_microphys.F90 -! need to add call refl calculation to calulate refl call rad_ref -! -! rsun check to make sure the variables going out of the routine -! the following list of variables can be calcualted here -! (no need for the following variables (the variables are updated in the gfdl_cld_mp_mod_driver) -! pt_dt, qa_dt, u_dt, v_dt, qv_dt, ql_dt, qr_dt, qi_dt, qs_dt, qg_dt -! take a look how qnl and qi1 are initialized - else write(errmsg,'(*(a))') 'Invalid imp_physics option for GFDL MP v3' errflg = 1 @@ -370,28 +318,11 @@ subroutine gfdl_cld_mp_v3_run( snow0 = snow0*tem graupel0 = graupel0*tem -!rsun: move this after the call of the each driver - ! flip vertical coordinate back do k=1,levs kk = levs-k+1 do i=1,im -!rsun add update the following fields only for v1 -! if (imp_physics == imp_physics_gfdl) then -! - ! gq0(i,k) = qv1(i,kk) + qv_dt(i,kk) * dtp - ! gq0_ntcw(i,k) = ql1(i,kk) + ql_dt(i,kk) * dtp - ! gq0_ntrw(i,k) = qr1(i,kk) + qr_dt(i,kk) * dtp - ! gq0_ntiw(i,k) = qi1(i,kk) + qi_dt(i,kk) * dtp - ! gq0_ntsw(i,k) = qs1(i,kk) + qs_dt(i,kk) * dtp - ! gq0_ntgl(i,k) = qg1(i,kk) + qg_dt(i,kk) * dtp - ! gq0_ntclamt(i,k) = qa1(i,kk) + qa_dt(i,kk) * dtp - ! gt0(i,k) = gt0(i,k) + pt_dt(i,kk) * dtp - ! gu0(i,k) = gu0(i,k) + u_dt(i,kk) * dtp - ! gv0(i,k) = gv0(i,k) + v_dt(i,kk) * dtp - ! refl_10cm(i,k) = refl(i,kk) - !else if(imp_physics == imp_physics_gfdl_v3) then if (imp_physics == imp_physics_gfdl_v3) then gq0(i,k) = qv1(i,kk) gq0_ntcw(i,k) = ql1(i,kk) @@ -400,7 +331,7 @@ subroutine gfdl_cld_mp_v3_run( gq0_ntsw(i,k) = qs1(i,kk) gq0_ntgl(i,k) = qg1(i,kk) gq0_ntclamt(i,k) = qa1(i,kk) - gt0(i,k) = pt(i,kk) ! rsun double check this + gt0(i,k) = pt(i,kk) gu0(i,k) = uin(i,kk) gv0(i,k) = vin(i,kk) refl_10cm(i,k) = refl(i,kk) @@ -417,16 +348,9 @@ subroutine gfdl_cld_mp_v3_run( do k=1,levs kk = levs-k+1 do i=1,im - !if(imp_physics==imp_physics_gfdl) then - ! pfi_lsan(i,k) = pfils(i,1,kk) !rsun this need special attention to have the same variable in v3 - ! pfl_lsan(i,k) = pflls(i,1,kk) - !else if (imp_physics==imp_physics_gfdl_v3) then if (imp_physics==imp_physics_gfdl_v3) then - -!rsun make sure prefluxw is the same as pfils - - pfi_lsan(i,k) = prefluxi (i,kk) + prefluxs (i,kk) + prefluxg (i,kk)! rsun: use the same unit as pfils - pfl_lsan(i,k) = prefluxr (i,kk) ! rsun + pfi_lsan(i,k) = prefluxi (i,kk) + prefluxs (i,kk) + prefluxg (i,kk) + pfl_lsan(i,k) = prefluxr (i,kk) else write(errmsg,'(*(a))') 'Invalid imp_physics option for GFDL MP v3' errflg = 1 @@ -437,21 +361,6 @@ subroutine gfdl_cld_mp_v3_run( endif if(effr_in) then - !allocate(den(1:im,1:levs)) - !do k=1,levs - ! do i=1,im - ! den(i,k)=con_eps*prsl(i,k)/(con_rd*gt0(i,k)*(gq0(i,k)+con_eps)) - ! enddo - !enddo - !call cloud_diagnosis (1, im, 1, levs, den(1:im,1:levs), & - ! del(1:im,1:levs), islmsk(1:im), & - ! gq0_ntcw(1:im,1:levs), gq0_ntiw(1:im,1:levs), & - ! gq0_ntrw(1:im,1:levs), & - ! gq0_ntsw(1:im,1:levs) + gq0_ntgl(1:im,1:levs), & - ! gq0_ntgl(1:im,1:levs)*0.0, gt0(1:im,1:levs), & - ! rew(1:im,1:levs), rei(1:im,1:levs), rer(1:im,1:levs),& - ! res(1:im,1:levs), reg(1:im,1:levs)) - !deallocate(den) call cld_eff_rad (1, im, 1, levs, slmsk(1:im), & prsl(1:im,1:levs), del(1:im,1:levs), & gt0(1:im,1:levs), gq0(1:im,1:levs), & @@ -463,9 +372,6 @@ subroutine gfdl_cld_mp_v3_run( endif if(lradar) then - ! need peln, zvir; print and check - ! need to use qv1 etc (top 1 and bottom 127) - ! make sure the consistency between peln, zvir and qv1 etc call rad_ref (1, im, 1, 1, qv1(1:im,1:levs), qr1(1:im,1:levs), & qs1(1:im,1:levs),qg1(1:im,1:levs),pt(1:im,1:levs), & delp(1:im,1:levs), dz(1:im,1:levs), refl(1:im,1:levs), levs, hydrostatic, & From f61341c5a66f3f7b89b74434cfdc2c7376d3f41e Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Wed, 7 Feb 2024 21:21:14 +0000 Subject: [PATCH 09/10] remove comments in module_gfdl_cld_mp.F90 --- physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 b/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 index 6a5c8e4e7..41defcd3e 100644 --- a/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 +++ b/physics/MP/GFDL_2022_v3/module_gfdl_cld_mp.F90 @@ -391,8 +391,7 @@ module module_gfdl_cld_mp real :: tau_v2l = 150.0 ! water vapor to cloud water condensation time scale (s) real :: tau_l2v = 300.0 ! cloud water to water vapor evaporation time scale (s) real :: tau_revp = 0.0 ! rain evaporation time scale (s) - !rsun real :: tau_imlt = 1200.0 ! cloud ice melting time scale (s) ! ori in v3 - real :: tau_imlt = 600.0 ! cloud ice melting time scale (s) ! 600.0 is the origin in v1 + real :: tau_imlt = 1200.0 ! cloud ice melting time scale (s) real :: tau_smlt = 900.0 ! snow melting time scale (s) real :: tau_gmlt = 600.0 ! graupel melting time scale (s) real :: tau_wbf = 300.0 ! graupel melting time scale (s) @@ -1367,8 +1366,6 @@ subroutine mpdrv (hydrostatic, ua, va, wa, delp, pt, qv, ql, qr, qi, qs, qg, & enddo -!rsun ke is sufface - do k = ks, ke denfac (k) = sqrt (den (ke) / den (k)) enddo @@ -1608,10 +1605,6 @@ subroutine mpdrv (hydrostatic, ua, va, wa, delp, pt, qv, ql, qr, qi, qs, qg, & qg (i, k) = qgz (k) qa (i, k) = qaz (k) -!rsun - !if(qaz(k) > 0.0) print*,'qa(i,k):',i,k, qaz(k) - - ! ----------------------------------------------------------------------- ! calculate some more variables needed outside ! ----------------------------------------------------------------------- @@ -6065,11 +6058,6 @@ subroutine cld_eff_rad (is, ie, ks, ke, lsm, p, delp, t, qv, qw, qi, qr, qs, qg, enddo endif - - !print*,'cld_eff_rad: radius option:',rewflag, reiflag, resflag, rerflag, regflag: 1 2 1 1 1 - !print*,'in cld_eff_rad:ccn_o, ccn_l:',ccn_o, ccn_l - - do i = is, ie do k = ks, ke @@ -6481,7 +6469,6 @@ subroutine rad_ref (is, ie, js, je, qv, qr, qs, qg, pt, delp, & ! ----------------------------------------------------------------------- do k = 1, npz - ! rsun: find more about this !if (hydrostatic) then ! den (k) = delp (i, j, k) / ((peln (i, k + 1, j) - peln (i, k, j)) * & ! rdgas * pt (i, j, k) * (1. + zvir * qv (i, j, k))) From 3e319275d4643d0bb3348e6e63b53900de76fc3b Mon Sep 17 00:00:00 2001 From: Ruiyu Sun Date: Wed, 7 Feb 2024 21:24:52 +0000 Subject: [PATCH 10/10] correct a bug --- physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 b/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 index 09b3f6cac..c11bec68d 100644 --- a/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 +++ b/physics/MP/GFDL_2022_v3/gfdl_cld_mp_v3.F90 @@ -183,7 +183,7 @@ subroutine gfdl_cld_mp_v3_run( real(kind=kind_phys), dimension(1:im,1,1:levs) :: pfils, pflls real(kind=kind_phys), dimension(1:im,1,1:levs) :: adj_vmr, te real(kind=kind_phys), dimension(1:im,1:levs) :: prefluxw, prefluxr, prefluxi, prefluxs, prefluxg - real(kind=kind_phys), dimension(1:im) :: dte, hs + real(kind=kind_phys), dimension(1:im) :: dte, hs, gsize !real(kind=kind_phys), dimension(:,:), allocatable :: den real(kind=kind_phys), dimension(1:im) :: water0 real(kind=kind_phys) :: onebg @@ -262,9 +262,10 @@ subroutine gfdl_cld_mp_v3_run( last_step = .false. do_inline_mp = .false. hs = oro(:) * con_g + gsize = sqrt(garea(:)) call module_gfdl_cld_mp_driver( qv1, ql1, qr1, qi1, qs1, qg1, qa1, qnl, qni, pt, w,& - uin, vin, dz, delp, garea, dtp, hs, water0, rain0, & + uin, vin, dz, delp, gsize, dtp, hs, water0, rain0, & ice0, snow0, graupel0, hydrostatic, iis, iie, kks, kke, q_con, cappa, & fast_mp_consv, adj_vmr, te, dte, prefluxw, prefluxr, prefluxi, prefluxs, & prefluxg, last_step, do_inline_mp )