LCOV - code coverage report
Current view: top level - physics/cam - ebert_curry_ice_optics.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 8 84 9.5 %
Date: 2024-12-17 17:57:11 Functions: 1 3 33.3 %

          Line data    Source code
       1             : module ebert_curry_ice_optics
       2             : 
       3             : 
       4             : use shr_kind_mod,     only: r8 => shr_kind_r8
       5             : use physconst,        only: gravit
       6             : use ppgrid,           only: pcols, pver
       7             : use physics_types,    only: physics_state
       8             : use physics_buffer,   only: physics_buffer_desc, pbuf_get_index, pbuf_get_field, pbuf_old_tim_idx
       9             : use constituents,     only: cnst_get_ind
      10             : use radconstants,     only: nswbands, nlwbands, get_sw_spectral_boundaries
      11             : use cam_abortutils,   only: endrun
      12             : 
      13             : implicit none
      14             : private
      15             : save
      16             : 
      17             : public :: &
      18             :    ec_rad_props_init,        &
      19             :    ec_ice_optics_sw,       &
      20             :    ec_ice_get_rad_props_lw
      21             : 
      22             : 
      23             : real(r8), public, parameter:: scalefactor = 1._r8 !500._r8/917._r8
      24             : 
      25             : ! indices into pbuf
      26             : integer :: iciwp_idx   = 0 
      27             : integer :: iclwp_idx   = 0 
      28             : integer :: cld_idx     = 0  
      29             : integer :: rei_idx     = 0  
      30             : 
      31             : ! indices into constituents for old optics
      32             : integer :: ixcldice  ! cloud ice water index
      33             : integer :: ixcldliq  ! cloud liquid water index
      34             : 
      35             : 
      36             : !==============================================================================
      37             : contains
      38             : !==============================================================================
      39             : 
      40        1536 : subroutine ec_rad_props_init()
      41             : 
      42             :    integer :: err
      43             : 
      44        1536 :    iciwp_idx  = pbuf_get_index('ICIWP',errcode=err)
      45        1536 :    iclwp_idx  = pbuf_get_index('ICLWP',errcode=err)
      46        1536 :    cld_idx    = pbuf_get_index('CLD')
      47        1536 :    rei_idx    = pbuf_get_index('REI')
      48             : 
      49             :    ! old optics
      50        1536 :    call cnst_get_ind('CLDICE', ixcldice)
      51        1536 :    call cnst_get_ind('CLDLIQ', ixcldliq)
      52             : 
      53        1536 : end subroutine ec_rad_props_init
      54             : 
      55             : !==============================================================================
      56             : 
      57           0 : subroutine ec_ice_optics_sw   (state, pbuf, ice_tau, ice_tau_w, ice_tau_w_g, ice_tau_w_f, oldicewp)
      58             : 
      59             :    type(physics_state),    intent(in) :: state
      60             :    type(physics_buffer_desc), pointer :: pbuf(:)
      61             : 
      62             :    real(r8),intent(out) :: ice_tau    (nswbands,pcols,pver) ! extinction optical depth
      63             :    real(r8),intent(out) :: ice_tau_w  (nswbands,pcols,pver) ! single scattering albedo * tau
      64             :    real(r8),intent(out) :: ice_tau_w_g(nswbands,pcols,pver) ! asymmetry parameter * tau * w
      65             :    real(r8),intent(out) :: ice_tau_w_f(nswbands,pcols,pver) ! forward scattered fraction * tau * w
      66             :    logical, intent(in) :: oldicewp
      67             : 
      68           0 :    real(r8), pointer, dimension(:,:) :: rei
      69           0 :    real(r8), pointer, dimension(:,:) :: cldn
      70           0 :    real(r8), pointer, dimension(:,:) :: tmpptr
      71             :    real(r8), dimension(pcols,pver) :: cicewp
      72             :    real(r8), dimension(nswbands) :: wavmin
      73             :    real(r8), dimension(nswbands) :: wavmax
      74             :    !
      75             :    ! ice water coefficients (Ebert and Curry,1992, JGR, 97, 3831-3836)
      76             :    real(r8) :: abari(4) = &     ! a coefficient for extinction optical depth
      77             :       (/ 3.448e-03_r8, 3.448e-03_r8,3.448e-03_r8,3.448e-03_r8/)
      78             :    real(r8) :: bbari(4) = &     ! b coefficient for extinction optical depth
      79             :       (/ 2.431_r8    , 2.431_r8    ,2.431_r8    ,2.431_r8    /)
      80             :    real(r8) :: cbari(4) = &     ! c coefficient for single scat albedo
      81             :       (/ 1.00e-05_r8 , 1.10e-04_r8 ,1.861e-02_r8,.46658_r8   /)
      82             :    real(r8) :: dbari(4) = &     ! d coefficient for single scat albedo
      83             :       (/ 0.0_r8      , 1.405e-05_r8,8.328e-04_r8,2.05e-05_r8 /)
      84             :    real(r8) :: ebari(4) = &     ! e coefficient for asymmetry parameter
      85             :       (/ 0.7661_r8   , 0.7730_r8   ,0.794_r8    ,0.9595_r8   /)
      86             :    real(r8) :: fbari(4) = &     ! f coefficient for asymmetry parameter
      87             :       (/ 5.851e-04_r8, 5.665e-04_r8,7.267e-04_r8,1.076e-04_r8/)
      88             : 
      89             :    real(r8) :: abarii           ! A coefficient for current spectral band
      90             :    real(r8) :: bbarii           ! B coefficient for current spectral band
      91             :    real(r8) :: cbarii           ! C coefficient for current spectral band
      92             :    real(r8) :: dbarii           ! D coefficient for current spectral band
      93             :    real(r8) :: ebarii           ! E coefficient for current spectral band
      94             :    real(r8) :: fbarii           ! F coefficient for current spectral band
      95             : 
      96             :    ! Minimum cloud amount (as a fraction of the grid-box area) to 
      97             :    ! distinguish from clear sky
      98             :    real(r8), parameter :: cldmin = 1.0e-80_r8
      99             : 
     100             :    ! Decimal precision of cloud amount (0 -> preserve full resolution;
     101             :    ! 10^-n -> preserve n digits of cloud amount)
     102             :    real(r8), parameter :: cldeps = 0.0_r8
     103             : 
     104             :    integer :: ns, i, k, indxsl, lchnk, Nday
     105             :    integer :: itim_old
     106             :    real(r8) :: tmp1i, tmp2i, tmp3i, g
     107             : 
     108           0 :    Nday = state%ncol
     109           0 :    lchnk = state%lchnk
     110             : 
     111           0 :    itim_old = pbuf_old_tim_idx()
     112           0 :    call pbuf_get_field(pbuf, cld_idx,cldn, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
     113           0 :    call pbuf_get_field(pbuf, rei_idx,rei)
     114             : 
     115           0 :    if(oldicewp) then
     116           0 :      do k=1,pver
     117           0 :         do i = 1,Nday
     118           0 :            cicewp(i,k) = 1000.0_r8*state%q(i,k,ixcldice)*state%pdel(i,k) /(gravit* max(0.01_r8,cldn(i,k)))
     119             :         end do
     120             :      end do
     121             :    else
     122           0 :      if (iciwp_idx<=0) then 
     123           0 :         call endrun('ec_ice_optics_sw: oldicewp must be set to true since ICIWP was not found in pbuf')
     124             :      endif
     125           0 :      call pbuf_get_field(pbuf, iciwp_idx, tmpptr)
     126           0 :      cicewp(1:pcols,1:pver) =  1000.0_r8*tmpptr(1:pcols,1:pver)
     127             :    endif
     128             :    
     129           0 :    call get_sw_spectral_boundaries(wavmin,wavmax,'microns')
     130             : 
     131           0 :    do ns = 1, nswbands
     132             : 
     133           0 :       if(wavmax(ns) <= 0.7_r8) then
     134             :          indxsl = 1
     135           0 :       else if(wavmax(ns) <= 1.25_r8) then
     136             :          indxsl = 2
     137           0 :       else if(wavmax(ns) <= 2.38_r8) then
     138             :          indxsl = 3
     139           0 :       else if(wavmax(ns) > 2.38_r8) then
     140             :          indxsl = 4
     141             :       end if
     142             : 
     143           0 :       abarii = abari(indxsl)
     144           0 :       bbarii = bbari(indxsl)
     145           0 :       cbarii = cbari(indxsl)
     146           0 :       dbarii = dbari(indxsl)
     147           0 :       ebarii = ebari(indxsl)
     148           0 :       fbarii = fbari(indxsl)
     149             : 
     150           0 :       do k=1,pver
     151           0 :          do i=1,Nday
     152             : 
     153             :             ! note that optical properties for ice valid only
     154             :             ! in range of 13 > rei > 130 micron (Ebert and Curry 92)
     155           0 :             if (cldn(i,k) >= cldmin .and. cldn(i,k) >= cldeps) then
     156           0 :                tmp1i = abarii + bbarii/max(13._r8,min(scalefactor*rei(i,k),130._r8))
     157           0 :                ice_tau(ns,i,k) = cicewp(i,k)*tmp1i
     158             :             else
     159           0 :                ice_tau(ns,i,k) = 0.0_r8
     160             :             endif
     161             : 
     162           0 :             tmp2i = 1._r8 - cbarii - dbarii*min(max(13._r8,scalefactor*rei(i,k)),130._r8)
     163           0 :             tmp3i = fbarii*min(max(13._r8,scalefactor*rei(i,k)),130._r8)
     164             :             ! Do not let single scatter albedo be 1.  Delta-eddington solution
     165             :             ! for non-conservative case has different analytic form from solution
     166             :             ! for conservative case, and raddedmx is written for non-conservative case.
     167           0 :             ice_tau_w(ns,i,k) = ice_tau(ns,i,k) * min(tmp2i,.999999_r8)
     168           0 :             g = ebarii + tmp3i
     169           0 :             ice_tau_w_g(ns,i,k) = ice_tau_w(ns,i,k) * g
     170           0 :             ice_tau_w_f(ns,i,k) = ice_tau_w(ns,i,k) * g * g
     171             : 
     172             :          end do ! End do i=1,Nday
     173             :       end do    ! End do k=1,pver
     174             :    end do ! nswbands
     175             : 
     176           0 : end subroutine ec_ice_optics_sw
     177             : 
     178             : !==============================================================================
     179             : 
     180           0 : subroutine ec_ice_get_rad_props_lw(state, pbuf, abs_od, oldicewp)
     181             : 
     182             :    type(physics_state), intent(in)   :: state
     183             :    type(physics_buffer_desc),pointer :: pbuf(:)
     184             :     real(r8), intent(out) :: abs_od(nlwbands,pcols,pver)
     185             :    logical, intent(in) :: oldicewp
     186             : 
     187             :    real(r8) :: gicewp(pcols,pver)
     188             :    real(r8) :: gliqwp(pcols,pver)
     189             :    real(r8) :: cicewp(pcols,pver)
     190             :    real(r8) :: cliqwp(pcols,pver)
     191             :    real(r8) :: ficemr(pcols,pver)
     192             :    real(r8) :: cwp(pcols,pver)
     193             :    real(r8) :: cldtau(pcols,pver)
     194             : 
     195           0 :    real(r8), pointer, dimension(:,:) :: cldn
     196           0 :    real(r8), pointer, dimension(:,:) :: rei
     197             :    integer :: ncol, itim_old, lwband, i, k, lchnk
     198             : 
     199             :     real(r8) :: kabs, kabsi
     200             : 
     201             :     real(r8) kabsl                  ! longwave liquid absorption coeff (m**2/g)
     202             :     parameter (kabsl = 0.090361_r8)
     203             : 
     204           0 :    real(r8), pointer, dimension(:,:) :: iclwpth, iciwpth
     205             : 
     206             : 
     207           0 :    ncol = state%ncol
     208           0 :    lchnk = state%lchnk
     209             : 
     210           0 :    itim_old  =  pbuf_old_tim_idx()
     211           0 :    call pbuf_get_field(pbuf, rei_idx,   rei)
     212           0 :    call pbuf_get_field(pbuf, cld_idx,   cldn, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
     213             : 
     214             : 
     215           0 :    if(oldicewp) then
     216           0 :      do k=1,pver
     217           0 :          do i = 1,ncol
     218           0 :             gicewp(i,k) = state%q(i,k,ixcldice)*state%pdel(i,k)/gravit*1000.0_r8  ! Grid box ice water path.
     219           0 :             gliqwp(i,k) = state%q(i,k,ixcldliq)*state%pdel(i,k)/gravit*1000.0_r8  ! Grid box liquid water path.
     220           0 :             cicewp(i,k) = gicewp(i,k) / max(0.01_r8,cldn(i,k))                 ! In-cloud ice water path.
     221           0 :             cliqwp(i,k) = gliqwp(i,k) / max(0.01_r8,cldn(i,k))                 ! In-cloud liquid water path.
     222             :             ficemr(i,k) = state%q(i,k,ixcldice) /                 &
     223           0 :                  max(1.e-10_r8,(state%q(i,k,ixcldice)+state%q(i,k,ixcldliq)))
     224             :          end do
     225             :      end do
     226           0 :      cwp(:ncol,:pver) = cicewp(:ncol,:pver) + cliqwp(:ncol,:pver)
     227             :    else
     228           0 :       if (iclwp_idx<=0 .or. iciwp_idx<=0) then 
     229           0 :          call endrun('ec_ice_get_rad_props_lw: oldicewp must be set to true since ICIWP and/or ICLWP were not found in pbuf')
     230             :       endif
     231           0 :       call pbuf_get_field(pbuf, iclwp_idx, iclwpth)
     232           0 :       call pbuf_get_field(pbuf, iciwp_idx, iciwpth)
     233           0 :       do k=1,pver
     234           0 :          do i = 1,ncol
     235           0 :             cwp(i,k) = 1000.0_r8 *iciwpth(i,k) + 1000.0_r8 *iclwpth(i,k)
     236           0 :             ficemr(i,k) = 1000.0_r8*iciwpth(i,k)/(max(1.e-18_r8,cwp(i,k)))
     237             :          end do
     238             :       end do
     239             :    endif
     240             : 
     241           0 :    do k=1,pver
     242           0 :        do i=1,ncol
     243             : 
     244             :           ! Note from Andrew Conley:
     245             :           !  Optics for RK no longer supported, This is constructed to get
     246             :           !  close to bit for bit.  Otherwise we could simply use ice water path
     247             :           !note that optical properties for ice valid only
     248             :           !in range of 13 > rei > 130 micron (Ebert and Curry 92)
     249           0 :           kabsi = 0.005_r8 + 1._r8/min(max(13._r8,scalefactor*rei(i,k)),130._r8)
     250           0 :           kabs =  kabsi*ficemr(i,k) ! kabsl*(1._r8-ficemr(i,k)) + kabsi*ficemr(i,k)
     251             :           !emis(i,k) = 1._r8 - exp(-1.66_r8*kabs*clwp(i,k))
     252           0 :           cldtau(i,k) = kabs*cwp(i,k)
     253             :        end do
     254             :    end do
     255             : 
     256           0 :    do lwband = 1,nlwbands
     257           0 :       abs_od(lwband,1:ncol,1:pver)=cldtau(1:ncol,1:pver)
     258             :    enddo
     259             : 
     260           0 : end subroutine ec_ice_get_rad_props_lw
     261             : 
     262             : !==============================================================================
     263             : 
     264             : end module ebert_curry_ice_optics

Generated by: LCOV version 1.14