module radlw 2,5
!-----------------------------------------------------------------------
!
! Purpose: Longwave radiation calculations.
!
!-----------------------------------------------------------------------
use shr_kind_mod
, only: r8 => shr_kind_r8
use ppgrid
, only: pcols, pver, pverp
use abortutils
, only: endrun
use scamMod
, only: single_column, scm_crm_mode
use radconstants
, only: nlwbands
implicit none
private
save
! Longwave spectral band limits (cm-1)
real(r8), public, parameter :: wavenumber1_longwave(nlwbands) = &
(/10.,350.,500.,650.,800.,1000.,1200./)
! Longwave spectral band limits (cm-1)
real(r8), public, parameter :: wavenumber2_longwave(nlwbands) = &
(/350.,500.,650.,800.,1000.,1200.,2000./)
! Public methods
public ::&
radlw_init, &! initialize constants
radclwmx ! driver for longwave radiation code
! Private module data
real(r8) :: gravit_cgs ! Acceleration of gravity (cm/s**2)
real(r8) :: stebol_cgs ! Stefan-Boltzmann constant (CGS)
!===============================================================================
CONTAINS
!===============================================================================
subroutine radclwmx(lchnk ,ncol ,doabsems , & 1,15
lwupcgs ,tnm ,qnm ,o3 , &
pmid ,pint ,pmln ,piln , &
n2o ,ch4 ,cfc11 ,cfc12 , &
cld ,emis ,pmxrgn ,nmxrgn ,qrl,qrlc, &
flns ,flnt ,flnsc ,flntc ,flwds , &
fldsc ,flut ,flutc , &
fnl ,fcnl ,co2mmr, odap_aer)
!-----------------------------------------------------------------------
!
! Purpose:
! Compute longwave radiation heating rates and boundary fluxes
!
! Method:
! Uses broad band absorptivity/emissivity method to compute clear sky;
! assumes randomly overlapped clouds with variable cloud emissivity to
! include effects of clouds.
!
! Computes clear sky absorptivity/emissivity at lower frequency (in
! general) than the model radiation frequency; uses previously computed
! and stored values for efficiency
!
! Note: This subroutine contains vertical indexing which proceeds
! from bottom to top rather than the top to bottom indexing
! used in the rest of the model.
!
! Author: B. Collins
!
!-----------------------------------------------------------------------
use radae
, only: nbands, radems, radabs, radtpl, abstot_3d, &
absnxt_3d, emstot_3d, ntoplw, radoz2, trcpth, ntopcld
use cam_history
, only: outfld
use quicksort
, only: quick_sort
use radconstants
, only: nlwbands
integer, parameter :: pverp2=pver+2, pverp3=pver+3, pverp4=pver+4
real(r8), parameter :: cldmin = 1.0e-80_r8
!------------------------------Arguments--------------------------------
!
! Input arguments
!
integer, intent(in) :: lchnk ! chunk identifier
integer, intent(in) :: ncol ! number of atmospheric columns
logical, intent(in) :: doabsems ! True => abs/emiss calculation this timestep
! maximally overlapped region.
! 0->pmxrgn(i,1) is range of pmid for
! 1st region, pmxrgn(i,1)->pmxrgn(i,2) for
! 2nd region, etc
integer, intent(in) :: nmxrgn(pcols) ! Number of maximally overlapped regions
real(r8), intent(in) :: pmxrgn(pcols,pverp) ! Maximum values of pmid for each
real(r8), intent(in) :: lwupcgs(pcols) ! Longwave up flux in CGS units
!
! Input arguments which are only passed to other routines
!
real(r8), intent(in) :: tnm(pcols,pver) ! Level temperature
real(r8), intent(in) :: qnm(pcols,pver) ! Level moisture field
real(r8), intent(in) :: o3(pcols,pver) ! ozone mass mixing ratio
real(r8), intent(in) :: pmid(pcols,pver) ! Level pressure
real(r8), intent(in) :: pint(pcols,pverp) ! Model interface pressure
real(r8), intent(in) :: pmln(pcols,pver) ! Ln(pmid)
real(r8), intent(in) :: piln(pcols,pverp) ! Ln(pint)
real(r8), intent(in) :: co2mmr(pcols) ! co2 column mean mass mixing ratio
real(r8), intent(in) :: n2o(pcols,pver) ! nitrous oxide mass mixing ratio
real(r8), intent(in) :: ch4(pcols,pver) ! methane mass mixing ratio
real(r8), intent(in) :: cfc11(pcols,pver) ! cfc11 mass mixing ratio
real(r8), intent(in) :: cfc12(pcols,pver) ! cfc12 mass mixing ratio
real(r8), intent(in) :: cld(pcols,pver) ! Cloud cover
real(r8), intent(in) :: emis(pcols,pver) ! Cloud emissivity
! [fraction] absorbtion optical depth, cumulative from top
real(r8), intent(in) :: odap_aer(pcols,pver,nlwbands)
!
! Output arguments
!
real(r8), intent(out) :: qrl (pcols,pver) ! Longwave heating rate
real(r8), intent(out) :: qrlc(pcols,pver) ! Clearsky longwave heating rate
real(r8), intent(out) :: flns(pcols) ! Surface cooling flux
real(r8), intent(out) :: flnt(pcols) ! Net outgoing flux
real(r8), intent(out) :: flut(pcols) ! Upward flux at top of model
real(r8), intent(out) :: flnsc(pcols) ! Clear sky surface cooing
real(r8), intent(out) :: flntc(pcols) ! Net clear sky outgoing flux
real(r8), intent(out) :: flutc(pcols) ! Upward clear-sky flux at top of model
real(r8), intent(out) :: flwds(pcols) ! Down longwave flux at surface
real(r8), intent(out) :: fldsc(pcols) ! Down clear-sky longwave flux at surface
real(r8),intent(out) :: fcnl(pcols,pverp) ! clear sky net flux at interfaces
real(r8),intent(out) :: fnl(pcols,pverp) ! net flux at interfaces
!
!---------------------------Local variables-----------------------------
!
integer i ! Longitude index
integer ilon ! Longitude index
integer ii ! Longitude index
integer iimx ! Longitude index (max overlap)
integer k ! Level index
integer k1 ! Level index
integer k2 ! Level index
integer k3 ! Level index
integer km ! Level index
integer km1 ! Level index
integer km3 ! Level index
integer km4 ! Level index
integer irgn ! Index for max-overlap regions
integer l ! Index for clouds to overlap
integer l1 ! Index for clouds to overlap
integer n ! Counter
!
real(r8) :: plco2(pcols,pverp) ! Path length co2
real(r8) :: plh2o(pcols,pverp) ! Path length h2o
real(r8) tmp(pcols) ! Temporary workspace
real(r8) tmp2(pcols) ! Temporary workspace
real(r8) tmp3(0:pverp) ! Temporary workspace
real(r8) tmp4 ! Temporary workspace
real(r8) tfdl ! Temporary workspace
real(r8) tful ! Temporary workspace
real(r8) absbt(pcols) ! Downward emission at model top
real(r8) plol(pcols,pverp) ! O3 pressure wghted path length
real(r8) plos(pcols,pverp) ! O3 path length
real(r8) co2em(pcols,pverp) ! Layer co2 normalized planck funct. derivative
real(r8) co2eml(pcols,pver) ! Interface co2 normalized planck funct. deriv.
real(r8) delt(pcols) ! Diff t**4 mid layer to top interface
real(r8) delt1(pcols) ! Diff t**4 lower intrfc to mid layer
real(r8) bk1(pcols) ! Absrptvty for vertical quadrature
real(r8) bk2(pcols) ! Absrptvty for vertical quadrature
real(r8) cldp(pcols,pverp) ! Cloud cover with extra layer
real(r8) ful(pcols,pverp) ! Total upwards longwave flux
real(r8) fsul(pcols,pverp) ! Clear sky upwards longwave flux
real(r8) fdl(pcols,pverp) ! Total downwards longwave flux
real(r8) fsdl(pcols,pverp) ! Clear sky downwards longwv flux
real(r8) fclb4(pcols,-1:pver) ! Sig t**4 for cld bottom interfc
real(r8) fclt4(pcols,0:pver) ! Sig t**4 for cloud top interfc
real(r8) s(pcols,pverp,pverp) ! Flx integral sum
real(r8) tplnka(pcols,pverp) ! Planck fnctn temperature
real(r8) s2c(pcols,pverp) ! H2o cont amount
real(r8) tcg(pcols,pverp) ! H2o-mass-wgted temp. (Curtis-Godson approx.)
real(r8) w(pcols,pverp) ! H2o path
real(r8) tplnke(pcols) ! Planck fnctn temperature
real(r8) h2otr(pcols,pverp) ! H2o trnmsn for o3 overlap
real(r8) co2t(pcols,pverp) ! Prs wghted temperature path
real(r8) tint(pcols,pverp) ! Interface temperature
real(r8) tint4(pcols,pverp) ! Interface temperature**4
real(r8) tlayr(pcols,pverp) ! Level temperature
real(r8) tlayr4(pcols,pverp) ! Level temperature**4
real(r8) plh2ob(nbands,pcols,pverp)! Pressure weighted h2o path with
! Hulst-Curtis-Godson temp. factor
! for H2O bands
real(r8) wb(nbands,pcols,pverp) ! H2o path length with
! Hulst-Curtis-Godson temp. factor
! for H2O bands
real(r8) cld0 ! previous cloud amt (for max overlap)
real(r8) cld1 ! next cloud amt (for max overlap)
real(r8) emx(0:pverp) ! Emissivity factors (max overlap)
real(r8) emx0 ! Emissivity factors for BCs (max overlap)
real(r8) trans ! 1 - emis
real(r8) asort(pver) ! 1 - cloud amounts to be sorted for max ovrlp.
real(r8) atmp ! Temporary storage for sort when nxs = 2
real(r8) maxcld(pcols) ! Maximum cloud at any layer
integer indx(pcols) ! index vector of gathered array values
integer indxmx(pcols+1,pverp)! index vector of gathered array values
! integer indxmx(pcols,pverp)! index vector of gathered array values
! (max overlap)
integer nrgn(pcols) ! Number of max overlap regions at longitude
integer npts ! number of values satisfying some criterion
integer ncolmx(pverp) ! number of columns with clds in region
integer kx1(pcols,pverp) ! Level index for top of max-overlap region
integer kx2(pcols,0:pverp)! Level index for bottom of max-overlap region
integer kxs(0:pverp,pcols,pverp)! Level indices for cld layers sorted by cld()
! in descending order
integer nxs(pcols,pverp) ! Number of cloudy layers between kx1 and kx2
integer nxsk ! Number of cloudy layers between (kx1/kx2)&k
integer ksort(0:pverp) ! Level indices of cloud amounts to be sorted
! for max ovrlp. calculation
integer ktmp ! Temporary storage for sort when nxs = 2
!
! Pointer variables to 3d structures
!
real(r8), pointer :: abstot(:,:,:)
real(r8), pointer :: absnxt(:,:,:)
real(r8), pointer :: emstot(:,:)
! [fraction] Total transmission between interfaces k1 and k2
real(r8) :: aer_trn_ttl(pcols,pverp,pverp,nlwbands)
!
! Trace gas variables
!
real(r8) ucfc11(pcols,pverp) ! CFC11 path length
real(r8) ucfc12(pcols,pverp) ! CFC12 path length
real(r8) un2o0(pcols,pverp) ! N2O path length
real(r8) un2o1(pcols,pverp) ! N2O path length (hot band)
real(r8) uch4(pcols,pverp) ! CH4 path length
real(r8) uco211(pcols,pverp) ! CO2 9.4 micron band path length
real(r8) uco212(pcols,pverp) ! CO2 9.4 micron band path length
real(r8) uco213(pcols,pverp) ! CO2 9.4 micron band path length
real(r8) uco221(pcols,pverp) ! CO2 10.4 micron band path length
real(r8) uco222(pcols,pverp) ! CO2 10.4 micron band path length
real(r8) uco223(pcols,pverp) ! CO2 10.4 micron band path length
real(r8) bn2o0(pcols,pverp) ! pressure factor for n2o
real(r8) bn2o1(pcols,pverp) ! pressure factor for n2o
real(r8) bch4(pcols,pverp) ! pressure factor for ch4
real(r8) uptype(pcols,pverp) ! p-type continuum path length
real(r8) abplnk1(14,pcols,pverp) ! non-nearest layer Plack factor
real(r8) abplnk2(14,pcols,pverp) ! nearest layer factor
!
!
!-----------------------------------------------------------------------
!
!
! Set pointer variables
!
abstot => abstot_3d(:,:,:,lchnk)
absnxt => absnxt_3d(:,:,:,lchnk)
emstot => emstot_3d(:,:,lchnk)
!
! Calculate some temperatures needed to derive absorptivity and
! emissivity, as well as some h2o path lengths
!
call radtpl
(ncol , &
tnm ,lwupcgs ,qnm ,pint ,plco2 ,plh2o , &
tplnka ,s2c ,tcg ,w ,tplnke , &
tint ,tint4 ,tlayr ,tlayr4 ,pmln , &
piln ,plh2ob ,wb ,co2mmr)
if (doabsems) then
!
! Compute ozone path lengths at frequency of a/e calculation.
!
call radoz2
(ncol, o3, pint, plol, plos)
!
! Compute trace gas path lengths
!
call trcpth
(ncol , &
tnm ,pint ,cfc11 ,cfc12 ,n2o , &
ch4 ,qnm ,ucfc11 ,ucfc12 ,un2o0 , &
un2o1 ,uch4 ,uco211 ,uco212 ,uco213 , &
uco221 ,uco222 ,uco223 ,bn2o0 ,bn2o1 , &
bch4 ,uptype ,co2mmr)
!
! Compute transmission through aerosols from (absorption) optical depths
!
call aer_trans_from_od
(ncol, odap_aer, aer_trn_ttl)
!
! Compute total emissivity:
!
call radems
(lchnk ,ncol , &
s2c ,tcg ,w ,tplnke ,plh2o , &
pint ,plco2 ,tint ,tint4 ,tlayr , &
tlayr4 ,plol ,plos ,ucfc11 ,ucfc12 , &
un2o0 ,un2o1 ,uch4 ,uco211 ,uco212 , &
uco213 ,uco221 ,uco222 ,uco223 ,uptype , &
bn2o0 ,bn2o1 ,bch4 ,co2em ,co2eml , &
co2t ,h2otr ,abplnk1 ,abplnk2 ,emstot , &
plh2ob ,wb , &
aer_trn_ttl, co2mmr)
!
! Compute total absorptivity:
!
call radabs
(lchnk ,ncol , &
pmid ,pint ,co2em ,co2eml ,tplnka , &
s2c ,tcg ,w ,h2otr ,plco2 , &
plh2o ,co2t ,tint ,tlayr ,plol , &
plos ,pmln ,piln ,ucfc11 ,ucfc12 , &
un2o0 ,un2o1 ,uch4 ,uco211 ,uco212 , &
uco213 ,uco221 ,uco222 ,uco223 ,uptype , &
bn2o0 ,bn2o1 ,bch4 ,abplnk1 ,abplnk2 , &
abstot ,absnxt ,plh2ob ,wb , &
odap_aer,aer_trn_ttl, co2mmr)
end if
!
! Compute sums used in integrals (all longitude points)
!
! Definition of bk1 & bk2 depends on finite differencing. for
! trapezoidal rule bk1=bk2. trapezoidal rule applied for nonadjacent
! layers only.
!
! delt=t**4 in layer above current sigma level km.
! delt1=t**4 in layer below current sigma level km.
!
do i=1,ncol
delt(i) = tint4(i,pver) - tlayr4(i,pverp)
delt1(i) = tlayr4(i,pverp) - tint4(i,pverp)
s(i,pverp,pverp) = stebol_cgs*(delt1(i)*absnxt(i,pver,1) + delt (i)*absnxt(i,pver,4))
s(i,pver,pverp) = stebol_cgs*(delt (i)*absnxt(i,pver,2) + delt1(i)*absnxt(i,pver,3))
end do
do k=ntoplw,pver-1
do i=1,ncol
bk2(i) = (abstot_3d(i,k,pver,lchnk) + abstot_3d(i,k,pverp,lchnk))*0.5_r8
bk1(i) = bk2(i)
s(i,k,pverp) = stebol_cgs*(bk2(i)*delt(i) + bk1(i)*delt1(i))
end do
end do
!
! All k, km>1
!
do km=pver,ntoplw+1,-1
do i=1,ncol
delt(i) = tint4(i,km-1) - tlayr4(i,km)
delt1(i) = tlayr4(i,km) - tint4(i,km)
end do
!CSD$ PARALLEL DO PRIVATE( i, k, bk1, bk2 )
do k=pverp,ntoplw,-1
if (k == km) then
do i=1,ncol
bk2(i) = absnxt(i,km-1,4)
bk1(i) = absnxt(i,km-1,1)
end do
else if (k == km-1) then
do i=1,ncol
bk2(i) = absnxt(i,km-1,2)
bk1(i) = absnxt(i,km-1,3)
end do
else
do i=1,ncol
bk2(i) = (abstot_3d(i,k,km-1,lchnk) + abstot_3d(i,k,km,lchnk))*0.5_r8
bk1(i) = bk2(i)
end do
end if
do i=1,ncol
s(i,k,km) = s(i,k,km+1) + stebol_cgs*(bk2(i)*delt(i) + bk1(i)*delt1(i))
end do
end do
!CSD$ END PARALLEL DO
end do
!
! Computation of clear sky fluxes always set first level of fsul
!
do i=1,ncol
fsul(i,pverp) = lwupcgs(i)
end do
!
! Downward clear sky fluxes store intermediate quantities in down flux
! Initialize fluxes to clear sky values.
!
do i=1,ncol
tmp(i) = fsul(i,pverp) - stebol_cgs*tint4(i,pverp)
fsul(i,ntoplw) = fsul(i,pverp) - abstot_3d(i,ntoplw,pverp,lchnk)*tmp(i) + s(i,ntoplw,ntoplw+1)
fsdl(i,ntoplw) = stebol_cgs*(tplnke(i)**4)*emstot(i,ntoplw)
end do
!
! fsdl(i,pverp) assumes isothermal layer
!
do k=ntoplw+1,pver
do i=1,ncol
fsul(i,k) = fsul(i,pverp) - abstot_3d(i,k,pverp,lchnk)*tmp(i) + s(i,k,k+1)
fsdl(i,k) = stebol_cgs*(tplnke(i)**4)*emstot(i,k) - (s(i,k,ntoplw+1) - s(i,k,k+1))
end do
end do
!
! Store the downward emission from level 1 = total gas emission * sigma
! t**4. fsdl does not yet include all terms
!
do i=1,ncol
absbt(i) = stebol_cgs*(tplnke(i)**4)*emstot(i,pverp)
fsdl(i,pverp) = absbt(i) - s(i,pverp,ntoplw+1)
end do
do k = ntoplw,pverp
do i = 1,ncol
fcnl(i,k) = fsul(i,k) - fsdl(i,k)
end do
end do
!
!----------------------------------------------------------------------
! Modifications for clouds -- max/random overlap assumption
!
! The column is divided into sets of adjacent layers, called regions,
! in which the clouds are maximally overlapped. The clouds are
! randomly overlapped between different regions. The number of
! regions in a column is set by nmxrgn, and the range of pressures
! included in each region is set by pmxrgn. The max/random overlap
! can be written in terms of the solutions of random overlap with
! cloud amounts = 1. The random overlap assumption is equivalent to
! setting the flux boundary conditions (BCs) at the edges of each region
! equal to the mean all-sky flux at those boundaries. Since the
! emissivity array for propogating BCs is only computed for the
! TOA BC, the flux BCs elsewhere in the atmosphere have to be formulated
! in terms of solutions to the random overlap equations. This is done
! by writing the flux BCs as the sum of a clear-sky flux and emission
! from a cloud outside the region weighted by an emissivity. This
! emissivity is determined from the location of the cloud and the
! flux BC.
!
! Copy cloud amounts to buffer with extra layer (needed for overlap logic)
!
cldp(:ncol,1:ntopcld) = 0.0_r8
cldp(:ncol,ntopcld+1:pver) = cld(:ncol,ntopcld+1:pver)
cldp(:ncol,pverp) = 0.0_r8
!
!
! Select only those locations where there are no clouds
! (maximum cloud fraction <= 1.e-3 treated as clear)
! Set all-sky fluxes to clear-sky values.
!
maxcld(1:ncol) = maxval(cldp(1:ncol,ntoplw:pver),dim=2)
npts = 0
do i=1,ncol
if (maxcld(i) < cldmin) then
npts = npts + 1
indx(npts) = i
end if
end do
!DIR$ CONCURRENT
do ii = 1, npts
i = indx(ii)
do k = ntoplw, pverp
fdl(i,k) = fsdl(i,k)
ful(i,k) = fsul(i,k)
end do
end do
!
! Select only those locations where there are clouds
!
npts = 0
do i=1,ncol
if (maxcld(i) >= cldmin) then
npts = npts + 1
indx(npts) = i
end if
end do
!
! Initialize all-sky fluxes. fdl(i,1) & ful(i,pverp) are boundary conditions
!
!DIR$ CONCURRENT
do ii = 1, npts
i = indx(ii)
fdl(i,ntoplw) = fsdl(i,ntoplw)
fdl(i,pverp) = 0.0_r8
ful(i,ntoplw) = 0.0_r8
ful(i,pverp) = fsul(i,pverp)
do k = ntoplw+1, pver
fdl(i,k) = 0.0_r8
ful(i,k) = 0.0_r8
end do
!
! Initialize Planck emission from layer boundaries
!
do k = ntoplw, pver
fclt4(i,k-1) = stebol_cgs*tint4(i,k)
fclb4(i,k-1) = stebol_cgs*tint4(i,k+1)
enddo
fclb4(i,ntoplw-2) = stebol_cgs*tint4(i,ntoplw)
fclt4(i,pver) = stebol_cgs*tint4(i,pverp)
!
! Initialize indices for layers to be max-overlapped
!
do irgn = 0, nmxrgn(i)
kx2(i,irgn) = ntoplw-1
end do
nrgn(i) = 0
end do
!----------------------------------------------------------------------
! INDEX CALCULATIONS FOR MAX OVERLAP
!CSD$ PARALLEL DO PRIVATE( ii, ilon, irgn, n, k1, k2, k, indxmx, ncolmx, iimx, i, ksort ) &
!CSD$ PRIVATE( asort, ktmp, atmp, km1, km4, k3, emx0, nxsk, emx, cld0 ) &
!CSD$ PRIVATE( tmp4, l1, tmp3, tfdl, l, cld1, trans, km3, tful )
do ii = 1, npts
ilon = indx(ii)
!
! Outermost loop over regions (sets of adjacent layers) to be max overlapped
!
do irgn = 1, nmxrgn(ilon)
!
! Calculate min/max layer indices inside region.
!
n = 0
if (kx2(ilon,irgn-1) < pver) then
nrgn(ilon) = irgn
k1 = kx2(ilon,irgn-1)+1
kx1(ilon,irgn) = k1
kx2(ilon,irgn) = k1 - 1
!cdir novector
do k2 = pver, k1, -1
if (pmid(ilon,k2) <= pmxrgn(ilon,irgn)) then
kx2(ilon,irgn) = k2
exit
end if
end do
!
! Identify columns with clouds in the given region.
!
!cdir novector
do k = k1, k2
if (cldp(ilon,k) >= cldmin) then
n = n+1
indxmx(n,irgn) = ilon
exit
endif
end do
endif
ncolmx(irgn) = n
!
! Dummy value for handling clear-sky regions
!
indxmx(ncolmx(irgn)+1,irgn) = ncol+1
!
! Outer loop over columns with clouds in the max-overlap region
!
do iimx = 1, ncolmx(irgn)
i = indxmx(iimx,irgn)
!
! Sort cloud areas and corresponding level indices.
!
n = 0
!cdir novector
do k = kx1(i,irgn),kx2(i,irgn)
if (cldp(i,k) >= cldmin) then
n = n+1
ksort(n) = k
!
! We need indices for clouds in order of largest to smallest, so
! sort 1-cld in ascending order
!
asort(n) = 1.0_r8-cldp(i,k)
end if
end do
nxs(i,irgn) = n
!
! If nxs(i,irgn) eq 1, no need to sort.
! If nxs(i,irgn) eq 2, sort by swapping if necessary
! If nxs(i,irgn) ge 3, sort using local sort routine
!
if (nxs(i,irgn) == 2) then
if (asort(2) < asort(1)) then
ktmp = ksort(1)
ksort(1) = ksort(2)
ksort(2) = ktmp
atmp = asort(1)
asort(1) = asort(2)
asort(2) = atmp
endif
else if (nxs(i,irgn) >= 3) then
call quick_sort
(asort(1:nxs(i,irgn)),ksort(1:nxs(i,irgn)))
endif
!cdir novector
do l = 1, nxs(i,irgn)
kxs(l,i,irgn) = ksort(l)
end do
!
! End loop over longitude i for fluxes
!
end do
!
! End loop over regions irgn for max-overlap
!
end do
!
!----------------------------------------------------------------------
! DOWNWARD FLUXES:
! Outermost loop over regions (sets of adjacent layers) to be max overlapped
!
do irgn = 1, nmxrgn(ilon)
!
! Compute clear-sky fluxes for regions without clouds
!
iimx = 1
if (ilon < indxmx(iimx,irgn) .and. irgn <= nrgn(ilon)) then
!
! Calculate emissivity so that downward flux at upper boundary of region
! can be cast in form of solution for downward flux from cloud above
! that boundary. Then solutions for fluxes at other levels take form of
! random overlap expressions. Try to locate "cloud" as close as possible
! to TOA such that the "cloud" pseudo-emissivity is between 0 and 1.
!
k1 = kx1(ilon,irgn)
!cdir novector
do km1 = ntoplw-2, k1-2
km4 = km1+3
k2 = k1
k3 = k2+1
tmp(ilon) = s(ilon,k2,min(k3,pverp))*min(1,pverp2-k3)
emx0 = (fdl(ilon,k1)-fsdl(ilon,k1))/ &
((fclb4(ilon,km1)-s(ilon,k2,km4)+tmp(ilon))- fsdl(ilon,k1))
if (emx0 >= 0.0_r8 .and. emx0 <= 1.0_r8) exit
end do
km1 = min(km1,k1-2)
!cdir novector
do k2 = kx1(ilon,irgn)+1, kx2(ilon,irgn)+1
k3 = k2+1
tmp(ilon) = s(ilon,k2,min(k3,pverp))*min(1,pverp2-k3)
fdl(ilon,k2) = (1.0_r8-emx0)*fsdl(ilon,k2) + &
emx0*(fclb4(ilon,km1)-s(ilon,k2,km4)+tmp(ilon))
end do
else if (ilon==indxmx(iimx,irgn) .and. iimx<=ncolmx(irgn)) then
iimx = iimx+1
end if
!
! Outer loop over columns with clouds in the max-overlap region
!
do iimx = 1, ncolmx(irgn)
i = indxmx(iimx,irgn)
!
! Calculate emissivity so that downward flux at upper boundary of region
! can be cast in form of solution for downward flux from cloud above that
! boundary. Then solutions for fluxes at other levels take form of
! random overlap expressions. Try to locate "cloud" as close as possible
! to TOA such that the "cloud" pseudo-emissivity is between 0 and 1.
!
k1 = kx1(i,irgn)
!cdir novector
do km1 = ntoplw-2,k1-2
km4 = km1+3
k2 = k1
k3 = k2 + 1
tmp(i) = s(i,k2,min(k3,pverp))*min(1,pverp2-k3)
tmp2(i) = s(i,k2,min(km4,pverp))*min(1,pverp2-km4)
emx0 = (fdl(i,k1)-fsdl(i,k1))/((fclb4(i,km1)-tmp2(i)+tmp(i))-fsdl(i,k1))
if (emx0 >= 0.0_r8 .and. emx0 <= 1.0_r8) exit
end do
km1 = min(km1,k1-2)
ksort(0) = km1 + 1
!
! Loop to calculate fluxes at level k
!
nxsk = 0
do k = kx1(i,irgn), kx2(i,irgn)
!
! Identify clouds (largest to smallest area) between kx1 and k
! Since nxsk will increase with increasing k up to nxs(i,irgn), once
! nxsk == nxs(i,irgn) then use the list constructed for previous k
!
if (nxsk < nxs(i,irgn)) then
nxsk = 0
!cdir novector
do l = 1, nxs(i,irgn)
k1 = kxs(l,i,irgn)
if (k >= k1) then
nxsk = nxsk + 1
ksort(nxsk) = k1
endif
end do
endif
!
! Dummy value of index to insure computation of cloud amt is valid for l=nxsk+1
!
ksort(nxsk+1) = pverp
!
! Initialize iterated emissivity factors
!
!cdir novector
do l = 1, nxsk
emx(l) = emis(i,ksort(l))
end do
!
! Initialize iterated emissivity factor for bnd. condition at upper interface
!
emx(0) = emx0
!
! Initialize previous cloud amounts
!
cld0 = 1.0_r8
!
! Indices for flux calculations
!
k2 = k+1
k3 = k2+1
tmp4 = s(i,k2,min(k3,pverp))*min(1,pverp2-k3)
!
! Special case nxsk == 0
!
if ( nxsk == 0 ) then
fdl(i,k2) = fdl(i,k2)+fsdl(i,k2)
if ( emx0 /= 0.0_r8 ) then
km1 = ksort(0)-1
km4 = km1+3
fdl(i,k2) = fdl(i,k2)+emx0* &
(fclb4(i,km1)-(s(i,k2,min(km4,pverp))*min(1,pverp2-km4))+tmp4-fsdl(i,k2))
end if
cycle
end if ! nxsk == 0
!
! Loop over number of cloud levels inside region (biggest to smallest cld area)
!
!cdir novector
do l1 = 0, nxsk
km1 = ksort(l1)-1
km4 = km1+3
tmp3(l1) = fclb4(i,km1)-(s(i,k2,min(km4,pverp))*min(1,pverp2-km4))+tmp4-fsdl(i,k2)
end do
tfdl = 0.0_r8
do l = 1, nxsk+1
!
! Calculate downward fluxes
!
cld1 = cldp(i,ksort(l))*min(1,nxsk+1-l)
if (cld0 /= cld1) then
tfdl = tfdl+(cld0-cld1)*fsdl(i,k2)
!cdir novector
do l1 = 0, l - 1
tfdl = tfdl+(cld0-cld1)*emx(l1)*tmp3(l1)
end do
endif
cld0 = cld1
!
! Multiply emissivity factors by current cloud transmissivity
!
if (l <= nxsk) then
k1 = ksort(l)
trans = 1.0_r8-emis(i,k1)
!
! Ideally the upper bound on l1 would be l-1, but the sort routine
! scrambles the order of layers with identical cloud amounts
!
!cdir novector
do l1 = 0, nxsk
if (ksort(l1) < k1) then
emx(l1) = emx(l1)*trans
endif
end do
end if
!
! End loop over number l of cloud levels
!
end do
fdl(i,k2) = tfdl
!
! End loop over level k for fluxes
!
end do
!
! End loop over longitude i for fluxes
!
end do
!
! End loop over regions irgn for max-overlap
!
end do
!
!----------------------------------------------------------------------
! UPWARD FLUXES:
! Outermost loop over regions (sets of adjacent layers) to be max overlapped
!
do irgn = nmxrgn(ilon), 1, -1
!
! Compute clear-sky fluxes for regions without clouds
!
iimx = 1
if (ilon < indxmx(iimx,irgn) .and. irgn <= nrgn(ilon)) then
!
! Calculate emissivity so that upward flux at lower boundary of region
! can be cast in form of solution for upward flux from cloud below that
! boundary. Then solutions for fluxes at other levels take form of
! random overlap expressions. Try to locate "cloud" as close as possible
! to surface such that the "cloud" pseudo-emissivity is between 0 and 1.
! Include allowance for surface emissivity (both numerator and denominator
! equal 1)
!
k1 = kx2(ilon,irgn)+1
if (k1 < pverp) then
!cdir novector
do km1 = pver-1,kx2(ilon,irgn),-1
km3 = km1+2
k2 = k1
k3 = k2+1
tmp(ilon) = s(ilon,k2,min(km3,pverp))* min(1,pverp2-km3)
emx0 = (ful(ilon,k1)-fsul(ilon,k1))/ &
((fclt4(ilon,km1)+s(ilon,k2,k3)-tmp(ilon))- fsul(ilon,k1))
if (emx0 >= 0.0_r8 .and. emx0 <= 1.0_r8) exit
end do
km1 = max(km1,kx2(ilon,irgn))
else
km1 = k1-1
km3 = km1+2
emx0 = 1.0_r8
endif
!cdir novector
do k2 = kx1(ilon,irgn), kx2(ilon,irgn)
k3 = k2+1
!
! If km3 == pver+2, one of the s integrals = 0 (integration limits both = p_s)
!
tmp(ilon) = s(ilon,k2,min(km3,pverp))* min(1,pverp2-km3)
ful(ilon,k2) =(1.0_r8-emx0)*fsul(ilon,k2) + emx0* &
(fclt4(ilon,km1)+s(ilon,k2,k3)-tmp(ilon))
end do
else if (ilon==indxmx(iimx,irgn) .and. iimx<=ncolmx(irgn)) then
iimx = iimx+1
end if
!
! Outer loop over columns with clouds in the max-overlap region
!
do iimx = 1, ncolmx(irgn)
i = indxmx(iimx,irgn)
!
! Calculate emissivity so that upward flux at lower boundary of region
! can be cast in form of solution for upward flux from cloud at that
! boundary. Then solutions for fluxes at other levels take form of
! random overlap expressions. Try to locate "cloud" as close as possible
! to surface such that the "cloud" pseudo-emissivity is between 0 and 1.
! Include allowance for surface emissivity (both numerator and denominator
! equal 1)
!
k1 = kx2(i,irgn)+1
if (k1 < pverp) then
!cdir novector
do km1 = pver-1,kx2(i,irgn),-1
km3 = km1+2
k2 = k1
k3 = k2+1
tmp(i) = s(i,k2,min(km3,pverp))*min(1,pverp2-km3)
emx0 = (ful(i,k1)-fsul(i,k1))/((fclt4(i,km1)+s(i,k2,k3)-tmp(i))-fsul(i,k1))
if (emx0 >= 0.0_r8 .and. emx0 <= 1.0_r8) exit
end do
km1 = max(km1,kx2(i,irgn))
else
emx0 = 1.0_r8
km1 = k1-1
endif
ksort(0) = km1 + 1
!
! Loop to calculate fluxes at level k
!
nxsk = 0
do k = kx2(i,irgn), kx1(i,irgn), -1
!
! Identify clouds (largest to smallest area) between k and kx2
! Since nxsk will increase with decreasing k up to nxs(i,irgn), once
! nxsk == nxs(i,irgn) then use the list constructed for previous k
!
if (nxsk < nxs(i,irgn)) then
nxsk = 0
!cdir novector
do l = 1, nxs(i,irgn)
k1 = kxs(l,i,irgn)
if (k <= k1) then
nxsk = nxsk + 1
ksort(nxsk) = k1
endif
end do
endif
!
! Dummy value of index to insure computation of cloud amt is valid for l=nxsk+1
!
ksort(nxsk+1) = pverp
!
! Initialize iterated emissivity factors
!
!cdir novector
do l = 1, nxsk
emx(l) = emis(i,ksort(l))
end do
!
! Initialize iterated emissivity factor for bnd. condition at lower interface
!
emx(0) = emx0
!
! Initialize previous cloud amounts
!
cld0 = 1.0_r8
!
! Indices for flux calculations
!
k2 = k
k3 = k2+1
!
! Special case nxsk == 0
!
if ( nxsk == 0 ) then
ful(i,k2) = ful(i,k2)+fsul(i,k2)
if ( emx0 /= 0.0_r8 ) then
km1 = ksort(0)-1
km3 = km1+2
!
! If km3 == pver+2, one of the s integrals = 0 (integration limits both = p_s)
!
ful(i,k2) = ful(i,k2)+emx0* &
(fclt4(i,km1)+s(i,k2,k3)-(s(i,k2,min(km3,pverp))*min(1,pverp2-km3))-fsul(i,k2))
end if
cycle
end if
!
! Loop over number of cloud levels inside region (biggest to smallest cld area)
!
!cdir novector
do l1 = 0, nxsk
km1 = ksort(l1)-1
km3 = km1+2
!
! If km3 == pver+2, one of the s integrals = 0 (integration limits both = p_s)
!
tmp3(l1) = fclt4(i,km1)+s(i,k2,k3)-(s(i,k2,min(km3,pverp))*min(1,pverp2-km3))- fsul(i,k2)
end do
tful = 0.0_r8
do l = 1, nxsk+1
!
! Calculate upward fluxes
!
cld1 = cldp(i,ksort(l))*min(1,nxsk+1-l)
if (cld0 /= cld1) then
tful = tful+(cld0-cld1)*fsul(i,k2)
!cdir novector
do l1 = 0, l - 1
tful = tful+(cld0-cld1)*emx(l1)*tmp3(l1)
end do
endif
cld0 = cld1
!
! Multiply emissivity factors by current cloud transmissivity
!
if (l <= nxsk) then
k1 = ksort(l)
trans = 1.0_r8-emis(i,k1)
!
! Ideally the upper bound on l1 would be l-1, but the sort routine
! scrambles the order of layers with identical cloud amounts
!
!cdir novector
do l1 = 0, nxsk
if (ksort(l1) > k1) then
emx(l1) = emx(l1)*trans
endif
end do
end if
!
! End loop over number l of cloud levels
!
end do
ful(i,k2) = tful
!
! End loop over level k for fluxes
!
end do
!
! End loop over longitude i for fluxes
!
end do
!
! End loop over regions irgn for max-overlap
!
end do
!
! End outermost longitude loop
!
end do
!CSD$ END PARALLEL DO
!
! End cloud modification loops
!
!----------------------------------------------------------------------
! All longitudes: store history tape quantities
!
do i=1,ncol
flwds(i) = fdl (i,pverp )
fldsc(i) = fsdl(i,pverp )
flns(i) = ful (i,pverp ) - fdl (i,pverp )
flnsc(i) = fsul(i,pverp ) - fsdl(i,pverp )
flnt(i) = ful (i,ntoplw) - fdl (i,ntoplw)
flntc(i) = fsul(i,ntoplw) - fsdl(i,ntoplw)
flut(i) = ful (i,ntoplw)
flutc(i) = fsul(i,ntoplw)
end do
if (single_column.and.scm_crm_mode) then
call outfld
('FUL ',ful*1.e-3_r8,pcols,lchnk)
call outfld
('FDL ',fdl*1.e-3_r8,pcols,lchnk)
call outfld
('FULC ',fsul*1.e-3_r8,pcols,lchnk)
call outfld
('FDLC ',fsdl*1.e-3_r8,pcols,lchnk)
endif
do k = ntoplw,pverp
do i = 1,ncol
fnl(i,k) = ful(i,k) - fdl(i,k)
end do
end do
!
! Computation of longwave heating (J/kg/s)
!
do k=ntoplw,pver
do i=1,ncol
qrl(i,k) = (ful(i,k) - fdl(i,k) - ful(i,k+1) + fdl(i,k+1))* &
1.E-4_r8*gravit_cgs/((pint(i,k) - pint(i,k+1)))
qrlc(i,k) = (fsul(i,k) - fsdl(i,k) - fsul(i,k+1) + fsdl(i,k+1))* &
1.E-4_r8*gravit_cgs/((pint(i,k) - pint(i,k+1)))
end do
end do
! Return 0 above solution domain
if ( ntoplw > 1 )then
qrl(:ncol,:ntoplw-1) = 0._r8
qrlc(:ncol,:ntoplw-1) = 0._r8
end if
!
return
end subroutine radclwmx
!-------------------------------------------------------------------------------
subroutine radlw_init(gravit, stebol) 1
!-----------------------------------------------------------------------
!
! Purpose:
! Initialize various constants for radiation scheme; note that
! the radiation scheme uses cgs units.
!-----------------------------------------------------------------------
!
! Input arguments
!
real(r8), intent(in) :: gravit ! Acceleration of gravity (MKS)
real(r8), intent(in) :: stebol ! Stefan-Boltzmann's constant (MKS)
!
!-----------------------------------------------------------------------
!
! Set general radiation consts; convert to cgs units where appropriate:
!
gravit_cgs = 100._r8*gravit
stebol_cgs = 1.e3_r8*stebol
end subroutine radlw_init
!-------------------------------------------------------------------------------
subroutine aer_trans_from_od(ncol, odap_aer, aer_trn_ttl) 1,2
use radconstants
, only: nlwbands
use ppgrid
, only: pcols, pver, pverp
integer, intent(in) :: ncol
! [fraction] absorption optical depth, per layer
real(r8), intent(in) :: odap_aer(pcols,pver,nlwbands)
! [fraction] Total transmission between interfaces k1 and k2
real(r8), intent(out) :: aer_trn_ttl(pcols,pverp,pverp,nlwbands)
! [fraction] absorption optical depth, cumulative from top
real(r8) :: odap_aer_ttl(pcols,pverp,nlwbands)
integer i, k1, k2, bnd_idx ! column iterator, level iterators, band iterator
! odap_aer_ttl is cumulative total optical depth from top of atmosphere
odap_aer_ttl = 0._r8
do bnd_idx=1,nlwbands
do k1=1,pver
do i=1,ncol
odap_aer_ttl(i,k1+1,bnd_idx) = odap_aer_ttl(i,k1,bnd_idx) + odap_aer(i,k1,bnd_idx)
end do
end do
end do
! compute transmission from top of atmosphere to level
! where angular dependence of optical depth has been
! integrated (giving factor 1.666666)
do k1=1,pverp
aer_trn_ttl(1:pcols,k1,k1,:)=1._r8
enddo
aer_trn_ttl(1:ncol,1,2:pverp,1:nlwbands) = &
exp(-1.66_r8 * odap_aer_ttl(1:ncol,2:pverp,1:nlwbands) )
! compute transmission between a given layer (k1) and lower layers.
do k1=2,pver
do k2=k1+1,pverp
aer_trn_ttl(1:ncol,k1,k2,1:nlwbands) = &
aer_trn_ttl(1:ncol,1,k2,1:nlwbands) / &
aer_trn_ttl(1:ncol,1,k1,1:nlwbands)
end do
end do
! transmission from k1 to k2 is same as transmission from k2 to k1.
do k1=2,pverp
do k2=1,k1-1
aer_trn_ttl(1:ncol,k1,k2,1:nlwbands)=aer_trn_ttl(1:ncol,k2,k1,1:nlwbands)
end do
end do
return
end subroutine aer_trans_from_od
end module radlw