From d8f4ffbfbe519ee627c6144505d029c4720bd9f3 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Sat, 13 Feb 2021 07:13:55 -0700 Subject: [PATCH 01/18] update Thompson more similar to WRF-v4.3 --- physics/module_mp_thompson.F90 | 437 +++++++++++++++------------------ 1 file changed, 194 insertions(+), 243 deletions(-) diff --git a/physics/module_mp_thompson.F90 b/physics/module_mp_thompson.F90 index c19b594dd..fcbcb8164 100644 --- a/physics/module_mp_thompson.F90 +++ b/physics/module_mp_thompson.F90 @@ -53,6 +53,10 @@ !! perturbations to the graupel intercept parameter, !! the cloud water shape parameter, and the number !! concentration of nucleated aerosols. +!! - Last modified: 12 Feb 2021 G. Thompson updated to align more closely +!! with his WRF version, including bug fixes and designed +!! changes. + MODULE module_mp_thompson USE machine, only : kind_phys @@ -120,8 +124,8 @@ MODULE module_mp_thompson !.. mixing ratio. Also, when mu_g is non-zero, these become equiv !.. y-intercept for an exponential distrib and proper values are !.. computed based on same mixing ratio and total number concentration. - REAL, PARAMETER, PRIVATE:: gonv_min = 1.E4 - REAL, PARAMETER, PRIVATE:: gonv_max = 3.E6 + REAL, PARAMETER, PRIVATE:: gonv_min = 1.E2 + REAL, PARAMETER, PRIVATE:: gonv_max = 1.E6 !..Mass power law relations: mass = am*D**bm !.. Snow from Field et al. (2005), others assume spherical form. @@ -183,7 +187,7 @@ MODULE module_mp_thompson REAL, PRIVATE:: Sc3 !..Homogeneous freezing temperature - REAL, PARAMETER, PRIVATE:: HGFR = 235.16 !< Homogeneous freezing temperature + REAL, PARAMETER, PRIVATE:: HGFR = 235.16 !..Water vapor and air gas constants at constant pressure REAL, PARAMETER, PRIVATE:: Rv = 461.5 @@ -214,6 +218,15 @@ MODULE module_mp_thompson REAL, PARAMETER, PRIVATE:: D0g = 250.E-6 REAL, PRIVATE:: D0i, xm0s, xm0g +!..Min and max radiative effective radius of cloud water, cloud ice, and snow; +!.. performed by subroutine calc_effectRad + REAL, PARAMETER:: re_qc_min = 2.50E-6 ! 2.5 microns + REAL, PARAMETER:: re_qc_max = 50.0E-6 ! 50 microns + REAL, PARAMETER:: re_qi_min = 2.50E-6 ! 2.5 microns + REAL, PARAMETER:: re_qi_max = 125.0E-6 ! 125 microns + REAL, PARAMETER:: re_qs_min = 5.00E-6 ! 5 microns + REAL, PARAMETER:: re_qs_max = 999.0E-6 ! 999 microns (1 mm) + !..Lookup table dimensions INTEGER, PARAMETER, PRIVATE:: nbins = 100 INTEGER, PARAMETER, PRIVATE:: nbc = nbins @@ -226,7 +239,7 @@ MODULE module_mp_thompson INTEGER, PARAMETER, PRIVATE:: ntb_r = 37 INTEGER, PARAMETER, PRIVATE:: ntb_s = 28 INTEGER, PARAMETER, PRIVATE:: ntb_g = 28 - INTEGER, PARAMETER, PRIVATE:: ntb_g1 = 28 + INTEGER, PARAMETER, PRIVATE:: ntb_g1 = 37 INTEGER, PARAMETER, PRIVATE:: ntb_r1 = 37 INTEGER, PARAMETER, PRIVATE:: ntb_i1 = 55 INTEGER, PARAMETER, PRIVATE:: ntb_t = 9 @@ -299,10 +312,11 @@ MODULE module_mp_thompson !> Lookup tables for graupel y-intercept parameter (/m**4). REAL, DIMENSION(ntb_g1), PARAMETER, PRIVATE:: & - N0g_exp = (/1.e4,2.e4,3.e4,4.e4,5.e4,6.e4,7.e4,8.e4,9.e4, & + N0g_exp = (/1.e2,2.e2,3.e2,4.e2,5.e2,6.e2,7.e2,8.e2,9.e2, & + 1.e3,2.e3,3.e3,4.e3,5.e3,6.e3,7.e3,8.e3,9.e3, & + 1.e4,2.e4,3.e4,4.e4,5.e4,6.e4,7.e4,8.e4,9.e4, & 1.e5,2.e5,3.e5,4.e5,5.e5,6.e5,7.e5,8.e5,9.e5, & - 1.e6,2.e6,3.e6,4.e6,5.e6,6.e6,7.e6,8.e6,9.e6, & - 1.e7/) + 1.e6/) !> Lookup tables for ice number concentration (/m**3). REAL, DIMENSION(ntb_i1), PARAMETER, PRIVATE:: & @@ -354,6 +368,15 @@ MODULE module_mp_thompson !.. and temperature array indices. Variables beginning with t-p/c/m/n !.. represent lookup tables. Save compile-time memory by making !.. allocatable (2009Jun12, J. Michalakes). + +!..To permit possible creation of new lookup tables as variables expand/change, +!.. specify a name of external file(s) including version number for pre-computed +!.. Thompson tables. + character(len=*), parameter :: thomp_table_file = 'thompson_tables_precomp_v2.sl' + character(len=*), parameter :: qr_acr_qg_file = 'qr_acr_qgV2.dat' + character(len=*), parameter :: qr_acr_qs_file = 'qr_acr_qsV2.dat' + character(len=*), parameter :: freeze_h2o_file = 'freezeH2O.dat' + INTEGER, PARAMETER, PRIVATE:: R8SIZE = 8 INTEGER, PARAMETER, PRIVATE:: R4SIZE = 4 REAL (KIND=R8SIZE), ALLOCATABLE, DIMENSION(:,:,:,:):: & @@ -748,7 +771,7 @@ SUBROUTINE thompson_init(nwfa2d, nifa2d, nwfa, nifa, & mpi_communicator = mpicomm #ifdef SION call cpu_time(stime) - call readwrite_tables("read", mpicomm, mpirank, mpiroot, ierr) + call readwrite_tables(thomp_table_file, "read", mpicomm, mpirank, mpiroot, ierr) call cpu_time(etime) if (ierr==0) then precomputed_tables = .true. @@ -897,6 +920,10 @@ SUBROUTINE thompson_init(nwfa2d, nifa2d, nwfa, nifa, & if (mpirank==mpiroot) write(0,*) ' creating rain evap table' call table_dropEvap +!> - Call qi_aut_qs() to create conversion of some ice mass into snow category + if (mpirank==mpiroot) write(0,*) ' creating ice converting to snow table' + call qi_aut_qs + call cpu_time(etime) if (mpirank==mpiroot) print '("Calculating Thompson tables part 1 took ",f10.3," seconds.")', etime-stime @@ -945,19 +972,12 @@ SUBROUTINE thompson_init(nwfa2d, nifa2d, nwfa, nifa, & call cpu_time(etime) if (mpirank==mpiroot) print '("Computing freezing of water drops table took ",f10.3," seconds.")', etime-stime -!> - Call qi_aut_qs() to create conversion of some ice mass into snow category - if (mpirank==mpiroot) write(0,*) ' creating ice converting to snow table' - call cpu_time(stime) - call qi_aut_qs - call cpu_time(etime) - if (mpirank==mpiroot) print '("Computing ice converting to snow table took ",f10.3," seconds.")', etime-stime - call cpu_time(etime) if (mpirank==mpiroot) print '("Calculating Thompson tables part 2 took ",f10.3," seconds.")', etime-stime #ifdef SION call cpu_time(stime) - call readwrite_tables("write", mpicomm, mpirank, mpiroot, ierr) + call readwrite_tables(thomp_table_file, "write", mpicomm, mpirank, mpiroot, ierr) if (ierr/=0) then write(0,*) "An error occurred writing Thompson tables to disk" stop 1 @@ -1019,7 +1039,7 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & REAL, DIMENSION(ims:ime, kms:kme, jms:jme), OPTIONAL, INTENT(INOUT):: & nc, nwfa, nifa REAL, DIMENSION(ims:ime, jms:jme), OPTIONAL, INTENT(IN):: nwfa2d, nifa2d - REAL, DIMENSION(ims:ime, kms:kme, jms:jme), OPTIONAL, INTENT(OUT):: & + REAL, DIMENSION(ims:ime, kms:kme, jms:jme), OPTIONAL, INTENT(INOUT):: & re_cloud, re_ice, re_snow INTEGER, INTENT(IN) :: rand_perturb_on, kme_stoch REAL, DIMENSION(ims:ime,kms:kme_stoch,jms:jme), INTENT(IN), OPTIONAL:: & @@ -1059,7 +1079,6 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & REAL, DIMENSION(its:ite, jts:jte):: pcp_ra, pcp_sn, pcp_gr, pcp_ic REAL:: dt, pptrain, pptsnow, pptgraul, pptice REAL:: qc_max, qr_max, qs_max, qi_max, qg_max, ni_max, nr_max - REAL:: nwfa1 REAL:: rand1, rand2, rand3, min_rand INTEGER:: i, j, k, m INTEGER:: imax_qc,imax_qr,imax_qi,imax_qs,imax_qg,imax_ni,imax_nr @@ -1195,8 +1214,8 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & ! 5 gives both 1+4 ! 6 gives both 2+4 ! 7 gives all 1+2+4 -! For now (22Mar2018), standard deviation should be only 0.25 and cut-off at 1.5 -! in order to constrain the various perturbations from being too extreme. +! For now (22Mar2018), standard deviation should be up to 0.75 and cut-off at 3.0 +! stddev in order to constrain the various perturbations from being too extreme. !+---+-----------------------------------------------------------------+ rand1 = 0.0 rand2 = 0.0 @@ -1206,7 +1225,7 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & m = RSHIFT(ABS(rand_perturb_on),1) if (MOD(m,2) .ne. 0) rand2 = rand_pert(i,1,j)*2. m = RSHIFT(ABS(rand_perturb_on),2) - if (MOD(m,2) .ne. 0) rand3 = 0.1*(rand_pert(i,1,j)+ABS(min_rand)) + if (MOD(m,2) .ne. 0) rand3 = 0.25*(rand_pert(i,1,j)+ABS(min_rand)) m = RSHIFT(ABS(rand_perturb_on),3) endif !+---+-----------------------------------------------------------------+ @@ -1244,6 +1263,7 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & qg1d(k) = qg(i,k,j) ni1d(k) = ni(i,k,j) nr1d(k) = nr(i,k,j) + rho(k) = 0.622*p1d(k)/(R*t1d(k)*(qv1d(k)+0.622)) enddo if (is_aerosol_aware) then do k = kts, kte @@ -1251,10 +1271,8 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & nwfa1d(k) = nwfa(i,k,j) nifa1d(k) = nifa(i,k,j) enddo - nwfa1 = nwfa2d(i,j) else do k = kts, kte - rho(k) = 0.622*p1d(k)/(R*t1d(k)*(qv1d(k)+0.622)) nc1d(k) = Nt_c/rho(k) nwfa1d(k) = 11.1E6/rho(k) nifa1d(k) = naIN1*0.01/rho(k) @@ -1305,7 +1323,6 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & !.. Changed 13 May 2013 to fake emissions in which nwfa2d is aerosol !.. number tendency (number per kg per second). if (is_aerosol_aware) then -!-GT nwfa1d(kts) = nwfa1 nwfa1d(kts) = nwfa1d(kts) + nwfa2d(i,j)*dt_in nifa1d(kts) = nifa1d(kts) + nifa2d(i,j)*dt_in @@ -1439,17 +1456,17 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & IF (has_reqc.ne.0 .and. has_reqi.ne.0 .and. has_reqs.ne.0) THEN do k = kts, kte - re_qc1d(k) = 2.50E-6 ! 2.49E-6 - re_qi1d(k) = 5.00E-6 ! 4.99E-6 - re_qs1d(k) = 1.00E-5 ! 9.99E-6 + re_qc1d(k) = re_qc_min + re_qi1d(k) = re_qi_min + re_qs1d(k) = re_qs_min enddo !> - Call calc_effectrad() call calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & re_qc1d, re_qi1d, re_qs1d, kts, kte) do k = kts, kte - re_cloud(i,k,j) = MAX(2.50E-6, MIN(re_qc1d(k), 50.E-6)) ! MAX(2.49E-6, MIN(re_qc1d(k), 50.E-6)) - re_ice(i,k,j) = MAX(5.00E-6, MIN(re_qi1d(k), 125.E-6)) ! MAX(4.99E-6, MIN(re_qi1d(k), 125.E-6)) - re_snow(i,k,j) = MAX(1.00E-5, MIN(re_qs1d(k), 999.E-6)) ! MAX(9.99E-6, MIN(re_qs1d(k), 999.E-6)) + re_cloud(i,k,j) = MAX(re_qc_min, MIN(re_qc1d(k), re_qc_max)) + re_ice(i,k,j) = MAX(re_qi_min, MIN(re_qi1d(k), re_qi_max)) + re_snow(i,k,j) = MAX(re_qs_min, MIN(re_qs1d(k), re_qs_max)) enddo ENDIF @@ -1631,7 +1648,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & REAL:: r_frac, g_frac REAL:: Ef_rw, Ef_sw, Ef_gw, Ef_rr REAL:: Ef_ra, Ef_sa, Ef_ga - REAL:: dtsave, odts, odt, odzq, hgt_agl + REAL:: dtsave, odts, odt, odzq, hgt_agl, SR REAL:: xslw1, ygra1, zans1, eva_factor INTEGER:: i, k, k2, n, nn, nstep, k_0, kbot, IT, iexfrq INTEGER, DIMENSION(5):: ksed1 @@ -1785,14 +1802,17 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & nwfa(k) = MAX(11.1E6, MIN(9999.E6, nwfa1d(k)*rho(k))) nifa(k) = MAX(naIN1*0.01, MIN(9999.E6, nifa1d(k)*rho(k))) mvd_r(k) = D0r + mvd_c(k) = D0c if (qc1d(k) .gt. R1) then no_micro = .false. rc(k) = qc1d(k)*rho(k) nc(k) = MAX(2., MIN(nc1d(k)*rho(k), Nt_c_max)) L_qc(k) = .true. - if (rand2 .eq. 0.0) then - nu_c = MIN(15, NINT(1000.E6/nc(k)) + 2) + if (nc(k).gt.10000.E6) then + nu_c = 2 + elseif (nc(k).lt.100.) then + nu_c = 15 else nu_c = NINT(1000.E6/nc(k)) + 2 nu_c = MAX(2, MIN(nu_c+NINT(rand2), 15)) @@ -1820,8 +1840,8 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & ri(k) = qi1d(k)*rho(k) ni(k) = MAX(R2, ni1d(k)*rho(k)) if (ni(k).le. R2) then - lami = cie(2)/25.E-6 - ni(k) = MIN(499.D3, cig(1)*oig2*ri(k)/am_i*lami**bm_i) + lami = cie(2)/5.E-6 + ni(k) = MIN(9999.D3, cig(1)*oig2*ri(k)/am_i*lami**bm_i) endif L_qi(k) = .true. lami = (am_i*cig(2)*oig1*ni(k)/ri(k))**obmi @@ -1829,7 +1849,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & xDi = (bm_i + mu_i + 1.) * ilami if (xDi.lt. 5.E-6) then lami = cie(2)/5.E-6 - ni(k) = MIN(499.D3, cig(1)*oig2*ri(k)/am_i*lami**bm_i) + ni(k) = MIN(9999.D3, cig(1)*oig2*ri(k)/am_i*lami**bm_i) elseif (xDi.gt. 300.E-6) then lami = cie(2)/300.E-6 ni(k) = cig(1)*oig2*ri(k)/am_i*lami**bm_i @@ -2033,26 +2053,11 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & !+---+-----------------------------------------------------------------+ !> - Calculate y-intercept, slope values for graupel. !+---+-----------------------------------------------------------------+ - N0_min = gonv_max - k_0 = kts - do k = kte, kts, -1 - if (temp(k).ge.270.65) k_0 = MAX(k_0, k) - enddo do k = kte, kts, -1 - if (k.gt.k_0 .and. L_qr(k) .and. mvd_r(k).gt.100.E-6) then - xslw1 = 4.01 + alog10(mvd_r(k)) - else - xslw1 = 0.01 - endif - ygra1 = 4.31 + alog10(max(5.E-5, rg(k))) - zans1 = (3.1 + (100./(300.*xslw1*ygra1/(10./xslw1+1.+0.25*ygra1)+30.+10.*ygra1))) + rand1 - if (rand1 .ne. 0.0) then - zans1 = MAX(2., MIN(zans1, 7.)) - endif + ygra1 = alog10(max(1.E-9, rg(k))) + zans1 = 3.0 + 2./7.*(ygra1+8.) + rand1 N0_exp = 10.**(zans1) N0_exp = MAX(DBLE(gonv_min), MIN(N0_exp, DBLE(gonv_max))) - N0_min = MIN(N0_exp, N0_min) - N0_exp = N0_min lam_exp = (N0_exp*am_g*cgg(1)/rg(k))**oge1 lamg = lam_exp * (cgg(3)*ogg2*ogg1)**obmg ilamg(k) = 1./lamg @@ -2087,10 +2092,11 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & pnr_rcr(k) = Ef_rr * 2.0*nr(k)*rr(k) endif - mvd_c(k) = D0c if (L_qc(k)) then - if (rand2 .eq. 0.0) then - nu_c = MIN(15, NINT(1000.E6/nc(k)) + 2) + if (nc(k).gt.10000.E6) then + nu_c = 2 + elseif (nc(k).lt.100.) then + nu_c = 15 else nu_c = NINT(1000.E6/nc(k)) + 2 nu_c = MAX(2, MIN(nu_c+NINT(rand2), 15)) @@ -2098,6 +2104,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & xDc = MAX(D0c*1.E6, ((rc(k)/(am_r*nc(k)))**obmr) * 1.E6) lamc = (nc(k)*am_r* ccg(2,nu_c) * ocg1(nu_c) / rc(k))**obmr mvd_c(k) = (3.0+nu_c+0.672) / lamc + mvd_c(k) = MAX(D0c, MIN(mvd_c(k), D0r)) endif !> - Autoconversion follows Berry & Reinhardt (1974) with characteristic @@ -2113,7 +2120,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & tau = 3.72/(rc(k)*taud) prr_wau(k) = zeta/tau prr_wau(k) = MIN(DBLE(rc(k)*odts), prr_wau(k)) - pnr_wau(k) = prr_wau(k) / (am_r*nu_c*D0r*D0r*D0r) ! RAIN2M + pnr_wau(k) = prr_wau(k) / (am_r*nu_c*200.*D0r*D0r*D0r) ! RAIN2M pnc_wau(k) = MIN(DBLE(nc(k)*odts), prr_wau(k) & / (am_r*mvd_c(k)*mvd_c(k)*mvd_c(k))) ! Qc2M endif @@ -2153,7 +2160,9 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & !+---+-----------------------------------------------------------------+ if (.not. iiwarm) then do k = kts, kte - vts_boost(k) = 1.5 + vts_boost(k) = 1.0 + xDs = 0.0 + if (L_qs(k)) xDs = smoc(k) / smob(k) !> - Temperature lookup table indexes. tempc = temp(k) - 273.15 @@ -2305,13 +2314,12 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & !> - Snow collecting cloud water. In CE, assume Dc< - Snow and graupel collecting aerosols, wet scavenging. if (rs(k) .gt. r_s(1)) then - xDs = smoc(k) / smob(k) Ef_sa = Eff_aero(xDs,0.04E-6,visco(k),rho(k),temp(k),'s') pna_sca(k) = rhof(k)*t1_qs_qc*Ef_sa*nwfa(k)*smoe(k) pna_sca(k) = MIN(DBLE(nwfa(k)*odts), pna_sca(k)) @@ -2387,6 +2394,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & + tnr_racs2(idx_s,idx_t,idx_r1,idx_r) & + tnr_sacr1(idx_s,idx_t,idx_r1,idx_r) & + tnr_sacr2(idx_s,idx_t,idx_r1,idx_r) + pnr_rcs(k) = MIN(DBLE(nr(k)*odts), pnr_rcs(k)) else prs_rcs(k) = -tcs_racs1(idx_s,idx_t,idx_r1,idx_r) & - tms_sacr1(idx_s,idx_t,idx_r1,idx_r) & @@ -2394,10 +2402,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & + tcr_sacr2(idx_s,idx_t,idx_r1,idx_r) prs_rcs(k) = MAX(DBLE(-rs(k)*odts), prs_rcs(k)) prr_rcs(k) = -prs_rcs(k) - pnr_rcs(k) = tnr_racs2(idx_s,idx_t,idx_r1,idx_r) & ! RAIN2M - + tnr_sacr2(idx_s,idx_t,idx_r1,idx_r) endif - pnr_rcs(k) = MIN(DBLE(nr(k)*odts), pnr_rcs(k)) endif !> - Rain collecting graupel. Cannot assume Wisner (1972) approximation @@ -2422,17 +2427,59 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & endif endif + if (temp(k).lt.T_0) then + rate_max = (qv(k)-qvsi(k))*rho(k)*odts*0.999 + +!> - Deposition/sublimation of snow/graupel follows Srivastava & Coen (1992) + if (L_qs(k)) then + C_snow = C_sqrd + (tempc+1.5)*(C_cube-C_sqrd)/(-30.+1.5) + C_snow = MAX(C_sqrd, MIN(C_snow, C_cube)) + prs_sde(k) = C_snow*t1_subl*diffu(k)*ssati(k)*rvs & + * (t1_qs_sd*smo1(k) & + + t2_qs_sd*rhof2(k)*vsc2(k)*smof(k)) + if (prs_sde(k).lt. 0.) then + prs_sde(k) = MAX(DBLE(-rs(k)*odts), prs_sde(k), DBLE(rate_max)) + else + prs_sde(k) = MIN(prs_sde(k), DBLE(rate_max)) + endif + endif + + if (L_qg(k) .and. ssati(k).lt. -eps) then + prg_gde(k) = C_cube*t1_subl*diffu(k)*ssati(k)*rvs & + * N0_g(k) * (t1_qg_sd*ilamg(k)**cge(10) & + + t2_qg_sd*vsc2(k)*rhof2(k)*ilamg(k)**cge(11)) + if (prg_gde(k).lt. 0.) then + prg_gde(k) = MAX(DBLE(-rg(k)*odts), prg_gde(k), DBLE(rate_max)) + else + prg_gde(k) = MIN(prg_gde(k), DBLE(rate_max)) + endif + endif + +!> - A portion of rimed snow converts to graupel but some remains snow. +!! Interp from 15 to 95% as riming factor increases from 5.0 to 30.0 +!! 0.028 came from (.75-.15)/(30.-5.). This remains ad-hoc and should +!! be revisited. + if (prs_scw(k).gt.5.0*prs_sde(k) .and. & + prs_sde(k).gt.eps) then + r_frac = MIN(30.0D0, prs_scw(k)/prs_sde(k)) + g_frac = MIN(0.75, 0.15 + (r_frac-5.)*.028) + vts_boost(k) = MIN(1.5, 1.1 + (r_frac-5.)*.016) + prg_scw(k) = g_frac*prs_scw(k) + prs_scw(k) = (1. - g_frac)*prs_scw(k) + endif + + endif + !+---+-----------------------------------------------------------------+ !> - Next IF block handles only those processes below 0C. !+---+-----------------------------------------------------------------+ if (temp(k).lt.T_0) then - vts_boost(k) = 1.0 rate_max = (qv(k)-qvsi(k))*rho(k)*odts*0.999 !+---+---------------- BEGIN NEW ICE NUCLEATION -----------------------+ -!> - Begin NEW ICE NUCLEATION: Freezing of supercooled water (rain or cloud) is influenced by dust +!> - Freezing of supercooled water (rain or cloud) is influenced by dust !! but still using Bigg 1953 with a temperature adjustment of a few !! degrees depending on dust concentration. A default value by way !! of idx_IN is 1.0 per Liter of air is used when dustyIce flag is @@ -2475,7 +2522,6 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & pnr_rfz(k) = MIN(DBLE(nr(k)*odts), pnr_rfz(k)) elseif (rr(k).gt. R1 .and. temp(k).lt.HGFR) then pri_rfz(k) = rr(k)*odts - pnr_rfz(k) = nr(k)*odts ! RAIN2M pni_rfz(k) = pnr_rfz(k) endif @@ -2496,7 +2542,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & .and. temp(k).lt.253.15) ) then if (dustyIce .AND. is_aerosol_aware) then xnc = iceDeMott(tempc,qv(k),qvs(k),qvsi(k),rho(k),nifa(k)) - xnc = xnc*(1.0 + 3.*rand3) + xnc = xnc*(1.0 + 50.*rand3) else xnc = MIN(250.E3, TNO*EXP(ATO*(T_0-temp(k)))) endif @@ -2508,7 +2554,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & !> - Freezing of aqueous aerosols based on Koop et al (2001, Nature) xni = smo0(k)+ni(k) + (pni_rfz(k)+pni_wfz(k)+pni_inu(k))*dtsave - if (is_aerosol_aware .AND. homogIce .AND. (xni.le.500.E3) & + if (is_aerosol_aware .AND. homogIce .AND. (xni.le.999.E3) & & .AND.(temp(k).lt.238).AND.(ssati(k).ge.0.4) ) then xnc = iceKoop(temp(k),qv(k),qvs(k),nwfa(k), dtsave) pni_iha(k) = xnc*odts @@ -2554,32 +2600,6 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & endif endif -!> - Deposition/sublimation of snow/graupel follows Srivastava & Coen -!! (1992). - if (L_qs(k)) then - C_snow = C_sqrd + (tempc+1.5)*(C_cube-C_sqrd)/(-30.+1.5) - C_snow = MAX(C_sqrd, MIN(C_snow, C_cube)) - prs_sde(k) = C_snow*t1_subl*diffu(k)*ssati(k)*rvs & - * (t1_qs_sd*smo1(k) & - + t2_qs_sd*rhof2(k)*vsc2(k)*smof(k)) - if (prs_sde(k).lt. 0.) then - prs_sde(k) = MAX(DBLE(-rs(k)*odts), prs_sde(k), DBLE(rate_max)) - else - prs_sde(k) = MIN(prs_sde(k), DBLE(rate_max)) - endif - endif - - if (L_qg(k) .and. ssati(k).lt. -eps) then - prg_gde(k) = C_cube*t1_subl*diffu(k)*ssati(k)*rvs & - * N0_g(k) * (t1_qg_sd*ilamg(k)**cge(10) & - + t2_qg_sd*vsc2(k)*rhof2(k)*ilamg(k)**cge(11)) - if (prg_gde(k).lt. 0.) then - prg_gde(k) = MAX(DBLE(-rg(k)*odts), prg_gde(k), DBLE(rate_max)) - else - prg_gde(k) = MIN(prg_gde(k), DBLE(rate_max)) - endif - endif - !> - Snow collecting cloud ice. In CE, assume Di< - A portion of rimed snow converts to graupel but some remains snow. -!! Interp from 15 to 95% as riming factor increases from 2.0 to 30.0 -!! 0.028 came from (.95-.15)/(30.-2.). This remains ad-hoc and should -!! be revisited. - if (prs_scw(k).gt.2.0*prs_sde(k) .and. & - prs_sde(k).gt.eps) then - r_frac = MIN(30.0D0, prs_scw(k)/prs_sde(k)) - g_frac = MIN(0.95, 0.15 + (r_frac-2.)*.028) - vts_boost(k) = MIN(1.5, 1.1 + (r_frac-2.)*.016) - prg_scw(k) = g_frac*prs_scw(k) - prs_scw(k) = (1. - g_frac)*prs_scw(k) - endif - else !> - Melt snow and graupel and enhance from collisions with liquid. @@ -2643,12 +2650,13 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & if (L_qs(k)) then prr_sml(k) = (tempc*tcond(k)-lvap0*diffu(k)*delQvs(k)) & * (t1_qs_me*smo1(k) + t2_qs_me*rhof2(k)*vsc2(k)*smof(k)) - prr_sml(k) = prr_sml(k) + 4218.*olfus*tempc & - * (prr_rcs(k)+prs_scw(k)) + if (prr_sml(k) .gt. 0.) then + prr_sml(k) = prr_sml(k) + 4218.*olfus*tempc & + * (prr_rcs(k)+prs_scw(k)) + endif prr_sml(k) = MIN(DBLE(rs(k)*odts), MAX(0.D0, prr_sml(k))) pnr_sml(k) = smo0(k)/rs(k)*prr_sml(k) * 10.0**(-0.25*tempc) ! RAIN2M pnr_sml(k) = MIN(DBLE(smo0(k)*odts), pnr_sml(k)) -! if (tempc.gt.3.5 .or. rs(k).lt.0.005E-3) pnr_sml(k)=0.0 if (ssati(k).lt. 0.) then prs_sde(k) = C_cube*t1_subl*diffu(k)*ssati(k)*rvs & @@ -2667,7 +2675,6 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & prr_gml(k) = MIN(DBLE(rg(k)*odts), MAX(0.D0, prr_gml(k))) pnr_gml(k) = N0_g(k)*cgg(2)*ilamg(k)**cge(2) / rg(k) & ! RAIN2M * prr_gml(k) * 10.0**(-0.5*tempc) -! if (tempc.gt.7.5 .or. rg(k).lt.0.005E-3) pnr_gml(k)=0.0 if (ssati(k).lt. 0.) then prg_gde(k) = C_cube*t1_subl*diffu(k)*ssati(k)*rvs & @@ -2677,7 +2684,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & endif endif -!> - This change will be required if users run adaptive time step that +!> - This change will be required if users run adaptive time step that !! results in delta-t that is generally too long to allow cloud water !! collection by snow/graupel above melting temperature. !! Credit to Bjorn-Egil Nygaard for discovering. @@ -2835,8 +2842,10 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & xrc=MAX(R1, (qc1d(k) + qcten(k)*dtsave)*rho(k)) xnc=MAX(2., (nc1d(k) + ncten(k)*dtsave)*rho(k)) if (xrc .gt. R1) then - if (rand2 .eq. 0.0) then - nu_c = MIN(15, NINT(1000.E6/xnc) + 2) + if (xnc.gt.10000.E6) then + nu_c = 2 + elseif (xnc.lt.100.) then + nu_c = 15 else nu_c = NINT(1000.E6/xnc) + 2 nu_c = MAX(2, MIN(nu_c+NINT(rand2), 15)) @@ -2881,7 +2890,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & xDi = (bm_i + mu_i + 1.) * ilami if (xDi.lt. 5.E-6) then lami = cie(2)/5.E-6 - xni = MIN(499.D3, cig(1)*oig2*xri/am_i*lami**bm_i) + xni = MIN(9999.D3, cig(1)*oig2*xri/am_i*lami**bm_i) niten(k) = (xni-ni1d(k)*rho(k))*odts*orho elseif (xDi.gt. 300.E-6) then lami = cie(2)/300.E-6 @@ -2905,7 +2914,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & !> - Rain number tendency nrten(k) = nrten(k) + (pnr_wau(k) + pnr_sml(k) + pnr_gml(k) & - (pnr_rfz(k) + pnr_rcr(k) + pnr_rcg(k) & - + pnr_rcs(k) + pnr_rci(k)) ) & + + pnr_rcs(k) + pnr_rci(k) + pni_rfz(k)) ) & * orho !> - Rain mass/number balance; keep median volume diameter between @@ -2993,7 +3002,9 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & lvt2(k)=lvap(k)*lvap(k)*ocp(k)*oRv*otemp*otemp nwfa(k) = MAX(11.1E6, (nwfa1d(k) + nwfaten(k)*DT)*rho(k)) + enddo + do k = kts, kte if ((qc1d(k) + qcten(k)*DT) .gt. R1) then rc(k) = (qc1d(k) + qcten(k)*DT)*rho(k) nc(k) = MAX(2., MIN((nc1d(k)+ncten(k)*DT)*rho(k), Nt_c_max)) @@ -3118,26 +3129,11 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & !+---+-----------------------------------------------------------------+ !> - Calculate y-intercept, slope values for graupel. !+---+-----------------------------------------------------------------+ - N0_min = gonv_max - k_0 = kts - do k = kte, kts, -1 - if (temp(k).ge.270.65) k_0 = MAX(k_0, k) - enddo do k = kte, kts, -1 - if (k.gt.k_0 .and. L_qr(k) .and. mvd_r(k).gt.100.E-6) then - xslw1 = 4.01 + alog10(mvd_r(k)) - else - xslw1 = 0.01 - endif - ygra1 = 4.31 + alog10(max(5.E-5, rg(k))) - zans1 = (3.1 + (100./(300.*xslw1*ygra1/(10./xslw1+1.+0.25*ygra1)+30.+10.*ygra1))) + rand1 - if (rand1 .ne. 0.0) then - zans1 = MAX(2., MIN(zans1, 7.)) - endif + ygra1 = alog10(max(1.E-9, rg(k))) + zans1 = 3.0 + 2./7.*(ygra1+8.) + rand1 N0_exp = 10.**(zans1) N0_exp = MAX(DBLE(gonv_min), MIN(N0_exp, DBLE(gonv_max))) - N0_min = MIN(N0_exp, N0_min) - N0_exp = N0_min lam_exp = (N0_exp*am_g*cgg(1)/rg(k))**oge1 lamg = lam_exp * (cgg(3)*ogg2*ogg1)**obmg ilamg(k) = 1./lamg @@ -3313,11 +3309,11 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & !..TEST: G. Thompson 10 May 2013 !> - Reduce the rain evaporation in same places as melting graupel occurs. -!Rationale: falling and simultaneous melting graupel in subsaturated -!regions will not melt as fast because particle temperature stays -!..at 0C. Also not much shedding of the water from the graupel so -!..likely that the water-coated graupel evaporating much slower than -!..if the water was immediately shed off. +!! Rationale: falling and simultaneous melting graupel in subsaturated +!! regions will not melt as fast because particle temperature stays +!! at 0C. Also not much shedding of the water from the graupel so +!! likely that the water-coated graupel evaporating much slower than +!! if the water was immediately shed off. IF (prr_gml(k).gt.0.0) THEN eva_factor = MIN(1.0, 0.01+(0.99-0.01)*(tempc/20.0)) prv_rev(k) = prv_rev(k)*eva_factor @@ -3420,8 +3416,10 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & do k = ksed1(5), kts, -1 vtc = 0. if (rc(k) .gt. R1 .and. w1d(k) .lt. 1.E-1) then - if (rand2 .eq. 0.0) then - nu_c = MIN(15, NINT(1000.E6/nc(k)) + 2) + if (nc(k).gt.10000.E6) then + nu_c = 2 + elseif (nc(k).lt.100.) then + nu_c = 15 else nu_c = NINT(1000.E6/nc(k)) + 2 nu_c = MAX(2, MIN(nu_c+NINT(rand2), 15)) @@ -3490,13 +3488,10 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & t4_vts = Kap1*Mrat**mu_s*csg(7)*ils2**cse(7) vts = rhof(k)*av_s * (t1_vts+t2_vts)/(t3_vts+t4_vts) if (temp(k).gt. (T_0+0.1)) then - vtsk(k) = MAX(vts*vts_boost(k), & - & vts*((vtrk(k)-vts*vts_boost(k))/(temp(k)-T_0))) ! -! DH* The version below is supposed to be a better formulation, -! but gave worse results in RAPv5/HRRRv4 than the line above. - ! this formulation for RAPv5/HRRRv4, reverted 20 Feb 2020 - ! SR = rs(k)/(rs(k)+rr(k)) ! bug fix from G. Thompson, 10 May 2019 - ! vtsk(k) = vts*SR + (1.-SR)*vtrk(k) +! vtsk(k) = MAX(vts*vts_boost(k), & +! & vts*((vtrk(k)-vts*vts_boost(k))/(temp(k)-T_0))) + SR = rs(k)/(rs(k)+rr(k)) + vtsk(k) = vts*SR + (1.-SR)*vtrk(k) else vtsk(k) = vts*vts_boost(k) endif @@ -3547,10 +3542,6 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & !> - Sedimentation of mixing ratio is the integral of v(D)*m(D)*N(D)*dD, !! whereas neglect m(D) term for number concentration. Therefore, !! cloud ice has proper differential sedimentation. -!.. New in v3.0+ is computing separate for rain, ice, snow, and -!.. graupel species thus making code faster with credit to J. Schmidt. -!.. Bug fix, 2013Nov01 to tendencies using rho(k+1) correction thanks to -!.. Eric Skyllingstad. !+---+-----------------------------------------------------------------+ if (ANY(L_qr .eqv. .true.)) then @@ -3580,11 +3571,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & *odzq*DT*onstep(1)) enddo -#if 1 if (rr(kts).gt.R1*10.) & -#else - if (rr(kts).gt.R1*1000.) & -#endif pptrain = pptrain + sed_r(kts)*DT*onstep(1) enddo endif @@ -3635,11 +3622,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & *odzq*DT*onstep(2)) enddo -#if 1 if (ri(kts).gt.R1*10.) & -#else - if (ri(kts).gt.R1*1000.) & -#endif pptice = pptice + sed_i(kts)*DT*onstep(2) enddo endif @@ -3666,11 +3649,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & *odzq*DT*onstep(3)) enddo -#if 1 if (rs(kts).gt.R1*10.) & -#else - if (rs(kts).gt.R1*1000.) & -#endif pptsnow = pptsnow + sed_s(kts)*DT*onstep(3) enddo endif @@ -3697,11 +3676,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & *odzq*DT*onstep(4)) enddo -#if 1 if (rg(kts).gt.R1*10.) & -#else - if (rg(kts).gt.R1*1000.) & -#endif pptgraul = pptgraul + sed_g(kts)*DT*onstep(4) enddo endif @@ -3742,19 +3717,21 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & qv1d(k) = MAX(1.E-10, qv1d(k) + qvten(k)*DT) qc1d(k) = qc1d(k) + qcten(k)*DT nc1d(k) = MAX(2./rho(k), MIN(nc1d(k) + ncten(k)*DT, Nt_c_max)) - nwfa1d(k) = MAX(11.1E6/rho(k), MIN(9999.E6/rho(k), & + nwfa1d(k) = MAX(11.1E6, MIN(9999.E6, & (nwfa1d(k)+nwfaten(k)*DT))) - nifa1d(k) = MAX(naIN1*0.01, MIN(9999.E6/rho(k), & + nifa1d(k) = MAX(naIN1*0.01, MIN(9999.E6, & (nifa1d(k)+nifaten(k)*DT))) if (qc1d(k) .le. R1) then qc1d(k) = 0.0 nc1d(k) = 0.0 else - if (rand2 .eq. 0.0) then - nu_c = MIN(15, NINT(1000.E6/(nc1d(k)*rho(k))) + 2) + if (nc1d(k)*rho(k).gt.10000.E6) then + nu_c = 2 + elseif (nc1d(k)*rho(k).lt.100.) then + nu_c = 15 else - nu_c = NINT(1000.E6/(nc1d(k)*rho(k))) + 2 - nu_c = MAX(2, MIN(nu_c+NINT(rand2), 15)) + nu_c = NINT(1000.E6/(nc1d(k)*rho(k)) + 2 + nu_c = MAX(2, MIN(nu_c+NINT(rand2), 15)) endif lamc = (am_r*ccg(2,nu_c)*ocg1(nu_c)*nc1d(k)/qc1d(k))**obmr xDc = (bm_r + nu_c + 1.) / lamc @@ -3782,7 +3759,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & lami = cie(2)/300.E-6 endif ni1d(k) = MIN(cig(1)*oig2*qi1d(k)/am_i*lami**bm_i, & - 499.D3/rho(k)) + 9999.D3/rho(k)) endif qr1d(k) = qr1d(k) + qrten(k)*DT nr1d(k) = MAX(R2/rho(k), nr1d(k) + nrten(k)*DT) @@ -3837,13 +3814,12 @@ subroutine qr_acr_qg good = 0 - INQUIRE(FILE="qr_acr_qg.dat",EXIST=lexist) + INQUIRE(FILE=qr_acr_qg_file, EXIST=lexist) #ifdef MPI call MPI_BARRIER(mpi_communicator,ierr) #endif IF ( lexist ) THEN - !write(0,*) "ThompMP: read qr_acr_qg.dat instead of computing" - OPEN(63,file="qr_acr_qg.dat",form="unformatted",err=1234) + OPEN(63,file=qr_acr_qg_file,form="unformatted",err=1234) !sms$serial begin READ(63,err=1234) tcg_racg READ(63,err=1234) tmr_racg @@ -3858,13 +3834,13 @@ subroutine qr_acr_qg INQUIRE(63,opened=lopen) IF (lopen) THEN IF( force_read_thompson ) THEN - write(0,*) "Error reading qr_acr_qg.dat. Aborting because force_read_thompson is .true." + write(0,*) "Error reading "//qr_acr_qg_file//" Aborting because force_read_thompson is .true." return ENDIF CLOSE(63) ELSE IF( force_read_thompson ) THEN - write(0,*) "Error opening qr_acr_qg.dat. Aborting because force_read_thompson is .true." + write(0,*) "Error opening "//qr_acr_qg_file//" Aborting because force_read_thompson is .true." return ENDIF ENDIF @@ -3876,7 +3852,7 @@ subroutine qr_acr_qg ENDIF ELSE IF( force_read_thompson ) THEN - write(0,*) "Non-existent qr_acr_qg.dat. Aborting because force_read_thompson is .true." + write(0,*) "Non-existent "//qr_acr_qg_file//" Aborting because force_read_thompson is .true." return ENDIF ENDIF @@ -3959,7 +3935,7 @@ subroutine qr_acr_qg tcg_racg(i,j,k,m) = t1 tmr_racg(i,j,k,m) = DMIN1(z1, r_r(m)*1.0d0) tcr_gacr(i,j,k,m) = t2 - tmg_gacr(i,j,k,m) = z2 + tmg_gacr(i,j,k,m) = DMIN1(z2, r_g(j)*1.0d0) tnr_racg(i,j,k,m) = y1 tnr_gacr(i,j,k,m) = y2 enddo @@ -3967,8 +3943,8 @@ subroutine qr_acr_qg enddo IF ( write_thompson_tables ) THEN - write(0,*) "Writing qr_acr_qg.dat in Thompson MP init" - OPEN(63,file="qr_acr_qg.dat",form="unformatted",err=9234) + write(0,*) "Writing "//qr_acr_qg_file//" in Thompson MP init" + OPEN(63,file=qr_acr_qg_file,form="unformatted",err=9234) WRITE(63,err=9234) tcg_racg WRITE(63,err=9234) tmr_racg WRITE(63,err=9234) tcr_gacr @@ -3978,7 +3954,7 @@ subroutine qr_acr_qg CLOSE(63) RETURN ! ----- RETURN 9234 CONTINUE - write(0,*) "Error writing qr_acr_qg.dat" + write(0,*) "Error writing //qr_acr_qg_file return ENDIF ENDIF @@ -4013,13 +3989,13 @@ subroutine qr_acr_qs write_thompson_tables = .false. good = 0 - INQUIRE(FILE="qr_acr_qs.dat",EXIST=lexist) + INQUIRE(FILE=qr_acr_qs_file, EXIST=lexist) #ifdef MPI call MPI_BARRIER(mpi_communicator,ierr) #endif IF ( lexist ) THEN - !write(0,*) "ThompMP: read qr_acr_qs.dat instead of computing" - OPEN(63,file="qr_acr_qs.dat",form="unformatted",err=1234) + !write(0,*) "ThompMP: read "//qr_acr_qs_file//" instead of computing" + OPEN(63,file=qr_acr_qs_file,form="unformatted",err=1234) !sms$serial begin READ(63,err=1234)tcs_racs1 READ(63,err=1234)tmr_racs1 @@ -4040,13 +4016,13 @@ subroutine qr_acr_qs INQUIRE(63,opened=lopen) IF (lopen) THEN IF( force_read_thompson ) THEN - write(0,*) "Error reading qr_acr_qs.dat. Aborting because force_read_thompson is .true." + write(0,*) "Error reading "//qr_acr_qs_file//" Aborting because force_read_thompson is .true." return ENDIF CLOSE(63) ELSE IF( force_read_thompson ) THEN - write(0,*) "Error opening qr_acr_qs.dat. Aborting because force_read_thompson is .true." + write(0,*) "Error opening "//qr_acr_qs_file//" Aborting because force_read_thompson is .true." return ENDIF ENDIF @@ -4058,7 +4034,7 @@ subroutine qr_acr_qs ENDIF ELSE IF( force_read_thompson ) THEN - write(0,*) "Non-existent qr_acr_qs.dat. Aborting because force_read_thompson is .true." + write(0,*) "Non-existent "//qr_acr_qs_file//" Aborting because force_read_thompson is .true." return ENDIF ENDIF @@ -4219,8 +4195,8 @@ subroutine qr_acr_qs enddo IF ( write_thompson_tables ) THEN - write(0,*) "Writing qr_acr_qs.dat in Thompson MP init" - OPEN(63,file="qr_acr_qs.dat",form="unformatted",err=9234) + write(0,*) "Writing "//qr_acr_qs_file//" in Thompson MP init" + OPEN(63,file=qr_acr_qs_file,form="unformatted",err=9234) WRITE(63,err=9234)tcs_racs1 WRITE(63,err=9234)tmr_racs1 WRITE(63,err=9234)tcs_racs2 @@ -4236,7 +4212,7 @@ subroutine qr_acr_qs CLOSE(63) RETURN ! ----- RETURN 9234 CONTINUE - write(0,*) "Error writing qr_acr_qs.dat" + write(0,*) "Error writing "//qr_acr_qs_file ENDIF ENDIF @@ -4274,13 +4250,13 @@ subroutine freezeH2O(threads) write_thompson_tables = .false. good = 0 - INQUIRE(FILE="freezeH2O.dat",EXIST=lexist) + INQUIRE(FILE=freeze_h2o_file",EXIST=lexist) #ifdef MPI call MPI_BARRIER(mpi_communicator,ierr) #endif IF ( lexist ) THEN - !write(0,*) "ThompMP: read freezeH2O.dat instead of computing" - OPEN(63,file="freezeH2O.dat",form="unformatted",err=1234) + !write(0,*) "ThompMP: read "//freeze_h2o_file//" instead of computing" + OPEN(63,file=freeze_h2o_file,form="unformatted",err=1234) !sms$serial begin READ(63,err=1234)tpi_qrfz READ(63,err=1234)tni_qrfz @@ -4295,13 +4271,13 @@ subroutine freezeH2O(threads) INQUIRE(63,opened=lopen) IF (lopen) THEN IF( force_read_thompson ) THEN - write(0,*) "Error reading freezeH2O.dat. Aborting because force_read_thompson is .true." + write(0,*) "Error reading "//freeze_h2o_file//" Aborting because force_read_thompson is .true." return ENDIF CLOSE(63) ELSE IF( force_read_thompson ) THEN - write(0,*) "Error opening freezeH2O.dat. Aborting because force_read_thompson is .true." + write(0,*) "Error opening "//freeze_h2o_file//" Aborting because force_read_thompson is .true." return ENDIF ENDIF @@ -4313,7 +4289,7 @@ subroutine freezeH2O(threads) ENDIF ELSE IF( force_read_thompson ) THEN - write(0,*) "Non-existent freezeH2O.dat. Aborting because force_read_thompson is .true." + write(0,*) "Non-existent "//freeze_h2o_file//" Aborting because force_read_thompson is .true." return ENDIF ENDIF @@ -4397,8 +4373,8 @@ subroutine freezeH2O(threads) enddo IF ( write_thompson_tables ) THEN - write(0,*) "Writing freezeH2O.dat in Thompson MP init" - OPEN(63,file="freezeH2O.dat",form="unformatted",err=9234) + write(0,*) "Writing "//freeze_h2o_file//" in Thompson MP init" + OPEN(63,file=freeze_h2o_file,form="unformatted",err=9234) WRITE(63,err=9234)tpi_qrfz WRITE(63,err=9234)tni_qrfz WRITE(63,err=9234)tpg_qrfz @@ -4408,7 +4384,7 @@ subroutine freezeH2O(threads) CLOSE(63) RETURN ! ----- RETURN 9234 CONTINUE - write(0,*) "Error writing freezeH2O.dat" + write(0,*) "Error writing "//freeze_h2o_file return ENDIF ENDIF @@ -5120,7 +5096,7 @@ real function iceDeMott(tempc, qv, qvs, qvsi, rho, nifa) ! mux = hx*p_alpha*n_in*rho ! xni = mux*((6700.*nifa)-200.)/((6700.*5.E5)-200.) ! elseif (satw.ge.0.985 .and. tempc.gt.HGFR-273.15) then - nifa_cc = nifa*RHO_NOT0*1.E-6/rho + nifa_cc = MAX(0.5, nifa*RHO_NOT0*1.E-6/rho) ! xni = 3.*nifa_cc**(1.25)*exp((0.46*(-tempc))-11.6) ! [DeMott, 2015] xni = (5.94e-5*(-tempc)**3.33) & ! [DeMott, 2010] * (nifa_cc**((-0.0264*(tempc))+0.0033)) @@ -5233,23 +5209,6 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & has_qi = .false. has_qs = .false. -! DH* 2020-06-08 Moved the initial values and bounds from -! the calling routines into calc_effectRad (to prevent -! multiple definitions that may be inconsistent). The -! initial values and bounds from the calling routines were -! -! re_cloud(i,k) = MAX(2.49, MIN(re_cloud(i,k)*1.e6, 50.)) -! re_ice(i,k) = MAX(4.99, MIN(re_ice(i,k)*1.e6, 125.)) -! re_snow(i,k) = MAX(9.99, MIN(re_snow(i,k)*1.e6, 999.)) -! -! independent of the version of Thompson MP. These values -! are consistent with the WRFv3.8.1 settings, but inconsistent -! with the WRFv4+ settings. In order to apply the same bounds -! as before this change, use the WRF v3.8.1 settings throughout. - re_qc1d(:) = 2.50E-6 ! 2.49E-6 - re_qi1d(:) = 5.00E-6 ! 4.99E-6 - re_qs1d(:) = 1.00E-5 ! 9.99E-6 - do k = kts, kte rho(k) = 0.622*p1d(k)/(R*t1d(k)*(qv1d(k)+0.622)) rc(k) = MAX(R1, qc1d(k)*rho(k)) @@ -5274,7 +5233,7 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & inu_c = MIN(15, NINT(1000.E6/nc(k)) + 2) endif lamc = (nc(k)*am_r*g_ratio(inu_c)/rc(k))**obmr - re_qc1d(k) = MAX(2.51E-6, MIN(SNGL(0.5D0 * DBLE(3.+inu_c)/lamc), 50.E-6)) + re_qc1d(k) = SNGL(0.5D0 * DBLE(3.+inu_c)/lamc) enddo endif @@ -5282,7 +5241,7 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & do k = kts, kte if (ri(k).le.R1 .or. ni(k).le.R2) CYCLE lami = (am_i*cig(2)*oig1*ni(k)/ri(k))**obmi - re_qi1d(k) = MAX(5.01E-6, MIN(SNGL(0.5D0 * DBLE(3.+mu_i)/lami), 125.E-6)) + re_qi1d(k) = SNGL(0.5D0 * DBLE(3.+mu_i)/lami) enddo endif @@ -5322,7 +5281,7 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & & + sb(7)*tc0*tc0*cse(1) + sb(8)*tc0*cse(1)*cse(1) & & + sb(9)*tc0*tc0*tc0 + sb(10)*cse(1)*cse(1)*cse(1) smoc = a_ * smo2**b_ - re_qs1d(k) = MAX(1.01E-5, MIN(0.5*(smoc/smob), 999.E-6)) + re_qs1d(k) = 0.5*(smoc/smob) enddo endif @@ -5441,8 +5400,15 @@ subroutine calc_refl10cm (qv1d, qc1d, qr1d, nr1d, qs1d, qg1d, & !+---+-----------------------------------------------------------------+ !..Calculate y-intercept, slope, and useful moments for snow. !+---+-----------------------------------------------------------------+ + do k = kts, kte + smo2(k) = 0. + smob(k) = 0. + smoc(k) = 0. + smoz(k) = 0. + enddo if (ANY(L_qs .eqv. .true.)) then do k = kts, kte + if (.not. L_qs(k)) CYCLE tc0 = MIN(-0.1, temp(k)-273.15) smob(k) = rs(k)*oams @@ -5498,26 +5464,11 @@ subroutine calc_refl10cm (qv1d, qc1d, qr1d, nr1d, qs1d, qg1d, & !+---+-----------------------------------------------------------------+ if (ANY(L_qg .eqv. .true.)) then - N0_min = gonv_max - k_0 = kts - do k = kte, kts, -1 - if (temp(k).ge.270.65) k_0 = MAX(k_0, k) - enddo do k = kte, kts, -1 - if (k.gt.k_0 .and. L_qr(k) .and. mvd_r(k).gt.100.E-6) then - xslw1 = 4.01 + alog10(mvd_r(k)) - else - xslw1 = 0.01 - endif - ygra1 = 4.31 + alog10(max(5.E-5, rg(k))) - zans1 = (3.1 + (100./(300.*xslw1*ygra1/(10./xslw1+1.+0.25*ygra1)+30.+10.*ygra1))) + rand1 - if (rand1 .ne. 0.0) then - zans1 = MAX(2., MIN(zans1, 7.)) - endif + ygra1 = alog10(max(1.E-9, rg(k))) + zans1 = 3.0 + 2./7.*(ygra1+8.) + rand1 N0_exp = 10.**(zans1) N0_exp = MAX(DBLE(gonv_min), MIN(N0_exp, DBLE(gonv_max))) - N0_min = MIN(N0_exp, N0_min) - N0_exp = N0_min lam_exp = (N0_exp*am_g*cgg(1)/rg(k))**oge1 lamg = lam_exp * (cgg(3)*ogg2*ogg1)**obmg ilamg(k) = 1./lamg @@ -5666,7 +5617,7 @@ end subroutine calc_refl10cm #ifdef SION !>\ingroup aathompson - subroutine readwrite_tables(mode, mpicomm, mpirank, mpiroot, ierr) + subroutine readwrite_tables(filename, mode, mpicomm, mpirank, mpiroot, ierr) #ifdef MPI use mpi @@ -5676,6 +5627,7 @@ subroutine readwrite_tables(mode, mpicomm, mpirank, mpiroot, ierr) implicit none ! Interface variables + character(len=*), intent(in) :: filename character(len=*), intent(in) :: mode integer, intent(in) :: mpicomm integer, intent(in) :: mpirank @@ -5702,7 +5654,6 @@ subroutine readwrite_tables(mode, mpicomm, mpirank, mpiroot, ierr) logical :: exists integer*8 :: tables_size real*8 :: checksum - character(len=*), parameter :: filename = 'thompson_tables_precomp.sl' integer :: i From 68113c9989ddaa203a7c84a1dabbc58adcc86f39 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Sat, 13 Feb 2021 11:50:04 -0700 Subject: [PATCH 02/18] simplify initialization a bit and add convert_dry_rho flag --- physics/module_mp_thompson.F90 | 17 +-- physics/mp_thompson.F90 | 245 +++++++++++---------------------- 2 files changed, 86 insertions(+), 176 deletions(-) diff --git a/physics/module_mp_thompson.F90 b/physics/module_mp_thompson.F90 index fcbcb8164..444e867ae 100644 --- a/physics/module_mp_thompson.F90 +++ b/physics/module_mp_thompson.F90 @@ -219,7 +219,7 @@ MODULE module_mp_thompson REAL, PRIVATE:: D0i, xm0s, xm0g !..Min and max radiative effective radius of cloud water, cloud ice, and snow; -!.. performed by subroutine calc_effectRad +!.. performed by subroutine calc_effectRad. On purpose, these should stay PUBLIC. REAL, PARAMETER:: re_qc_min = 2.50E-6 ! 2.5 microns REAL, PARAMETER:: re_qc_max = 50.0E-6 ! 50 microns REAL, PARAMETER:: re_qi_min = 2.50E-6 ! 2.5 microns @@ -440,24 +440,17 @@ MODULE module_mp_thompson !! lookup tables in Thomspson scheme. !>\section gen_thompson_init thompson_init General Algorithm !> @{ - SUBROUTINE thompson_init(nwfa2d, nifa2d, nwfa, nifa, & - mpicomm, mpirank, mpiroot, & + SUBROUTINE thompson_init(mpicomm, mpirank, mpiroot, & threads, errmsg, errflg) IMPLICIT NONE -!..OPTIONAL variables that control application of aerosol-aware scheme - - REAL, DIMENSION(:,:), OPTIONAL, INTENT(IN) :: nwfa, nifa - REAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: nwfa2d, nifa2d INTEGER, INTENT(IN) :: mpicomm, mpirank, mpiroot INTEGER, INTENT(IN) :: threads CHARACTER(len=*), INTENT(INOUT) :: errmsg INTEGER, INTENT(INOUT) :: errflg - INTEGER:: i, j, k, l, m, n - REAL:: h_01, airmass, niIN3, niCCN3, max_test LOGICAL:: micro_init real :: stime, etime #ifdef SION @@ -467,14 +460,8 @@ SUBROUTINE thompson_init(nwfa2d, nifa2d, nwfa, nifa, & LOGICAL, PARAMETER :: precomputed_tables = .FALSE. #endif - is_aerosol_aware = .FALSE. micro_init = .FALSE. - if (present(nwfa2d) .and. & - present(nifa2d) .and. & - present(nwfa) .and. & - present(nifa) ) is_aerosol_aware = .true. - !> - Allocate space for lookup tables (J. Michalakes 2009Jun08). if (.NOT. ALLOCATED(tcg_racg) ) then diff --git a/physics/mp_thompson.F90 b/physics/mp_thompson.F90 index ec19945b0..e22d82316 100644 --- a/physics/mp_thompson.F90 +++ b/physics/mp_thompson.F90 @@ -10,6 +10,7 @@ module mp_thompson use module_mp_thompson, only : thompson_init, mp_gt_driver, thompson_finalize, calc_effectRad use module_mp_thompson, only : naIN0, naIN1, naCCN0, naCCN1, eps, Nt_c + use module_mp_thompson, only : re_qc_min, re_qc_max, re_qi_min, re_qi_max, re_qs_min, re_qs_max use module_mp_thompson_make_number_concentrations, only: make_IceNumber, make_DropletNumber, make_RainNumber @@ -20,6 +21,7 @@ module mp_thompson private logical :: is_initialized = .False. + logical :: convert_dry_rho = .False. contains @@ -80,17 +82,8 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & character(len=*), intent( out) :: errmsg integer, intent( out) :: errflg - ! Hydrometeors - real(kind_phys) :: qv_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qc_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qr_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qi_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qs_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qg_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: ni_mp(1:ncol,1:nlev) !< kg-1 - real(kind_phys) :: nr_mp(1:ncol,1:nlev) !< kg-1 - real(kind_phys) :: nc_mp(1:ncol,1:nlev) !< kg-1 ! + real(kind_phys) :: qv(1:ncol,1:nlev) ! kg kg-1 (water vapor mixing ratio) real(kind_phys) :: hgt(1:ncol,1:nlev) ! m real(kind_phys) :: rho(1:ncol,1:nlev) ! kg m-3 real(kind_phys) :: orho(1:ncol,1:nlev) ! m3 kg-1 @@ -120,16 +113,9 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & end if ! Call Thompson init - if (is_aerosol_aware) then - call thompson_init(nwfa2d=nwfa2d, nifa2d=nifa2d, nwfa=nwfa, nifa=nifa, & - mpicomm=mpicomm, mpirank=mpirank, mpiroot=mpiroot, & - threads=threads, errmsg=errmsg, errflg=errflg) - if (errflg /= 0) return - else - call thompson_init(mpicomm=mpicomm, mpirank=mpirank, mpiroot=mpiroot, & - threads=threads, errmsg=errmsg, errflg=errflg) - if (errflg /= 0) return - end if + call thompson_init(mpicomm=mpicomm, mpirank=mpirank, mpiroot=mpiroot, & + threads=threads, errmsg=errmsg, errflg=errflg) + if (errflg /= 0) return ! For restart runs, the init is done here if (restart) then @@ -137,25 +123,6 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & return end if - ! Fix initial values of hydrometeors - where(spechum<0) spechum = 0.0 - where(qc<0) qc = 0.0 - where(qr<0) qr = 0.0 - where(qi<0) qi = 0.0 - where(qs<0) qs = 0.0 - where(qg<0) qg = 0.0 - where(ni<0) ni = 0.0 - where(nr<0) nr = 0.0 - - if (is_aerosol_aware) then - ! Fix initial values of aerosols - where(nc<0) nc = 0.0 - where(nwfa<0) nwfa = 0.0 - where(nifa<0) nifa = 0.0 - where(nwfa2d<0) nwfa2d = 0.0 - where(nifa2d<0) nifa2d = 0.0 - end if - ! Geopotential height in m2 s-2 to height in m hgt = phil/con_g @@ -163,49 +130,33 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & rho = prsl/(con_rd*tgrs) orho = 1.0/rho - ! Prior to calling the functions: make_DropletNumber, make_IceNumber, make_RainNumber, - ! the incoming mixing ratios should be converted to units of mass/num per cubic meter - ! rather than per kg of air. So, to pass back to the model state variables, - ! they also need to be switched back to mass/number per kg of air, because - ! what is returned by the functions is in units of number per cubic meter. - ! They also need to be converted to dry mixing ratios. - - !> - Convert specific humidity/moist mixing ratios to dry mixing ratios - qv_mp = spechum/(1.0_kind_phys-spechum) - qc_mp = qc/(1.0_kind_phys-spechum) - qr_mp = qr/(1.0_kind_phys-spechum) - qi_mp = qi/(1.0_kind_phys-spechum) - qs_mp = qs/(1.0_kind_phys-spechum) - qg_mp = qg/(1.0_kind_phys-spechum) - - !> - Convert number concentrations from moist to dry - ni_mp = ni/(1.0_kind_phys-spechum) - nr_mp = nr/(1.0_kind_phys-spechum) - if (is_aerosol_aware) then - nc_mp = nc/(1.0_kind_phys-spechum) - end if + ! Ensure non-negative mass mixing ratios of all water variables + where(spechum<0) spechum = 1.0E-10 ! COMMENT, gthompsn, spechum should *never* be identically zero. + where(qc<0) qc = 0.0 + where(qr<0) qr = 0.0 + where(qi<0) qi = 0.0 + where(qs<0) qs = 0.0 + where(qg<0) qg = 0.0 - ! If qi is in boundary conditions but ni is not, calculate ni from qi, rho and tgrs - if (maxval(qi_mp)>0.0 .and. maxval(ni_mp)==0.0) then - ni_mp = make_IceNumber(qi_mp*rho, tgrs) * orho - end if + ! Convert specific humidity to water vapor mixing ratio + qv = spechum/(1.0_kind_phys-spechum) - ! If ni is in boundary conditions but qi is not, reset ni to zero - if (maxval(ni_mp)>0.0 .and. maxval(qi_mp)==0.0) ni_mp = 0.0 + ! Ensure we have 1st guess ice number where mass non-zero but no number. + where(qi <= 0.0) ni=0.0 + where(qi > 0 .and. ni <= 0.0) ni = make_IceNumber(qi*rho, tgrs) * orho + where(qi = 0.0 .and. ni > 0.0) ni=0.0 - ! If qr is in boundary conditions but nr is not, calculate nr from qr, rho and tgrs - if (maxval(qr_mp)>0.0 .and. maxval(nr_mp)==0.0) then - nr_mp = make_RainNumber(qr_mp*rho, tgrs) * orho - end if + ! Ensure we have 1st guess rain number where mass non-zero but no number. + where(qr <= 0.0) nr=0.0 + where(qr > 0 .and. nr <= 0.0) nr = make_RainNumber(qr*rho, tgrs) * orho + where(qr = 0.0 .and. nr > 0.0) nr=0.0 - ! If nr is in boundary conditions but qr is not, reset nr to zero - if (maxval(nr_mp)>0.0 .and. maxval(qr_mp)==0.0) nr_mp = 0.0 !..Check for existing aerosol data, both CCN and IN aerosols. If missing !.. fill in just a basic vertical profile, somewhat boundary-layer following. if (is_aerosol_aware) then - ! CCN + ! Potential cloud condensation nuclei (CCN) if (MAXVAL(nwfa) .lt. eps) then if (mpirank==mpiroot) write(*,*) ' Apparently there are no initial CCN aerosols.' do i = 1, ncol @@ -219,7 +170,7 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & niCCN3 = -1.0*ALOG(naCCN1/naCCN0)/h_01 nwfa(i,1) = naCCN1+naCCN0*exp(-((hgt(i,2)-hgt(i,1))/1000.)*niCCN3) airmass = 1./orho(i,1) * (hgt(i,2)-hgt(i,1))*area(i) ! kg - nwfa2d(i) = nwfa(i,1) * 0.000196 * (airmass*2.E-10) + nwfa2d(i) = nwfa(i,1) * 0.000196 * (airmass*5.E-11) do k = 2, nlev nwfa(i,k) = naCCN1+naCCN0*exp(-((hgt(i,k)-hgt(i,1))/1000.)*niCCN3) enddo @@ -227,8 +178,6 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & else if (mpirank==mpiroot) write(*,*) ' Apparently initial CCN aerosols are present.' if (MAXVAL(nwfa2d) .lt. eps) then -! Hard-coded switch between new (from WRFv4.0, top) and old (until WRFv3.9.1.1, bottom) surface emission rate calculations -#if 0 !+---+-----------------------------------------------------------------+ !..Scale the lowest level aerosol data into an emissions rate. This is !.. very far from ideal, but need higher emissions where larger amount @@ -239,41 +188,16 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & !.. that was tested as ~(20kmx20kmx50m = 2.E10 m**-3) !+---+-----------------------------------------------------------------+ if (mpirank==mpiroot) write(*,*) ' Apparently there are no initial CCN aerosol surface emission rates.' - if (mpirank==mpiroot) write(*,*) ' Use new (WRFv4+) formula to calculate CCN surface emission rates.' do i = 1, ncol airmass = 1./orho(i,1) * (hgt(i,2)-hgt(i,1))*area(i) ! kg - nwfa2d(i) = nwfa(i,1) * 0.000196 * (airmass*2.E-10) - enddo -#else - !+---+-----------------------------------------------------------------+ - !..Scale the lowest level aerosol data into an emissions rate. This is - !.. very far from ideal, but need higher emissions where larger amount - !.. of existing and lesser emissions where not already lots of aerosols - !.. for first-order simplistic approach. Later, proper connection to - !.. emission inventory would be better, but, for now, scale like this: - !.. where: Nwfa=50 per cc, emit 0.875E4 aerosols per kg per second - !.. Nwfa=500 per cc, emit 0.875E5 aerosols per kg per second - !.. Nwfa=5000 per cc, emit 0.875E6 aerosols per kg per second - !.. for a grid with 20km spacing and scale accordingly for other spacings. - !+---+-----------------------------------------------------------------+ - if (mpirank==mpiroot) write(*,*) ' Apparently there are no initial CCN aerosol surface emission rates.' - if (mpirank==mpiroot) write(*,*) ' Use old (pre WRFv4) formula to calculate CCN surface emission rates.' - do i = 1, ncol - if (SQRT(area(i))/20000.0 .ge. 1.0) then - h_01 = 0.875 - else - h_01 = (0.875 + 0.125*((20000.-SQRT(area(i)))/16000.)) * SQRT(area(i))/20000. - endif - nwfa2d(i) = 10.0**(LOG10(nwfa(i,1)*1.E-6)-3.69897) - nwfa2d(i) = nwfa2d(i)*h_01 * 1.E6 + nwfa2d(i) = nwfa(i,1) * 0.000196 * (airmass*5.E-11) enddo -#endif else if (mpirank==mpiroot) write(*,*) ' Apparently initial CCN aerosol surface emission rates are present.' endif endif - ! IN + ! Potential ice nuclei (IN) if (MAXVAL(nifa) .lt. eps) then if (mpirank==mpiroot) write(*,*) ' Apparently there are no initial IN aerosols.' do i = 1, ncol @@ -302,19 +226,20 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & endif endif - ! If qc is in boundary conditions but nc is not, calculate nc from qc, rho and nwfa - if (maxval(qc_mp)>0.0 .and. maxval(nc_mp)==0.0) then - nc_mp = make_DropletNumber(qc_mp*rho, nwfa) * orho - end if + ! Ensure we have 1st guess cloud droplet number where mass non-zero but no number. + where(qc <= 0.0) nc=0.0 + where(qc > 0 .and. nc <= 0.0) nc = make_DropletNumber(qc*rho, nwfa) * orho + where(qc = 0.0 .and. nc > 0.0) nc=0.0 - ! If nc is in boundary conditions but qc is not, reset nc to zero - if (maxval(nc_mp)>0.0 .and. maxval(qc_mp)==0.0) nc_mp = 0.0 + ! Ensure non-negative aerosol number concentrations. + where(nwfa <= 0.0) nwfa = 1.1E6 + where(nifa <= 0.0) nifa = naIN1*0.01 else ! Constant droplet concentration for single moment cloud water as in ! module_mp_thompson.F90, only needed for effective radii calculation - nc_mp = Nt_c/rho + nc = Nt_c/rho end if @@ -322,9 +247,14 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & if (present(re_cloud) .and. present(re_ice) .and. present(re_snow)) then ! Effective radii [m] are now intent(out), bounds applied in calc_effectRad do i = 1, ncol - call calc_effectRad (tgrs(i,:), prsl(i,:), qv_mp(i,:), qc_mp(i,:), & - nc_mp(i,:), qi_mp(i,:), ni_mp(i,:), qs_mp(i,:), & + call calc_effectRad (tgrs(i,:), prsl(i,:), qv(i,:), qc(i,:), & + nc(i,:), qi(i,:), ni(i,:), qs(i,:), & re_cloud(i,:), re_ice(i,:), re_snow(i,:), 1, nlev) + do k = 1, nlev + re_cloud(i,k) = MAX(re_qc_min, MIN(re_cloud(i,k), re_qc_max)) + re_ice(i,k) = MAX(re_qi_min, MIN(re_ice(i,k), re_qi_max)) + re_snow(i,k) = MAX(re_qs_min, MIN(re_snow(i,k), re_qs_max)) + end do end do !! Convert to micron: required for bit-for-bit identical restarts; !! otherwise entering mp_thompson_init and converting mu to m and @@ -341,13 +271,6 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & return end if - !> - Convert number concentrations from dry to moist - ni = ni_mp/(1.0_kind_phys+qv_mp) - nr = nr_mp/(1.0_kind_phys+qv_mp) - if (is_aerosol_aware) then - nc = nc_mp/(1.0_kind_phys+qv_mp) - end if - is_initialized = .true. end subroutine mp_thompson_init @@ -428,17 +351,8 @@ subroutine mp_thompson_run(ncol, nlev, con_g, con_rd, & ! Air density real(kind_phys) :: rho(1:ncol,1:nlev) !< kg m-3 - ! Hydrometeors - real(kind_phys) :: qv_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qc_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qr_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qi_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qs_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: qg_mp(1:ncol,1:nlev) !< kg kg-1 (dry mixing ratio) - real(kind_phys) :: ni_mp(1:ncol,1:nlev) !< kg-1 - real(kind_phys) :: nr_mp(1:ncol,1:nlev) !< kg-1 - real(kind_phys) :: nc_mp(1:ncol,1:nlev) !< kg-1 - + ! Water vapor mixing ratio (instead of specific humidity) + real(kind_phys) :: qv(1:ncol,1:nlev) !< kg kg-1 ! Vertical velocity and level width real(kind_phys) :: w(1:ncol,1:nlev) !< m s-1 real(kind_phys) :: dz(1:ncol,1:nlev) !< m @@ -494,19 +408,26 @@ subroutine mp_thompson_run(ncol, nlev, con_g, con_rd, & return end if - !> - Convert specific humidity/moist mixing ratios to dry mixing ratios - qv_mp = spechum/(1.0_kind_phys-spechum) - qc_mp = qc/(1.0_kind_phys-spechum) - qr_mp = qr/(1.0_kind_phys-spechum) - qi_mp = qi/(1.0_kind_phys-spechum) - qs_mp = qs/(1.0_kind_phys-spechum) - qg_mp = qg/(1.0_kind_phys-spechum) - - !> - Convert number concentrations from moist to dry - ni_mp = ni/(1.0_kind_phys-spechum) - nr_mp = nr/(1.0_kind_phys-spechum) - if (is_aerosol_aware) then - nc_mp = nc/(1.0_kind_phys-spechum) + !> - Convert specific humidity to water vapor mixing ratio. + !> - Also, hydrometeor variables are mass or number mixing ratio + !> - either kg of species per kg of dry air, or per kg of (dry + vapor). + + qv = spechum/(1.0_kind_phys-spechum) + + if (convert_dry_rho) then + qc = qc/(1.0_kind_phys-spechum) + qr = qr/(1.0_kind_phys-spechum) + qi = qi/(1.0_kind_phys-spechum) + qs = qs/(1.0_kind_phys-spechum) + qg = qg/(1.0_kind_phys-spechum) + + ni = ni/(1.0_kind_phys-spechum) + nr = nr/(1.0_kind_phys-spechum) + if (is_aerosol_aware) then + nc = nc/(1.0_kind_phys-spechum) + nwfa = nwfa/(1.0_kind_phys-spechum) + nifa = nifa/(1.0_kind_phys-spechum) + end if end if !> - Density of air in kg m-3 @@ -582,9 +503,8 @@ subroutine mp_thompson_run(ncol, nlev, con_g, con_rd, & !> - Call mp_gt_driver() with or without aerosols if (is_aerosol_aware) then - call mp_gt_driver(qv=qv_mp, qc=qc_mp, qr=qr_mp, qi=qi_mp, qs=qs_mp, qg=qg_mp, & - ni=ni_mp, nr=nr_mp, nc=nc_mp, & - nwfa=nwfa, nifa=nifa, nwfa2d=nwfa2d, nifa2d=nifa2d, & + call mp_gt_driver(qv=qv, qc=qc, qr=qr, qi=qi, qs=qs, qg=qg, ni=ni, nr=nr, & + nc=nc, nwfa=nwfa, nifa=nifa, nwfa2d=nwfa2d, nifa2d=nifa2d, & tt=tgrs, p=prsl, w=w, dz=dz, dt_in=dtp, & rainnc=rain_mp, rainncv=delta_rain_mp, & snownc=snow_mp, snowncv=delta_snow_mp, & @@ -604,8 +524,7 @@ subroutine mp_thompson_run(ncol, nlev, con_g, con_rd, & errmsg=errmsg, errflg=errflg, reset=reset) else - call mp_gt_driver(qv=qv_mp, qc=qc_mp, qr=qr_mp, qi=qi_mp, qs=qs_mp, qg=qg_mp, & - ni=ni_mp, nr=nr_mp, & + call mp_gt_driver(qv=qv, qc=qc, qr=qr, qi=qi, qs=qs, qg=qg, ni=ni, nr=nr, & tt=tgrs, p=prsl, w=w, dz=dz, dt_in=dtp, & rainnc=rain_mp, rainncv=delta_rain_mp, & snownc=snow_mp, snowncv=delta_snow_mp, & @@ -626,19 +545,23 @@ subroutine mp_thompson_run(ncol, nlev, con_g, con_rd, & end if if (errflg/=0) return - !> - Convert dry mixing ratios to specific humidity/moist mixing ratios - spechum = qv_mp/(1.0_kind_phys+qv_mp) - qc = qc_mp/(1.0_kind_phys+qv_mp) - qr = qr_mp/(1.0_kind_phys+qv_mp) - qi = qi_mp/(1.0_kind_phys+qv_mp) - qs = qs_mp/(1.0_kind_phys+qv_mp) - qg = qg_mp/(1.0_kind_phys+qv_mp) - - !> - Convert number concentrations from dry to moist - ni = ni_mp/(1.0_kind_phys+qv_mp) - nr = nr_mp/(1.0_kind_phys+qv_mp) - if (is_aerosol_aware) then - nc = nc_mp/(1.0_kind_phys+qv_mp) + !> - Convert water vapor mixing ratio back to specific humidity + spechum = qv/(1.0_kind_phys+qv) + + if (convert_dry_rho) then + qc = qc/(1.0_kind_phys+qv) + qr = qr/(1.0_kind_phys+qv) + qi = qi/(1.0_kind_phys+qv) + qs = qs/(1.0_kind_phys+qv) + qg = qg/(1.0_kind_phys+qv) + + ni = ni/(1.0_kind_phys+qv) + nr = nr/(1.0_kind_phys+qv) + if (is_aerosol_aware) then + nc = nc/(1.0_kind_phys+qv) + nwfa = nwfa/(1.0_kind_phys+qv) + nifa = nifa/(1.0_kind_phys+qv) + end if end if !> - Convert rainfall deltas from mm to m (on physics timestep); add to inout variables From b204497750d1fad78f9752eff8a7dabc60eb8a83 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Wed, 17 Feb 2021 10:05:14 -0700 Subject: [PATCH 03/18] fix bug to include rho(air) in nwfa --- physics/mp_thompson.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/physics/mp_thompson.F90 b/physics/mp_thompson.F90 index e22d82316..ac8437262 100644 --- a/physics/mp_thompson.F90 +++ b/physics/mp_thompson.F90 @@ -228,7 +228,7 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & ! Ensure we have 1st guess cloud droplet number where mass non-zero but no number. where(qc <= 0.0) nc=0.0 - where(qc > 0 .and. nc <= 0.0) nc = make_DropletNumber(qc*rho, nwfa) * orho + where(qc > 0 .and. nc <= 0.0) nc = make_DropletNumber(qc*rho, nwfa*rho) * orho where(qc = 0.0 .and. nc > 0.0) nc=0.0 ! Ensure non-negative aerosol number concentrations. From cae708d26b4a4fe3fc06c0191fbe72fb8af0674c Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Wed, 24 Feb 2021 11:27:23 -0700 Subject: [PATCH 04/18] fix for one more consistency check of ice number --- physics/module_mp_thompson.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/physics/module_mp_thompson.F90 b/physics/module_mp_thompson.F90 index 444e867ae..2e6331c33 100644 --- a/physics/module_mp_thompson.F90 +++ b/physics/module_mp_thompson.F90 @@ -2888,8 +2888,8 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & niten(k) = -ni1d(k)*odts endif xni=MAX(0.,(ni1d(k) + niten(k)*dtsave)*rho(k)) - if (xni.gt.499.E3) & - niten(k) = (499.E3-ni1d(k)*rho(k))*odts*orho + if (xni.gt.9999.E3) & + niten(k) = (9999.E3-ni1d(k)*rho(k))*odts*orho !> - Rain tendency qrten(k) = qrten(k) + (prr_wau(k) + prr_rcw(k) & From f6d5fc1352c0a93fa9876cab200e5b3af05b4ac1 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Thu, 25 Feb 2021 09:09:29 -0700 Subject: [PATCH 05/18] small compile-time bug fixes --- physics/module_mp_thompson.F90 | 7 +++---- physics/mp_thompson.F90 | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/physics/module_mp_thompson.F90 b/physics/module_mp_thompson.F90 index 2e6331c33..ed8309789 100644 --- a/physics/module_mp_thompson.F90 +++ b/physics/module_mp_thompson.F90 @@ -1264,7 +1264,6 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & nwfa1d(k) = 11.1E6/rho(k) nifa1d(k) = naIN1*0.01/rho(k) enddo - nwfa1 = 11.1E6 endif !> - Call mp_thompson() @@ -3717,7 +3716,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & elseif (nc1d(k)*rho(k).lt.100.) then nu_c = 15 else - nu_c = NINT(1000.E6/(nc1d(k)*rho(k)) + 2 + nu_c = NINT(1000.E6/(nc1d(k)*rho(k))) + 2 nu_c = MAX(2, MIN(nu_c+NINT(rand2), 15)) endif lamc = (am_r*ccg(2,nu_c)*ocg1(nu_c)*nc1d(k)/qc1d(k))**obmr @@ -3941,7 +3940,7 @@ subroutine qr_acr_qg CLOSE(63) RETURN ! ----- RETURN 9234 CONTINUE - write(0,*) "Error writing //qr_acr_qg_file + write(0,*) "Error writing "//qr_acr_qg_file return ENDIF ENDIF @@ -4237,7 +4236,7 @@ subroutine freezeH2O(threads) write_thompson_tables = .false. good = 0 - INQUIRE(FILE=freeze_h2o_file",EXIST=lexist) + INQUIRE(FILE=freeze_h2o_file,EXIST=lexist) #ifdef MPI call MPI_BARRIER(mpi_communicator,ierr) #endif diff --git a/physics/mp_thompson.F90 b/physics/mp_thompson.F90 index ac8437262..79994674f 100644 --- a/physics/mp_thompson.F90 +++ b/physics/mp_thompson.F90 @@ -142,14 +142,14 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & qv = spechum/(1.0_kind_phys-spechum) ! Ensure we have 1st guess ice number where mass non-zero but no number. - where(qi <= 0.0) ni=0.0 - where(qi > 0 .and. ni <= 0.0) ni = make_IceNumber(qi*rho, tgrs) * orho - where(qi = 0.0 .and. ni > 0.0) ni=0.0 + where(qi .LE. 0.0) ni=0.0 + where(qi .GT. 0 .and. ni .LE. 0.0) ni = make_IceNumber(qi*rho, tgrs) * orho + where(qi .EQ. 0.0 .and. ni .GT. 0.0) ni=0.0 ! Ensure we have 1st guess rain number where mass non-zero but no number. - where(qr <= 0.0) nr=0.0 - where(qr > 0 .and. nr <= 0.0) nr = make_RainNumber(qr*rho, tgrs) * orho - where(qr = 0.0 .and. nr > 0.0) nr=0.0 + where(qr .LE. 0.0) nr=0.0 + where(qr .GT. 0 .and. nr .LE. 0.0) nr = make_RainNumber(qr*rho, tgrs) * orho + where(qr .EQ. 0.0 .and. nr .GT. 0.0) nr=0.0 !..Check for existing aerosol data, both CCN and IN aerosols. If missing @@ -227,13 +227,13 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & endif ! Ensure we have 1st guess cloud droplet number where mass non-zero but no number. - where(qc <= 0.0) nc=0.0 - where(qc > 0 .and. nc <= 0.0) nc = make_DropletNumber(qc*rho, nwfa*rho) * orho - where(qc = 0.0 .and. nc > 0.0) nc=0.0 + where(qc .LE. 0.0) nc=0.0 + where(qc .GT. 0 .and. nc .LE. 0.0) nc = make_DropletNumber(qc*rho, nwfa*rho) * orho + where(qc .EQ. 0.0 .and. nc .GT. 0.0) nc=0.0 ! Ensure non-negative aerosol number concentrations. - where(nwfa <= 0.0) nwfa = 1.1E6 - where(nifa <= 0.0) nifa = naIN1*0.01 + where(nwfa .LE. 0.0) nwfa = 1.1E6 + where(nifa .LE. 0.0) nifa = naIN1*0.01 else From a13ef16702a01b971192c319afe812e46a40b3f9 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Fri, 26 Feb 2021 15:07:12 -0700 Subject: [PATCH 06/18] adopt moist air density in place of dry air density --- physics/mp_thompson.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/physics/mp_thompson.F90 b/physics/mp_thompson.F90 index 79994674f..84c30a18e 100644 --- a/physics/mp_thompson.F90 +++ b/physics/mp_thompson.F90 @@ -126,10 +126,6 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & ! Geopotential height in m2 s-2 to height in m hgt = phil/con_g - ! Density of air in kg m-3 and inverse density of air - rho = prsl/(con_rd*tgrs) - orho = 1.0/rho - ! Ensure non-negative mass mixing ratios of all water variables where(spechum<0) spechum = 1.0E-10 ! COMMENT, gthompsn, spechum should *never* be identically zero. where(qc<0) qc = 0.0 @@ -141,6 +137,10 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & ! Convert specific humidity to water vapor mixing ratio qv = spechum/(1.0_kind_phys-spechum) + ! Density of moist air in kg m-3 and inverse density of air + rho = 0.622*prsl/(con_rd*tgrs*(qv+0.622)) + orho = 1.0/rho + ! Ensure we have 1st guess ice number where mass non-zero but no number. where(qi .LE. 0.0) ni=0.0 where(qi .GT. 0 .and. ni .LE. 0.0) ni = make_IceNumber(qi*rho, tgrs) * orho From c6f1cab8cc644c803739047aa238c7155102c0ef Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 1 Mar 2021 07:32:32 -0700 Subject: [PATCH 07/18] Fix bug due to merge in physics/mp_thompson.F90 --- physics/mp_thompson.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/physics/mp_thompson.F90 b/physics/mp_thompson.F90 index 337161140..fbfbe72a9 100644 --- a/physics/mp_thompson.F90 +++ b/physics/mp_thompson.F90 @@ -431,7 +431,7 @@ subroutine mp_thompson_run(ncol, nlev, con_g, con_rd, & end if !> - Density of air in kg m-3 - rho = 0.622*prsl/(con_rd*tgrs*(qv_mp+0.622)) + rho = 0.622*prsl/(con_rd*tgrs*(qv+0.622)) !> - Convert omega in Pa s-1 to vertical velocity w in m s-1 w = -omega/(rho*con_g) From 2a2d75076ab43f60b7ea7776f5e3b0e7dc98d9dd Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Mon, 1 Mar 2021 08:40:16 -0700 Subject: [PATCH 08/18] finalze the correct min,max aerosol numbers with regard to air density --- physics/module_mp_thompson.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/physics/module_mp_thompson.F90 b/physics/module_mp_thompson.F90 index ed8309789..09bb5c939 100644 --- a/physics/module_mp_thompson.F90 +++ b/physics/module_mp_thompson.F90 @@ -1261,8 +1261,8 @@ SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, nc, & else do k = kts, kte nc1d(k) = Nt_c/rho(k) - nwfa1d(k) = 11.1E6/rho(k) - nifa1d(k) = naIN1*0.01/rho(k) + nwfa1d(k) = 11.1E6 + nifa1d(k) = naIN1*0.01 enddo endif @@ -1785,8 +1785,8 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & qv(k) = MAX(1.E-10, qv1d(k)) pres(k) = p1d(k) rho(k) = 0.622*pres(k)/(R*temp(k)*(qv(k)+0.622)) - nwfa(k) = MAX(11.1E6, MIN(9999.E6, nwfa1d(k)*rho(k))) - nifa(k) = MAX(naIN1*0.01, MIN(9999.E6, nifa1d(k)*rho(k))) + nwfa(k) = MAX(11.1E6*rho(k), MIN(9999.E6*rho(k), nwfa1d(k)*rho(k))) + nifa(k) = MAX(naIN1*0.01*rho(k), MIN(9999.E6*rho(k), nifa1d(k)*rho(k))) mvd_r(k) = D0r mvd_c(k) = D0c @@ -2987,7 +2987,7 @@ subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & ocp(k) = 1./(Cp*(1.+0.887*qv(k))) lvt2(k)=lvap(k)*lvap(k)*ocp(k)*oRv*otemp*otemp - nwfa(k) = MAX(11.1E6, (nwfa1d(k) + nwfaten(k)*DT)*rho(k)) + nwfa(k) = MAX(11.1E6*rho(k), (nwfa1d(k) + nwfaten(k)*DT)*rho(k)) enddo do k = kts, kte From 3f2c4e5f3278e88934ebc5119c8e20707feb9e02 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Thu, 4 Mar 2021 11:56:26 -0700 Subject: [PATCH 09/18] Make convert_dry_rho an input argument, fix a bug in the non-aerosol-aware version (nc not allocated), reduce noise written to stdout --- physics/module_mp_thompson.F90 | 11 +++--- physics/mp_thompson.F90 | 62 ++++++++++++++++++++++++++++------ physics/mp_thompson.meta | 16 +++++++++ 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/physics/module_mp_thompson.F90 b/physics/module_mp_thompson.F90 index 09bb5c939..25466f412 100644 --- a/physics/module_mp_thompson.F90 +++ b/physics/module_mp_thompson.F90 @@ -423,9 +423,7 @@ MODULE module_mp_thompson !..If SIONlib isn't used, write Thompson tables with master MPI task !.. after computing them in thompson_init -#ifndef SION LOGICAL:: thompson_table_writer -#endif !+---+ !+---+-----------------------------------------------------------------+ @@ -767,7 +765,7 @@ SUBROUTINE thompson_init(mpicomm, mpirank, mpiroot, & precomputed_tables = .false. if (mpirank==mpiroot) write(0,*) "An error occurred reading Thompson tables from disk, recalculate" end if -#else +#endif ! Standard tables are only written by master MPI task; ! (physics init cannot be called by multiple threads, ! hence no need to test for a specific thread number) @@ -776,7 +774,6 @@ SUBROUTINE thompson_init(mpicomm, mpirank, mpiroot, & else thompson_table_writer = .false. end if -#endif precomputed_tables_1: if (.not.precomputed_tables) then @@ -3847,7 +3844,7 @@ subroutine qr_acr_qg #ifndef SION if (thompson_table_writer) write_thompson_tables = .true. #endif - write(0,*) "ThompMP: computing qr_acr_qg" + if (thompson_table_writer) write(0,*) "ThompMP: computing qr_acr_qg" do n2 = 1, nbr ! vr(n2) = av_r*Dr(n2)**bv_r * DEXP(-fv_r*Dr(n2)) vr(n2) = -0.1021 + 4.932E3*Dr(n2) - 0.9551E6*Dr(n2)*Dr(n2) & @@ -4029,7 +4026,7 @@ subroutine qr_acr_qs #ifndef SION if (thompson_table_writer) write_thompson_tables = .true. #endif - write(0,*) "ThompMP: computing qr_acr_qs" + if (thompson_table_writer) write(0,*) "ThompMP: computing qr_acr_qs" do n2 = 1, nbr ! vr(n2) = av_r*Dr(n2)**bv_r * DEXP(-fv_r*Dr(n2)) vr(n2) = -0.1021 + 4.932E3*Dr(n2) - 0.9551E6*Dr(n2)*Dr(n2) & @@ -4284,7 +4281,7 @@ subroutine freezeH2O(threads) #ifndef SION if (thompson_table_writer) write_thompson_tables = .true. #endif - write(0,*) "ThompMP: computing freezeH2O" + if (thompson_table_writer) write(0,*) "ThompMP: computing freezeH2O" orho_w = 1./rho_w diff --git a/physics/mp_thompson.F90 b/physics/mp_thompson.F90 index fbfbe72a9..252944b77 100644 --- a/physics/mp_thompson.F90 +++ b/physics/mp_thompson.F90 @@ -21,7 +21,6 @@ module mp_thompson private logical :: is_initialized = .False. - logical :: convert_dry_rho = .False. contains @@ -31,6 +30,7 @@ module mp_thompson !! subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & imp_physics, imp_physics_thompson, & + convert_dry_rho, & spechum, qc, qr, qi, qs, qg, ni, nr, & is_aerosol_aware, nc, nwfa2d, nifa2d, & nwfa, nifa, tgrs, prsl, phil, area, & @@ -48,6 +48,7 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & integer, intent(in ) :: imp_physics integer, intent(in ) :: imp_physics_thompson ! Hydrometeors + logical, intent(in ) :: convert_dry_rho real(kind_phys), intent(inout) :: spechum(:,:) real(kind_phys), intent(inout) :: qc(:,:) real(kind_phys), intent(inout) :: qr(:,:) @@ -83,10 +84,11 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & integer, intent( out) :: errflg ! - real(kind_phys) :: qv(1:ncol,1:nlev) ! kg kg-1 (water vapor mixing ratio) - real(kind_phys) :: hgt(1:ncol,1:nlev) ! m - real(kind_phys) :: rho(1:ncol,1:nlev) ! kg m-3 - real(kind_phys) :: orho(1:ncol,1:nlev) ! m3 kg-1 + real(kind_phys) :: qv(1:ncol,1:nlev) ! kg kg-1 (water vapor mixing ratio) + real(kind_phys) :: hgt(1:ncol,1:nlev) ! m + real(kind_phys) :: rho(1:ncol,1:nlev) ! kg m-3 + real(kind_phys) :: orho(1:ncol,1:nlev) ! m3 kg-1 + real(kind_phys) :: nc_local(1:ncol,1:nlev) ! needed because nc is only allocated if is_aerosol_aware is true ! real (kind=kind_phys) :: h_01, airmass, niIN3, niCCN3 integer :: i, k @@ -134,9 +136,28 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & where(qs<0) qs = 0.0 where(qg<0) qg = 0.0 - ! Convert specific humidity to water vapor mixing ratio + !> - Convert specific humidity to water vapor mixing ratio. + !> - Also, hydrometeor variables are mass or number mixing ratio + !> - either kg of species per kg of dry air, or per kg of (dry + vapor). + qv = spechum/(1.0_kind_phys-spechum) + if (convert_dry_rho) then + qc = qc/(1.0_kind_phys-spechum) + qr = qr/(1.0_kind_phys-spechum) + qi = qi/(1.0_kind_phys-spechum) + qs = qs/(1.0_kind_phys-spechum) + qg = qg/(1.0_kind_phys-spechum) + + ni = ni/(1.0_kind_phys-spechum) + nr = nr/(1.0_kind_phys-spechum) + if (is_aerosol_aware) then + nc = nc/(1.0_kind_phys-spechum) + nwfa = nwfa/(1.0_kind_phys-spechum) + nifa = nifa/(1.0_kind_phys-spechum) + end if + end if + ! Density of moist air in kg m-3 and inverse density of air rho = 0.622*prsl/(con_rd*tgrs*(qv+0.622)) orho = 1.0/rho @@ -229,17 +250,20 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & ! Ensure we have 1st guess cloud droplet number where mass non-zero but no number. where(qc .LE. 0.0) nc=0.0 where(qc .GT. 0 .and. nc .LE. 0.0) nc = make_DropletNumber(qc*rho, nwfa*rho) * orho - where(qc .EQ. 0.0 .and. nc .GT. 0.0) nc=0.0 + where(qc .EQ. 0.0 .and. nc .GT. 0.0) nc = 0.0 ! Ensure non-negative aerosol number concentrations. where(nwfa .LE. 0.0) nwfa = 1.1E6 where(nifa .LE. 0.0) nifa = naIN1*0.01 + ! Copy to local array for calculating cloud effective radii below + nc_local = nc + else ! Constant droplet concentration for single moment cloud water as in ! module_mp_thompson.F90, only needed for effective radii calculation - nc = Nt_c/rho + nc_local = Nt_c/rho end if @@ -247,8 +271,8 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & if (present(re_cloud) .and. present(re_ice) .and. present(re_snow)) then ! Effective radii [m] are now intent(out), bounds applied in calc_effectRad do i = 1, ncol - call calc_effectRad (tgrs(i,:), prsl(i,:), qv(i,:), qc(i,:), & - nc(i,:), qi(i,:), ni(i,:), qs(i,:), & + call calc_effectRad (tgrs(i,:), prsl(i,:), qv(i,:), qc(i,:), & + nc_local(i,:), qi(i,:), ni(i,:), qs(i,:), & re_cloud(i,:), re_ice(i,:), re_snow(i,:), 1, nlev) do k = 1, nlev re_cloud(i,k) = MAX(re_qc_min, MIN(re_cloud(i,k), re_qc_max)) @@ -271,6 +295,22 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & return end if + if (convert_dry_rho) then + !qc = qc/(1.0_kind_phys+qv) + !qr = qr/(1.0_kind_phys+qv) + !qi = qi/(1.0_kind_phys+qv) + !qs = qs/(1.0_kind_phys+qv) + !qg = qg/(1.0_kind_phys+qv) + + ni = ni/(1.0_kind_phys+qv) + nr = nr/(1.0_kind_phys+qv) + if (is_aerosol_aware) then + nc = nc/(1.0_kind_phys+qv) + nwfa = nwfa/(1.0_kind_phys+qv) + nifa = nifa/(1.0_kind_phys+qv) + end if + end if + is_initialized = .true. end subroutine mp_thompson_init @@ -283,6 +323,7 @@ end subroutine mp_thompson_init !>\section gen_thompson_hrrr Thompson MP General Algorithm !>@{ subroutine mp_thompson_run(ncol, nlev, con_g, con_rd, & + convert_dry_rho, & spechum, qc, qr, qi, qs, qg, ni, nr, & is_aerosol_aware, nc, nwfa, nifa, & nwfa2d, nifa2d, & @@ -303,6 +344,7 @@ subroutine mp_thompson_run(ncol, nlev, con_g, con_rd, & real(kind_phys), intent(in ) :: con_g real(kind_phys), intent(in ) :: con_rd ! Hydrometeors + logical, intent(in ) :: convert_dry_rho real(kind_phys), intent(inout) :: spechum(1:ncol,1:nlev) real(kind_phys), intent(inout) :: qc(1:ncol,1:nlev) real(kind_phys), intent(inout) :: qr(1:ncol,1:nlev) diff --git a/physics/mp_thompson.meta b/physics/mp_thompson.meta index 4cfee6afc..ed54f8d02 100644 --- a/physics/mp_thompson.meta +++ b/physics/mp_thompson.meta @@ -65,6 +65,14 @@ type = integer intent = in optional = F +[convert_dry_rho] + standard_name = flag_for_converting_hydrometeors_from_moist_to_dry_air + long_name = flag for converting hydrometeors from moist to dry air + units = flag + dimensions = () + type = logical + intent = in + optional = F [spechum] standard_name = water_vapor_specific_humidity long_name = water vapor specific humidity @@ -341,6 +349,14 @@ kind = kind_phys intent = in optional = F +[convert_dry_rho] + standard_name = flag_for_converting_hydrometeors_from_moist_to_dry_air + long_name = flag for converting hydrometeors from moist to dry air + units = flag + dimensions = () + type = logical + intent = in + optional = F [spechum] standard_name = water_vapor_specific_humidity_updated_by_physics long_name = water vapor specific humidity From 15f1aa751a67aa2593f1700f951265f49d735947 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Fri, 5 Mar 2021 10:15:27 -0700 Subject: [PATCH 10/18] More bugfixes for Thompson MP: set is_aerosol_aware in mp_thompson_init -> init_thompson, apply bounds after calls to calc_effectRad in radiation, set intent(out) variables in calc_effectRad --- physics/GFS_rrtmg_pre.F90 | 16 ++++++++++++---- physics/GFS_rrtmgp_thompsonmp_pre.F90 | 11 +++++++++-- physics/module_mp_thompson.F90 | 20 +++++++++++++++++++- physics/mp_thompson.F90 | 9 +++++---- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/physics/GFS_rrtmg_pre.F90 b/physics/GFS_rrtmg_pre.F90 index ab488c687..fee9b8815 100644 --- a/physics/GFS_rrtmg_pre.F90 +++ b/physics/GFS_rrtmg_pre.F90 @@ -68,10 +68,13 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, & use surface_perturbation, only: cdfnor ! For Thompson MP - use module_mp_thompson, only: calc_effectRad, Nt_c - use module_mp_thompson_make_number_concentrations, only: & - make_IceNumber, & - make_DropletNumber, & + use module_mp_thompson, only: calc_effectRad, Nt_c, & + re_qc_min, re_qc_max, & + re_qi_min, re_qi_max, & + re_qs_min, re_qs_max + use module_mp_thompson_make_number_concentrations, only: & + make_IceNumber, & + make_DropletNumber, & make_RainNumber implicit none @@ -779,6 +782,11 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, & call calc_effectRad (tlyr(i,:), plyr(i,:)*100., qv_mp(i,:), qc_mp(i,:), & nc_mp(i,:), qi_mp(i,:), ni_mp(i,:), qs_mp(i,:), & re_cloud(i,:), re_ice(i,:), re_snow(i,:), 1, lm ) + do k=1,lm + re_cloud(i,k) = MAX(re_qc_min, MIN(re_cloud(i,k), re_qc_max)) + re_ice(i,k) = MAX(re_qi_min, MIN(re_ice(i,k), re_qi_max)) + re_snow(i,k) = MAX(re_qs_min, MIN(re_snow(i,k), re_qs_max)) + end do end do ! Scale Thompson's effective radii from meter to micron do k=1,lm diff --git a/physics/GFS_rrtmgp_thompsonmp_pre.F90 b/physics/GFS_rrtmgp_thompsonmp_pre.F90 index 58e1bddea..08cc1b292 100644 --- a/physics/GFS_rrtmgp_thompsonmp_pre.F90 +++ b/physics/GFS_rrtmgp_thompsonmp_pre.F90 @@ -8,8 +8,10 @@ module GFS_rrtmgp_thompsonmp_pre use rrtmgp_aux, only: & check_error_msg use module_mp_thompson, only: & - calc_effectRad, & - Nt_c + calc_effectRad, Nt_c, & + re_qc_min, re_qc_max, & + re_qi_min, re_qi_max, & + re_qs_min, re_qs_max use module_mp_thompson_make_number_concentrations, only: & make_IceNumber, & make_DropletNumber, & @@ -179,6 +181,11 @@ subroutine GFS_rrtmgp_thompsonmp_pre_run(nCol, nLev, nTracers, ncnd, doSWrad, do call calc_effectRad (t_lay(iCol,:), p_lay(iCol,:), qv_mp(iCol,:), qc_mp(iCol,:), & nc_mp(iCol,:), qi_mp(iCol,:), ni_mp(iCol,:), qs_mp(iCol,:), & re_cloud(iCol,:), re_ice(iCol,:), re_snow(iCol,:), 1, nLev ) + do iLay = 1, nLev + re_cloud(iCol,iLay) = MAX(re_qc_min, MIN(re_cloud(iCol,iLay), re_qc_max)) + re_ice(iCol,iLay) = MAX(re_qi_min, MIN(re_ice(iCol,iLay), re_qi_max)) + re_snow(iCol,iLay) = MAX(re_qs_min, MIN(re_snow(iCol,iLay), re_qs_max)) + end do enddo ! Scale Thompson's effective radii from meter to micron diff --git a/physics/module_mp_thompson.F90 b/physics/module_mp_thompson.F90 index 25466f412..8ba269388 100644 --- a/physics/module_mp_thompson.F90 +++ b/physics/module_mp_thompson.F90 @@ -438,11 +438,13 @@ MODULE module_mp_thompson !! lookup tables in Thomspson scheme. !>\section gen_thompson_init thompson_init General Algorithm !> @{ - SUBROUTINE thompson_init(mpicomm, mpirank, mpiroot, & + SUBROUTINE thompson_init(is_aerosol_aware_in, & + mpicomm, mpirank, mpiroot, & threads, errmsg, errflg) IMPLICIT NONE + LOGICAL, INTENT(IN) :: is_aerosol_aware_in INTEGER, INTENT(IN) :: mpicomm, mpirank, mpiroot INTEGER, INTENT(IN) :: threads CHARACTER(len=*), INTENT(INOUT) :: errmsg @@ -458,6 +460,16 @@ SUBROUTINE thompson_init(mpicomm, mpirank, mpiroot, & LOGICAL, PARAMETER :: precomputed_tables = .FALSE. #endif +! Set module variable is_aerosol_aware + is_aerosol_aware = is_aerosol_aware_in + if (mpirank==mpiroot) then + if (is_aerosol_aware) then + write (0,'(a)') 'Using aerosol-aware version of Thompson microphysics' + else + write (0,'(a)') 'Using non-aerosol-aware version of Thompson microphysics' + end if + end if + micro_init = .FALSE. !> - Allocate space for lookup tables (J. Michalakes 2009Jun08). @@ -5218,6 +5230,8 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & lamc = (nc(k)*am_r*g_ratio(inu_c)/rc(k))**obmr re_qc1d(k) = SNGL(0.5D0 * DBLE(3.+inu_c)/lamc) enddo + else + re_qc1d(:) = 0.0D0 endif if (has_qi) then @@ -5226,6 +5240,8 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & lami = (am_i*cig(2)*oig1*ni(k)/ri(k))**obmi re_qi1d(k) = SNGL(0.5D0 * DBLE(3.+mu_i)/lami) enddo + else + re_qi1d(:) = 0.0D0 endif if (has_qs) then @@ -5266,6 +5282,8 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & smoc = a_ * smo2**b_ re_qs1d(k) = 0.5*(smoc/smob) enddo + else + re_qs1d(:) = 0.0D0 endif end subroutine calc_effectRad diff --git a/physics/mp_thompson.F90 b/physics/mp_thompson.F90 index 252944b77..5d5e631f5 100644 --- a/physics/mp_thompson.F90 +++ b/physics/mp_thompson.F90 @@ -115,8 +115,9 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & end if ! Call Thompson init - call thompson_init(mpicomm=mpicomm, mpirank=mpirank, mpiroot=mpiroot, & - threads=threads, errmsg=errmsg, errflg=errflg) + call thompson_init(is_aerosol_aware_in=is_aerosol_aware, mpicomm=mpicomm, & + mpirank=mpirank, mpiroot=mpiroot, threads=threads, & + errmsg=errmsg, errflg=errflg) if (errflg /= 0) return ! For restart runs, the init is done here @@ -276,8 +277,8 @@ subroutine mp_thompson_init(ncol, nlev, con_g, con_rd, restart, & re_cloud(i,:), re_ice(i,:), re_snow(i,:), 1, nlev) do k = 1, nlev re_cloud(i,k) = MAX(re_qc_min, MIN(re_cloud(i,k), re_qc_max)) - re_ice(i,k) = MAX(re_qi_min, MIN(re_ice(i,k), re_qi_max)) - re_snow(i,k) = MAX(re_qs_min, MIN(re_snow(i,k), re_qs_max)) + re_ice(i,k) = MAX(re_qi_min, MIN(re_ice(i,k), re_qi_max)) + re_snow(i,k) = MAX(re_qs_min, MIN(re_snow(i,k), re_qs_max)) end do end do !! Convert to micron: required for bit-for-bit identical restarts; From 4d8f7f4117d5695c534580bdf6350c39eb95c2ad Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Fri, 5 Mar 2021 17:30:51 -0700 Subject: [PATCH 11/18] Bugfix of my own bugfix in physics/module_mp_thompson.F90: always initialize cloud effective radii --- physics/module_mp_thompson.F90 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/physics/module_mp_thompson.F90 b/physics/module_mp_thompson.F90 index 8ba269388..dfe31f375 100644 --- a/physics/module_mp_thompson.F90 +++ b/physics/module_mp_thompson.F90 @@ -5204,6 +5204,10 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & has_qi = .false. has_qs = .false. + re_qc1d(:) = 0.0D0 + re_qi1d(:) = 0.0D0 + re_qs1d(:) = 0.0D0 + do k = kts, kte rho(k) = 0.622*p1d(k)/(R*t1d(k)*(qv1d(k)+0.622)) rc(k) = MAX(R1, qc1d(k)*rho(k)) @@ -5230,8 +5234,6 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & lamc = (nc(k)*am_r*g_ratio(inu_c)/rc(k))**obmr re_qc1d(k) = SNGL(0.5D0 * DBLE(3.+inu_c)/lamc) enddo - else - re_qc1d(:) = 0.0D0 endif if (has_qi) then @@ -5240,8 +5242,6 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & lami = (am_i*cig(2)*oig1*ni(k)/ri(k))**obmi re_qi1d(k) = SNGL(0.5D0 * DBLE(3.+mu_i)/lami) enddo - else - re_qi1d(:) = 0.0D0 endif if (has_qs) then @@ -5282,8 +5282,6 @@ subroutine calc_effectRad (t1d, p1d, qv1d, qc1d, nc1d, qi1d, ni1d, qs1d, & smoc = a_ * smo2**b_ re_qs1d(k) = 0.5*(smoc/smob) enddo - else - re_qs1d(:) = 0.0D0 endif end subroutine calc_effectRad From f5733901180d8fe6919425c47b56aef5b7c44939 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Fri, 12 Mar 2021 16:38:07 -0700 Subject: [PATCH 12/18] physics/radlw_main.F90: apply local bounds for cloud effective radii instead of aborting the model run --- physics/radlw_main.F90 | 66 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/physics/radlw_main.F90 b/physics/radlw_main.F90 index de8d9e973..7655e76d2 100644 --- a/physics/radlw_main.F90 +++ b/physics/radlw_main.F90 @@ -1250,7 +1250,7 @@ subroutine rrtmg_lw_run & endif !mz* HWRF: calculate taucmc with mcica - if (iovr == 4) then + if (iovr == 4) then call cldprmc(nlay, inflglw, iceflglw, liqflglw, & & cldfmc, ciwpmc, & & clwpmc, cswpmc, reicmc, relqmc, resnmc, & @@ -8854,25 +8854,25 @@ subroutine cldprmc(nlayers, inflag, iceflag, liqflag, cldfmc, & abscosno(ig) = 0.0_rb elseif (iceflag .eq. 0) then - if (radice .lt. 10.0_rb) stop 'ICE RADIUS TOO SMALL' - abscoice(ig) = absice0(1) + absice0(2)/radice +! if (radice .lt. 10.0_rb) stop 'ICE RADIUS TOO SMALL' + abscoice(ig) = absice0(1) + absice0(2)/max(radice,10.0_rb) abscosno(ig) = 0.0_rb elseif (iceflag .eq. 1) then - if (radice .lt. 13.0_rb .or. radice .gt. 130._rb) stop& - & 'ICE RADIUS OUT OF BOUNDS' +! if (radice .lt. 13.0_rb .or. radice .gt. 130._rb) stop& +! & 'ICE RADIUS OUT OF BOUNDS' ncbands = 5 ib = icb(ngb(ig)) - abscoice(ig) = absice1(1,ib) + absice1(2,ib)/radice + abscoice(ig) = absice1(1,ib) + absice1(2,ib)/min(max(radice,13.0_rb),130._rb) abscosno(ig) = 0.0_rb ! For iceflag=2 option, ice particle effective radius is limited to 5.0 to 131.0 microns elseif (iceflag .eq. 2) then - if (radice .lt. 5.0_rb .or. radice .gt. 131.0_rb) stop& - & 'ICE RADIUS OUT OF BOUNDS' +! if (radice .lt. 5.0_rb .or. radice .gt. 131.0_rb) stop& +! & 'ICE RADIUS OUT OF BOUNDS' ncbands = 16 - factor = (radice - 2._rb)/3._rb + factor = (min(max(radice,5.0_rb),131._rb) - 2._rb)/3._rb index = int(factor) if (index .eq. 43) index = 42 fint = factor - float(index) @@ -8885,15 +8885,15 @@ subroutine cldprmc(nlayers, inflag, iceflag, liqflag, cldfmc, & ! For iceflag=3 option, ice particle generalized effective size is limited to 5.0 to 140.0 microns elseif (iceflag .ge. 3) then - if (radice .lt. 5.0_rb .or. radice .gt. 140.0_rb) then - write(errmsg,'(a,i5,i5,f8.2,f8.2)' ) & - & 'ERROR: ICE GENERALIZED EFFECTIVE SIZE OUT OF BOUNDS' & - & ,ig, lay, ciwpmc(ig,lay), radice - errflg = 1 - return - end if +! if (radice .lt. 5.0_rb .or. radice .gt. 140.0_rb) then +! write(errmsg,'(a,i5,i5,f8.2,f8.2)' ) & +! & 'ERROR: ICE GENERALIZED EFFECTIVE SIZE OUT OF BOUNDS' & +! & ,ig, lay, ciwpmc(ig,lay), radice +! errflg = 1 +! return +! end if ncbands = 16 - factor = (radice - 2._rb)/3._rb + factor = (min(max(radice,5.0_rb),140._rb) - 2._rb)/3._rb index = int(factor) if (index .eq. 46) index = 45 fint = factor - float(index) @@ -8908,15 +8908,15 @@ subroutine cldprmc(nlayers, inflag, iceflag, liqflag, cldfmc, & !..Incorporate additional effects due to snow. if (cswpmc(ig,lay).gt.0.0_rb .and. iceflag .eq. 5) then radsno = resnmc(lay) - if (radsno .lt. 5.0_rb .or. radsno .gt. 140.0_rb) then - write(errmsg,'(a,i5,i5,f8.2,f8.2)' ) & - & 'ERROR: SNOW GENERALIZED EFFECTIVE SIZE OUT OF BOUNDS' & - & ,ig, lay, cswpmc(ig,lay), radsno - errflg = 1 - return - end if +! if (radsno .lt. 5.0_rb .or. radsno .gt. 140.0_rb) then +! write(errmsg,'(a,i5,i5,f8.2,f8.2)' ) & +! & 'ERROR: SNOW GENERALIZED EFFECTIVE SIZE OUT OF BOUNDS' & +! & ,ig, lay, cswpmc(ig,lay), radsno +! errflg = 1 +! return +! end if ncbands = 16 - factor = (radsno - 2._rb)/3._rb + factor = (min(max(radsno,5.0_rb),140.0_rb) - 2._rb)/3._rb index = int(factor) if (index .eq. 46) index = 45 fint = factor - float(index) @@ -8937,14 +8937,14 @@ subroutine cldprmc(nlayers, inflag, iceflag, liqflag, cldfmc, & elseif (liqflag .eq. 1) then radliq = relqmc(lay) - if (radliq .lt. 2.5_rb .or. radliq .gt. 60._rb) then - write(errmsg,'(a,i5,i5,f8.2,f8.2)' ) & -& 'ERROR: LIQUID EFFECTIVE SIZE OUT OF BOUNDS' & -& ,ig, lay, clwpmc(ig,lay), radliq - errflg = 1 - return - end if - index = int(radliq - 1.5_rb) +! if (radliq .lt. 2.5_rb .or. radliq .gt. 60._rb) then +! write(errmsg,'(a,i5,i5,f8.2,f8.2)' ) & +!& 'ERROR: LIQUID EFFECTIVE SIZE OUT OF BOUNDS' & +!& ,ig, lay, clwpmc(ig,lay), radliq +! errflg = 1 +! return +! end if + index = int(min(max(radliq,2.5_rb),60._rb) - 1.5_rb) if (index .eq. 0) index = 1 if (index .eq. 58) index = 57 fint = radliq - 1.5_rb - float(index) From c579871215ecfcc432ded8531f3a66defce4a9e6 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Fri, 12 Mar 2021 16:38:40 -0700 Subject: [PATCH 13/18] Bugfix for uninitialized variable in physics/module_bl_mynn.F90 --- physics/module_bl_mynn.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/physics/module_bl_mynn.F90 b/physics/module_bl_mynn.F90 index fa892eba8..d691de909 100644 --- a/physics/module_bl_mynn.F90 +++ b/physics/module_bl_mynn.F90 @@ -2947,6 +2947,7 @@ SUBROUTINE mynn_tendencies(kts,kte, & khdz(k) = rhoz(k)*dfh(k) kmdz(k) = rhoz(k)*dfm(k) ENDDO + rhoz(kte+1)=rhoz(kte) khdz(kte+1)=rhoz(kte+1)*dfh(kte) kmdz(kte+1)=rhoz(kte+1)*dfm(kte) From b23f06a4bcdafd5effc20a20333eaa125c160ace Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 15 Mar 2021 05:42:25 -0600 Subject: [PATCH 14/18] Bugfix in physics/module_sf_noahmplsm.f90 for uninitialized variable in subroutine surrad --- physics/module_sf_noahmplsm.f90 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/physics/module_sf_noahmplsm.f90 b/physics/module_sf_noahmplsm.f90 index 567f4a0cf..54bec6de5 100644 --- a/physics/module_sf_noahmplsm.f90 +++ b/physics/module_sf_noahmplsm.f90 @@ -2597,6 +2597,12 @@ subroutine albedo (parameters,vegtyp ,ist ,ice ,nsoil , & !in ftid(ib) = 0. ftii(ib) = 0. if (ib.eq.1) fsun = 0. + frevd = 0. + frevi = 0. + fregd = 0. + fregi = 0. + bgap = 0. + wgap = 0. end do if(cosz <= 0) goto 100 @@ -3262,7 +3268,6 @@ subroutine twostream (parameters,ib ,ic ,vegtyp ,cosz ,vai , & ! frev(ib) = freveg freg(ib) = frebar - ! flux absorbed by vegetation fab(ib) = 1. - fre(ib) - (1.-albgrd(ib))*ftd(ib) & From b67acadf85ca69e274e24097b53efd77b75add39 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 15 Mar 2021 05:44:13 -0600 Subject: [PATCH 15/18] Bugfixes in UGWP v1 for uninitialized variable azmeti(jk-1) --- physics/cires_ugwpv1_module.F90 | 25 ++++++++++++++----------- physics/cires_ugwpv1_solv2.F90 | 19 +++++++++---------- physics/ugwpv1_gsldrag.F90 | 5 +++-- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/physics/cires_ugwpv1_module.F90 b/physics/cires_ugwpv1_module.F90 index 13b7752a5..c8108cba2 100644 --- a/physics/cires_ugwpv1_module.F90 +++ b/physics/cires_ugwpv1_module.F90 @@ -191,16 +191,19 @@ subroutine cires_ugwpv1_init (me, master, nlunit, logunit, jdat_gfs, con_pi, & integer :: k integer :: ddd_ugwp, curday_ugwp ! integer :: version - + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 ! if (me == master) print *, trim (fn_nml), ' GW-namelist file ' inquire (file =trim (fn_nml) , exist = exists) ! if (.not. exists) then - if (me == master) & - write (6, *) 'separate ugwp :: namelist file: ', trim (fn_nml), ' does not exist' - + write(errmsg,'(3a)') 'cires_ugwpv1_init: namelist file: ', trim (fn_nml), ' does not exist' + errflg = 1 + return else open (unit = nlunit, file = trim(fn_nml), action = 'read', status = 'old', iostat = ios) endif @@ -209,11 +212,6 @@ subroutine cires_ugwpv1_init (me, master, nlunit, logunit, jdat_gfs, con_pi, & close (nlunit) ! - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - strsolver= knob_ugwp_orosolv curday_ugwp = jdat_gfs(1)*10000 + jdat_gfs(2)*100 +jdat_gfs(3) @@ -248,7 +246,7 @@ subroutine cires_ugwpv1_init (me, master, nlunit, logunit, jdat_gfs, con_pi, & ! allocate(fcor(latr), fcor2(latr) ) ! allocate( kvg(levs+1), ktg(levs+1) ) - allocate( krad(levs+1), kion(levs+1) ) + allocate( krad(levs+1), kion(levs+1) ) allocate( zkm(levs), pmb(levs) ) ! @@ -263,7 +261,12 @@ subroutine cires_ugwpv1_init (me, master, nlunit, logunit, jdat_gfs, con_pi, & ! ! find ilaunch ! - + if (knob_ugwp_palaunch gt 900.e2) then + write(errmsg,'(a,e16.7)') 'cires_ugwpv1_init: unrealistic value of knob_ugwp_palaunch', knob_ugwp_palaunch + errflg = 1 + return + endif + do k=levs, 1, -1 if (pmb(k) .gt. knob_ugwp_palaunch ) exit enddo diff --git a/physics/cires_ugwpv1_solv2.F90 b/physics/cires_ugwpv1_solv2.F90 index ee8f7bc83..afd94ff5c 100644 --- a/physics/cires_ugwpv1_solv2.F90 +++ b/physics/cires_ugwpv1_solv2.F90 @@ -267,15 +267,14 @@ subroutine cires_ugwpv1_ngw_solv2(mpi_id, master, im, levs, kdt, dtp, & !=====ksrc - aum(km2:levs) = um(jl,km2:levs) - avm(km2:levs) = vm(jl,km2:levs) - atm(km2:levs) = tm(jl,km2:levs) - aqm(km2:levs) = qm(jl,km2:levs) - azmet(km2:levs) = zmet(jl,km2:levs) - aprsi(km2:levs+1) = prsi(jl,km2:levs+1) - azmeti(km2:levs+1) = zmeti(jl,km2:levs+1) + aum(1:levs) = um(jl,1:levs) + avm(1:levs) = vm(jl,1:levs) + atm(1:levs) = tm(jl,1:levs) + aqm(1:levs) = qm(jl,1:levs) + azmet(1:levs) = zmet(jl,1:levs) + aprsi(1:levs+1) = prsi(jl,1:levs+1) + azmeti(1:levs+1) = zmeti(jl,1:levs+1) - rho_src = aprsl(ksrc)*rdi/atm(ksrc) taub_ch = max(tau_ngw(jl), tau_min) taub_src = taub_ch @@ -288,8 +287,8 @@ subroutine cires_ugwpv1_ngw_solv2(mpi_id, master, im, levs, kdt, dtp, & ! do jk = km2, levs dz_meti(jk) = azmeti(jk+1)-azmeti(jk) - dz_met(jk) = azmet(jk)-azmeti(jk-1) - enddo + dz_met(jk) = azmet(jk)-azmeti(jk-1) + enddo ! --------------------------------------------- ! interface mean flow parameters launch -> levs+1 ! --------------------------------------------- diff --git a/physics/ugwpv1_gsldrag.F90 b/physics/ugwpv1_gsldrag.F90 index 00fd42dbd..f473dc9bd 100644 --- a/physics/ugwpv1_gsldrag.F90 +++ b/physics/ugwpv1_gsldrag.F90 @@ -160,7 +160,7 @@ subroutine ugwpv1_gsldrag_init ( & if ( do_ugwp_v0_orog_only .or. do_ugwp_v0) then print *, ' ccpp do_ugwp_v0 active ', do_ugwp_v0 print *, ' ccpp do_ugwp_v1_orog_only active ', do_ugwp_v0_orog_only - write(errmsg,'(*(a))') " the CIRES CCPP-suite does not & + write(errmsg,'(*(a))') " the CIRES CCPP-suite does not & support schemes " errflg = 1 return @@ -171,7 +171,7 @@ subroutine ugwpv1_gsldrag_init ( & print *, ' do_ugwp_v1_w_gsldrag ', do_ugwp_v1_w_gsldrag print *, ' do_ugwp_v1_orog_only ', do_ugwp_v1_orog_only print *, ' do_gsl_drag_ls_bl ',do_gsl_drag_ls_bl - write(errmsg,'(*(a))') " the CIRES CCPP-suite intend to & + write(errmsg,'(*(a))') " the CIRES CCPP-suite intend to & support with but has Logic error" errflg = 1 return @@ -232,6 +232,7 @@ subroutine ugwpv1_gsldrag_init ( & call cires_ugwpv1_init (me, master, nlunit, logunit, jdat, con_pi, & con_rerth, fn_nml2, lonr, latr, levs, ak, bk, & con_p0, dtp, errmsg, errflg) + if (errflg/=0) return end if if (me == master) then From 10f532cd7feb8b8a6f9a6028d8e061b2a70b2b91 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 15 Mar 2021 15:19:12 -0600 Subject: [PATCH 16/18] Bugfix in physics/cires_ugwpv1_module.F90 --- physics/cires_ugwpv1_module.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/physics/cires_ugwpv1_module.F90 b/physics/cires_ugwpv1_module.F90 index c8108cba2..4746d61ff 100644 --- a/physics/cires_ugwpv1_module.F90 +++ b/physics/cires_ugwpv1_module.F90 @@ -261,7 +261,7 @@ subroutine cires_ugwpv1_init (me, master, nlunit, logunit, jdat_gfs, con_pi, & ! ! find ilaunch ! - if (knob_ugwp_palaunch gt 900.e2) then + if (knob_ugwp_palaunch > 900.e2) then write(errmsg,'(a,e16.7)') 'cires_ugwpv1_init: unrealistic value of knob_ugwp_palaunch', knob_ugwp_palaunch errflg = 1 return From 62df7ba52c8b559a7745a8e0382bf1503dd5337f Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 15 Mar 2021 15:24:48 -0600 Subject: [PATCH 17/18] Adjust two tuning parameters for RUC LSM in physics/module_sf_ruclsm.F90 and physics/module_soil_pre.F90 --- physics/module_sf_ruclsm.F90 | 3 ++- physics/module_soil_pre.F90 | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/physics/module_sf_ruclsm.F90 b/physics/module_sf_ruclsm.F90 index a0e74ce7a..1eceaf183 100644 --- a/physics/module_sf_ruclsm.F90 +++ b/physics/module_sf_ruclsm.F90 @@ -2586,7 +2586,8 @@ SUBROUTINE SOIL (debug_print, & ! evaporation, effects sparsely vegetated areas--> cooler during the day ! fc=max(qmin,ref*0.25) ! ! For now we'll go back to ref*0.5 - fc=max(qmin,ref*0.5) +! Replace 0.5 with 0.7 2021/03/15 + fc=max(qmin,ref*0.7) fex_fc=1. if((soilmois(1)+qmin) > fc .or. (qvatm-qvg) > 0.) then soilres = 1. diff --git a/physics/module_soil_pre.F90 b/physics/module_soil_pre.F90 index 82fe23f24..8eb5a5775 100644 --- a/physics/module_soil_pre.F90 +++ b/physics/module_soil_pre.F90 @@ -42,8 +42,8 @@ SUBROUTINE init_soil_depth_3 ( zs , dzs , num_soil_levels ) IF ( num_soil_levels .EQ. 6) THEN zs = (/ 0.00 , 0.05 , 0.20 , 0.40 , 1.60 , 3.00 /) ELSEIF ( num_soil_levels .EQ. 9) THEN - !zs = (/ 0.00 , 0.01 , 0.04 , 0.10 , 0.30, 0.60, 1.00 , 1.60, 3.00 /) - zs = (/ 0.00 , 0.05 , 0.20 , 0.40 , 0.60, 1.00, 1.60 , 2.20, 3.00 /) + zs = (/ 0.00 , 0.01 , 0.04 , 0.10 , 0.30, 0.60, 1.00 , 1.60, 3.00 /) + !zs = (/ 0.00 , 0.05 , 0.20 , 0.40 , 0.60, 1.00, 1.60 , 2.20, 3.00 /) ENDIF zs2(1) = 0. From bbec192809f8e283b79eced5d032faf45060b423 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Mon, 15 Mar 2021 15:36:53 -0600 Subject: [PATCH 18/18] Optimize initializing intent(out) variables in physics/module_sf_noahmplsm.f90 --- physics/module_sf_noahmplsm.f90 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/physics/module_sf_noahmplsm.f90 b/physics/module_sf_noahmplsm.f90 index 54bec6de5..8041d07b4 100644 --- a/physics/module_sf_noahmplsm.f90 +++ b/physics/module_sf_noahmplsm.f90 @@ -2583,6 +2583,10 @@ subroutine albedo (parameters,vegtyp ,ist ,ice ,nsoil , & !in mpe = 1.e-06 bgap = 0. wgap = 0. + frevd = 0. + frevi = 0. + fregd = 0. + fregi = 0. ! initialize output because solar radiation only done if cosz > 0 @@ -2597,12 +2601,6 @@ subroutine albedo (parameters,vegtyp ,ist ,ice ,nsoil , & !in ftid(ib) = 0. ftii(ib) = 0. if (ib.eq.1) fsun = 0. - frevd = 0. - frevi = 0. - fregd = 0. - fregi = 0. - bgap = 0. - wgap = 0. end do if(cosz <= 0) goto 100