module hk_conv 3,4 ! ! Moist convection. Primarily data used by both Zhang-McFarlane convection ! and Hack shallow convective schemes. ! ! $Id$ ! use shr_kind_mod, only: r8 => shr_kind_r8 use cam_logfile, only: iulog use spmd_utils, only: masterproc use abortutils, only: endrun implicit none private save ! ! Public interfaces ! public mfinti ! Initialization of data for moist convection public cmfmca ! Hack shallow convection public hkconv_readnl ! read hkconv_nl namelist ! ! Private data used for Hack shallow convection ! real(r8), parameter :: unset_r8 = huge(1.0_r8) ! Namelist variables real(r8) :: hkconv_c0 = unset_r8 real(r8) :: hkconv_cmftau = unset_r8 real(r8) :: hlat ! latent heat of vaporization real(r8) :: c0 ! rain water autoconversion coefficient set from namelist input hkconv_c0 real(r8) :: betamn ! minimum overshoot parameter real(r8) :: rhlat ! reciprocal of hlat real(r8) :: rcp ! reciprocal of cp real(r8) :: cmftau ! characteristic adjustment time scale set from namelist input hkconv_cmftau real(r8) :: rhoh2o ! density of liquid water (STP) real(r8) :: dzmin ! minimum convective depth for precipitation real(r8) :: tiny ! arbitrary small num used in transport estimates real(r8) :: eps ! convergence criteria (machine dependent) real(r8) :: tpmax ! maximum acceptable t perturbation (degrees C) real(r8) :: shpmax ! maximum acceptable q perturbation (g/g) integer :: iloc ! longitude location for diagnostics integer :: jloc ! latitude location for diagnostics integer :: nsloc ! nstep for which to produce diagnostics ! logical :: rlxclm ! logical to relax column versus cloud triplet real(r8) cp ! specific heat of dry air real(r8) grav ! gravitational constant real(r8) rgrav ! reciprocal of grav real(r8) rgas ! gas constant for dry air integer limcnv ! top interface level limit for convection contains subroutine hkconv_readnl(nlfile) 1,9 use namelist_utils, only: find_group_name use units, only: getunit, freeunit use mpishorthand character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input ! Local variables integer :: unitn, ierr character(len=*), parameter :: subname = 'hkconv_readnl' namelist /hkconv_nl/ hkconv_cmftau, hkconv_c0 !----------------------------------------------------------------------------- if (masterproc) then unitn = getunit() open( unitn, file=trim(nlfile), status='old' ) call find_group_name(unitn, 'hkconv_nl', status=ierr) if (ierr == 0) then read(unitn, hkconv_nl, iostat=ierr) if (ierr /= 0) then call endrun(subname // ':: ERROR reading namelist') end if end if close(unitn) call freeunit(unitn) ! set local variables cmftau = hkconv_cmftau c0 = hkconv_c0 end if #ifdef SPMD ! Broadcast namelist variables call mpibcast(cmftau, 1, mpir8, 0, mpicom) call mpibcast(c0, 1, mpir8, 0, mpicom) #endif end subroutine hkconv_readnl !================================================================================================ subroutine mfinti (rair ,cpair ,gravit ,latvap ,rhowtr,limcnv_in ) 1,2 !----------------------------------------------------------------------- ! ! Purpose: ! Initialize moist convective mass flux procedure common block, cmfmca ! ! Method: ! <Describe the algorithm(s) used in the routine.> ! <Also include any applicable external references.> ! ! Author: J. Hack ! !----------------------------------------------------------------------- use dycore, only: dycore_is, get_resolution use spmd_utils, only: masterproc !------------------------------Arguments-------------------------------- ! ! Input arguments ! real(r8), intent(in) :: rair ! gas constant for dry air real(r8), intent(in) :: cpair ! specific heat of dry air real(r8), intent(in) :: gravit ! acceleration due to gravity real(r8), intent(in) :: latvap ! latent heat of vaporization real(r8), intent(in) :: rhowtr ! density of liquid water (STP) integer, intent(in) :: limcnv_in ! top interface level limit for convection ! local variables character(len=32) :: hgrid ! horizontal grid specifier ! !----------------------------------------------------------------------- ! ! Initialize physical constants for moist convective mass flux procedure ! cp = cpair ! specific heat of dry air hlat = latvap ! latent heat of vaporization grav = gravit ! gravitational constant rgas = rair ! gas constant for dry air rhoh2o = rhowtr ! density of liquid water (STP) limcnv = limcnv_in ! Initialize free parameters for moist convective mass flux procedure ! cmftau - characteristic adjustment time scale ! c0 - rain water autoconversion coeff (1/m) if (masterproc) then write(iulog,*) 'tuning parameters hk_conv: cmftau',cmftau write(iulog,*) 'tuning parameters hk_conv: c0',c0 endif dzmin = 0.0_r8 ! minimum cloud depth to precipitate (m) betamn = 0.10_r8 ! minimum overshoot parameter tpmax = 1.50_r8 ! maximum acceptable t perturbation (deg C) shpmax = 1.50e-3_r8 ! maximum acceptable q perturbation (g/g) rlxclm = .true. ! logical variable to specify that relaxation ! time scale should applied to column as ! opposed to triplets individually ! ! Initialize miscellaneous (frequently used) constants ! rhlat = 1.0_r8/hlat ! reciprocal latent heat of vaporization rcp = 1.0_r8/cp ! reciprocal specific heat of dry air rgrav = 1.0_r8/grav ! reciprocal gravitational constant ! ! Initialize diagnostic location information for moist convection scheme ! iloc = 1 ! longitude point for diagnostic info jloc = 1 ! latitude point for diagnostic info nsloc = 1 ! nstep value at which to begin diagnostics ! ! Initialize other miscellaneous parameters ! tiny = 1.0e-36_r8 ! arbitrary small number (scalar transport) eps = 1.0e-13_r8 ! convergence criteria (machine dependent) ! return end subroutine mfinti subroutine cmfmca(lchnk ,ncol , & 1,11 nstep ,ztodt ,pmid ,pdel , & rpdel ,zm ,tpert ,qpert ,phis , & pblht ,t ,q ,cmfdt ,dq , & cmfmc ,cmfdqr ,cmfsl ,cmflq ,precc , & qc ,cnt ,cnb ,icwmr ,rliq , & pmiddry ,pdeldry ,rpdeldry) !----------------------------------------------------------------------- ! ! Purpose: ! Moist convective mass flux procedure: ! ! Method: ! If stratification is unstable to nonentraining parcel ascent, ! complete an adjustment making successive use of a simple cloud model ! consisting of three layers (sometimes referred to as a triplet) ! ! Code generalized to allow specification of parcel ("updraft") ! properties, as well as convective transport of an arbitrary ! number of passive constituents (see q array). The code ! is written so the water vapor field is passed independently ! in the calling list from the block of other transported ! constituents, even though as currently designed, it is the ! first component in the constituents field. ! ! Author: J. Hack ! ! BAB: changed code to report tendencies in cmfdt and dq, instead of ! updating profiles. Cmfdq contains water only, made it a local variable ! made dq (all constituents) the argument. ! !----------------------------------------------------------------------- !####################################################################### !# # !# Debugging blocks are marked this way for easy identification # !# # !####################################################################### use constituents, only: pcnst use constituents, only: cnst_get_type_byind use ppgrid, only: pcols, pver, pverp use phys_grid, only: get_lat_all_p, get_lon_all_p use wv_saturation, only: aqsatd, vqsatd real(r8) ssfac ! supersaturation bound (detrained air) parameter (ssfac = 1.001_r8) !------------------------------Arguments-------------------------------- ! ! Input arguments ! integer, intent(in) :: lchnk ! chunk identifier integer, intent(in) :: ncol ! number of atmospheric columns integer, intent(in) :: nstep ! current time step index real(r8), intent(in) :: ztodt ! 2 delta-t (seconds) real(r8), intent(in) :: pmid(pcols,pver) ! pressure real(r8), intent(in) :: pdel(pcols,pver) ! delta-p real(r8), intent(in) :: pmiddry(pcols,pver) ! pressure real(r8), intent(in) :: pdeldry(pcols,pver) ! delta-p real(r8), intent(in) :: rpdel(pcols,pver) ! 1./pdel real(r8), intent(in) :: rpdeldry(pcols,pver) ! 1./pdel real(r8), intent(in) :: zm(pcols,pver) ! height abv sfc at midpoints real(r8), intent(in) :: tpert(pcols) ! PBL perturbation theta real(r8), intent(in) :: qpert(pcols,pcnst) ! PBL perturbation specific humidity real(r8), intent(in) :: phis(pcols) ! surface geopotential real(r8), intent(in) :: pblht(pcols) ! PBL height (provided by PBL routine) real(r8), intent(in) :: t(pcols,pver) ! temperature (t bar) real(r8), intent(in) :: q(pcols,pver,pcnst) ! specific humidity (sh bar) ! ! Output arguments ! real(r8), intent(out) :: cmfdt(pcols,pver) ! dt/dt due to moist convection real(r8), intent(out) :: cmfmc(pcols,pverp) ! moist convection cloud mass flux real(r8), intent(out) :: cmfdqr(pcols,pver) ! dq/dt due to convective rainout real(r8), intent(out) :: cmfsl(pcols,pver ) ! convective lw static energy flux real(r8), intent(out) :: cmflq(pcols,pver ) ! convective total water flux real(r8), intent(out) :: precc(pcols) ! convective precipitation rate ! JJH mod to explicitly export cloud water real(r8), intent(out) :: qc(pcols,pver) ! dq/dt due to export of cloud water real(r8), intent(out) :: cnt(pcols) ! top level of convective activity real(r8), intent(out) :: cnb(pcols) ! bottom level of convective activity real(r8), intent(out) :: dq(pcols,pver,pcnst) ! constituent tendencies real(r8), intent(out) :: icwmr(pcols,pver) real(r8), intent(out) :: rliq(pcols) ! !---------------------------Local workspace----------------------------- ! real(r8) pm(pcols,pver) ! pressure real(r8) pd(pcols,pver) ! delta-p real(r8) rpd(pcols,pver) ! 1./pdel real(r8) cmfdq(pcols,pver) ! dq/dt due to moist convection real(r8) gam(pcols,pver) ! 1/cp (d(qsat)/dT) real(r8) sb(pcols,pver) ! dry static energy (s bar) real(r8) hb(pcols,pver) ! moist static energy (h bar) real(r8) shbs(pcols,pver) ! sat. specific humidity (sh bar star) real(r8) hbs(pcols,pver) ! sat. moist static energy (h bar star) real(r8) shbh(pcols,pverp) ! specific humidity on interfaces real(r8) sbh(pcols,pverp) ! s bar on interfaces real(r8) hbh(pcols,pverp) ! h bar on interfaces real(r8) cmrh(pcols,pverp) ! interface constituent mixing ratio real(r8) prec(pcols) ! instantaneous total precipitation real(r8) dzcld(pcols) ! depth of convective layer (m) real(r8) beta(pcols) ! overshoot parameter (fraction) real(r8) betamx(pcols) ! local maximum on overshoot real(r8) eta(pcols) ! convective mass flux (kg/m^2 s) real(r8) etagdt(pcols) ! eta*grav*dt real(r8) cldwtr(pcols) ! cloud water (mass) real(r8) rnwtr(pcols) ! rain water (mass) ! JJH extension to facilitate export of cloud liquid water real(r8) totcond(pcols) ! total condensate; mix of precip and cloud water (mass) real(r8) sc (pcols) ! dry static energy ("in-cloud") real(r8) shc (pcols) ! specific humidity ("in-cloud") real(r8) hc (pcols) ! moist static energy ("in-cloud") real(r8) cmrc(pcols) ! constituent mix rat ("in-cloud") real(r8) dq1(pcols) ! shb convective change (lower lvl) real(r8) dq2(pcols) ! shb convective change (mid level) real(r8) dq3(pcols) ! shb convective change (upper lvl) real(r8) ds1(pcols) ! sb convective change (lower lvl) real(r8) ds2(pcols) ! sb convective change (mid level) real(r8) ds3(pcols) ! sb convective change (upper lvl) real(r8) dcmr1(pcols) ! q convective change (lower lvl) real(r8) dcmr2(pcols) ! q convective change (mid level) real(r8) dcmr3(pcols) ! q convective change (upper lvl) real(r8) estemp(pcols,pver) ! saturation vapor pressure (scratch) real(r8) vtemp1(2*pcols) ! intermediate scratch vector real(r8) vtemp2(2*pcols) ! intermediate scratch vector real(r8) vtemp3(2*pcols) ! intermediate scratch vector real(r8) vtemp4(2*pcols) ! intermediate scratch vector integer indx1(pcols) ! longitude indices for condition true logical etagt0 ! true if eta > 0.0 real(r8) sh1 ! dummy arg in qhalf statement func. real(r8) sh2 ! dummy arg in qhalf statement func. real(r8) shbs1 ! dummy arg in qhalf statement func. real(r8) shbs2 ! dummy arg in qhalf statement func. real(r8) cats ! modified characteristic adj. time real(r8) rtdt ! 1./ztodt real(r8) qprime ! modified specific humidity pert. real(r8) tprime ! modified thermal perturbation real(r8) pblhgt ! bounded pbl height (max[pblh,1m]) real(r8) fac1 ! intermediate scratch variable real(r8) shprme ! intermediate specific humidity pert. real(r8) qsattp ! sat mix rat for thermally pert PBL parcels real(r8) dz ! local layer depth real(r8) temp1 ! intermediate scratch variable real(r8) b1 ! bouyancy measure in detrainment lvl real(r8) b2 ! bouyancy measure in condensation lvl real(r8) temp2 ! intermediate scratch variable real(r8) temp3 ! intermediate scratch variable real(r8) g ! bounded vertical gradient of hb real(r8) tmass ! total mass available for convective exch real(r8) denom ! intermediate scratch variable real(r8) qtest1 ! used in negative q test (middle lvl) real(r8) qtest2 ! used in negative q test (lower lvl) real(r8) fslkp ! flux lw static energy (bot interface) real(r8) fslkm ! flux lw static energy (top interface) real(r8) fqlkp ! flux total water (bottom interface) real(r8) fqlkm ! flux total water (top interface) real(r8) botflx ! bottom constituent mixing ratio flux real(r8) topflx ! top constituent mixing ratio flux real(r8) efac1 ! ratio q to convectively induced chg (btm lvl) real(r8) efac2 ! ratio q to convectively induced chg (mid lvl) real(r8) efac3 ! ratio q to convectively induced chg (top lvl) real(r8) tb(pcols,pver) ! working storage for temp (t bar) real(r8) shb(pcols,pver) ! working storage for spec hum (sh bar) real(r8) adjfac ! adjustment factor (relaxation related) real(r8) rktp real(r8) rk #if ( defined DIAGNS ) ! ! Following 7 real variables are used in diagnostics calculations ! real(r8) rh ! relative humidity real(r8) es ! sat vapor pressure real(r8) hsum1 ! moist static energy integral real(r8) qsum1 ! total water integral real(r8) hsum2 ! final moist static energy integral real(r8) qsum2 ! final total water integral real(r8) fac ! intermediate scratch variable #endif integer i,k ! longitude, level indices integer ii ! index on "gathered" vectors integer len1 ! vector length of "gathered" vectors integer m ! constituent index integer ktp ! tmp indx used to track top of convective layer #if ( defined DIAGNS ) integer n ! vertical index (diagnostics) integer kp ! vertical index (diagnostics) integer kpp ! index offset, kp+1 (diagnostics) integer kpm1 ! index offset, kp-1 (diagnostics) integer lat(pcols) ! latitude indices integer lon(pcols) ! longitude indices #endif ! !---------------------------Statement functions------------------------- ! real(r8) qhalf qhalf(sh1,sh2,shbs1,shbs2) = min(max(sh1,sh2),(shbs2*sh1 + shbs1*sh2)/(shbs1+shbs2)) ! !----------------------------------------------------------------------- !** BAB initialize output tendencies here ! copy q to dq; use dq below for passive tracer transport cmfdt(:ncol,:) = 0._r8 cmfdq(:ncol,:) = 0._r8 dq(:ncol,:,2:) = q(:ncol,:,2:) cmfmc(:ncol,:) = 0._r8 cmfdqr(:ncol,:) = 0._r8 cmfsl(:ncol,:) = 0._r8 cmflq(:ncol,:) = 0._r8 qc(:ncol,:) = 0._r8 rliq(:ncol) = 0._r8 ! #if ( defined DIAGNS ) ! Determine chunk latitudes and longitudes call get_lat_all_p(lchnk, ncol, lat) call get_lon_all_p(lchnk, ncol, lon) #endif ! ! Ensure that characteristic adjustment time scale (cmftau) assumed ! in estimate of eta isn't smaller than model time scale (ztodt) ! The time over which the convection is assumed to act (the adjustment ! time scale) can be applied with each application of the three-level ! cloud model, or applied to the column tendencies after a "hard" ! adjustment (i.e., on a 2-delta t time scale) is evaluated ! if (rlxclm) then cats = ztodt ! relaxation applied to column adjfac = ztodt/(max(ztodt,cmftau)) else cats = max(ztodt,cmftau) ! relaxation applied to triplet adjfac = 1.0_r8 endif rtdt = 1.0_r8/ztodt ! ! Move temperature and moisture into working storage ! do k=limcnv,pver do i=1,ncol tb (i,k) = t(i,k) shb(i,k) = q(i,k,1) end do end do do k=1,pver do i=1,ncol icwmr(i,k) = 0._r8 end do end do ! ! Compute sb,hb,shbs,hbs ! call aqsatd(tb ,pmid ,estemp ,shbs ,gam , & pcols ,ncol ,pver ,limcnv ,pver ) ! do k=limcnv,pver do i=1,ncol sb (i,k) = cp*tb(i,k) + zm(i,k)*grav + phis(i) hb (i,k) = sb(i,k) + hlat*shb(i,k) hbs(i,k) = sb(i,k) + hlat*shbs(i,k) end do end do ! ! Compute sbh, shbh ! do k=limcnv+1,pver do i=1,ncol sbh (i,k) = 0.5_r8*(sb(i,k-1) + sb(i,k)) shbh(i,k) = qhalf(shb(i,k-1),shb(i,k),shbs(i,k-1),shbs(i,k)) hbh (i,k) = sbh(i,k) + hlat*shbh(i,k) end do end do ! ! Specify properties at top of model (not used, but filling anyway) ! do i=1,ncol sbh (i,limcnv) = sb(i,limcnv) shbh(i,limcnv) = shb(i,limcnv) hbh (i,limcnv) = hb(i,limcnv) end do ! ! Zero vertically independent control, tendency & diagnostic arrays ! do i=1,ncol prec(i) = 0.0_r8 dzcld(i) = 0.0_r8 cnb(i) = 0.0_r8 cnt(i) = real(pver+1,r8) end do #if ( defined DIAGNS ) !####################################################################### !# # !# output initial thermodynamic profile if debug diagnostics # !# # do i=1,ncol if ((lat(i).eq.jloc) .and. (lon(i).eq.iloc) & .and. (nstep.ge.nsloc)) then !# # !# approximate vertical integral of moist static energy # !# and total preciptable water # !# # hsum1 = 0.0_r8 qsum1 = 0.0_r8 do k=limcnv,pver hsum1 = hsum1 + pdel(i,k)*rgrav*hb(i,k) qsum1 = qsum1 + pdel(i,k)*rgrav*shb(i,k) end do !# # write(iulog,8010) fac = grav*864._r8 do k=limcnv,pver rh = shb(i,k)/shbs(i,k) write(iulog,8020) shbh(i,k),sbh(i,k),hbh(i,k),fac*cmfmc(i,k),cmfsl(i,k), cmflq(i,k) write(iulog,8040) tb(i,k),shb(i,k),rh,sb(i,k),hb(i,k),hbs(i,k),ztodt*cmfdt(i,k), & ztodt*cmfdq(i,k),ztodt*cmfdqr(i,k) end do write(iulog, 8000) prec(i) end if enddo #endif !# # !# # !####################################################################### ! ! Begin moist convective mass flux adjustment procedure. ! Formalism ensures that negative cloud liquid water can never occur ! do 70 k=pver-1,limcnv+1,-1 do 10 i=1,ncol etagdt(i) = 0.0_r8 eta (i) = 0.0_r8 beta (i) = 0.0_r8 ds1 (i) = 0.0_r8 ds2 (i) = 0.0_r8 ds3 (i) = 0.0_r8 dq1 (i) = 0.0_r8 dq2 (i) = 0.0_r8 dq3 (i) = 0.0_r8 ! ! Specification of "cloud base" conditions ! qprime = 0.0_r8 tprime = 0.0_r8 ! ! Assign tprime within the PBL to be proportional to the quantity ! tpert (which will be bounded by tpmax), passed to this routine by ! the PBL routine. Don't allow perturbation to produce a dry ! adiabatically unstable parcel. Assign qprime within the PBL to be ! an appropriately modified value of the quantity qpert (which will be ! bounded by shpmax) passed to this routine by the PBL routine. The ! quantity qprime should be less than the local saturation value ! (qsattp=qsat[t+tprime,p]). In both cases, tpert and qpert are ! linearly reduced toward zero as the PBL top is approached. ! pblhgt = max(pblht(i),1.0_r8) if ( (zm(i,k+1) <= pblhgt) .and. dzcld(i) == 0.0_r8 ) then fac1 = max(0.0_r8,1.0_r8-zm(i,k+1)/pblhgt) tprime = min(tpert(i),tpmax)*fac1 qsattp = shbs(i,k+1) + cp*rhlat*gam(i,k+1)*tprime shprme = min(min(qpert(i,1),shpmax)*fac1,max(qsattp-shb(i,k+1),0.0_r8)) qprime = max(qprime,shprme) else tprime = 0.0_r8 qprime = 0.0_r8 end if ! ! Specify "updraft" (in-cloud) thermodynamic properties ! sc (i) = sb (i,k+1) + cp*tprime shc(i) = shb(i,k+1) + qprime hc (i) = sc (i ) + hlat*shc(i) vtemp4(i) = hc(i) - hbs(i,k) dz = pdel(i,k)*rgas*tb(i,k)*rgrav/pmid(i,k) if (vtemp4(i) > 0.0_r8) then dzcld(i) = dzcld(i) + dz else dzcld(i) = 0.0_r8 end if 10 continue #if ( defined DIAGNS ) !####################################################################### !# # !# output thermodynamic perturbation information # !# # do i=1,ncol if ((lat(i)==jloc).and.(lon(i)==iloc).and.(nstep>=nsloc)) then write(iulog,8090) k+1,sc(iloc),shc(iloc),hc(iloc) end if enddo !# # !####################################################################### #endif ! ! Check on moist convective instability ! Build index vector of points where instability exists ! len1 = 0 do i=1,ncol if (vtemp4(i) > 0.0_r8) then len1 = len1 + 1 indx1(len1) = i end if end do if (len1 <= 0) go to 70 ! ! Current level just below top level => no overshoot ! if (k <= limcnv+1) then do ii=1,len1 i = indx1(ii) temp1 = vtemp4(i)/(1.0_r8 + gam(i,k)) cldwtr(i) = max(0.0_r8,(sb(i,k) - sc(i) + temp1)) beta(i) = 0.0_r8 vtemp3(i) = (1.0_r8 + gam(i,k))*(sc(i) - sbh(i,k)) end do else ! ! First guess at overshoot parameter using crude buoyancy closure ! 10% overshoot assumed as a minimum and 1-c0*dz maximum to start ! If pre-existing supersaturation in detrainment layer, beta=0 ! cldwtr is temporarily equal to hlat*l (l=> liquid water) ! !cdir nodep !DIR$ CONCURRENT do ii=1,len1 i = indx1(ii) temp1 = vtemp4(i)/(1.0_r8 + gam(i,k)) cldwtr(i) = max(0.0_r8,(sb(i,k)-sc(i)+temp1)) betamx(i) = 1.0_r8 - c0*max(0.0_r8,(dzcld(i)-dzmin)) b1 = (hc(i) - hbs(i,k-1))*pdel(i,k-1) b2 = (hc(i) - hbs(i,k ))*pdel(i,k ) beta(i) = max(betamn,min(betamx(i), 1.0_r8 + b1/b2)) if (hbs(i,k-1) <= hb(i,k-1)) beta(i) = 0.0_r8 ! ! Bound maximum beta to ensure physically realistic solutions ! ! First check constrains beta so that eta remains positive ! (assuming that eta is already positive for beta equal zero) ! vtemp1(i) = -(hbh(i,k+1) - hc(i))*pdel(i,k)*rpdel(i,k+1)+ & (1.0_r8 + gam(i,k))*(sc(i) - sbh(i,k+1) + cldwtr(i)) vtemp2(i) = (1.0_r8 + gam(i,k))*(sc(i) - sbh(i,k)) vtemp3(i) = vtemp2(i) if ((beta(i)*vtemp2(i) - vtemp1(i)) > 0._r8) then betamx(i) = 0.99_r8*(vtemp1(i)/vtemp2(i)) beta(i) = max(0.0_r8,min(betamx(i),beta(i))) end if end do ! ! Second check involves supersaturation of "detrainment layer" ! small amount of supersaturation acceptable (by ssfac factor) ! !cdir nodep !DIR$ CONCURRENT do ii=1,len1 i = indx1(ii) if (hb(i,k-1) < hbs(i,k-1)) then vtemp1(i) = vtemp1(i)*rpdel(i,k) temp2 = gam(i,k-1)*(sbh(i,k) - sc(i) + cldwtr(i)) - & hbh(i,k) + hc(i) - sc(i) + sbh(i,k) temp3 = vtemp3(i)*rpdel(i,k) vtemp2(i) = (ztodt/cats)*(hc(i) - hbs(i,k))*temp2/ & (pdel(i,k-1)*(hbs(i,k-1) - hb(i,k-1))) + temp3 if ((beta(i)*vtemp2(i) - vtemp1(i)) > 0._r8) then betamx(i) = ssfac*(vtemp1(i)/vtemp2(i)) beta(i) = max(0.0_r8,min(betamx(i),beta(i))) end if else beta(i) = 0.0_r8 end if end do ! ! Third check to avoid introducing 2 delta x thermodynamic ! noise in the vertical ... constrain adjusted h (or theta e) ! so that the adjustment doesn't contribute to "kinks" in h ! !cdir nodep !DIR$ CONCURRENT do ii=1,len1 i = indx1(ii) g = min(0.0_r8,hb(i,k) - hb(i,k-1)) temp1 = (hb(i,k) - hb(i,k-1) - g)*(cats/ztodt)/(hc(i) - hbs(i,k)) vtemp1(i) = temp1*vtemp1(i) + (hc(i) - hbh(i,k+1))*rpdel(i,k) vtemp2(i) = temp1*vtemp3(i)*rpdel(i,k) + (hc(i) - hbh(i,k) - cldwtr(i))* & (rpdel(i,k) + rpdel(i,k+1)) if ((beta(i)*vtemp2(i) - vtemp1(i)) > 0._r8) then if (vtemp2(i) /= 0.0_r8) then betamx(i) = vtemp1(i)/vtemp2(i) else betamx(i) = 0.0_r8 end if beta(i) = max(0.0_r8,min(betamx(i),beta(i))) end if end do end if ! ! Calculate mass flux required for stabilization. ! ! Ensure that the convective mass flux, eta, is positive by ! setting negative values of eta to zero.. ! Ensure that estimated mass flux cannot move more than the ! minimum of total mass contained in either layer k or layer k+1. ! Also test for other pathological cases that result in non- ! physical states and adjust eta accordingly. ! !cdir nodep !DIR$ CONCURRENT do ii=1,len1 i = indx1(ii) beta(i) = max(0.0_r8,beta(i)) temp1 = hc(i) - hbs(i,k) temp2 = ((1.0_r8 + gam(i,k))*(sc(i) - sbh(i,k+1) + cldwtr(i)) - & beta(i)*vtemp3(i))*rpdel(i,k) - (hbh(i,k+1) - hc(i))*rpdel(i,k+1) eta(i) = temp1/(temp2*grav*cats) tmass = min(pdel(i,k),pdel(i,k+1))*rgrav if (eta(i) > tmass*rtdt .or. eta(i) <= 0.0_r8) eta(i) = 0.0_r8 ! ! Check on negative q in top layer (bound beta) ! if (shc(i)-shbh(i,k) < 0.0_r8 .and. beta(i)*eta(i) /= 0.0_r8) then denom = eta(i)*grav*ztodt*(shc(i) - shbh(i,k))*rpdel(i,k-1) beta(i) = max(0.0_r8,min(-0.999_r8*shb(i,k-1)/denom,beta(i))) end if ! ! Check on negative q in middle layer (zero eta) ! qtest1 = shb(i,k) + eta(i)*grav*ztodt*((shc(i) - shbh(i,k+1)) - & (1.0_r8 - beta(i))*cldwtr(i)*rhlat - beta(i)*(shc(i) - shbh(i,k)))* & rpdel(i,k) if (qtest1 <= 0.0_r8) eta(i) = 0.0_r8 ! ! Check on negative q in lower layer (bound eta) ! fac1 = -(shbh(i,k+1) - shc(i))*rpdel(i,k+1) qtest2 = shb(i,k+1) - eta(i)*grav*ztodt*fac1 if (qtest2 < 0.0_r8) then eta(i) = 0.99_r8*shb(i,k+1)/(grav*ztodt*fac1) end if etagdt(i) = eta(i)*grav*ztodt end do ! #if ( defined DIAGNS ) !####################################################################### !# # do i=1,ncol if ((lat(i)==jloc).and.(lon(i)==iloc).and.(nstep >= nsloc)) then write(iulog,8080) beta(iloc), eta(iloc) end if enddo !# # !####################################################################### #endif ! ! Calculate cloud water, rain water, and thermodynamic changes ! !cdir nodep !DIR$ CONCURRENT do 30 ii=1,len1 i = indx1(ii) icwmr(i,k) = cldwtr(i)*rhlat cldwtr(i) = etagdt(i)*cldwtr(i)*rhlat*rgrav ! JJH changes to facilitate export of cloud liquid water -------------------------------- totcond(i) = (1.0_r8 - beta(i))*cldwtr(i) rnwtr(i) = min(totcond(i),c0*(dzcld(i)-dzmin)*cldwtr(i)) ds1(i) = etagdt(i)*(sbh(i,k+1) - sc(i))*rpdel(i,k+1) dq1(i) = etagdt(i)*(shbh(i,k+1) - shc(i))*rpdel(i,k+1) ds2(i) = (etagdt(i)*(sc(i) - sbh(i,k+1)) + & hlat*grav*cldwtr(i) - beta(i)*etagdt(i)*(sc(i) - sbh(i,k)))*rpdel(i,k) ! JJH change for export of cloud liquid water; must use total condensate ! since rainwater no longer represents total condensate dq2(i) = (etagdt(i)*(shc(i) - shbh(i,k+1)) - grav*totcond(i) - beta(i)* & etagdt(i)*(shc(i) - shbh(i,k)))*rpdel(i,k) ds3(i) = beta(i)*(etagdt(i)*(sc(i) - sbh(i,k)) - hlat*grav*cldwtr(i))* & rpdel(i,k-1) dq3(i) = beta(i)*etagdt(i)*(shc(i) - shbh(i,k))*rpdel(i,k-1) ! ! Isolate convective fluxes for later diagnostics ! fslkp = eta(i)*(sc(i) - sbh(i,k+1)) fslkm = beta(i)*(eta(i)*(sc(i) - sbh(i,k)) - hlat*cldwtr(i)*rtdt) fqlkp = eta(i)*(shc(i) - shbh(i,k+1)) fqlkm = beta(i)*eta(i)*(shc(i) - shbh(i,k)) ! ! Update thermodynamic profile (update sb, hb, & hbs later) ! tb (i,k+1) = tb(i,k+1) + ds1(i)*rcp tb (i,k ) = tb(i,k ) + ds2(i)*rcp tb (i,k-1) = tb(i,k-1) + ds3(i)*rcp shb(i,k+1) = shb(i,k+1) + dq1(i) shb(i,k ) = shb(i,k ) + dq2(i) shb(i,k-1) = shb(i,k-1) + dq3(i) ! ! ** Update diagnostic information for final budget ** ! Tracking precipitation, temperature & specific humidity tendencies, ! rainout term, convective mass flux, convective liquid ! water static energy flux, and convective total water flux ! The variable afac makes the necessary adjustment to the ! diagnostic fluxes to account for adjustment time scale based on ! how relaxation time scale is to be applied (column vs. triplet) ! prec(i) = prec(i) + (rnwtr(i)/rhoh2o)*adjfac ! ! The following variables have units of "units"/second ! cmfdt (i,k+1) = cmfdt (i,k+1) + ds1(i)*rtdt*adjfac cmfdt (i,k ) = cmfdt (i,k ) + ds2(i)*rtdt*adjfac cmfdt (i,k-1) = cmfdt (i,k-1) + ds3(i)*rtdt*adjfac cmfdq (i,k+1) = cmfdq (i,k+1) + dq1(i)*rtdt*adjfac cmfdq (i,k ) = cmfdq (i,k ) + dq2(i)*rtdt*adjfac cmfdq (i,k-1) = cmfdq (i,k-1) + dq3(i)*rtdt*adjfac ! JJH changes to export cloud liquid water -------------------------------- qc (i,k ) = (grav*(totcond(i)-rnwtr(i))*rpdel(i,k))*rtdt*adjfac cmfdqr(i,k ) = cmfdqr(i,k ) + (grav*rnwtr(i)*rpdel(i,k))*rtdt*adjfac cmfmc (i,k+1) = cmfmc (i,k+1) + eta(i)*adjfac cmfmc (i,k ) = cmfmc (i,k ) + beta(i)*eta(i)*adjfac ! ! The following variables have units of w/m**2 ! cmfsl (i,k+1) = cmfsl (i,k+1) + fslkp*adjfac cmfsl (i,k ) = cmfsl (i,k ) + fslkm*adjfac cmflq (i,k+1) = cmflq (i,k+1) + hlat*fqlkp*adjfac cmflq (i,k ) = cmflq (i,k ) + hlat*fqlkm*adjfac 30 continue ! ! Next, convectively modify passive constituents ! For now, when applying relaxation time scale to thermal fields after ! entire column has undergone convective overturning, constituents will ! be mixed using a "relaxed" value of the mass flux determined above ! Although this will be inconsistant with the treatment of the thermal ! fields, it's computationally much cheaper, no more-or-less justifiable, ! and consistent with how the history tape mass fluxes would be used in ! an off-line mode (i.e., using an off-line transport model) ! do 50 m=2,pcnst ! note: indexing assumes water is first field if (cnst_get_type_byind(m).eq.'dry') then pd(:ncol,:) = pdeldry(:ncol,:) rpd(:ncol,:) = rpdeldry(:ncol,:) pm(:ncol,:) = pmiddry(:ncol,:) else pd(:ncol,:) = pdel(:ncol,:) rpd(:ncol,:) = rpdel(:ncol,:) pm(:ncol,:) = pmid(:ncol,:) endif !cdir nodep !DIR$ CONCURRENT do 40 ii=1,len1 i = indx1(ii) ! ! If any of the reported values of the constituent is negative in ! the three adjacent levels, nothing will be done to the profile ! if ((dq(i,k+1,m) < 0.0_r8) .or. (dq(i,k,m) < 0.0_r8) .or. (dq(i,k-1,m) < 0.0_r8)) go to 40 ! ! Specify constituent interface values (linear interpolation) ! cmrh(i,k ) = 0.5_r8*(dq(i,k-1,m) + dq(i,k ,m)) cmrh(i,k+1) = 0.5_r8*(dq(i,k ,m) + dq(i,k+1,m)) ! ! Specify perturbation properties of constituents in PBL ! pblhgt = max(pblht(i),1.0_r8) if ( (zm(i,k+1) <= pblhgt) .and. dzcld(i) == 0.0_r8 ) then fac1 = max(0.0_r8,1.0_r8-zm(i,k+1)/pblhgt) cmrc(i) = dq(i,k+1,m) + qpert(i,m)*fac1 else cmrc(i) = dq(i,k+1,m) end if ! ! Determine fluxes, flux divergence => changes due to convection ! Logic must be included to avoid producing negative values. A bit ! messy since there are no a priori assumptions about profiles. ! Tendency is modified (reduced) when pending disaster detected. ! botflx = etagdt(i)*(cmrc(i) - cmrh(i,k+1))*adjfac topflx = beta(i)*etagdt(i)*(cmrc(i)-cmrh(i,k))*adjfac dcmr1(i) = -botflx*rpd(i,k+1) efac1 = 1.0_r8 efac2 = 1.0_r8 efac3 = 1.0_r8 ! if (dq(i,k+1,m)+dcmr1(i) < 0.0_r8) then if ( abs(dcmr1(i)) > 1.e-300_r8 ) then efac1 = max(tiny,abs(dq(i,k+1,m)/dcmr1(i)) - eps) else efac1 = tiny endif end if ! if (efac1 == tiny .or. efac1 > 1.0_r8) efac1 = 0.0_r8 dcmr1(i) = -efac1*botflx*rpd(i,k+1) dcmr2(i) = (efac1*botflx - topflx)*rpd(i,k) ! if (dq(i,k,m)+dcmr2(i) < 0.0_r8) then if ( abs(dcmr2(i)) > 1.e-300_r8 ) then efac2 = max(tiny,abs(dq(i,k ,m)/dcmr2(i)) - eps) else efac2 = tiny endif end if ! if (efac2 == tiny .or. efac2 > 1.0_r8) efac2 = 0.0_r8 dcmr2(i) = (efac1*botflx - efac2*topflx)*rpd(i,k) dcmr3(i) = efac2*topflx*rpd(i,k-1) ! if ( (dq(i,k-1,m)+dcmr3(i) < 0.0_r8 ) ) then if ( abs(dcmr3(i)) > 1.e-300_r8 ) then efac3 = max(tiny,abs(dq(i,k-1,m)/dcmr3(i)) - eps) else efac3 = tiny endif end if ! if (efac3 == tiny .or. efac3 > 1.0_r8) efac3 = 0.0_r8 efac3 = min(efac2,efac3) dcmr2(i) = (efac1*botflx - efac3*topflx)*rpd(i,k) dcmr3(i) = efac3*topflx*rpd(i,k-1) ! dq(i,k+1,m) = dq(i,k+1,m) + dcmr1(i) dq(i,k ,m) = dq(i,k ,m) + dcmr2(i) dq(i,k-1,m) = dq(i,k-1,m) + dcmr3(i) 40 continue 50 continue ! end of m=2,pcnst loop ! ! Constituent modifications complete ! if (k == limcnv+1) go to 60 ! ! Complete update of thermodynamic structure at integer levels ! gather/scatter points that need new values of shbs and gamma ! do ii=1,len1 i = indx1(ii) vtemp1(ii ) = tb(i,k) vtemp1(ii+len1) = tb(i,k-1) vtemp2(ii ) = pmid(i,k) vtemp2(ii+len1) = pmid(i,k-1) end do call vqsatd (vtemp1 ,vtemp2 ,estemp ,vtemp3 , vtemp4 , & 2*len1 ) ! using estemp as extra long vector !cdir nodep !DIR$ CONCURRENT do ii=1,len1 i = indx1(ii) shbs(i,k ) = vtemp3(ii ) shbs(i,k-1) = vtemp3(ii+len1) gam(i,k ) = vtemp4(ii ) gam(i,k-1) = vtemp4(ii+len1) sb (i,k ) = sb(i,k ) + ds2(i) sb (i,k-1) = sb(i,k-1) + ds3(i) hb (i,k ) = sb(i,k ) + hlat*shb(i,k ) hb (i,k-1) = sb(i,k-1) + hlat*shb(i,k-1) hbs(i,k ) = sb(i,k ) + hlat*shbs(i,k ) hbs(i,k-1) = sb(i,k-1) + hlat*shbs(i,k-1) end do ! ! Update thermodynamic information at half (i.e., interface) levels ! !DIR$ CONCURRENT do ii=1,len1 i = indx1(ii) sbh (i,k) = 0.5_r8*(sb(i,k) + sb(i,k-1)) shbh(i,k) = qhalf(shb(i,k-1),shb(i,k),shbs(i,k-1),shbs(i,k)) hbh (i,k) = sbh(i,k) + hlat*shbh(i,k) sbh (i,k-1) = 0.5_r8*(sb(i,k-1) + sb(i,k-2)) shbh(i,k-1) = qhalf(shb(i,k-2),shb(i,k-1),shbs(i,k-2),shbs(i,k-1)) hbh (i,k-1) = sbh(i,k-1) + hlat*shbh(i,k-1) end do ! #if ( defined DIAGNS ) !####################################################################### !# # !# this update necessary, only if debugging diagnostics requested # !# # do i=1,ncol if (lat(i) == jloc .and. nstep >= nsloc) then call vqsatd(tb(i,k+1),pmid(i,k+1),es,shbs(i,k+1),gam(i,k+1), & 1) sb (i,k+1) = sb(i,k+1) + ds1(i) hb (i,k+1) = sb(i,k+1) + hlat*shb(i,k+1) hbs(i,k+1) = sb(i,k+1) + hlat*shbs(i,k+1) kpp = k + 2 if (k+1 == pver) kpp = k + 1 do kp=k+1,kpp kpm1 = kp-1 sbh(i,kp) = 0.5_r8*(sb(i,kpm1) + sb(i,kp)) shbh(i,kp) = qhalf(shb(i,kpm1),shb(i,kp),shbs(i,kpm1),shbs(i,kp)) hbh(i,kp) = sbh(i,kp) + hlat*shbh(i,kp) end do end if end do !# # !# diagnostic output # !# # do i=1,ncol if ((lat(i)== jloc).and.(lon(i)==iloc).and.(nstep>=nsloc)) then write(iulog, 8060) k fac = grav*864._r8 do n=limcnv,pver rh = shb(i,n)/shbs(i,n) write(iulog,8020)shbh(i,n),sbh(i,n),hbh(i,n),fac*cmfmc(i,n), & cmfsl(i,n), cmflq(i,n) !--------------write(iulog, 8050) !--------------write(iulog, 8030) fac*cmfmc(i,n),cmfsl(i,n), cmflq(i,n) write(iulog, 8040) tb(i,n),shb(i,n),rh,sb(i,n),hb(i,n), & hbs(i,n), ztodt*cmfdt(i,n),ztodt*cmfdq(i,n), & ztodt*cmfdqr(i,n) end do write(iulog, 8000) prec(i) end if end do !# # !# # !####################################################################### #endif ! ! Ensure that dzcld is reset if convective mass flux zero ! specify the current vertical extent of the convective activity ! top of convective layer determined by size of overshoot param. ! 60 do i=1,ncol etagt0 = eta(i).gt.0.0_r8 if ( .not. etagt0) dzcld(i) = 0.0_r8 if (etagt0 .and. beta(i) > betamn) then ktp = k-1 else ktp = k end if if (etagt0) then rk=k rktp=ktp cnt(i) = min(cnt(i),rktp) cnb(i) = max(cnb(i),rk) end if end do 70 continue ! end of k loop ! ! ** apply final thermodynamic tendencies ** ! !**BAB don't update input profiles !!$ do k=limcnv,pver !!$ do i=1,ncol !!$ t (i,k) = t (i,k) + cmfdt(i,k)*ztodt !!$ q(i,k,1) = q(i,k,1) + cmfdq(i,k)*ztodt !!$ end do !!$ end do ! Set output q tendencies dq(:ncol,:,1 ) = cmfdq(:ncol,:) dq(:ncol,:,2:) = (dq(:ncol,:,2:) - q(:ncol,:,2:))/ztodt ! ! Kludge to prevent cnb-cnt from being zero (in the event ! someone decides that they want to divide by this quantity) ! do i=1,ncol if (cnb(i) /= 0.0_r8 .and. cnb(i) == cnt(i)) then cnt(i) = cnt(i) - 1.0_r8 end if end do ! do i=1,ncol precc(i) = prec(i)*rtdt end do ! ! Compute reserved liquid (not yet in cldliq) for energy integrals. ! Treat rliq as flux out bottom, to be added back later. do k = 1, pver do i = 1, ncol rliq(i) = rliq(i) + qc(i,k)*pdel(i,k)/grav end do end do rliq(:ncol) = rliq(:ncol) /1000._r8 #if ( defined DIAGNS ) !####################################################################### !# # !# we're done ... show final result if debug diagnostics requested # !# # do i=1,ncol if ((lat(i)==jloc).and.(lon(i)==iloc).and.(nstep>=nsloc)) then fac = grav*864._r8 write(iulog, 8010) do k=limcnv,pver rh = shb(i,k)/shbs(i,k) write(iulog, 8020) shbh(i,k),sbh(i,k),hbh(i,k),fac*cmfmc(i,k), & cmfsl(i,k), cmflq(i,k) write(iulog, 8040) tb(i,k),shb(i,k),rh ,sb(i,k),hb(i,k), & hbs(i,k), ztodt*cmfdt(i,k),ztodt*cmfdq(i,k), & ztodt*cmfdqr(i,k) end do write(iulog, 8000) prec(i) !# # !# approximate vertical integral of moist static energy and # !# total preciptable water after adjustment and output changes # !# # hsum2 = 0.0_r8 qsum2 = 0.0_r8 do k=limcnv,pver hsum2 = hsum2 + pdel(i,k)*rgrav*hb(i,k) qsum2 = qsum2 + pdel(i,k)*rgrav*shb(i,k) end do !# # write(iulog,8070) hsum1, hsum2, abs(hsum2-hsum1)/hsum2, & qsum1, qsum2, abs(qsum2-qsum1)/qsum2 end if enddo !# # !# # !####################################################################### #endif return ! we're all done ... return to calling procedure #if ( defined DIAGNS ) ! ! Formats ! 8000 format(///,10x,'PREC = ',3pf12.6,/) 8010 format('1** TB SHB RH SB', & ' HB HBS CAH CAM PRECC ', & ' ETA FSL FLQ **', /) 8020 format(' ----- ', 9x,3p,f7.3,2x,2p, 9x,-3p,f7.3,2x, & f7.3, 37x, 0p,2x,f8.2, 0p,2x,f8.2,2x,f8.2, ' ----- ') 8030 format(' ----- ', 0p,82x,f8.2, 0p,2x,f8.2,2x,f8.2, & ' ----- ') 8040 format(' - - - ',f7.3,2x,3p,f7.3,2x,2p,f7.3,2x,-3p,f7.3,2x, & f7.3, 2x,f8.3,2x,0p,f7.3,3p,2x,f7.3,2x,f7.3,30x, & ' - - - ') 8050 format(' ----- ',110x,' ----- ') 8060 format('1 K =>', i4,/, & ' TB SHB RH SB', & ' HB HBS CAH CAM PREC ', & ' ETA FSL FLQ', /) 8070 format(' VERTICALLY INTEGRATED MOIST STATIC ENERGY BEFORE, AFTER', & ' AND PERCENTAGE DIFFERENCE => ',1p,2e15.7,2x,2p,f7.3,/, & ' VERTICALLY INTEGRATED MOISTURE BEFORE, AFTER' &, ' AND PERCENTAGE DIFFERENCE => ',1p,2e15_r8.7_r8,2x,2p,f7.3,/) 8080 format(' BETA, ETA => ', 1p,2e12.3) 8090 format (' k+1, sc, shc, hc => ', 1x, i2, 1p, 3e12.4) #endif ! end subroutine cmfmca end module hk_conv