LCOV - code coverage report
Current view: top level - physics/cam - cloud_fraction.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 68 208 32.7 %
Date: 2025-03-14 01:23:43 Functions: 4 5 80.0 %

          Line data    Source code
       1             : module cloud_fraction
       2             : 
       3             :   ! Cloud fraction parameterization.
       4             : 
       5             : 
       6             :   use shr_kind_mod,   only: r8 => shr_kind_r8
       7             :   use ppgrid,         only: pcols, pver, pverp
       8             :   use ref_pres,       only: pref_mid
       9             :   use spmd_utils,     only: masterproc
      10             :   use cam_logfile,    only: iulog
      11             :   use cam_abortutils, only: endrun
      12             :   use ref_pres,       only: trop_cloud_top_lev
      13             : 
      14             :   implicit none
      15             :   private
      16             :   save
      17             : 
      18             :   ! Public interfaces
      19             :   public &
      20             :      cldfrc_readnl,    &! read cldfrc_nl namelist
      21             :      cldfrc_register,  &! add fields to pbuf
      22             :      cldfrc_init,      &! Inititialization of cloud_fraction run-time parameters
      23             :      cldfrc_getparams, &! public access of tuning parameters
      24             :      cldfrc,           &! Computation of cloud fraction
      25             :      dp1,              &! parameter for deep convection cloud fraction needed in clubb_intr
      26             :      dp2               ! parameter for deep convection cloud fraction needed in clubb_intr
      27             : 
      28             :   ! Private data
      29             :   real(r8), parameter :: unset_r8 = huge(1.0_r8)
      30             : 
      31             :   ! Top level
      32             :   integer :: top_lev = 1
      33             : 
      34             :   ! Physics buffer indices
      35             :   integer :: sh_frac_idx   = 0
      36             :   integer :: dp_frac_idx   = 0
      37             : 
      38             :   ! Namelist variables
      39             :   logical  :: cldfrc_freeze_dry           ! switch for Vavrus correction
      40             :   logical  :: cldfrc_ice                  ! switch to compute ice cloud fraction
      41             :   real(r8) :: cldfrc_rhminl = unset_r8    ! minimum rh for low stable clouds
      42             :   real(r8) :: cldfrc_rhminl_adj_land = unset_r8   ! rhminl adjustment for snowfree land
      43             :   real(r8) :: cldfrc_rhminh = unset_r8    ! minimum rh for high stable clouds
      44             :   real(r8) :: cldfrc_sh1    = unset_r8    ! parameter for shallow convection cloud fraction
      45             :   real(r8) :: cldfrc_sh2    = unset_r8    ! parameter for shallow convection cloud fraction
      46             :   real(r8) :: cldfrc_dp1    = unset_r8    ! parameter for deep convection cloud fraction
      47             :   real(r8) :: cldfrc_dp2    = unset_r8    ! parameter for deep convection cloud fraction
      48             :   real(r8) :: cldfrc_premit = unset_r8    ! top pressure bound for mid level cloud
      49             :   real(r8) :: cldfrc_premib  = unset_r8   ! bottom pressure bound for mid level cloud
      50             :   integer  :: cldfrc_iceopt               ! option for ice cloud closure
      51             :                                           ! 1=wang & sassen 2=schiller (iciwc)
      52             :                                           ! 3=wood & field, 4=Wilson (based on smith)
      53             :   real(r8) :: cldfrc_icecrit = unset_r8   ! Critical RH for ice clouds in Wilson & Ballard closure (smaller = more ice clouds)
      54             : 
      55             :   real(r8) :: rhminl             ! set from namelist input cldfrc_rhminl
      56             :   real(r8) :: rhminl_adj_land    ! set from namelist input cldfrc_rhminl_adj_land
      57             :   real(r8) :: rhminh             ! set from namelist input cldfrc_rhminh
      58             :   real(r8) :: sh1, sh2           ! set from namelist input cldfrc_sh1, cldfrc_sh2
      59             :   real(r8) :: dp1,dp2            ! set from namelist input cldfrc_dp1, cldfrc_dp2
      60             :   real(r8) :: premit             ! set from namelist input cldfrc_premit
      61             :   real(r8) :: premib             ! set from namelist input cldfrc_premib
      62             :   integer  :: iceopt             ! set from namelist input cldfrc_iceopt
      63             :   real(r8) :: icecrit            ! set from namelist input cldfrc_icecrit
      64             : 
      65             :   ! constants
      66             :   real(r8), parameter :: pnot = 1.e5_r8         ! reference pressure
      67             :   real(r8), parameter :: lapse = 6.5e-3_r8      ! U.S. Standard Atmosphere lapse rate
      68             :   real(r8), parameter :: pretop = 1.0e2_r8      ! pressure bounding high cloud
      69             : 
      70             :   integer count
      71             : 
      72             :   logical :: inversion_cld_off    ! Turns off stratification-based cld frc
      73             : 
      74             :   integer :: k700   ! model level nearest 700 mb
      75             : 
      76             : !================================================================================================
      77             :   contains
      78             : !================================================================================================
      79             : 
      80        1536 : subroutine cldfrc_readnl(nlfile)
      81             : 
      82             :    use namelist_utils,  only: find_group_name
      83             :    use units,           only: getunit, freeunit
      84             :    use mpishorthand
      85             : 
      86             :    character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
      87             : 
      88             :    ! Local variables
      89             :    integer :: unitn, ierr
      90             :    character(len=*), parameter :: subname = 'cldfrc_readnl'
      91             : 
      92             :    namelist /cldfrc_nl/ cldfrc_freeze_dry,      cldfrc_ice,    cldfrc_rhminl, &
      93             :                         cldfrc_rhminl_adj_land, cldfrc_rhminh, cldfrc_sh1,    &
      94             :                         cldfrc_sh2,             cldfrc_dp1,    cldfrc_dp2,    &
      95             :                         cldfrc_premit,          cldfrc_premib, cldfrc_iceopt, &
      96             :                         cldfrc_icecrit
      97             :    !-----------------------------------------------------------------------------
      98             : 
      99        1536 :    if (masterproc) then
     100           2 :       unitn = getunit()
     101           2 :       open( unitn, file=trim(nlfile), status='old' )
     102           2 :       call find_group_name(unitn, 'cldfrc_nl', status=ierr)
     103           2 :       if (ierr == 0) then
     104           2 :          read(unitn, cldfrc_nl, iostat=ierr)
     105           2 :          if (ierr /= 0) then
     106           0 :             call endrun(subname // ':: ERROR reading namelist')
     107             :          end if
     108             :       end if
     109           2 :       close(unitn)
     110           2 :       call freeunit(unitn)
     111             : 
     112             :       ! set local variables
     113           2 :       rhminl = cldfrc_rhminl
     114           2 :       rhminl_adj_land = cldfrc_rhminl_adj_land
     115           2 :       rhminh = cldfrc_rhminh
     116           2 :       sh1    = cldfrc_sh1
     117           2 :       sh2    = cldfrc_sh2
     118           2 :       dp1    = cldfrc_dp1
     119           2 :       dp2    = cldfrc_dp2
     120           2 :       premit = cldfrc_premit
     121           2 :       premib  = cldfrc_premib
     122           2 :       iceopt  = cldfrc_iceopt
     123           2 :       icecrit = cldfrc_icecrit
     124             : 
     125             :    end if
     126             : 
     127             : #ifdef SPMD
     128             :    ! Broadcast namelist variables
     129        1536 :    call mpibcast(cldfrc_freeze_dry, 1, mpilog, 0, mpicom)
     130        1536 :    call mpibcast(cldfrc_ice,        1, mpilog, 0, mpicom)
     131        1536 :    call mpibcast(rhminl,            1, mpir8,  0, mpicom)
     132        1536 :    call mpibcast(rhminl_adj_land,   1, mpir8,  0, mpicom)
     133        1536 :    call mpibcast(rhminh,            1, mpir8,  0, mpicom)
     134        1536 :    call mpibcast(sh1   ,            1, mpir8,  0, mpicom)
     135        1536 :    call mpibcast(sh2   ,            1, mpir8,  0, mpicom)
     136        1536 :    call mpibcast(dp1   ,            1, mpir8,  0, mpicom)
     137        1536 :    call mpibcast(dp2   ,            1, mpir8,  0, mpicom)
     138        1536 :    call mpibcast(premit,            1, mpir8,  0, mpicom)
     139        1536 :    call mpibcast(premib,            1, mpir8,  0, mpicom)
     140        1536 :    call mpibcast(iceopt,            1, mpiint, 0, mpicom)
     141        1536 :    call mpibcast(icecrit,           1, mpir8,  0, mpicom)
     142             : #endif
     143             : 
     144        1536 : end subroutine cldfrc_readnl
     145             : 
     146             : !================================================================================================
     147             : 
     148        1536 : subroutine cldfrc_register
     149             : 
     150             :    ! Register fields in the physics buffer.
     151             : 
     152             :    use physics_buffer, only : pbuf_add_field, dtype_r8
     153             : 
     154             :    !-----------------------------------------------------------------------
     155             : 
     156        1536 :    call pbuf_add_field('SH_FRAC', 'physpkg', dtype_r8, (/pcols,pver/), sh_frac_idx)
     157        1536 :    call pbuf_add_field('DP_FRAC', 'physpkg', dtype_r8, (/pcols,pver/), dp_frac_idx)
     158             : 
     159        1536 : end subroutine cldfrc_register
     160             : 
     161             : !================================================================================================
     162             : 
     163        1536 : subroutine cldfrc_getparams(rhminl_out, rhminl_adj_land_out, rhminh_out,  premit_out, &
     164             :                             premib_out, iceopt_out,          icecrit_out)
     165             : !-----------------------------------------------------------------------
     166             : ! Purpose: Return cldfrc tuning parameters
     167             : !-----------------------------------------------------------------------
     168             : 
     169             :    real(r8),          intent(out), optional :: rhminl_out
     170             :    real(r8),          intent(out), optional :: rhminl_adj_land_out
     171             :    real(r8),          intent(out), optional :: rhminh_out
     172             :    real(r8),          intent(out), optional :: premit_out
     173             :    real(r8),          intent(out), optional :: premib_out
     174             :    integer,           intent(out), optional :: iceopt_out
     175             :    real(r8),          intent(out), optional :: icecrit_out
     176             : 
     177        1536 :    if ( present(rhminl_out) )      rhminl_out = rhminl
     178        1536 :    if ( present(rhminl_adj_land_out) ) rhminl_adj_land_out = rhminl_adj_land
     179        1536 :    if ( present(rhminh_out) )      rhminh_out = rhminh
     180        1536 :    if ( present(premit_out) )      premit_out = premit
     181        1536 :    if ( present(premib_out) )      premib_out  = premib
     182        1536 :    if ( present(iceopt_out) )      iceopt_out  = iceopt
     183        1536 :    if ( present(icecrit_out) )     icecrit_out = icecrit
     184             : 
     185        1536 : end subroutine cldfrc_getparams
     186             : 
     187             : !===============================================================================
     188             : 
     189        1536 : subroutine cldfrc_init
     190             : 
     191             :    ! Initialize cloud fraction run-time parameters
     192             : 
     193             :    use cam_history,   only:  addfld
     194             :    use phys_control,  only:  phys_getopts
     195             : 
     196             :    ! query interfaces for scheme settings
     197             :    character(len=16) :: shallow_scheme, eddy_scheme, macrop_scheme
     198             : 
     199             :    integer :: k
     200             :    !-----------------------------------------------------------------------------
     201             : 
     202             :    call phys_getopts(shallow_scheme_out = shallow_scheme ,&
     203             :                      eddy_scheme_out    = eddy_scheme    ,&
     204        1536 :                      macrop_scheme_out  = macrop_scheme  )
     205             : 
     206             :    ! Limit CAM5 cloud physics to below top cloud level.
     207        1536 :    if ( .not. macrop_scheme == "rk") top_lev = trop_cloud_top_lev
     208             : 
     209             :    ! Turn off inversion_cld if any UW PBL scheme is being used
     210        1536 :    if ( eddy_scheme .eq. 'diag_TKE'  .or.  shallow_scheme .eq. 'UW' ) then
     211           0 :       inversion_cld_off = .true.
     212             :    else
     213        1536 :       inversion_cld_off = .false.
     214             :    endif
     215             : 
     216        1536 :    if ( masterproc ) then
     217           2 :       write(iulog,*)'tuning parameters cldfrc_init: inversion_cld_off',inversion_cld_off
     218           2 :       write(iulog,*)'tuning parameters cldfrc_init: dp1',dp1,'dp2',dp2,'sh1',sh1,'sh2',sh2
     219           2 :       if (shallow_scheme .ne. 'UW') then
     220           2 :          write(iulog,*)'tuning parameters cldfrc_init: rhminl',rhminl,'rhminl_adj_land',rhminl_adj_land, &
     221           4 :                        'rhminh',rhminh,'premit',premit,'premib',premib
     222           2 :          write(iulog,*)'tuning parameters cldfrc_init: iceopt',iceopt,'icecrit',icecrit
     223             :       endif
     224             :    endif
     225             : 
     226        1536 :    if (pref_mid(top_lev) > 7.e4_r8) &
     227           0 :         call endrun ('cldfrc_init: model levels bracketing 700 mb not found')
     228             : 
     229             :    ! Find vertical level nearest 700 mb.
     230       67584 :    k700 = minloc(abs(pref_mid(top_lev:pver) - 7.e4_r8), 1)
     231             : 
     232        1536 :    if (masterproc) then
     233           2 :       write(iulog,*)'cldfrc_init: model level nearest 700 mb is',k700,'which is',pref_mid(k700),'pascals'
     234             :    end if
     235             : 
     236        3072 :    call addfld ('SH_CLD', (/ 'lev' /), 'A', 'fraction', 'Shallow convective cloud cover' )
     237        3072 :    call addfld ('DP_CLD', (/ 'lev' /), 'A', 'fraction', 'Deep convective cloud cover'    )
     238             : 
     239        1536 : end subroutine cldfrc_init
     240             : 
     241             : !===============================================================================
     242             : 
     243           0 : subroutine cldfrc(lchnk   ,ncol    , pbuf,  &
     244             :        pmid    ,temp    ,q       ,omga    , phis, &
     245             :        shfrc   ,use_shfrc, &
     246             :        cloud   ,rhcloud, clc     ,pdel    , &
     247             :        cmfmc   ,cmfmc2  ,landfrac,snowh   ,concld  ,cldst   , &
     248             :        ts      ,sst     ,ps      ,zdu     ,ocnfrac ,&
     249             :        rhu00   ,cldice  ,icecldf ,liqcldf ,relhum  ,dindex )
     250             :     !-----------------------------------------------------------------------
     251             :     !
     252             :     ! Purpose:
     253             :     ! Compute cloud fraction
     254             :     !
     255             :     !
     256             :     ! Method:
     257             :     ! This calculate cloud fraction using a relative humidity threshold
     258             :     ! The threshold depends upon pressure, and upon the presence or absence
     259             :     ! of convection as defined by a reasonably large vertical mass flux
     260             :     ! entering that layer from below.
     261             :     !
     262             :     ! Author: Many. Last modified by Jim McCaa
     263             :     !
     264             :     !-----------------------------------------------------------------------
     265        1536 :     use cam_history,   only: outfld
     266             :     use physconst,     only: cappa, gravit, rair, tmelt
     267             :     use wv_saturation, only: qsat, qsat_water, svp_ice_vect
     268             :     use phys_grid,     only: get_rlat_all_p, get_rlon_all_p
     269             : 
     270             : 
     271             : !RBN - Need this to write shallow,deep fraction to phys buffer.
     272             : !PJR - we should probably make seperate modules for determining convective
     273             : !      clouds and make this one just responsible for relative humidity clouds
     274             : 
     275             :     use physics_buffer, only: physics_buffer_desc, pbuf_get_field
     276             : 
     277             :     ! Arguments
     278             :     integer, intent(in) :: lchnk                  ! chunk identifier
     279             :     integer, intent(in) :: ncol                   ! number of atmospheric columns
     280             :     integer, intent(in) :: dindex                 ! 0 or 1 to perturb rh
     281             : 
     282             :     type(physics_buffer_desc), pointer :: pbuf(:)
     283             :     real(r8), intent(in) :: pmid(pcols,pver)      ! midpoint pressures
     284             :     real(r8), intent(in) :: temp(pcols,pver)      ! temperature
     285             :     real(r8), intent(in) :: q(pcols,pver)         ! specific humidity
     286             :     real(r8), intent(in) :: omga(pcols,pver)      ! vertical pressure velocity
     287             :     real(r8), intent(in) :: cmfmc(pcols,pverp)    ! convective mass flux--m sub c
     288             :     real(r8), intent(in) :: cmfmc2(pcols,pverp)   ! shallow convective mass flux--m sub c
     289             :     real(r8), intent(in) :: snowh(pcols)          ! snow depth (liquid water equivalent)
     290             :     real(r8), intent(in) :: pdel(pcols,pver)      ! pressure depth of layer
     291             :     real(r8), intent(in) :: landfrac(pcols)       ! Land fraction
     292             :     real(r8), intent(in) :: ocnfrac(pcols)        ! Ocean fraction
     293             :     real(r8), intent(in) :: ts(pcols)             ! surface temperature
     294             :     real(r8), intent(in) :: sst(pcols)            ! sea surface temperature
     295             :     real(r8), intent(in) :: ps(pcols)             ! surface pressure
     296             :     real(r8), intent(in) :: zdu(pcols,pver)       ! detrainment rate from deep convection
     297             :     real(r8), intent(in) :: phis(pcols)           ! surface geopotential
     298             :     real(r8), intent(in) :: shfrc(pcols,pver)     ! cloud fraction from convect_shallow
     299             :     real(r8), intent(in) :: cldice(pcols,pver)    ! cloud ice mixing ratio
     300             :     logical,  intent(in)  :: use_shfrc
     301             : 
     302             :     ! Output arguments
     303             :     real(r8), intent(out) :: cloud(pcols,pver)     ! cloud fraction
     304             :     real(r8), intent(out) :: rhcloud(pcols,pver)   ! cloud fraction
     305             :     real(r8), intent(out) :: clc(pcols)            ! column convective cloud amount
     306             :     real(r8), intent(out) :: cldst(pcols,pver)     ! cloud fraction
     307             :     real(r8), intent(out) :: rhu00(pcols,pver)     ! RH threshold for cloud
     308             :     real(r8), intent(out) :: relhum(pcols,pver)    ! RH
     309             :     real(r8), intent(out) :: icecldf(pcols,pver)   ! ice cloud fraction
     310             :     real(r8), intent(out) :: liqcldf(pcols,pver)   ! liquid cloud fraction (combined into cloud)
     311             : 
     312             :     !---------------------------Local workspace-----------------------------
     313             :     !
     314             :     real(r8) concld(pcols,pver)    ! convective cloud cover
     315             :     real(r8) cld                   ! intermediate scratch variable (low cld)
     316             :     real(r8) dthdpmn(pcols)         ! most stable lapse rate below 750 mb
     317             :     real(r8) dthdp                 ! lapse rate (intermediate variable)
     318             :     real(r8) es(pcols,pver)        ! saturation vapor pressure
     319             :     real(r8) qs(pcols,pver)        ! saturation specific humidity
     320             :     real(r8) rhwght                ! weighting function for rhlim transition
     321             :     real(r8) rh(pcols,pver)        ! relative humidity
     322             :     real(r8) rhdif                 ! intermediate scratch variable
     323             :     real(r8) strat                 ! intermediate scratch variable
     324             :     real(r8) theta(pcols,pver)     ! potential temperature
     325             :     real(r8) rhlim                 ! local rel. humidity threshold estimate
     326             :     real(r8) coef1                 ! coefficient to convert mass flux to mb/d
     327             :     real(r8) clrsky(pcols)         ! temporary used in random overlap calc
     328             :     real(r8) rpdeli(pcols,pver-1) ! 1./(pmid(k+1)-pmid(k))
     329             :     real(r8) rhpert                !the specified perturbation to rh
     330             : 
     331           0 :     real(r8), pointer, dimension(:,:) :: deepcu      ! deep convection cloud fraction
     332           0 :     real(r8), pointer, dimension(:,:) :: shallowcu   ! shallow convection cloud fraction
     333             : 
     334             :     logical cldbnd(pcols)          ! region below high cloud boundary
     335             : 
     336             :     integer i, ierror, k           ! column, level indices
     337             :     integer kp1, ifld
     338             :     integer kdthdp(pcols)
     339             :     integer numkcld                ! number of levels in which to allow clouds
     340             : 
     341             :     !  In Cloud Ice Content variables
     342             :     real(r8) :: a,b,c,as,bs,cs        !fit parameters
     343             :     real(r8) :: Kc                    !constant for ice cloud calc (wood & field)
     344             :     real(r8) :: ttmp                  !limited temperature
     345             :     real(r8) :: icicval               !empirical iwc value
     346             :     real(r8) :: rho                   !local air density
     347             :     real(r8) :: esl(pcols,pver)       !liq sat vapor pressure
     348             :     real(r8) :: esi(pcols,pver)       !ice sat vapor pressure
     349             :     real(r8) :: ncf,phi               !Wilson and Ballard parameters
     350             : 
     351             :     real(r8) thetas(pcols)                    ! ocean surface potential temperature
     352             :     real(r8) :: clat(pcols)                   ! current latitudes(radians)
     353             :     real(r8) :: clon(pcols)                   ! current longitudes(radians)
     354             : 
     355             :     ! Statement functions
     356             :     logical land
     357             :     land(i) = nint(landfrac(i)) == 1
     358             : 
     359           0 :     call get_rlat_all_p(lchnk, ncol, clat)
     360           0 :     call get_rlon_all_p(lchnk, ncol, clon)
     361             : 
     362           0 :     call pbuf_get_field(pbuf, sh_frac_idx, shallowcu )
     363           0 :     call pbuf_get_field(pbuf, dp_frac_idx, deepcu )
     364             : 
     365             :     ! Initialise cloud fraction
     366           0 :     shallowcu = 0._r8
     367           0 :     deepcu    = 0._r8
     368             : 
     369             :     !==================================================================================
     370             :     ! PHILOSOPHY OF PRESENT IMPLEMENTATION
     371             :     ! Modification to philosophy for ice supersaturation
     372             :     ! philosophy below is based on RH water only. This is 'liquid condensation'
     373             :     ! or liquid cloud (even though it will freeze immediately to ice)
     374             :     ! The idea is that the RH limits for condensation are strict only for
     375             :     ! water saturation
     376             :     !
     377             :     ! Ice clouds are formed by explicit parameterization of ice nucleation.
     378             :     ! Closure for ice cloud fraction is done on available cloud ice, such that
     379             :     ! the in-cloud ice content matches an empirical fit
     380             :     ! thus, icecldf = min(cldice/icicval,1) where icicval = f(temp,cldice,numice)
     381             :     ! for a first cut, icicval=f(temp) only.
     382             :     ! Combined cloud fraction is maximum overlap  cloud=max(1,max(icecldf,liqcldf))
     383             :     ! No dA/dt term for ice?
     384             :     !
     385             :     ! There are three co-existing cloud types: convective, inversion related low-level
     386             :     ! stratocumulus, and layered cloud (based on relative humidity).  Layered and
     387             :     ! stratocumulus clouds do not compete with convective cloud for which one creates
     388             :     ! the most cloud.  They contribute collectively to the total grid-box average cloud
     389             :     ! amount.  This is reflected in the way in which the total cloud amount is evaluated
     390             :     ! (a sum as opposed to a logical "or" operation)
     391             :     !
     392             :     !==================================================================================
     393             :     ! set defaults for rhu00
     394           0 :     rhu00(:,:) = 2.0_r8
     395             :     ! define rh perturbation in order to estimate rhdfda
     396           0 :     rhpert = 0.01_r8
     397             : 
     398             :     !set Wang and Sassen IWC paramters
     399           0 :     a=26.87_r8
     400           0 :     b=0.569_r8
     401           0 :     c=0.002892_r8
     402             :     !set schiller parameters
     403           0 :     as=-68.4202_r8
     404           0 :     bs=0.983917_r8
     405           0 :     cs=2.81795_r8
     406             :     !set wood and field paramters...
     407           0 :     Kc=75._r8
     408             : 
     409             :     ! Evaluate potential temperature and relative humidity
     410             :     ! If not computing ice cloud fraction then hybrid RH, if MG then water RH
     411           0 :     if ( cldfrc_ice ) then
     412           0 :        do k = top_lev,pver
     413           0 :           call qsat_water(temp(1:ncol,k), pmid(1:ncol,k), esl(1:ncol,k), qs(1:ncol,k), ncol)
     414           0 :           call svp_ice_vect(temp(1:ncol,k), esi(1:ncol,k), ncol)
     415             :        end do
     416             :     else
     417           0 :        do k = top_lev,pver
     418           0 :           call qsat(temp(1:ncol,k), pmid(1:ncol,k), es(1:ncol,k), qs(1:ncol,k), ncol)
     419             :        end do
     420             :     end if
     421             : 
     422           0 :     cloud    = 0._r8
     423           0 :     icecldf  = 0._r8
     424           0 :     liqcldf  = 0._r8
     425           0 :     rhcloud  = 0._r8
     426           0 :     cldst    = 0._r8
     427           0 :     concld   = 0._r8
     428             : 
     429           0 :     do k=top_lev,pver
     430           0 :        theta(:ncol,k)    = temp(:ncol,k)*(pnot/pmid(:ncol,k))**cappa
     431             : 
     432           0 :        do i=1,ncol
     433           0 :           rh(i,k)     = q(i,k)/qs(i,k)*(1.0_r8+real(dindex,r8)*rhpert)
     434             :           !  record relhum, rh itself will later be modified related with concld
     435           0 :           relhum(i,k) = rh(i,k)
     436             :        end do
     437             :     end do
     438             : 
     439             :     ! Initialize other temporary variables
     440           0 :     ierror = 0
     441           0 :     do i=1,ncol
     442             :        ! Adjust thetas(i) in the presence of non-zero ocean heights.
     443             :        ! This reduces the temperature for positive heights according to a standard lapse rate.
     444           0 :        if(ocnfrac(i).gt.0.01_r8) thetas(i)  = &
     445           0 :             ( sst(i) - lapse * phis(i) / gravit) * (pnot/ps(i))**cappa
     446           0 :        if(ocnfrac(i).gt.0.01_r8.and.sst(i).lt.260._r8) ierror = i
     447           0 :        clc(i) = 0.0_r8
     448             :     end do
     449           0 :     coef1 = gravit*864.0_r8    ! conversion to millibars/day
     450             : 
     451           0 :     if (ierror > 0) then
     452           0 :        write(iulog,*) 'COLDSST: encountered in cldfrc:', lchnk,ierror,ocnfrac(ierror),sst(ierror)
     453             :     endif
     454             : 
     455           0 :     do k=top_lev,pver-1
     456           0 :        rpdeli(:ncol,k) = 1._r8/(pmid(:ncol,k+1) - pmid(:ncol,k))
     457             :     end do
     458             : 
     459             :     !
     460             :     ! Estimate of local convective cloud cover based on convective mass flux
     461             :     ! Modify local large-scale relative humidity to account for presence of
     462             :     ! convective cloud when evaluating relative humidity based layered cloud amount
     463             :     !
     464           0 :     concld(:ncol,top_lev:pver) = 0.0_r8
     465             :     !
     466             :     ! cloud mass flux in SI units of kg/m2/s; should produce typical numbers of 20%
     467             :     ! shallow and deep convective cloudiness are evaluated separately (since processes
     468             :     ! are evaluated separately) and summed
     469             :     !
     470             : #ifndef PERGRO
     471           0 :     do k=top_lev,pver
     472           0 :        do i=1,ncol
     473           0 :           if ( .not. use_shfrc ) then
     474           0 :              shallowcu(i,k) = max(0.0_r8,min(sh1*log(1.0_r8+sh2*cmfmc2(i,k+1)),0.30_r8))
     475             :           else
     476           0 :              shallowcu(i,k) = shfrc(i,k)
     477             :           endif
     478           0 :           deepcu(i,k) = max(0.0_r8,min(dp1*log(1.0_r8+dp2*(cmfmc(i,k+1)-cmfmc2(i,k+1))),0.60_r8))
     479           0 :           concld(i,k) = min(shallowcu(i,k) + deepcu(i,k),0.80_r8)
     480           0 :           rh(i,k) = (rh(i,k) - concld(i,k))/(1.0_r8 - concld(i,k))
     481             :        end do
     482             :     end do
     483             : #endif
     484             :     !==================================================================================
     485             :     !
     486             :     !          ****** Compute layer cloudiness ******
     487             :     !
     488             :     !====================================================================
     489             :     ! Begin the evaluation of layered cloud amount based on (modified) RH
     490             :     !====================================================================
     491             :     !
     492           0 :     numkcld = pver
     493           0 :     do k=top_lev+1,numkcld
     494           0 :        kp1 = min(k + 1,pver)
     495           0 :        do i=1,ncol
     496             : 
     497             :           ! This is now designed to apply FOR LIQUID CLOUDS (condensation > RH water)
     498             : 
     499           0 :           cldbnd(i) = pmid(i,k).ge.pretop
     500             : 
     501           0 :           if ( pmid(i,k).ge.premib ) then
     502             :              !==============================================================
     503             :              ! This is the low cloud (below premib) block
     504             :              !==============================================================
     505             :              ! enhance low cloud activation over land with no snow cover
     506           0 :              if (land(i) .and. (snowh(i) <= 0.000001_r8)) then
     507           0 :                 rhlim = rhminl - rhminl_adj_land
     508             :              else
     509           0 :                 rhlim = rhminl
     510             :              endif
     511             : 
     512           0 :              rhdif = (rh(i,k) - rhlim)/(1.0_r8-rhlim)
     513           0 :              rhcloud(i,k) = min(0.999_r8,(max(rhdif,0.0_r8))**2)
     514             : 
     515             :              ! SJV: decrease cloud amount if very low water vapor content
     516             :              ! (thus very cold): "freeze dry"
     517           0 :              if (cldfrc_freeze_dry) then
     518           0 :                 rhcloud(i,k) = rhcloud(i,k)*max(0.15_r8,min(1.0_r8,q(i,k)/0.0030_r8))
     519             :              endif
     520             : 
     521           0 :           else if ( pmid(i,k).lt.premit ) then
     522             :              !==============================================================
     523             :              ! This is the high cloud (above premit) block
     524             :              !==============================================================
     525             :              !
     526           0 :              rhlim = rhminh
     527             :              !
     528           0 :              rhdif = (rh(i,k) - rhlim)/(1.0_r8-rhlim)
     529           0 :              rhcloud(i,k) = min(0.999_r8,(max(rhdif,0.0_r8))**2)
     530             :           else
     531             :              !==============================================================
     532             :              ! This is the middle cloud block
     533             :              !==============================================================
     534             :              !
     535             :              !       linear rh threshold transition between thresholds for low & high cloud
     536             :              !
     537           0 :              rhwght = (premib-(max(pmid(i,k),premit)))/(premib-premit)
     538             : 
     539           0 :              if (land(i) .and. (snowh(i) <= 0.000001_r8)) then
     540           0 :                 rhlim = rhminh*rhwght + (rhminl - rhminl_adj_land)*(1.0_r8-rhwght)
     541             :              else
     542           0 :                 rhlim = rhminh*rhwght + rhminl*(1.0_r8-rhwght)
     543             :              endif
     544           0 :              rhdif = (rh(i,k) - rhlim)/(1.0_r8-rhlim)
     545           0 :              rhcloud(i,k) = min(0.999_r8,(max(rhdif,0.0_r8))**2)
     546             :           end if
     547             :           !==================================================================================
     548             :           ! WE NEED TO DOCUMENT THE PURPOSE OF THIS TYPE OF CODE (ASSOCIATED WITH 2ND CALL)
     549             :           !==================================================================================
     550             :           !      !
     551             :           !      ! save rhlim to rhu00, it handles well by itself for low/high cloud
     552             :           !      !
     553           0 :           rhu00(i,k)=rhlim
     554             :           !==================================================================================
     555             : 
     556           0 :           if (cldfrc_ice) then
     557             : 
     558             :              ! Evaluate ice cloud fraction based on in-cloud ice content
     559             : 
     560             :              !--------ICE CLOUD OPTION 1--------Wang & Sassen 2002
     561             :              !         Evaluate desired in-cloud water content
     562             :              !               icicval = f(temp,cldice,numice)
     563             :              !         Start with a function of temperature.
     564             :              !         Wang & Sassen 2002 (JAS), based on ARM site MMCR (midlat cirrus)
     565             :              !           parameterization valid for 203-253K
     566             :              !           icival > 0 for t>195K
     567           0 :              if (iceopt.lt.3) then
     568           0 :                 if (iceopt.eq.1) then
     569           0 :                    ttmp=max(195._r8,min(temp(i,k),253._r8)) - 273.16_r8
     570           0 :                    icicval=a + b * ttmp + c * ttmp**2._r8
     571             :                    !convert units
     572           0 :                    rho=pmid(i,k)/(rair*temp(i,k))
     573           0 :                    icicval= icicval * 1.e-6_r8 / rho
     574             :                 else
     575             :                    !--------ICE CLOUD OPTION 2--------Schiller 2008 (JGR)
     576             :                    !          Use a curve based on FISH measurements in
     577             :                    !          tropics, mid-lats and arctic. Curve is for 180-250K (raise to 273K?)
     578             :                    !          use median all flights
     579             : 
     580           0 :                    ttmp=max(190._r8,min(temp(i,k),273.16_r8))
     581           0 :                    icicval = 10._r8 **(as * bs**ttmp + cs)
     582             :                    !convert units from ppmv to kg/kg
     583           0 :                    icicval= icicval * 1.e-6_r8 * 18._r8 / 28.97_r8
     584             :                 endif
     585             :                 !set icecldfraction  for OPTION 1 or OPTION2
     586           0 :                 icecldf(i,k) =  max(0._r8,min(cldice(i,k)/icicval,1._r8))
     587             : 
     588           0 :              else if (iceopt.eq.3) then
     589             : 
     590             :                 !--------ICE CLOUD OPTION 3--------Wood & Field 2000 (JAS)
     591             :                 ! eq 6: cloud fraction = 1 - exp (-K * qc/qsati)
     592             : 
     593           0 :                 icecldf(i,k)=1._r8 - exp(-Kc*cldice(i,k)/(qs(i,k)*(esi(i,k)/esl(i,k))))
     594           0 :                 icecldf(i,k)=max(0._r8,min(icecldf(i,k),1._r8))
     595             :              else
     596             :                 !--------ICE CLOUD OPTION 4--------Wilson and ballard 1999
     597             :                 ! inversion of smith....
     598             :                 !       ncf = cldice / ((1-RHcrit)*qs)
     599             :                 ! then a function of ncf....
     600           0 :                 ncf =cldice(i,k)/((1._r8 - icecrit)*qs(i,k))
     601           0 :                 if (ncf.le.0._r8) then
     602           0 :                    icecldf(i,k)=0._r8
     603           0 :                 else if (ncf.gt.0._r8 .and. ncf.le.1._r8/6._r8) then
     604           0 :                    icecldf(i,k)=0.5_r8*(6._r8 * ncf)**(2._r8/3._r8)
     605           0 :                 else if (ncf.gt.1._r8/6._r8 .and. ncf.lt.1._r8) then
     606           0 :                    phi=(acos(3._r8*(1._r8-ncf)/2._r8**(3._r8/2._r8))+4._r8*3.1415927_r8)/3._r8
     607           0 :                    icecldf(i,k)=(1._r8 - 4._r8 * cos(phi) * cos(phi))
     608             :                 else
     609           0 :                    icecldf(i,k)=1._r8
     610             :                 endif
     611           0 :                 icecldf(i,k)=max(0._r8,min(icecldf(i,k),1._r8))
     612             :              endif
     613             :              !TEST: if ice present, icecldf=1.
     614             :              !          if (cldice(i,k).ge.1.e-8_r8) then
     615             :              !             icecldf(i,k) = 0.99_r8
     616             :              !          endif
     617             : 
     618             :              !!          if ((cldice(i,k) .gt. icicval) .or. ((cldice(i,k) .gt. 0._r8) .and. (icecldf(i,k) .eq. 0._r8))) then
     619             :              !          if (cldice(i,k) .gt. 1.e-8_r8) then
     620             :              !             write(iulog,*) 'i,k,pmid,rho,t,cldice,icicval,icecldf,rhcloud: ', &
     621             :              !                i,k,pmid(i,k),rho,temp(i,k),cldice(i,k),icicval,icecldf(i,k),rhcloud(i,k)
     622             :              !          endif
     623             : 
     624             :              !         Combine ice and liquid cloud fraction assuming maximum overlap.
     625             :              ! Combined cloud fraction is maximum overlap
     626             :              !          cloud(i,k)=min(1._r8,max(icecldf(i,k),rhcloud(i,k)))
     627             : 
     628           0 :              liqcldf(i,k)=(1._r8 - icecldf(i,k))* rhcloud(i,k)
     629           0 :              cloud(i,k)=liqcldf(i,k) + icecldf(i,k)
     630             :           else
     631             :              ! For RK microphysics
     632           0 :              cloud(i,k) = rhcloud(i,k)
     633             :           end if
     634             :        end do
     635             :     end do
     636             :     !
     637             :     ! Add in the marine strat
     638             :     ! MARINE STRATUS SHOULD BE A SPECIAL CASE OF LAYERED CLOUD
     639             :     ! CLOUD CURRENTLY CONTAINS LAYERED CLOUD DETERMINED BY RH CRITERIA
     640             :     ! TAKE THE MAXIMUM OF THE DIAGNOSED LAYERED CLOUD OR STRATOCUMULUS
     641             :     !
     642             :     !===================================================================================
     643             :     !
     644             :     !  SOME OBSERVATIONS ABOUT THE FOLLOWING SECTION OF CODE (missed in earlier look)
     645             :     !  K700 IS SET AS A CONSTANT BASED ON HYBRID COORDINATE: IT DOES NOT DEPEND ON
     646             :     !  LOCAL PRESSURE; THERE IS NO PRESSURE RAMP => LOOKS LEVEL DEPENDENT AND
     647             :     !  DISCONTINUOUS IN SPACE (I.E., STRATUS WILL END SUDDENLY WITH NO TRANSITION)
     648             :     !
     649             :     !  IT APPEARS THAT STRAT IS EVALUATED ACCORDING TO KLEIN AND HARTMANN; HOWEVER,
     650             :     !  THE ACTUAL STRATUS AMOUNT (CLDST) APPEARS TO DEPEND DIRECTLY ON THE RH BELOW
     651             :     !  THE STRONGEST PART OF THE LOW LEVEL INVERSION.
     652             :     !PJR answers: 1) the rh limitation is a physical/mathematical limitation
     653             :     !             cant have more cloud than there is RH
     654             :     !             allowed the cloud to exist two layers below the inversion
     655             :     !             because the numerics frequently make 50% relative humidity
     656             :     !             in level below the inversion which would allow no cloud
     657             :     !             2) since  the cloud is only allowed over ocean, it should
     658             :     !             be very insensitive to surface pressure (except due to
     659             :     !             spectral ringing, which also causes so many other problems
     660             :     !             I didnt worry about it.
     661             :     !
     662             :     !==================================================================================
     663           0 :     if (.not.inversion_cld_off) then
     664             :     !
     665             :     ! Find most stable level below 750 mb for evaluating stratus regimes
     666             :     !
     667           0 :     do i=1,ncol
     668             :        ! Nothing triggers unless a stability greater than this minimum threshold is found
     669           0 :        dthdpmn(i) = -0.125_r8
     670           0 :        kdthdp(i) = 0
     671             :     end do
     672             :     !
     673           0 :     do k=top_lev+1,pver
     674           0 :        do i=1,ncol
     675           0 :           if (pmid(i,k) >= premib .and. ocnfrac(i).gt. 0.01_r8) then
     676             :              ! I think this is done so that dtheta/dp is in units of dg/mb (JJH)
     677           0 :              dthdp = 100.0_r8*(theta(i,k) - theta(i,k-1))*rpdeli(i,k-1)
     678           0 :              if (dthdp < dthdpmn(i)) then
     679           0 :                 dthdpmn(i) = dthdp
     680           0 :                 kdthdp(i) = k     ! index of interface of max inversion
     681             :              end if
     682             :           end if
     683             :        end do
     684             :     end do
     685             : 
     686             :     ! Also check between the bottom layer and the surface
     687             :     ! Only perform this check if the criteria were not met above
     688             : 
     689           0 :     do i = 1,ncol
     690           0 :        if ( kdthdp(i) .eq. 0 .and. ocnfrac(i).gt.0.01_r8) then
     691           0 :           dthdp = 100.0_r8 * (thetas(i) - theta(i,pver)) / (ps(i)-pmid(i,pver))
     692           0 :           if (dthdp < dthdpmn(i)) then
     693           0 :              dthdpmn(i) = dthdp
     694           0 :              kdthdp(i) = pver     ! index of interface of max inversion
     695             :           endif
     696             :        endif
     697             :     enddo
     698             : 
     699           0 :     do i=1,ncol
     700           0 :        if (kdthdp(i) /= 0) then
     701           0 :           k = kdthdp(i)
     702           0 :           kp1 = min(k+1,pver)
     703             :           ! Note: strat will be zero unless ocnfrac > 0.01
     704           0 :           strat = min(1._r8,max(0._r8, ocnfrac(i) * ((theta(i,k700)-thetas(i))*.057_r8-.5573_r8) ) )
     705             :           !
     706             :           ! assign the stratus to the layer just below max inversion
     707             :           ! the relative humidity changes so rapidly across the inversion
     708             :           ! that it is not safe to just look immediately below the inversion
     709             :           ! so limit the stratus cloud by rh in both layers below the inversion
     710             :           !
     711           0 :           cldst(i,k) = min(strat,max(rh(i,k),rh(i,kp1)))
     712             :        end if
     713             :     end do
     714             :     end if  ! .not.inversion_cld_off
     715             : 
     716           0 :     do k=top_lev,pver
     717           0 :        do i=1,ncol
     718             :           !
     719             :           !       which is greater; standard layered cloud amount or stratocumulus diagnosis
     720             :           !
     721           0 :           cloud(i,k) = max(rhcloud(i,k),cldst(i,k))
     722             :           !
     723             :           !       add in the contributions of convective cloud (determined separately and accounted
     724             :           !       for by modifications to the large-scale relative humidity.
     725             :           !
     726           0 :           cloud(i,k) = min(cloud(i,k)+concld(i,k), 1.0_r8)
     727             :        end do
     728             :     end do
     729             : 
     730           0 :     call outfld( 'SH_CLD  ', shallowcu   , pcols, lchnk )
     731           0 :     call outfld( 'DP_CLD  ', deepcu      , pcols, lchnk )
     732             : 
     733             :     !
     734           0 :     return
     735           0 :   end subroutine cldfrc
     736             : 
     737             : !================================================================================================
     738             : 
     739             : end module cloud_fraction

Generated by: LCOV version 1.14