module dust_intr 9,8
!---------------------------------------------------------------------------------
! Module to interface the aerosol parameterizations with CAM
! written by PJR (extensively modified from chemistry module)
!---------------------------------------------------------------------------------
use shr_kind_mod
,only: r8 => shr_kind_r8, cl => shr_kind_cl
use spmd_utils
, only: masterproc
use camsrfexch_types
, only: surface_state
use ppgrid
, only: pcols, pver,pverp
use physconst
, only: mwdry, mwh2o,gravit,rair
use constituents
,only: pcnst, cnst_add, cnst_name, cnst_get_ind
use abortutils
, only: endrun
use cam_logfile
, only: iulog
implicit none
private ! Make default type private to the module
save
#if (defined MODAL_AERO)
integer, parameter:: dust_number = 2
integer, parameter:: ndst =2
#else
integer, parameter:: dust_number = 4
integer, parameter:: ndst =4
#endif
integer, parameter:: dst_src_nbr =3
integer, parameter:: sz_nbr =200
integer :: ncyear
integer :: ix_dust = -1
#if (defined MODAL_AERO)
integer, parameter :: ncnst=ndst+2 ! number of constituents
character(len=8), dimension(ncnst), parameter :: & ! constituent names
#if (defined MODAL_AERO_7MODE)
cnst_names = (/'dst_a5', 'dst_a7', 'num_a5', 'num_a7'/)
#elif (defined MODAL_AERO_3MODE)
cnst_names = (/'dst_a1', 'dst_a3', 'num_a1', 'num_a3'/)
#endif
#else
integer, parameter :: ncnst=ndst ! number of constituents
character(len=8), dimension(ncnst), parameter :: & ! constituent names
cnst_names = (/'DST01', 'DST02', 'DST03', 'DST04'/)
#endif
!
! Public interfaces
!
public dust_register_cnst ! register consituents
public dust_implements_cnst ! returns true if consituent is implemented by this package
public dust_init_cnst ! initialize mixing ratios if not read from initial file
public dust_initialize ! initialize (history) variables
public dust_wet_intr ! interface to wet deposition
public dust_emis_intr ! interface to emission
public dust_drydep_intr ! interface to tendency computation
!!$ public dust_time_interp ! interpolate oxidants and fluxes to current time
public dust_idx1 ! allow other parts of code to know where dust is
public dust_names
public dust_number
public dust_set_idx
public dust_has_wet_dep
character(len=8), dimension(ncnst) :: dust_names = cnst_names
#if (defined MODAL_AERO)
logical :: dust_has_wet_dep(ncnst) = .true.
#else
logical :: dust_has_wet_dep(ndst) = .true.
#endif
real(r8) stk_crc(ndst) ![frc] Correction to Stokes settling velocity
real(r8) dns_aer ![kg m-3] Aerosol density
real(r8) tmp1 !Factor in saltation computation (named as in Charlie's code)
real(r8) ovr_src_snk_mss(dst_src_nbr,ndst)
real(r8) dmt_vwr(ndst) ![m] Mass-weighted mean diameter resolved
real(r8), allocatable :: soil_erodibility(:,:) ! soil erodibility factor
#if (defined MODAL_AERO)
integer, target :: spc_ndx(ndst)
integer, target :: spc_num_ndx(ndst)
#if (defined MODAL_AERO_7MODE)
integer, pointer :: dst_a5_ndx, dst_a7_ndx
integer, pointer :: num_a5_ndx, num_a7_ndx
#elif (defined MODAL_AERO_3MODE)
integer, pointer :: dst_a1_ndx, dst_a3_ndx
integer, pointer :: num_a1_ndx, num_a3_ndx
#endif
#endif
! Namelist variables
real(r8) :: dust_emis_fact = -1.e36 ! tuning parameter for dust emissions
character(cl) :: soil_erod = 'soil_erod' ! full pathname for soil erodibility dataset
!===============================================================================
contains
!===============================================================================
subroutine dust_register_cnst( ),5
!-----------------------------------------------------------------------
!
! Purpose: register advected constituents for all aerosols
!
! Method:
! <Describe the algorithm(s) used in the routine.>
! <Also include any applicable external references.>
!
! Author: P. J. Rasch
!
!-----------------------------------------------------------------------
!---------------------------Local workspace-----------------------------
integer :: m ! tracer index
real(r8), parameter :: one = 1._r8
real(r8), parameter :: zero = 0._r8
real(r8) :: mwght = one
!-----------------------------------------------------------------------
! Set names of variables undergoing evolution
! returns m as current index for tracer numbers
call cnst_add
(cnst_names(1), mwght, one, zero, m )
! and store the start index of dust species used elsewhere in model retrieved by dust_idx1
call dust_set_idx
(m)
call cnst_add
(cnst_names(2), mwght, one, zero, m )
call cnst_add
(cnst_names(3), mwght, one, zero, m )
call cnst_add
(cnst_names(4), mwght, one, zero, m )
return
end subroutine dust_register_cnst
!=======================================================================
function dust_implements_cnst(name) 1
!-----------------------------------------------------------------------
!
! Purpose: return true if specified constituent is implemented by this
! package
!
! Author: T. Henderson
!
!-----------------------------------------------------------------------
implicit none
!-----------------------------Arguments---------------------------------
character(len=*), intent(in) :: name ! constituent name
logical :: dust_implements_cnst ! return value
!---------------------------Local workspace-----------------------------
integer :: m
!-----------------------------------------------------------------------
dust_implements_cnst = .false.
if (ix_dust<1) return
do m = 1, ncnst
if (name == cnst_names(m)) then
dust_implements_cnst = .true.
return
end if
end do
end function dust_implements_cnst
!=======================================================================
subroutine dust_init_cnst(name, q, gcid) 1
!-----------------------------------------------------------------------
!
! Purpose:
! Set initial mass mixing ratios.
!
!-----------------------------------------------------------------------
implicit none
!-----------------------------Arguments---------------------------------
character(len=*), intent(in) :: name ! constituent name
real(r8), intent(out) :: q(:,:) ! mass mixing ratio
integer, intent(in) :: gcid(:) ! global column id
!-----------------------------------------------------------------------
if ( name == cnst_names(1) ) then
q = 0._r8
else if ( name == cnst_names(2) ) then
q = 0._r8
else if ( name == cnst_names(3) ) then
q = 0._r8
else if ( name == cnst_names(4) ) then
q = 0._r8
end if
end subroutine dust_init_cnst
!===============================================================================
function dust_idx1() 24
integer dust_idx1
dust_idx1 = ix_dust
end function dust_idx1
!===============================================================================
subroutine dust_set_idx(m) 1
integer, intent(in) :: m
ix_dust = m
end subroutine dust_set_idx
!===============================================================================
subroutine dust_initialize(dust_emis_fact_in, soil_erod_in) 2,47
!-----------------------------------------------------------------------
!
! Purpose: initialize parameterization of dust chemistry
! (declare history variables)
!
!-----------------------------------------------------------------------
use cam_history
, only: addfld, add_default, phys_decomp
use error_messages
, only: handle_ncerr
use ioFileMod
, only: getfil
#if (defined MODAL_AERO)
use mo_chem_utls, only: get_spc_ndx
#endif
use netcdf
! arguments
real(r8), intent(in) :: dust_emis_fact_in
character(cl), intent(in) :: soil_erod_in
! local variables
integer :: m
integer :: ix ! start index for dust species
character(len=32) :: dummy
character(cl) :: soil_erod_file
integer :: did, vid
integer ::&
ncid, &! ID for netCDF file
start(2), &! start vector for netCDF hyperslabs
count(2) ! count vector for netCDF hyperslabs
!-----------------------------------------------------------------------
! set module data from namelist vars read in aerosol_intr module
dust_emis_fact = dust_emis_fact_in
soil_erod = soil_erod_in
#if (defined MODAL_AERO)
#if (defined MODAL_AERO_7MODE)
dst_a5_ndx => spc_ndx(1)
dst_a7_ndx => spc_ndx(2)
num_a5_ndx => spc_num_ndx(1)
num_a7_ndx => spc_num_ndx(2)
dst_a5_ndx = get_spc_ndx( 'dst_a5' )
dst_a7_ndx = get_spc_ndx( 'dst_a7' )
num_a5_ndx = get_spc_ndx( 'num_a5' )
num_a7_ndx = get_spc_ndx( 'num_a7' )
#elif (defined MODAL_AERO_3MODE)
dst_a1_ndx => spc_ndx(1)
dst_a3_ndx => spc_ndx(2)
num_a1_ndx => spc_num_ndx(1)
num_a3_ndx => spc_num_ndx(2)
dst_a1_ndx = get_spc_ndx( 'dst_a1' )
dst_a3_ndx = get_spc_ndx( 'dst_a3' )
num_a1_ndx = get_spc_ndx( 'num_a1' )
num_a3_ndx = get_spc_ndx( 'num_a3' )
#endif
#endif
! use Sam's dust initialize subroutine: call equivalent here:
call Dustini
()
! for soil erodibility in mobilization, apply inside CAM instead of lsm.
! read in soil erodibility factors, similar to Zender's boundary conditions
! Get file name.
call getfil
(soil_erod, soil_erod_file, 0)
call handle_ncerr
( nf90_open( soil_erod_file, NF90_NOWRITE, ncid ), &
'dust_initialize: error opening file '//trim(soil_erod_file) )
! Get input data resolution.
call handle_ncerr
( nf90_inq_dimid( ncid, 'lon', did ), 'dust_initialize: ' )
call handle_ncerr
( nf90_inquire_dimension( ncid, did, len=count(1) ), 'dust_initialize: ' )
call handle_ncerr
( nf90_inq_dimid( ncid, 'lat', did ), 'dust_initialize: ' )
call handle_ncerr
( nf90_inquire_dimension( ncid, did, len=count(2) ), 'dust_initialize: ' )
call handle_ncerr
( nf90_inq_varid( ncid, 'mbl_bsn_fct_geo', vid ), &
'dust_initialize: cannot find variable '//'mbl_bsn_fct_geo' )
start(1) = 1
start(2) = 1
allocate(soil_erodibility(count(1),count(2)))
call handle_ncerr
( nf90_get_var( ncid, vid,soil_erodibility, start, count ), &
'dust_initialize: cannot read data for '//'mbl_bsn_fct_geo' )
! start index for dust species in constituent array
ix = dust_idx1
()
! Set names of variable tendencies and declare them as history variables
dummy = 'LND_MBL'
call addfld
(dummy,'frac ',1, 'A','Soil erodibility factor',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = 'RAM1'
call addfld
(dummy,'frac ',1, 'A','RAM1',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = 'airFV'
call addfld
(dummy,'frac ',1, 'A','FV',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = 'ORO'
call addfld
(dummy,'frac ',1, 'A','ORO',phys_decomp)
call add_default
(dummy, 1, ' ')
#if (defined MODAL_AERO)
do m = 1, ndst
dummy = trim(cnst_name(ix-spc_ndx(1)+spc_ndx(m))) // 'SF'
call addfld
(dummy,'kg/m2/s ',1, 'A',trim(cnst_name(ix-spc_ndx(1)+spc_ndx(m)))//' dust surface emission',phys_decomp)
call add_default
(dummy, 1, ' ')
end do
#else
do m = 1, 4
dummy = trim(cnst_name(ix-1+m))
call addfld
(dummy,'kg/kg ',pver, 'A',trim(cnst_name(ix-1+m))//' dust mixing ratio',phys_decomp)
call add_default
(dummy, 1, ' ' )
dummy = trim(cnst_name(ix-1+m)) // 'SF'
call addfld
(dummy,'kg/m2/s ',1, 'A',trim(cnst_name(ix-1+m))//' dust surface emission',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = trim(cnst_name(ix-1+m)) // 'TB'
call addfld
(dummy,'kg/m2/s ',1, 'A',trim(cnst_name(ix-1+m))//' turbulent dry deposition flux',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = trim(cnst_name(ix-1+m)) // 'GV'
call addfld
(dummy,'kg/m2/s ',1, 'A',trim(cnst_name(ix-1+m))//' gravitational dry deposition flux',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = trim(cnst_name(ix-1+m)) // 'DD'
call addfld
(dummy,'kg/m2/s ',1, 'A',trim(cnst_name(ix-1+m))//' dry deposition flux at bottom (grav + turb)',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = trim(cnst_name(ix-1+m)) // 'DT'
call addfld
(dummy,'kg/kg/s ',pver, 'A',trim(cnst_name(ix-1+m))//' dry deposition',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = trim(cnst_name(ix-1+m)) // 'PP'
call addfld
(dummy,'kg/kg/s ',pver, 'A',trim(cnst_name(ix-1+m))//' wet deposition',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = trim(cnst_name(ix-1+m)) // 'DV'
call addfld
(dummy,'m/s ',pver, 'A',trim(cnst_name(ix-1+m))//' deposition velocity',phys_decomp)
call add_default
(dummy, 1, ' ')
end do
#endif
dummy = 'DSTSFDRY'
call addfld
(dummy,'kg/m2/s',1, 'A','Dry deposition flux at surface',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = 'DSTSFMBL'
call addfld
(dummy,'kg/m2/s',1, 'A','Mobilization flux at surface',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = 'DSTSFWET'
call addfld
(dummy,'kg/m2/s',1, 'A','Wet deposition flux at surface',phys_decomp)
call add_default
(dummy, 1, ' ')
dummy = 'DSTODXC'
call addfld
(dummy,'Tau ',1, 'A','Optical depth for diagnostics',phys_decomp)
call add_default
(dummy, 1, ' ')
! Summary to log file
if (masterproc) then
write(iulog,*) 'Initializing prognostic dust (subroutine dust_initialize): '
write(iulog,*) ' start index for dust is ', ix
write(iulog,*) ' dust_emis_fact = ', dust_emis_fact
write(iulog,*) ' soil erodibility dataset: ', trim(soil_erod)
end if
end subroutine dust_initialize
!===============================================================================
subroutine dust_wet_intr (state, ptend, nstep, dt, lat, clat, cme, prain, & 1,8
evapr, cldv, cldc, cldn, fracis, calday, cmfdqr, conicw, rainmr, cam_out)
!-----------------------------------------------------------------------
!
! Purpose:
! Interface to wet processing of aerosols (source and sinks).
!
! Method:
! <Describe the algorithm(s) used in the routine.>
! <Also include any applicable external references.>
!
! Author: B.A. Boville
!
!-----------------------------------------------------------------------
use cam_history
, only: outfld
use physics_types
, only: physics_state, physics_ptend
use wetdep
, only: wetdepa_v1
!-----------------------------------------------------------------------
implicit none
!-----------------------------------------------------------------------
!
! Arguments:
!
real(r8), intent(in) :: dt ! time step
type(physics_state), intent(in ) :: state ! Physics state variables
integer, intent(in) :: nstep
integer, intent(in) :: lat(pcols) ! latitude index for S->N storage
real(r8), intent(in) :: clat(pcols) ! latitude
real(r8), intent(in) :: cme(pcols,pver) ! local condensation of cloud water
real(r8), intent(in) :: prain(pcols,pver) ! production of rain
real(r8), intent(in) :: evapr(pcols,pver) ! evaporation of rain
real(r8), intent(in) :: cldn(pcols,pver) ! cloud fraction
real(r8), intent(in) :: cldc(pcols,pver) ! convective cloud fraction
real(r8), intent(in) :: cldv(pcols,pver) ! cloudy volume undergoing scavenging
real(r8), intent(in) :: conicw(pcols, pver)
real(r8), intent(in) :: cmfdqr(pcols, pver)
real(r8), intent(in) :: rainmr(pcols, pver) ! rain mixing ratio
type(physics_ptend), intent(inout) :: ptend ! indivdual parameterization tendencies
type(surface_state), intent(inout) :: cam_out ! export state
real(r8), intent(inout) :: fracis(pcols,pver,pcnst) ! fraction of transported species that are insoluble
!
! Local variables
!
integer :: lchnk ! chunk identifier
integer :: ncol ! number of atmospheric columns
integer :: ix
real(r8) :: tstate(pcols, pver, 4) ! temporary state vector
real(r8) :: sflx(pcols) ! deposition flux per bin
real(r8) :: sflx_tot(pcols) ! deposition flux (accumulates all bins)
real(r8) :: obuf(1)
real(r8), intent(in) :: calday ! current calendar day
real(r8) :: iscavt(pcols, pver)
real(r8) :: scavt(pcols, pver)
real(r8) :: scavcoef(pcols, pver)
integer :: yr, mon, day, ncsec
integer :: ncdate
integer :: mm,i,k
integer :: m ! tracer index
integer :: ixcldliq
integer :: ixcldice
real(r8) totcond(pcols, pver) ! total condensate
real(r8) :: sol_fact
!-----------------------------------------------------------------------
lchnk = state%lchnk
ncol = state%ncol
sflx_tot(:)=0._r8
call cnst_get_ind
('CLDICE', ixcldice)
call cnst_get_ind
('CLDLIQ', ixcldliq)
totcond(:ncol,:) = state%q(:ncol,:,ixcldliq) + state%q(:ncol,:,ixcldice)
scavcoef(:ncol,:) = 0.1_r8
do m = 1, ndst
sflx(:) = 0._r8
if (dust_has_wet_dep(m) ) then
mm = ix_dust + m - 1
scavt=0._r8
! write(iulog,*) 'wet dep removed for debugging'
ptend%lq(mm) = .TRUE.
ptend%name = trim(ptend%name)//',dust'
sol_fact = 0.15_r8
call wetdepa_v1
( state%t, state%pmid, state%q, state%pdel, &
cldn, cldc, cmfdqr, conicw, prain, cme, &
evapr, totcond, state%q(:,:,mm), dt, &
scavt, iscavt, cldv, fracis(:,:,mm), sol_fact, ncol, scavcoef )
ptend%q(:ncol,:,mm)=scavt(:ncol,:)
call outfld
( trim(cnst_name(mm))//'PP', ptend%q(:,:,mm), pcols, lchnk)
! write(iulog,*) ' range of ptend ix ', minval(ptend%q(:ncol,:,mm)),maxval(ptend%q(:ncol,:,mm))
do k = 1, pver
do i = 1, ncol
sflx(i) = sflx(i) + ptend%q(i,k,mm)*state%pdel(i,k)/gravit
end do
end do
sflx_tot(:ncol) = sflx_tot(:ncol) + sflx(:ncol)
! set deposition in export state
select case (m)
case(1)
do i = 1, ncol
cam_out%dstwet1(i) = max(-sflx(i), 0._r8)
end do
case(2)
do i = 1, ncol
cam_out%dstwet2(i) = max(-sflx(i), 0._r8)
end do
case(3)
do i = 1, ncol
cam_out%dstwet3(i) = max(-sflx(i), 0._r8)
end do
case(4)
do i = 1, ncol
cam_out%dstwet4(i) = max(-sflx(i), 0._r8)
end do
end select
endif
end do
call outfld
( 'DSTSFWET', sflx_tot, pcols, lchnk)
! write(iulog,*) ' dust_wet_intr: pcols, pcols ', pcols, pcols
return
end subroutine dust_wet_intr
subroutine dust_drydep_intr (state, ptend, wvflx, dt, lat, clat, & 1,21
fsds, obklen, ts, ustar, prect, snowh, pblh, hflx, month, landfrac, &
icefrac, ocnfrac,fvin,ram1in, cam_out)
!-----------------------------------------------------------------------
!
! Purpose:
! Interface to dry deposition and sedimentation of dust
!
! Method:
! <Describe the algorithm(s) used in the routine.>
! <Also include any applicable external references.>
!
! Author: Natalie Mahowald and Phil Rasch
!
!-----------------------------------------------------------------------
use cam_history
, only: outfld
use physics_types
, only: physics_state, physics_ptend
use phys_grid
, only: get_lat_all_p
use constituents
, only: cnst_name
use drydep_mod
, only: setdvel, d3ddflux, calcram
use dust_sediment_mod
, only: dust_sediment_tend, dust_sediment_vel
!-----------------------------------------------------------------------
implicit none
!-----------------------------------------------------------------------
!
! Arguments:
!
real(r8), intent(in) :: dt ! time step
type(physics_state), intent(in ) :: state ! Physics state variables
integer, intent(in) :: lat(pcols) ! latitude index for S->N storage
real(r8), intent(in) :: clat(pcols) ! latitude
real(r8), intent(in) :: fsds(pcols) ! longwave down at sfc
real(r8), intent(in) :: obklen(pcols) ! obklen
real(r8), intent(in) :: ustar(pcols) ! sfc fric vel--used over oceans and sea ice.
real(r8), intent(in) :: ts(pcols) ! sfc temp
real(r8), intent(in) :: landfrac(pcols) ! land fraction
real(r8), intent(in) :: icefrac(pcols) ! ice fraction
real(r8), intent(in) :: ocnfrac(pcols) ! ocean fraction
real(r8), intent(in) :: hflx(pcols) ! sensible heat flux
real(r8), intent(in) :: prect(pcols) ! prect
real(r8), intent(in) :: snowh(pcols) ! snow depth
real(r8), intent(in) :: pblh(pcols) ! pbl height
integer, intent(in) :: month
real(r8), intent(in) :: wvflx(pcols) ! water vapor flux
real(r8), intent(in) :: fvin(pcols) ! for dry dep velocities from land model for dust
real(r8), intent(in) :: ram1in(pcols) ! for dry dep velocities from land model for dust
type(physics_ptend), intent(inout) :: ptend ! indivdual parameterization tendencies
type(surface_state), intent(inout) :: cam_out ! export state
! Local variables
!
integer :: m ! tracer index
integer :: mm ! tracer index
integer :: ioff ! offset for ghg indices
integer :: lchnk ! chunk identifier
integer :: ncol ! number of atmospheric columns
integer :: ix
real(r8) :: tvs(pcols,pver)
real(r8) :: dvel(pcols) ! deposition velocity
real(r8) :: sflx(pcols) ! deposition flux
real(r8) :: vlc_dry(pcols,pver,ndst) ! dep velocity
real(r8) :: vlc_grv(pcols,pver,ndst) ! dep velocity
real(r8):: vlc_trb(pcols,ndst) ! dep velocity
real(r8):: dep_trb(pcols) !kg/m2/s
real(r8):: dep_dry(pcols) !kg/m2/s (total of grav and trb)
real(r8):: dep_grv(pcols) !kg/m2/s (total of grav and trb)
real(r8):: dep_dry_tend(pcols,pver) !kg/kg/s (total of grav and trb)
real(r8) :: obuf(1)
real (r8) :: rho(pcols,pver) ! air density in kg/m3
real(r8) pvdust(pcols,pverp) ! sedimentation velocity in Pa
real(r8) :: tsflx(pcols)
real(r8) :: fv(pcols) ! for dry dep velocities, from land modified over ocean & ice
real(r8) :: ram1(pcols) ! for dry dep velocities, from land modified over ocean & ice
integer :: i,k
real(r8) :: oro(pcols)
!
!-----------------------------------------------------------------------
ix = dust_idx1
()
ioff = ix - 1
lchnk = state%lchnk
ncol = state%ncol
tvs(:ncol,:) = state%t(:ncol,:)!*(1+state%q(:ncol,k)
rho(:ncol,:)= state%pmid(:ncol,:)/(rair*state%t(:ncol,:))
tsflx(:)=0._r8
! calculate oro--need to run match
do i=1,ncol
oro(i)=1._r8
if(icefrac(i)>0.5_r8) oro(i)=2._r8
if(ocnfrac(i)>0.5_r8) oro(i)=0._r8
enddo
call outfld
( 'ORO', oro, pcols, lchnk )
! write(iulog,*) ' dust drydep invoked '
! Dry deposition of Dust Aerosols
! #################################
! call setdvel( ncol, landfrac, icefrac, ocnfrac, .001_r8, .001_r8, .001_r8, dvel )
! we get the ram1,fv from the land model as ram1in,fvin, but need to calculate it over oceans and ice.
! better if we got thse from the ocean and ice model
! for friction velocity, we use ustar (from taux and tauy), except over land, where we use fv from the land model.
call calcram
(ncol,landfrac,icefrac,ocnfrac,obklen,&
ustar,ram1in,ram1,state%t(:,pver),state%pmid(:,pver),&
state%pdel(:,pver),fvin,fv)
call outfld
( 'airFV', fv(:), pcols, lchnk )
call outfld
( 'RAM1', ram1(:), pcols, lchnk )
! call outfld( 'icefrc', icefrac(:), pcols, lchnk )
call DustDryDep
(ncol,state%t(:,:),state%pmid(:,:),ram1,fv,vlc_dry,vlc_trb,vlc_grv,landfrac)
do m=1,ndst
mm = dust_idx1
() + m - 1
! use pvdust instead (means making the top level 0)
pvdust(:ncol,1)=0._r8
pvdust(:ncol,2:pverp) = vlc_dry(:ncol,:,m)
call outfld
( trim(cnst_name(mm))//'DV', pvdust(:,2:pverp), pcols, lchnk )
if(.true.) then ! use phil's method
! convert from meters/sec to pascals/sec
! pvdust(:,1) is assumed zero, use density from layer above in conversion
pvdust(:ncol,2:pverp) = pvdust(:ncol,2:pverp) * rho(:ncol,:)*gravit
! calculate the tendencies and sfc fluxes from the above velocities
call dust_sediment_tend
( &
ncol, dt, state%pint(:,:), state%pmid, state%pdel, state%t , &
state%q(:,:,mm) , pvdust , ptend%q(:,:,mm), sflx )
else !use charlie's method
call d3ddflux
(ncol, vlc_dry(:,:,m), state%q(:,:,mm),state%pmid,state%pdel, tvs,sflx,ptend%q(:,:,mm),dt)
endif
! apportion dry deposition into turb and gravitational settling for tapes
do i=1,ncol
dep_trb(i)=sflx(i)*vlc_trb(i,m)/vlc_dry(i,pver,m)
dep_grv(i)=sflx(i)*vlc_grv(i,pver,m)/vlc_dry(i,pver,m)
enddo
tsflx(:ncol)=tsflx(:ncol)+sflx(:ncol)
! set deposition in export state
select case (m)
case(1)
do i = 1, ncol
cam_out%dstdry1(i) = max(sflx(i), 0._r8)
end do
case(2)
do i = 1, ncol
cam_out%dstdry2(i) = max(sflx(i), 0._r8)
end do
case(3)
do i = 1, ncol
cam_out%dstdry3(i) = max(sflx(i), 0._r8)
end do
case(4)
do i = 1, ncol
cam_out%dstdry4(i) = max(sflx(i), 0._r8)
end do
end select
call outfld
( trim(cnst_name(mm))//'DD',sflx, pcols, lchnk)
call outfld
( trim(cnst_name(mm))//'TB', dep_trb, pcols, lchnk )
call outfld
( trim(cnst_name(mm))//'GV', dep_grv, pcols, lchnk )
call outfld
( trim(cnst_name(mm))//'DT',ptend%q(:,:,mm), pcols, lchnk)
! write(iulog,*) ' range of tends for dust ', mm, minval(ptend%q(:ncol,:,mm)), maxval(ptend%q(:ncol,:,mm))
! call outfld( trim(cnst_name(mm))//'DRY', sflx, pcols, lchnk)
end do
! output the total dry deposition
call outfld
( 'DSTSFDRY', tsflx, pcols, lchnk)
! set flags for tendencies (water and 4 ghg's)
ptend%name = ptend%name//'+dust_drydep'
ptend%lq(ioff+1:ioff+4) = .TRUE.
return
end subroutine dust_drydep_intr
subroutine dust_emis_intr (state, ptend, dt,cflx) 2,29
!-----------------------------------------------------------------------
!
! Purpose:
! Interface to emission of all dusts.
! Notice that the mobilization is calculated in the land model (need #define BGC) and
! the soil erodibility factor is applied here.
!
! Method:
! <Describe the algorithm(s) used in the routine.>
! <Also include any applicable external references.>
!
! Author: Phil Rasch and Natalie Mahowald
!
!
!-----------------------------------------------------------------------
use cam_history
, only: outfld
use physics_types
, only: physics_state, physics_ptend
use phys_grid
, only: get_lon_all_p, get_lat_all_p
#if (defined MODAL_AERO)
use physconst
, only: pi,rair
use modal_aero_data
#endif
! use dust, only: dustsf
!-----------------------------------------------------------------------
implicit none
!-----------------------------------------------------------------------
!
! Arguments:
!
real(r8), intent(in) :: dt ! time step
type(physics_state), intent(in ) :: state ! Physics state variables
type(physics_ptend), intent(inout) :: ptend ! indivdual parameterization tendencies
real(r8), intent(inout) :: cflx(pcols,pcnst)
integer lat(pcols) ! latitude index
integer lon(pcols) ! longitude index
integer lchnk
integer ncol
integer i
integer m
real(r8):: sflx(pcols) ! accumulate over all bins for output
real(r8) :: soil_erod_tmp(pcols)
!
real :: fact ! tuning factor for dust emissions
#if (defined MODAL_AERO)
integer :: mm,l
real(r8) :: x_mton ! (aero # emit)/(aero mass emit) ratio (#/kg)
#endif
lchnk = state%lchnk
ncol = state%ncol
call get_lat_all_p
(lchnk, ncol, lat)
call get_lon_all_p
(lchnk, ncol, lon)
sflx(:)=0._r8
#if (defined MODAL_AERO)
! zero out the portion of cflx used for modal aerosol number because number is added up from sea salt and dst
! number and mass species
do m = 1, ntot_amode
l = numptr_amode(m)
if (l > 0) cflx(:,l) = 0.0_r8
end do
#endif
!
! write(40,*) cflx(1,1)
! write(41,*) soil_erodibility(1,lat(1))
! we use charlie's sandblasting size distribution (instead of what Sam used
! in clm (and overwrite them here).
#if (defined MODAL_AERO)
do i = 1, ncol
soil_erod_tmp(i) = soil_erodibility(lon(i),lat(i))
if(soil_erod_tmp(i) .lt. 0.1_r8) soil_erod_tmp(i)=0._r8
end do
cflx(:ncol,dust_idx1
())=cflx(:ncol,dust_idx1
())
cflx(:ncol,dust_idx1
()+spc_ndx(2)-spc_ndx(1))=cflx(:ncol,dust_idx1
()+spc_ndx(2)-spc_ndx(1))
if(spc_num_ndx(1) > 0) then
cflx(:ncol,dust_idx1
()+spc_num_ndx(1)-spc_ndx(1))=cflx(:ncol,dust_idx1
())
endif
if(spc_num_ndx(2) > 0) then
cflx(:ncol,dust_idx1
()+spc_num_ndx(2)-spc_ndx(1))=cflx(:ncol,dust_idx1
()+spc_ndx(2)-spc_ndx(1))
endif
#else
do i = 1, ncol
soil_erod_tmp(i) = soil_erodibility(lon(i),lat(i))
! jfl
! change test to from 0.1 to 0.001 after
! discussion with N. Mahowald April 8 2009
if(soil_erod_tmp(i) .lt. 0.001_r8) soil_erod_tmp(i)=0._r8
end do
cflx(:ncol,dust_idx1
())=cflx(:ncol,dust_idx1
())*0.038_r8/0.032456_r8
cflx(:ncol,dust_idx1
()+1)=cflx(:ncol,dust_idx1
()+1)*0.11_r8/0.174216_r8
cflx(:ncol,dust_idx1
()+2)=cflx(:ncol,dust_idx1
()+2)*0.17_r8/0.4085517_r8
cflx(:ncol,dust_idx1
()+3)=cflx(:ncol,dust_idx1
()+3)*0.67_r8/0.384811_r8
#endif
! tuning factor (fact) for dust emissions
fact = dust_emis_fact
#if (defined MODAL_AERO)
do mm=1,ndst
! multiply by soil erodibility factor
if(spc_num_ndx(mm) > 0) then
m=dust_idx1
()+spc_num_ndx(mm)-spc_ndx(1)
x_mton = 6.0_r8 / (pi*dns_aer*(dmt_vwr(mm)**3.0_r8))
cflx(:ncol,m)=cflx(:ncol,m)*x_mton*soil_erod_tmp(:ncol)/fact*1.15_r8
endif
m=dust_idx1
()+spc_ndx(mm)-spc_ndx(1)
cflx(:ncol,m)=cflx(:ncol,m)*soil_erod_tmp(:ncol)/fact*1.15_r8
sflx(:ncol)=sflx(:ncol)+cflx(:ncol,m)
#else
do m=dust_idx1
(),dust_idx1
()+3
! multiply by soil erodibility factor
cflx(:ncol,m)=cflx(:ncol,m)*soil_erod_tmp(:ncol)/fact*1.15_r8
sflx(:ncol)=sflx(:ncol)+cflx(:ncol,m)
#endif
call outfld
(trim(cnst_name(m)) // 'SF',cflx(:,m),pcols,lchnk)
! this is being done inside of the vertical diffusion automatically
! ptend%lq(m) = .true. ! tendencies for all dust on
! ptend%q(:ncol,pver,m) = cflx(:ncol,m)*gravit/state%pdel(:ncol,pver)
enddo
call outfld
('LND_MBL',soil_erod_tmp,pcols,lchnk)
call outfld
('DSTSFMBL',sflx(:),pcols,lchnk)
! write(42,*) cflx(1,1)
return
end subroutine dust_emis_intr
!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: subroutine Dustini()
!
! !INTERFACE:
!
subroutine Dustini() 2,14
!
! !DESCRIPTION:
!
! Compute source efficiency factor from topography
! Initialize other variables used in subroutine Dust:
! ovr_src_snk_mss(m,n) and tmp1.
! Define particle diameter and density needed by atm model
! as well as by dry dep model
! Source: Paul Ginoux (for source efficiency factor)
! Modifications by C. Zender and later by S. Levis
! Rest of subroutine from C. Zender's dust model
!
! !USES
!
use physconst
, only: pi,rair
!
! !ARGUMENTS:
!
implicit none
!
! !REVISION HISTORY
! Created by Samual Levis
! Revised for CAM by Natalie Mahowald
!EOP
!------------------------------------------------------------------------
!------------------------------------------------------------------------
!Local Variables
integer :: ci,m,n !indices
real(r8) :: ovr_src_snk_frc
real(r8) :: sqrt2lngsdi ![frc] Factor in erf argument
real(r8) :: lndmaxjovrdmdni ![frc] Factor in erf argument
real(r8) :: lndminjovrdmdni ![frc] Factor in erf argument
real(r8) :: ryn_nbr_frc_thr_prx_opt ![frc] Threshold friction Reynolds number approximation for optimal size
real(r8) :: ryn_nbr_frc_thr_opt_fnc ![frc] Threshold friction Reynolds factor for saltation calculation
real(r8) :: icf_fct !Interpartical cohesive forces factor for saltation calc
real(r8) :: dns_fct !Density ratio factor for saltation calculation
real(r8) :: dmt_min(ndst) ![m] Size grid minimum
real(r8) :: dmt_max(ndst) ![m] Size grid maximum
real(r8) :: dmt_ctr(ndst) ![m] Diameter at bin center
real(r8) :: dmt_dlt(ndst) ![m] Width of size bin
real(r8) :: slp_crc(ndst) ![frc] Slip correction factor
real(r8) :: vlm_rsl(ndst) ![m3 m-3] Volume concentration resolved
real(r8) :: vlc_stk(ndst) ![m s-1] Stokes settling velocity
real(r8) :: vlc_grv(ndst) ![m s-1] Settling velocity
real(r8) :: ryn_nbr_grv(ndst) ![frc] Reynolds number at terminal velocity
real(r8) :: cff_drg_grv(ndst) ![frc] Drag coefficient at terminal velocity
real(r8) :: tmp !temporary
real(r8) :: ln_gsd ![frc] ln(gsd)
real(r8) :: gsd_anl ![frc] Geometric standard deviation
real(r8) :: dmt_vma ![m] Mass median diameter analytic She84 p.75 Tabl.1
real(r8) :: dmt_nma ![m] Number median particle diameter
real(r8) :: lgn_dst !Lognormal distribution at sz_ctr
real(r8) :: eps_max ![frc] Relative accuracy for convergence
real(r8) :: eps_crr ![frc] Current relative accuracy
real(r8) :: itr_idx ![idx] Counting index
real(r8) :: dns_mdp ![kg m-3] Midlayer density
real(r8) :: mfp_atm ![m] Mean free path of air
real(r8) :: vsc_dyn_atm ![kg m-1 s-1] Dynamic viscosity of air
real(r8) :: vsc_knm_atm ![kg m-1 s-1] Kinematic viscosity of air
real(r8) :: vlc_grv_old ![m s-1] Previous gravitational settling velocity
real(r8) :: series_ratio !Factor for logarithmic grid
real(r8) :: lngsdsqrttwopi_rcp !Factor in lognormal distribution
real(r8) :: sz_min(sz_nbr) ![m] Size Bin minima
real(r8) :: sz_max(sz_nbr) ![m] Size Bin maxima
real(r8) :: sz_ctr(sz_nbr) ![m] Size Bin centers
real(r8) :: sz_dlt(sz_nbr) ![m] Size Bin widths
! constants
real(r8) :: dmt_vma_src(dst_src_nbr) = & ![m] Mass median diameter
(/ 0.832e-6_r8 , 4.82e-6_r8 , 19.38e-6_r8 /) !BSM96 p. 73 Table 2
real(r8) :: gsd_anl_src(dst_src_nbr) = & ![frc] Geometric std deviation
(/ 2.10_r8 , 1.90_r8 , 1.60_r8 /) !BSM96 p. 73 Table 2
real(r8) :: mss_frc_src(dst_src_nbr) = & ![frc] Mass fraction
(/ 0.036_r8, 0.957_r8, 0.007_r8 /) !BSM96 p. 73 Table 2
#if (defined MODAL_AERO)
real(r8) :: dmt_grd(3) = & ![m] Particle diameter grid
#if (defined MODAL_AERO_7MODE)
(/ 0.1e-6_r8, 2.0e-6_r8, 10.0e-6_r8/)
#elif (defined MODAL_AERO_3MODE)
(/ 0.1e-6_r8, 1.0e-6_r8, 10.0e-6_r8/)
#endif
#else
real(r8) :: dmt_grd(5) = & ![m] Particle diameter grid
(/ 0.1e-6_r8, 1.0e-6_r8, 2.5e-6_r8, 5.0e-6_r8, 10.0e-6_r8 /)
#endif
real(r8), parameter :: dmt_slt_opt = 75.0e-6_r8 ![m] Optim diam for saltation
real(r8), parameter :: dns_slt = 2650.0_r8 ![kg m-3] Density of optimal saltation particles
! declare erf intrinsic function
real(r8) :: dum !dummy variable for erf test
#if (defined AIX)
#define ERF erf
#else
#define ERF derf
real(r8) derf
#endif
!------------------------------------------------------------------------
! Sanity check on erf: erf() in SGI /usr/lib64/mips4/libftn.so is bogus
dum = 1.0_r8
if (abs(0.8427_r8-ERF(dum))/0.8427_r8>0.001_r8) then
write(iulog,*) 'erf(1.0) = ',ERF(dum)
call endrun
('Dustini: Error function error')
endif
dum = 0.0_r8
if (ERF(dum) /= 0.0_r8) then
write(iulog,*) 'erf(0.0) = ',ERF(dum)
call endrun
('Dustini: Error function error')
endif
! the following comes from (1) szdstlgn.F subroutine ovr_src_snk_frc_get
! and (2) dstszdst.F subroutine dst_szdst_ini
! purpose(1): given one set (the "source") of lognormal distributions,
! and one set of bin boundaries (the "sink"), compute and return
! the overlap factors between the source and sink distributions
! purpose(2): set important statistics of size distributions
do m = 1, dst_src_nbr
sqrt2lngsdi = sqrt(2.0_r8) * log(gsd_anl_src(m))
do n = 1, ndst
lndmaxjovrdmdni = log(dmt_grd(n+1)/dmt_vma_src(m))
lndminjovrdmdni = log(dmt_grd(n )/dmt_vma_src(m))
ovr_src_snk_frc = 0.5_r8 * (ERF(lndmaxjovrdmdni/sqrt2lngsdi) - &
ERF(lndminjovrdmdni/sqrt2lngsdi))
ovr_src_snk_mss(m,n) = ovr_src_snk_frc * mss_frc_src(m)
enddo
enddo
!delete portions that have to do only with the sink
! Introducing particle diameter. Needed by atm model and by dry dep model.
! Taken from Charlie Zender's subroutines dst_psd_ini, dst_sz_rsl,
! grd_mk (dstpsd.F90) and subroutine lgn_evl (psdlgn.F90)
! Charlie allows logarithmic or linear option for size distribution
! however, he hardwires the distribution to logarithmic in his code
! therefore, I take his logarithmic code only
! furthermore, if dst_nbr == 4, he overrides the automatic grid calculation
! he currently works with dst_nbr = 4, so I only take the relevant code
! if dust_number ever becomes different from 4, must add call grd_mk (dstpsd.F90)
! as done in subroutine dst_psd_ini
! note that here dust_number = dst_nbr
! Override automatic grid with preset grid if available
#if (defined MODAL_AERO)
if (dust_number == 2) then
#else
if (dust_number == 4) then
#endif
do n = 1, dust_number
dmt_min(n) = dmt_grd(n) ![m] Max diameter in bin
dmt_max(n) = dmt_grd(n+1) ![m] Min diameter in bin
dmt_ctr(n) = 0.5_r8 * (dmt_min(n)+dmt_max(n)) ![m] Diameter at bin ctr
dmt_dlt(n) = dmt_max(n)-dmt_min(n) ![m] Width of size bin
end do
else
#if (defined MODAL_AERO)
call endrun
('Dustini error: dust_number must equal to 2 with current code')
#else
call endrun
('Dustini error: dust_number must equal to 4 with current code')
#endif
!see more comments above)
endif
! Bin physical properties
gsd_anl = 2.0_r8 ! [frc] Geometric std dev PaG77 p. 2080 Table1
ln_gsd = log(gsd_anl)
dns_aer = 2.5e+3_r8 ! [kg m-3] Aerosol density
! Set a fundamental statistic for each bin
dmt_vma = 2.524e-6_r8 ! [m] Mass median diameter analytic She84 p.75 Table1
dmt_vma = 3.5e-6_r8
! Compute analytic size statistics
! Convert mass median diameter to number median diameter (call vma2nma)
dmt_nma = dmt_vma * exp(-3.0_r8*ln_gsd*ln_gsd) ! [m]
! Compute resolved size statistics for each size distribution
! In C. Zender's code call dst_sz_rsl
do n = 1, dust_number
series_ratio = (dmt_max(n)/dmt_min(n))**(1.0_r8/sz_nbr)
sz_min(1) = dmt_min(n)
do m = 2, sz_nbr ! Loop starts at 2
sz_min(m) = sz_min(m-1) * series_ratio
end do
! Derived grid values
do m = 1, sz_nbr-1 ! Loop ends at sz_nbr-1
sz_max(m) = sz_min(m+1) ! [m]
end do
sz_max(sz_nbr) = dmt_max(n) ! [m]
! Final derived grid values
do m = 1, sz_nbr
sz_ctr(m) = 0.5_r8 * (sz_min(m)+sz_max(m))
sz_dlt(m) = sz_max(m)-sz_min(m)
end do
lngsdsqrttwopi_rcp = 1.0_r8 / (ln_gsd*sqrt(2.0_r8*pi))
dmt_vwr(n) = 0.0_r8 ! [m] Mass wgted diameter resolved
vlm_rsl(n) = 0.0_r8 ! [m3 m-3] Volume concentration resolved
do m = 1, sz_nbr
! Evaluate lognormal distribution for these sizes (call lgn_evl)
tmp = log(sz_ctr(m)/dmt_nma) / ln_gsd
lgn_dst = lngsdsqrttwopi_rcp * exp(-0.5_r8*tmp*tmp) / sz_ctr(m)
! Integrate moments of size distribution
dmt_vwr(n) = dmt_vwr(n) + sz_ctr(m) * &
pi / 6.0_r8 * (sz_ctr(m)**3.0_r8) * & ![m3] Volume
lgn_dst * sz_dlt(m) ![# m-3] Number concentrn
vlm_rsl(n) = vlm_rsl(n) + &
pi / 6.0_r8 * (sz_ctr(m)**3.0_r8) * & ![m3] Volume
lgn_dst * sz_dlt(m) ![# m-3] Number concentrn
end do
dmt_vwr(n) = dmt_vwr(n) / vlm_rsl(n) ![m] Mass weighted diameter resolved
end do
! calculate correction to Stokes' settling velocity (subroutine stk_crc_get)
eps_max = 1.0e-4_r8
dns_mdp = 100000._r8 / (295.0_r8*rair) ![kg m-3] const prs_mdp & tpt_vrt
! Size-independent thermokinetic properties
vsc_dyn_atm = 1.72e-5_r8 * ((295.0_r8/273.0_r8)**1.5_r8) * 393.0_r8 / &
(295.0_r8+120.0_r8) ![kg m-1 s-1] RoY94 p.102 tpt_mdp=295.0
mfp_atm = 2.0_r8 * vsc_dyn_atm / & !SeP97 p. 455 constant prs_mdp, tpt_mdp
(100000._r8*sqrt(8.0_r8/(pi*rair*295.0_r8)))
vsc_knm_atm = vsc_dyn_atm / dns_mdp ![m2 s-1] Kinematic viscosity of air
do m = 1, dust_number
slp_crc(m) = 1.0_r8 + 2.0_r8 * mfp_atm * &
(1.257_r8+0.4_r8*exp(-1.1_r8*dmt_vwr(m)/(2.0_r8*mfp_atm))) / &
dmt_vwr(m) ! [frc] Slip correction factor SeP97 p.464
vlc_stk(m) = (1.0_r8/18.0_r8) * dmt_vwr(m) * dmt_vwr(m) * dns_aer * &
gravit * slp_crc(m) / vsc_dyn_atm ! [m s-1] SeP97 p.466
end do
! For Reynolds number flows Re < 0.1 Stokes' velocity is valid for
! vlc_grv SeP97 p. 466 (8.42). For larger Re, inertial effects become
! important and empirical drag coefficients must be employed
! Implicit equation for Re, Cd, and Vt is SeP97 p. 467 (8.44)
! Using Stokes' velocity rather than iterative solution with empirical
! drag coefficient causes 60% errors for D = 200 um SeP97 p. 468
! Iterative solution for drag coefficient, Reynolds number, and terminal veloc
do m = 1, dust_number
! Initialize accuracy and counter
eps_crr = eps_max + 1.0_r8 ![frc] Current relative accuracy
itr_idx = 0 ![idx] Counting index
! Initial guess for vlc_grv is exact for Re < 0.1
vlc_grv(m) = vlc_stk(m) ![m s-1]
do while(eps_crr > eps_max)
! Save terminal velocity for convergence test
vlc_grv_old = vlc_grv(m) ![m s-1]
ryn_nbr_grv(m) = vlc_grv(m) * dmt_vwr(m) / vsc_knm_atm !SeP97 p.460
! Update drag coefficient based on new Reynolds number
if (ryn_nbr_grv(m) < 0.1_r8) then
cff_drg_grv(m) = 24.0_r8 / ryn_nbr_grv(m) !Stokes' law Sep97 p.463 (8.32)
else if (ryn_nbr_grv(m) < 2.0_r8) then
cff_drg_grv(m) = (24.0_r8/ryn_nbr_grv(m)) * &
(1.0_r8 + 3.0_r8*ryn_nbr_grv(m)/16.0_r8 + &
9.0_r8*ryn_nbr_grv(m)*ryn_nbr_grv(m)* &
log(2.0_r8*ryn_nbr_grv(m))/160.0_r8) !Sep97 p.463 (8.32)
else if (ryn_nbr_grv(m) < 500.0_r8) then
cff_drg_grv(m) = (24.0_r8/ryn_nbr_grv(m)) * &
(1.0_r8 + 0.15_r8*ryn_nbr_grv(m)**0.687_r8) !Sep97 p.463 (8.32)
else if (ryn_nbr_grv(m) < 2.0e5_r8) then
cff_drg_grv(m) = 0.44_r8 !Sep97 p.463 (8.32)
else
write(iulog,'(a,es9.2)') "ryn_nbr_grv(m) = ",ryn_nbr_grv(m)
call endrun
('Dustini error: Reynolds number too large in stk_crc_get()')
endif
! Update terminal velocity based on new Reynolds number and drag coeff
! [m s-1] Terminal veloc SeP97 p.467 (8.44)
vlc_grv(m) = sqrt(4.0_r8 * gravit * dmt_vwr(m) * slp_crc(m) * dns_aer / &
(3.0_r8*cff_drg_grv(m)*dns_mdp))
eps_crr = abs((vlc_grv(m)-vlc_grv_old)/vlc_grv(m)) !Relative convergence
if (itr_idx == 12) then
! Numerical pingpong may occur when Re = 0.1, 2.0, or 500.0
! due to discontinuities in derivative of drag coefficient
vlc_grv(m) = 0.5_r8 * (vlc_grv(m)+vlc_grv_old) ! [m s-1]
endif
if (itr_idx > 20) then
write(iulog,*) 'Dustini error: Terminal velocity not converging ',&
' in stk_crc_get(), breaking loop...'
goto 100 !to next iteration
endif
itr_idx = itr_idx + 1
end do !end while
100 continue !Label to jump to when iteration does not converge
end do !end loop over size
! Compute factors to convert Stokes' settling velocities to
! actual settling velocities
do m = 1, dust_number
stk_crc(m) = vlc_grv(m) / vlc_stk(m)
end do
return
end subroutine Dustini
!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: subroutine DustDryDep(c)
!
! !INTERFACE:
!
subroutine DustDryDep(ncol,t,pmid,ram1,fv,vlc_dry,vlc_trb,vlc_grv,landfrac) 2,3
!
! !DESCRIPTION:
!
! Determine Turbulent dry deposition for dust. Calculate the turbulent
! component of dust dry deposition, (the turbulent deposition velocity
! through the lowest atmospheric layer. CAM will calculate the settling
! velocity through the whole atmospheric column. The two calculations
! will determine the dust dry deposition flux to the surface.
! Note: Same process should occur over oceans. For the coupled CCSM,
! we may find it more efficient to let CAM calculate the turbulent dep
! velocity over all surfaces. This would require passing the
! aerodynamic resistance, ram(1), and the friction velocity, fv, from
! the land to the atmosphere component. In that case, dustini need not
! calculate particle diamter (dmt_vwr) and particle density (dns_aer).
! Source: C. Zender's dry deposition code
!
! !USES
!
use physconst
, only: rair,pi,boltz
!
! !ARGUMENTS:
!
implicit none
!
real(r8) :: t(pcols,pver) !atm temperature (K)
real(r8) :: pmid(pcols,pver) !atm pressure (Pa)
real(r8) :: rho !atm density (kg/m**3)
real(r8),intent(in) :: fv(pcols) !friction velocity (m/s)
real(r8),intent(in) :: ram1(pcols)
! real(r8) :: ramxo1(pcols) !aerodynamical resistance (s/m)
real(r8) :: vlc_trb(pcols,ndst) !Turbulent deposn velocity (m/s)
real(r8) :: vlc_grv(pcols,pver,ndst) !grav deposn velocity (m/s)
real(r8) :: vlc_dry(pcols,pver,ndst) !dry deposn velocity (m/s)
real(r8), intent(in) :: landfrac(pcols) ! land fraction
integer, intent(in) :: ncol
!
! !REVISION HISTORY
! Created by Sam Levis
! Modified for CAM by Natalie Mahowald
!EOP
!------------------------------------------------------------------------
!------------------------------------------------------------------------
! Local Variables
integer :: m,i,k !indices
real(r8) :: vsc_dyn_atm(pcols,pver) ![kg m-1 s-1] Dynamic viscosity of air
real(r8) :: vsc_knm_atm(pcols,pver) ![m2 s-1] Kinematic viscosity of atmosphere
real(r8) :: shm_nbr_xpn ![frc] Sfc-dep exponent for aerosol-diffusion dependence on Schmidt number
real(r8) :: shm_nbr ![frc] Schmidt number
real(r8) :: stk_nbr ![frc] Stokes number
real(r8) :: mfp_atm(pcols,pver) ![m] Mean free path of air
real(r8) :: dff_aer ![m2 s-1] Brownian diffusivity of particle
real(r8) :: rss_trb ![s m-1] Resistance to turbulent deposition
real(r8) :: slp_crc(pcols,pver,ndst) ![frc] Slip correction factor
real(r8) :: rss_lmn(ndst) ![s m-1] Quasi-laminar layer resistance
real(r8) :: tmp !temporary
! constants
real(r8),parameter::shm_nbr_xpn_lnd=-2._r8/3._r8 ![frc] shm_nbr_xpn over land
real(r8),parameter::shm_nbr_xpn_ocn=-1._r8/2._r8 ![frc] shm_nbr_xpn over land
! needs fv and ram1 passed in from lnd model
!------------------------------------------------------------------------
do k=1,pver
do i=1,ncol
rho=pmid(i,k)/rair/t(i,k)
! from subroutine dst_dps_dry (consider adding sanity checks from line 212)
! when code asks to use midlayer density, pressure, temperature,
! I use the data coming in from the atmosphere, ie t(i,k), pmid(i,k)
! Quasi-laminar layer resistance: call rss_lmn_get
! Size-independent thermokinetic properties
vsc_dyn_atm(i,k) = 1.72e-5_r8 * ((t(i,k)/273.0_r8)**1.5_r8) * 393.0_r8 / &
(t(i,k)+120.0_r8) ![kg m-1 s-1] RoY94 p. 102
mfp_atm(i,k) = 2.0_r8 * vsc_dyn_atm(i,k) / & ![m] SeP97 p. 455
(pmid(i,k)*sqrt(8.0_r8/(pi*rair*t(i,k))))
vsc_knm_atm(i,k) = vsc_dyn_atm(i,k) / rho ![m2 s-1] Kinematic viscosity of air
do m = 1, dust_number
slp_crc(i,k,m) = 1.0_r8 + 2.0_r8 * mfp_atm(i,k) * &
(1.257_r8+0.4_r8*exp(-1.1_r8*dmt_vwr(m)/(2.0_r8*mfp_atm(i,k)))) / &
dmt_vwr(m) ![frc] Slip correction factor SeP97 p. 464
vlc_grv(i,k,m) = (1.0_r8/18.0_r8) * dmt_vwr(m) * dmt_vwr(m) * dns_aer * &
gravit * slp_crc(i,k,m) / vsc_dyn_atm(i,k) ![m s-1] Stokes' settling velocity SeP97 p. 466
vlc_grv(i,k,m) = vlc_grv(i,k,m) * stk_crc(m) ![m s-1] Correction to Stokes settling velocity
vlc_dry(i,k,m)=vlc_grv(i,k,m)
end do
enddo
enddo
k=pver ! only look at bottom level for next part
do i=1,ncol
do m = 1, dust_number
stk_nbr = vlc_grv(i,k,m) * fv(i) * fv(i) / (gravit*vsc_knm_atm(i,k)) ![frc] SeP97 p.965
dff_aer = boltz * t(i,k) * slp_crc(i,k,m) / & ![m2 s-1]
(3.0_r8*pi*vsc_dyn_atm(i,k)*dmt_vwr(m)) !SeP97 p.474
shm_nbr = vsc_knm_atm(i,k) / dff_aer ![frc] SeP97 p.972
! shm_nbr_xpn=shm_nbr_xpn_ocn
! if(landfrac(i) .gt. 0.5_r8 ) shm_nbr_xpn = shm_nbr_xpn_lnd ![frc]
shm_nbr_xpn = shm_nbr_xpn_lnd
! fxm: Turning this on dramatically reduces
! deposition velocity in low wind regimes
! Schmidt number exponent is -2/3 over solid surfaces and
! -1/2 over liquid surfaces SlS80 p. 1014
! if (oro(i)==0.0) shm_nbr_xpn=shm_nbr_xpn_ocn else shm_nbr_xpn=shm_nbr_xpn_lnd
! [frc] Surface-dependent exponent for aerosol-diffusion dependence on Schmidt #
tmp = shm_nbr**shm_nbr_xpn + 10.0_r8**(-3.0_r8/stk_nbr)
rss_lmn(m) = 1.0_r8 / (tmp*fv(i)) ![s m-1] SeP97 p.972,965
end do
! Lowest layer: Turbulent deposition (CAM will calc. gravitational dep)
do m = 1, dust_number
rss_trb = ram1(i) + rss_lmn(m) + ram1(i)*rss_lmn(m)*vlc_grv(i,k,m) ![s m-1]
vlc_trb(i,m) = 1.0_r8 / rss_trb ![m s-1]
vlc_dry(i,k,m) = vlc_trb(i,m) +vlc_grv(i,k,m)
end do
end do !end ncols loop
return
end subroutine DustDryDep
end module dust_intr