module rad_constituents 8,12
!------------------------------------------------------------------------------------------------
! Purpose:
!
! Provide constituent distributions to the radiation routines.
!
! By default the subroutine that returns constituent mixing ratios returns
! the distribution to be used for the interactive calculation. That method
! also provides an optional argument for indicating that the requested
! distribution is passive and only used in the diagnostic radiative forcing
! calculation.
!
! The logic to control which constituent distribution is interactive and
! which is passive is contained in this module. By default, if a prognostic
! version of a constituent is found (by looking in the constituent array),
! then it is used for the interactive calculation, and a prescribed
! distribution will be used for the diagnostic calculation.
!
! Revision history:
! 2004-08-28 B. Eaton Original version
! 2005-02-01 B. Eaton Add functionality for non-constant CO2
!------------------------------------------------------------------------------------------------
use shr_kind_mod
, only: r8 => shr_kind_r8
use spmd_utils
, only: masterproc
use error_messages
, only: alloc_err
use abortutils
, only: endrun
use cam_logfile
, only: iulog
use ppgrid
, only: pcols, pver
use physconst
, only: rga
use physics_types
, only: physics_state
use phys_buffer
, only: pbuf_size_max, pbuf_fld, pbuf_get_fld_name
use constituents
, only: cnst_name, cnst_get_ind
use radconstants
, only: gasnamelength, nradgas, gaslist, rad_gas_index, ot_length
use cam_history
, only: addfld, fieldname_len, phys_decomp, add_default, outfld
implicit none
private
save
! Public interfaces
public :: &
rad_cnst_readnl, &! read namelist values and parse
rad_cnst_init, &! find optics files and all constituents
rad_cnst_get_clim_info, &! return info about climate lists
rad_cnst_get_clim_gas, &! return pointer to mmr for gasses in climate list
rad_cnst_get_clim_aer, &! return pointer to mmr for aerosols in climate list
rad_cnst_get_clim_aer_props, &! return physical properties for aerosols in the climate list
rad_cnst_out, &! output constituent diagnostics (mass per layer and column burden)
rad_cnst_get_diag_list ! return list of diagnostic calls to radiation
! Private module data
integer, parameter :: N_RAD_CNST = 100
integer, public, parameter :: N_DIAG = 10
integer, parameter :: cs1 = 256
character(len=cs1),public :: iceopticsfile, liqopticsfile
character(len=32),public :: icecldoptics,liqcldoptics
logical,public :: oldcldoptics = .false.
! Namelist variables
character(len=cs1), dimension(N_RAD_CNST) :: rad_climate = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_1 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_2 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_3 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_4 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_5 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_6 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_7 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_8 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_9 = ' '
character(len=cs1), dimension(N_RAD_CNST) :: rad_diag_10 = ' '
type :: rad_cnst_namelist_t
integer :: ncnst
character(len= 1), pointer :: source(:) ! 'D' if in pbuf or 'P' if in state
character(len= 64), pointer :: camname(:) ! name registered in pbuf or constituents
character(len=cs1), pointer :: radname(:) ! radname is the name as identfied in radiation,
! must be one of (rgaslist if a gas) or
! (/fullpath/filename.nc if an aerosol)
character(len= 1), pointer :: type(:) ! 'A' if aerosol or 'G' if gas
end type rad_cnst_namelist_t
! Storage for parsed namelist variables
type(rad_cnst_namelist_t) :: clim_namelist ! list of constituents interacting with climate
type(rad_cnst_namelist_t) :: diag_namelist(N_DIAG) ! constituents for diagnostic calculations
logical :: calldiagnostic(N_DIAG) ! was nth diagnostic call to radiation specified?
type :: gas_t
character(len=1) :: source ='Z' ! P is state, D is pbuf, Z is as near to zero as rad allows
character(len=64) :: camname ! name of constituent in physics state or buffer
character(len=32) :: mass_name ! name for mass per layer field in history output
integer :: idx ! index from constituents or from pbuf
end type gas_t
type :: gaslist_t
integer :: ngas
character(len=2) :: list_id ! set to " " for climate list, or two character integer
! (include leading zero) to identify diagnostic list
type(gas_t), pointer :: gas(:) ! dimension(ngas) where ngas = nradgas is from radconstants
end type gaslist_t
! Storage for gas identifiers
type(gaslist_t), target :: clim_gaslist ! gasses interacting with climate
type(gaslist_t), target :: diag_gaslist(N_DIAG) ! gasses used in diagnostic calculations
type :: aerosol_t
character(len=1) :: source ! (numaersols) P is state, D is pbuf.
character(len=64) :: camname ! name of constituent in physics state or buffer
character(len=32) :: mass_name ! name for mass per layer field in history output
integer :: idx ! index of constituent in physics state or buffer
integer :: physprop_id ! ID used to access physical properties from phys_prop module
end type aerosol_t
type :: aerlist_t
integer :: numaerosols ! number of aerosols
character(len=2) :: list_id ! set to " " for climate list, or two character integer
! (include leading zero) to identify diagnostic list
type(aerosol_t), pointer :: aer(:) ! dimension(numaerosols)
end type aerlist_t
! Storage for aerosol identifiers and associated physical properties
type(aerlist_t), target :: clim_aerosollist ! list of aerosols interacting with climate
type(aerlist_t), target :: diag_aerosollist(N_DIAG) ! list of aerosols used in diagnostic calcs
! mmr values for gasses required by radiation but for which no source data is specified
real(r8), allocatable, target :: zerommr(:,:)
! produce a bunch of output about what is being associated by this module
logical :: debugthiscode = .true.
!==============================================================================
contains
!==============================================================================
subroutine rad_cnst_readnl(nlfile) 1,34
! Read rad_cnst_nl namelist group. Parse input.
use namelist_utils
, only: find_group_name
use units
, only: getunit, freeunit
use mpishorthand
character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
! Local variables
integer :: unitn, ierr, i
character(len=*), parameter :: subname = 'rad_cnst_readnl'
namelist /rad_cnst_nl/ rad_climate, &
rad_diag_1, &
rad_diag_2, &
rad_diag_3, &
rad_diag_4, &
rad_diag_5, &
rad_diag_6, &
rad_diag_7, &
rad_diag_8, &
rad_diag_9, &
rad_diag_10,&
iceopticsfile, &
liqopticsfile, &
icecldoptics, &
liqcldoptics, &
oldcldoptics
!-----------------------------------------------------------------------------
if (masterproc) then
unitn = getunit
()
open( unitn, file=trim(nlfile), status='old' )
call find_group_name
(unitn, 'rad_cnst_nl', status=ierr)
if (ierr == 0) then
read(unitn, rad_cnst_nl, iostat=ierr)
if (ierr /= 0) then
call endrun
(subname // ':: ERROR reading namelist')
end if
end if
close(unitn)
call freeunit
(unitn)
end if
#ifdef SPMD
! Broadcast namelist variables
call mpibcast
(rad_climate, len(rad_climate(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_1, len(rad_diag_1(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_2, len(rad_diag_2(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_3, len(rad_diag_3(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_4, len(rad_diag_4(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_5, len(rad_diag_5(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_6, len(rad_diag_6(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_7, len(rad_diag_7(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_8, len(rad_diag_8(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_9, len(rad_diag_9(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(rad_diag_10, len(rad_diag_10(1))*N_RAD_CNST, mpichar, 0, mpicom)
call mpibcast
(iceopticsfile, len(iceopticsfile), mpichar, 0, mpicom)
call mpibcast
(liqopticsfile, len(liqopticsfile), mpichar, 0, mpicom)
call mpibcast
(liqcldoptics, len(liqcldoptics), mpichar, 0, mpicom)
call mpibcast
(icecldoptics, len(icecldoptics), mpichar, 0, mpicom)
call mpibcast
(oldcldoptics, 1, mpilog , 0, mpicom)
#endif
! Parse the namelist input.
call parse_rad_specifier
(rad_climate, clim_namelist)
do i = 1,N_DIAG
select case (i)
case (1)
call parse_rad_specifier
(rad_diag_1, diag_namelist(i))
case (2)
call parse_rad_specifier
(rad_diag_2, diag_namelist(i))
case (3)
call parse_rad_specifier
(rad_diag_3, diag_namelist(i))
case (4)
call parse_rad_specifier
(rad_diag_4, diag_namelist(i))
case (5)
call parse_rad_specifier
(rad_diag_5, diag_namelist(i))
case (6)
call parse_rad_specifier
(rad_diag_6, diag_namelist(i))
case (7)
call parse_rad_specifier
(rad_diag_7, diag_namelist(i))
case (8)
call parse_rad_specifier
(rad_diag_8, diag_namelist(i))
case (9)
call parse_rad_specifier
(rad_diag_9, diag_namelist(i))
case (10)
call parse_rad_specifier
(rad_diag_10, diag_namelist(i))
end select
enddo
! were there any constituents specified for the nth diagnostic call?
! if so, radiation will make a call with those consituents
calldiagnostic(:) = (diag_namelist(:)%ncnst > 0)
end subroutine rad_cnst_readnl
!================================================================================================
subroutine rad_cnst_init(pbuf, phys_state) 1,11
use phys_prop
, only: physprop_accum_unique_files, physprop_init
type(pbuf_fld), intent(in) :: pbuf(pbuf_size_max)
type(physics_state), pointer :: phys_state(:)
integer :: num_aerosols
integer :: i
character(len=2) :: suffix
logical, parameter :: stricttest = .true.
!-----------------------------------------------------------------------------
! The list_id component can be used to identify whether a given list is the
! active (climate) constituents or one of the lists for diagnostic calculations
clim_gaslist%list_id = " "
clim_aerosollist%list_id = " "
! Create a list of the unique set of filenames containing property data
call physprop_accum_unique_files
(clim_namelist%radname, clim_namelist%type, num_aerosols)
clim_aerosollist%numaerosols = num_aerosols
do i = 1,N_DIAG
if ( diag_namelist(i)%ncnst > 0 ) then
call physprop_accum_unique_files
(diag_namelist(i)%radname, diag_namelist(i)%type, num_aerosols)
write ( suffix, fmt = '(i2.2)' ) i
diag_aerosollist(i)%numaerosols = num_aerosols
diag_aerosollist(i)%list_id = suffix
diag_gaslist(i)%list_id = suffix
else
diag_aerosollist(i)%numaerosols = 0
endif
enddo
! Allocate storage for the physical properties of each aerosol; read properties from
! the data files.
call physprop_init
()
! Start checking that specified radiative constituents are present
if (masterproc) write(iulog,*) 'rad_cnst_init: checking for radiative constituents'
! Initialize the gas and aerosol lists for the constituents affecting the climate.
call init_lists
(clim_namelist, clim_gaslist, clim_aerosollist, pbuf, phys_state)
! Check that all gases supported by the radiative transfer code have been specified.
if(stricttest) then
do i = 1, nradgas
if (clim_gaslist%gas(i)%source .eq. 'Z' ) then
call endrun
("list of radiative gasses must include all radiation gasses for the climate specication")
endif
enddo
endif
if (masterproc .and. debugthiscode) call debug_nl
(clim_gaslist, clim_aerosollist)
! Initialize history output of climate diagnostic quantities
call rad_gas_diag_init
(clim_gaslist)
call rad_aer_diag_init
(clim_aerosollist)
! Initialize the gas and aerosol lists for the constituents used in diagnostic calculations
do i = 1,N_DIAG
if (diag_namelist(i)%ncnst > 0) then
call init_lists
(diag_namelist(i), diag_gaslist(i), diag_aerosollist(i), pbuf, phys_state)
if (masterproc .and. debugthiscode) call debug_nl
(diag_gaslist(i), diag_aerosollist(i))
endif
enddo
! memory to point to if no mass is specified
allocate(zerommr(pcols,pver))
zerommr = 0._r8
end subroutine rad_cnst_init
!================================================================================================
subroutine rad_cnst_get_clim_gas(gasname, state, pbuf, mmr, diagnosticindex) 8,1
! Return pointer to mass mixing ratio for the the instance of the gas
! specified to affect the climate simulation.
! Arguments
character(len=*), intent(in) :: gasname
type(physics_state), target, intent(in) :: state
type(pbuf_fld), intent(in) :: pbuf(pbuf_size_max)
real(r8), pointer :: mmr(:,:)
integer, optional, intent(in) :: diagnosticindex
! Local variables
integer :: lchnk
integer :: igas
integer :: idx
character(len=1) :: source
type(gaslist_t),pointer :: gaslist
!-----------------------------------------------------------------------------
gaslist => clim_gaslist
if (present(diagnosticindex)) then
if (diagnosticindex<N_DIAG) then
gaslist => diag_gaslist(diagnosticindex)
endif
endif
lchnk = state%lchnk
! Get index of gas in internal arrays. rad_gas_index will abort if the
! specified gasname is not recognized by the radiative transfer code.
igas = rad_gas_index
(trim(gasname))
! Get data source from the climate gaslist
source = gaslist%gas(igas)%source
idx = gaslist%gas(igas)%idx
select case( source )
case ('P')
mmr => state%q(:,:,idx)
case ('D')
mmr => pbuf(idx)%fld_ptr(1,:,:,lchnk,1)
case ('Z')
mmr => zerommr(:,:)
end select
end subroutine rad_cnst_get_clim_gas
!================================================================================================
subroutine rad_cnst_get_clim_aer(list_idx, state, pbuf, mmr, diagnosticindex) 9,1
! Return pointer to mass mixing ratio for the the instance of the aerosol
! specified to affect the climate simulation.
! This method is used to access the aerosols in the climate list sequentially
! without specifying aerosol names.
! Arguments
integer, intent(in) :: list_idx
type(physics_state), target, intent(in) :: state
type(pbuf_fld), intent(in) :: pbuf(pbuf_size_max)
real(r8), pointer :: mmr(:,:)
integer, optional, intent(in) :: diagnosticindex
! Local variables
integer :: lchnk
integer :: idx
character(len=1) :: source
type(aerlist_t),pointer :: aerlist
!-----------------------------------------------------------------------------
aerlist => clim_aerosollist
if (present(diagnosticindex)) then
if (diagnosticindex<N_DIAG) then
aerlist => diag_aerosollist(diagnosticindex)
endif
endif
lchnk = state%lchnk
! Check for valid input index
if (list_idx < 1 .or. list_idx > aerlist%numaerosols) then
write(iulog,*) 'list_idx= ', list_idx, ' numaerosols= ', aerlist%numaerosols
call endrun
('rad_cnst_get_clim_aer: aerosol list index out of range')
end if
! Get data source from the climate aerosollist
source = aerlist%aer(list_idx)%source
idx = aerlist%aer(list_idx)%idx
select case( source )
case ('P')
mmr => state%q(:,:,idx)
case ('D')
mmr => pbuf(idx)%fld_ptr(1,:,:,lchnk,1)
end select
end subroutine rad_cnst_get_clim_aer
!================================================================================================
subroutine rad_cnst_get_clim_info( naero, aernames, aersources, aerindices, & 12,7
ngas, gasnames, gassources, gasindices, &
use_data_o3, diagnosticindex )
! Return info about aerosol climate list
! Arguments
integer, optional, intent(out) :: naero
integer, optional, intent(out) :: ngas
character(len=64), optional, intent(out) :: aernames(:)
character(len=64), optional, intent(out) :: gasnames(:)
character(len=1), optional, intent(out) :: aersources(:)
character(len=1), optional, intent(out) :: gassources(:)
integer, optional, intent(out) :: aerindices(:)
integer, optional, intent(out) :: gasindices(:)
logical, optional, intent(out) :: use_data_o3
integer, optional, intent(in) :: diagnosticindex
! Local variables
type(gaslist_t), pointer :: gaslist ! local pointer to gas list of interest
type(aerlist_t), pointer :: aerlist ! local pointer to aerosol list of interest
integer :: i
integer :: arrlen ! length of assumed shape array
integer :: gaslen ! length of assumed shape array
integer :: igas ! index of a gas in the gas list
character(len=1) :: source ! P is state, D is pbuf, Z is as near to zero as rad allows
character(len=*), parameter :: subname = 'rad_cnst_get_clim_info'
!-----------------------------------------------------------------------------
gaslist => clim_gaslist
aerlist => clim_aerosollist
if (present(diagnosticindex)) then
if (diagnosticindex<N_DIAG) then
gaslist => diag_gaslist(diagnosticindex)
aerlist => diag_aerosollist(diagnosticindex)
endif
endif
! number of aerosols in list
if (present(naero)) then
naero = aerlist%numaerosols
endif
! number of gases in list
if (present(ngas)) then
ngas = gaslist%ngas
endif
! names of aerosols in list
if (present(aernames)) then
! check that output array is long enough
arrlen = size(aernames)
if (arrlen < aerlist%numaerosols) then
write(iulog,*) subname//': ERROR: naero=', aerlist%numaerosols, ' arrlen=', arrlen
call endrun
(subname//': ERROR: aernames too short')
end if
do i = 1, aerlist%numaerosols
aernames(i) = aerlist%aer(i)%camname
end do
end if
! sources of aerosols in list
if (present(aersources)) then
! check that output array is long enough
arrlen = size(aersources)
if (arrlen < aerlist%numaerosols) then
write(iulog,*) subname//': ERROR: naero=', aerlist%numaerosols, ' arrlen=', arrlen
call endrun
(subname//': ERROR: aersources too short')
end if
do i = 1, aerlist%numaerosols
aersources(i) = aerlist%aer(i)%source
end do
end if
! indices of aerosols in list
if (present(aerindices)) then
! check that output array is long enough
arrlen = size(aerindices)
if (arrlen < aerlist%numaerosols) then
write(iulog,*) subname//': ERROR: naero=', aerlist%numaerosols, ' arrlen=', arrlen
call endrun
(subname//': ERROR: aerindices too short')
end if
do i = 1, aerlist%numaerosols
aerindices(i) = aerlist%aer(i)%idx
end do
end if
! names of gas in list
if (present(gasnames)) then
! check that output array is long enough
gaslen = size(gasnames)
if (gaslen < gaslist%ngas) then
write(iulog,*) subname//': ERROR: ngas=', gaslist%ngas, ' gaslen=', gaslen
call endrun
(subname//': ERROR: gasnames too short')
end if
do i = 1, gaslist%ngas
gasnames(i) = gaslist%gas(i)%camname
end do
end if
! sources of gas in list
if (present(gassources)) then
! check that output array is long enough
gaslen = size(gassources)
if (gaslen < gaslist%ngas) then
write(iulog,*) subname//': ERROR: ngas=', gaslist%ngas, ' gaslen=', gaslen
call endrun
(subname//': ERROR: gassources too short')
end if
do i = 1, gaslist%ngas
gassources(i) = gaslist%gas(i)%source
end do
end if
! indices of gas in list
if (present(gasindices)) then
! check that output array is long enough
gaslen = size(gasindices)
if (gaslen < gaslist%ngas) then
write(iulog,*) subname//': ERROR: ngas=', gaslist%ngas, ' gaslen=', gaslen
call endrun
(subname//': ERROR: gasindices too short')
end if
do i = 1, gaslist%ngas
gasindices(i) = gaslist%gas(i)%idx
end do
end if
! Does the climate calculation use data ozone?
if (present(use_data_o3)) then
! get index of O3 in gas list
igas = rad_gas_index
('O3')
! Get data source from the climate gaslist
source = gaslist%gas(igas)%source
use_data_o3 = .false.
if (source == 'D') use_data_o3 = .true.
endif
end subroutine rad_cnst_get_clim_info
!================================================================================================
subroutine rad_cnst_get_diag_list(diagnosticcalllist)
! Return info about aerosol climate list
! Arguments
logical, intent(out) :: diagnosticcalllist(N_DIAG)
!-----------------------------------------------------------------------------
diagnosticcalllist(:) = calldiagnostic(:)
end subroutine rad_cnst_get_diag_list
!================================================================================================
subroutine rad_cnst_get_clim_aer_props( & 32,32
list_idx, diagnosticindex, opticstype, &
sw_hygro_ext, sw_hygro_ssa, sw_hygro_asm, lw_hygro_ext, &
sw_nonhygro_ext, sw_nonhygro_ssa, sw_nonhygro_asm, &
sw_nonhygro_scat, sw_nonhygro_ascat, lw_ext, &
refindex_real_aer_sw, refindex_im_aer_sw, refindex_real_aer_lw, refindex_im_aer_lw, &
refindex_real_water_sw, refindex_im_water_sw, refindex_real_water_lw, refindex_im_water_lw, &
r_sw_ext, r_sw_scat, r_sw_ascat, r_lw_abs, mu, &
aername, density_aer, hygro_aer, dryrad_aer, dispersion_aer, num_to_mass_aer)
! Return requested properties for specified climate aerosol.
use phys_prop
, only: physprop_get
! Arguments
integer, intent(in) :: list_idx
integer, optional, intent(in) :: diagnosticindex ! index to rad diagnostic call
character(len=ot_length), optional, intent(out) :: opticstype
real(r8), optional, pointer :: sw_hygro_ext(:,:)
real(r8), optional, pointer :: sw_hygro_ssa(:,:)
real(r8), optional, pointer :: sw_hygro_asm(:,:)
real(r8), optional, pointer :: lw_hygro_ext(:,:)
real(r8), optional, pointer :: sw_nonhygro_ext(:)
real(r8), optional, pointer :: sw_nonhygro_ssa(:)
real(r8), optional, pointer :: sw_nonhygro_asm(:)
real(r8), optional, pointer :: sw_nonhygro_scat(:)
real(r8), optional, pointer :: sw_nonhygro_ascat(:)
real(r8), optional, pointer :: lw_ext(:)
real(r8), optional, pointer :: refindex_real_aer_sw(:)
real(r8), optional, pointer :: refindex_im_aer_sw(:)
real(r8), optional, pointer :: refindex_real_aer_lw(:)
real(r8), optional, pointer :: refindex_im_aer_lw(:)
real(r8), optional, pointer :: refindex_real_water_sw(:)
real(r8), optional, pointer :: refindex_im_water_sw(:)
real(r8), optional, pointer :: refindex_real_water_lw(:)
real(r8), optional, pointer :: refindex_im_water_lw(:)
character(len=20), optional, intent(out) :: aername
real(r8), optional, intent(out) :: density_aer
real(r8), optional, intent(out) :: hygro_aer
real(r8), optional, intent(out) :: dryrad_aer
real(r8), optional, intent(out) :: dispersion_aer
real(r8), optional, intent(out) :: num_to_mass_aer
real(r8), optional, pointer :: r_sw_ext(:,:)
real(r8), optional, pointer :: r_sw_scat(:,:)
real(r8), optional, pointer :: r_sw_ascat(:,:)
real(r8), optional, pointer :: r_lw_abs(:,:)
real(r8), optional, pointer :: mu(:)
! Local variables
integer :: id
character(len=*), parameter :: subname = 'rad_cnst_get_clim_aer_props'
type(aerlist_t), pointer :: aerlist
!------------------------------------------------------------------------------------
aerlist => clim_aerosollist
if (present(diagnosticindex)) then
if (diagnosticindex<N_DIAG) then
aerlist => diag_aerosollist(diagnosticindex)
endif
endif
if (list_idx <= 0 .or. list_idx > aerlist%numaerosols) then
if (.not. present(diagnosticindex)) then
write(iulog,*) subname//': climate aerosol list index out of range: ', list_idx
else
write(iulog,*) subname//': aerosol list index out of range: ', list_idx ,' diag call: ',diagnosticindex
endif
call endrun
(subname//': list_idx out of range')
end if
id = aerlist%aer(list_idx)%physprop_id
if (present(opticstype)) call physprop_get
(id, opticstype=opticstype)
if (present(sw_hygro_ext)) call physprop_get
(id, sw_hygro_ext=sw_hygro_ext)
if (present(sw_hygro_ssa)) call physprop_get
(id, sw_hygro_ssa=sw_hygro_ssa)
if (present(sw_hygro_asm)) call physprop_get
(id, sw_hygro_asm=sw_hygro_asm)
if (present(lw_hygro_ext)) call physprop_get
(id, lw_hygro_abs=lw_hygro_ext)
if (present(sw_nonhygro_ext)) call physprop_get
(id, sw_nonhygro_ext=sw_nonhygro_ext)
if (present(sw_nonhygro_ssa)) call physprop_get
(id, sw_nonhygro_ssa=sw_nonhygro_ssa)
if (present(sw_nonhygro_asm)) call physprop_get
(id, sw_nonhygro_asm=sw_nonhygro_asm)
if (present(sw_nonhygro_scat)) call physprop_get
(id, sw_nonhygro_scat=sw_nonhygro_scat)
if (present(sw_nonhygro_ascat)) call physprop_get
(id, sw_nonhygro_ascat=sw_nonhygro_ascat)
if (present(lw_ext)) call physprop_get
(id, lw_abs=lw_ext)
if (present(refindex_real_aer_sw)) call physprop_get
(id, refindex_real_aer_sw=refindex_real_aer_sw)
if (present(refindex_im_aer_sw)) call physprop_get
(id, refindex_im_aer_sw=refindex_im_aer_sw)
if (present(refindex_real_aer_lw)) call physprop_get
(id, refindex_real_aer_lw=refindex_real_aer_lw)
if (present(refindex_im_aer_lw)) call physprop_get
(id, refindex_im_aer_lw=refindex_im_aer_lw)
if (present(refindex_real_water_sw)) call physprop_get
(id, refindex_real_water_sw=refindex_real_water_sw)
if (present(refindex_im_water_sw)) call physprop_get
(id, refindex_im_water_sw=refindex_im_water_sw)
if (present(refindex_real_water_lw)) call physprop_get
(id, refindex_real_water_lw=refindex_real_water_lw)
if (present(refindex_im_water_lw)) call physprop_get
(id, refindex_im_water_lw=refindex_im_water_lw)
if (present(aername)) call physprop_get
(id, aername=aername)
if (present(density_aer)) call physprop_get
(id, density_aer=density_aer)
if (present(hygro_aer)) call physprop_get
(id, hygro_aer=hygro_aer)
if (present(dryrad_aer)) call physprop_get
(id, dryrad_aer=dryrad_aer)
if (present(dispersion_aer)) call physprop_get
(id, dispersion_aer=dispersion_aer)
if (present(num_to_mass_aer)) call physprop_get
(id, num_to_mass_aer=num_to_mass_aer)
if (present(r_lw_abs)) call physprop_get
(id, r_lw_abs=r_lw_abs)
if (present(r_sw_ext)) call physprop_get
(id, r_sw_ext=r_sw_ext)
if (present(r_sw_scat)) call physprop_get
(id, r_sw_scat=r_sw_scat)
if (present(r_sw_ascat)) call physprop_get
(id, r_sw_ascat=r_sw_ascat)
if (present(mu)) call physprop_get
(id, mu=mu)
end subroutine rad_cnst_get_clim_aer_props
!================================================================================================
subroutine rad_cnst_out(state, pbuf, diagnosticindex) 1,4
! Output the mass per layer, and total column burdens for gas and aerosol
! constituents in either the climate or diagnostic lists
! Arguments
type(physics_state), target, intent(in) :: state
type(pbuf_fld), intent(in) :: pbuf(pbuf_size_max)
integer, optional, intent(in) :: diagnosticindex
! Local variables
integer :: i, naer, ngas, lchnk, ncol
integer :: idx
character(len=1) :: source
character(len=32) :: name, cbname
real(r8) :: mass(pcols,pver)
real(r8) :: cb(pcols)
real(r8), pointer :: mmr(:,:)
type(aerlist_t), pointer :: aerlist
type(gaslist_t),pointer :: gaslist
!-----------------------------------------------------------------------------
lchnk = state%lchnk
ncol = state%ncol
! Associate pointer with requested aerosol list
aerlist => clim_aerosollist
if (present(diagnosticindex)) then
if (diagnosticindex<N_DIAG) then
aerlist => diag_aerosollist(diagnosticindex)
endif
endif
naer = aerlist%numaerosols
do i = 1, naer
source = aerlist%aer(i)%source
idx = aerlist%aer(i)%idx
name = aerlist%aer(i)%mass_name
! construct name for column burden field by replacing the 'm_' prefix by 'cb_'
cbname = 'cb_' // name(3:len_trim(name))
select case( source )
case ('P')
mmr => state%q(:,:,idx)
case ('D')
mmr => pbuf(idx)%fld_ptr(1,:,:,lchnk,1)
end select
mass(:ncol,:) = mmr(:ncol,:) * state%pdeldry(:ncol,:) * rga
call outfld
(trim(name), mass, pcols, lchnk)
cb(:ncol) = sum(mass(:ncol,:),2)
call outfld
(trim(cbname), cb, pcols, lchnk)
end do
! Associate pointer with requested gas list
gaslist => clim_gaslist
if (present(diagnosticindex)) then
if (diagnosticindex<N_DIAG) then
gaslist => diag_gaslist(diagnosticindex)
endif
endif
ngas = gaslist%ngas
do i = 1, ngas
source = gaslist%gas(i)%source
idx = gaslist%gas(i)%idx
name = gaslist%gas(i)%mass_name
cbname = 'cb_' // name(3:len_trim(name))
select case( source )
case ('P')
mmr => state%q(:,:,idx)
case ('D')
mmr => pbuf(idx)%fld_ptr(1,:,:,lchnk,1)
end select
mass(:ncol,:) = mmr(:ncol,:) * state%pdeldry(:ncol,:) * rga
call outfld
(trim(name), mass, pcols, lchnk)
cb(:ncol) = sum(mass(:ncol,:),2)
call outfld
(trim(cbname), cb, pcols, lchnk)
end do
end subroutine rad_cnst_out
!================================================================================================
! Private methods
!================================================================================================
subroutine init_lists(namelist, gaslist, aerlist, pbuf, phys_state) 2,17
! Initialize the gas and aerosol lists with the constituents specified in the
! namelist.
use ppgrid
, only: pcols, pver, begchunk, endchunk
use phys_buffer
, only: pbuf_get_fld_idx, pbuf_size_max, pbuf_fld
use physics_types
, only: physics_state
use phys_prop
, only: physprop_get_id
type(rad_cnst_namelist_t), intent(in) :: namelist ! namelist input for climate or diagnostics
type(pbuf_fld), intent(in) :: pbuf(pbuf_size_max)
type(physics_state), pointer :: phys_state(:)
type(gaslist_t), intent(inout) :: gaslist
type(aerlist_t), intent(inout) :: aerlist
! Local variables
integer :: constindx, idx
integer :: igas, ifileindex, aeridx
integer :: istat
integer, parameter :: pbuffailure = -1 ! if pbuf fails, return this value
!-----------------------------------------------------------------------------
! nradgas is set by the radiative transfer code
gaslist%ngas = nradgas
! index into list of aerosols
aeridx = 1
! allocate storage for the aerosol and gas lists
allocate(aerlist%aer(aerlist%numaerosols), stat=istat)
call alloc_err
(istat, 'init_lists', 'aerlist%aer', aerlist%numaerosols)
allocate(gaslist%gas(gaslist%ngas), stat=istat)
call alloc_err
(istat, 'rad_constituents', 'gaslist%gas', gaslist%ngas)
! Loop over the constituents specified in the namelist
do constindx = 1, namelist%ncnst
if (masterproc .and. debugthiscode) &
write(iulog,*) "rad namelist spec: "// trim(namelist%source(constindx)) &
//"_"//trim(namelist%camname(constindx))//":"//trim(namelist%radname(constindx))
! Check that the source specifier is legal.
if (namelist%source(constindx) /= 'D' .and. namelist%source(constindx) /= 'P') then
call endrun
("init_lists: constituent source must either be D or P:"//&
" illegal specifier in namelist input: "//namelist%source(constindx))
end if
! Add constituent to either the aerosol or the gas list.
if (namelist%type(constindx) == 'A') then
! Add to aerosol list
aerlist%aer(aeridx)%source = namelist%source(constindx)
aerlist%aer(aeridx)%camname = namelist%camname(constindx)
! get the physprop_id from the phys_prop module
aerlist%aer(aeridx)%physprop_id = physprop_get_id
(namelist%radname(constindx))
! locate in the pbuf or state
if (namelist%source(constindx) == 'D') then
idx = pbuf_get_fld_idx
(namelist%camname(constindx), pbuffailure)
if (idx == pbuffailure) then
call endrun
('init_lists: data constituent not found in pbuf: '//namelist%camname(constindx))
end if
aerlist%aer(aeridx)%idx = idx
else if (namelist%source(constindx) == 'P') then
call cnst_get_ind
(namelist%camname(constindx), idx, abort=.false.)
if (idx < 0) then
call endrun
('init_lists: prognostic constituent not found in state: '//namelist%camname(constindx))
end if
aerlist%aer(aeridx)%idx = idx
endif
aeridx = aeridx + 1
else
! Add to gas list
! The radiative transfer code requires the input of a specific set of gases
! which is hardwired into the code. The CAM interface to the RT code uses
! the names in the radconstants module to refer to these gases. The user
! interface (namelist) also uses these names to identify the gases treated
! by the RT code. We use the index order set in radconstants for convenience
! only.
! First check that the gas name specified by the user is allowed.
! rad_gas_index will abort on illegal names.
igas = rad_gas_index
(namelist%radname(constindx))
! Set values in the igas index
gaslist%gas(igas)%source = namelist%source(constindx)
gaslist%gas(igas)%camname = namelist%camname(constindx)
! locate in pbuf or state
if (namelist%source(constindx) == 'D') then
idx = pbuf_get_fld_idx
(namelist%camname(constindx), pbuffailure)
if (idx == pbuffailure) then
call endrun
('init_lists: data constituent not found in pbuf: '//namelist%camname(constindx))
end if
gaslist%gas(igas)%idx = idx
else if (namelist%source(constindx) == 'P') then
call cnst_get_ind
(namelist%camname(constindx), idx, abort=.false.)
if (idx < 0) then
call endrun
('init_lists: prognostic constituent not found in state: '//namelist%camname(constindx))
end if
gaslist%gas(igas)%idx = idx
endif
endif ! (gas vs aerosol)
enddo ! loop over constituents
end subroutine init_lists
!================================================================================================
subroutine rad_gas_diag_init(glist) 1,3
! Add diagnostic fields to the master fieldlist.
type(gaslist_t), intent(inout) :: glist
integer :: i, ngas
character(len=64) :: name
character(len=2) :: list_id
character(len=4) :: suffix
character(len=128):: long_name
character(len=32) :: long_name_description
!-----------------------------------------------------------------------------
ngas = glist%ngas
if (ngas == 0) return
! Determine whether this is a climate or diagnostic list.
list_id = glist%list_id
if (len_trim(list_id) == 0) then
suffix = '_c'
long_name_description = ' used in climate calculation'
else
suffix = '_d' // list_id
long_name_description = ' used in diagnostic calculation'
end if
do i = 1, ngas
! construct names for mass per layer diagnostics
name = 'm_' // trim(glist%gas(i)%camname) // trim(suffix)
glist%gas(i)%mass_name = name
long_name = trim(glist%gas(i)%camname)//' mass per layer'//long_name_description
call addfld
(trim(name), 'kg/m^2', pver, 'A', trim(long_name), phys_decomp)
! construct names for column burden diagnostics
name = 'cb_' // trim(glist%gas(i)%camname) // trim(suffix)
long_name = trim(glist%gas(i)%camname)//' column burden'//long_name_description
call addfld
(trim(name), 'kg/m^2', 1, 'A', trim(long_name), phys_decomp)
! error check for name length
if (len_trim(name) > fieldname_len) then
write(iulog,*) 'rad_gas_diag_init: '//trim(name)//' longer than ', fieldname_len, ' characters'
call endrun
('rad_gas_diag_init: name too long: '//trim(name))
end if
end do
end subroutine rad_gas_diag_init
!================================================================================================
subroutine rad_aer_diag_init(alist) 1,3
! Add diagnostic fields to the master fieldlist.
type(aerlist_t), intent(inout) :: alist
integer :: i, naer
character(len=64) :: name
character(len=2) :: list_id
character(len=4) :: suffix
character(len=128):: long_name
character(len=32) :: long_name_description
!-----------------------------------------------------------------------------
naer = alist%numaerosols
if (naer == 0) return
! Determine whether this is a climate or diagnostic list.
list_id = alist%list_id
if (len_trim(list_id) == 0) then
suffix = '_c'
long_name_description = ' used in climate calculation'
else
suffix = '_d' // list_id
long_name_description = ' used in diagnostic calculation'
end if
do i = 1, naer
! construct names for mass per layer diagnostic fields
name = 'm_' // trim(alist%aer(i)%camname) // trim(suffix)
alist%aer(i)%mass_name = name
long_name = trim(alist%aer(i)%camname)//' mass per layer'//long_name_description
call addfld
(trim(name), 'kg/m^2', pver, 'A', trim(long_name), phys_decomp)
! construct names for column burden diagnostic fields
name = 'cb_' // trim(alist%aer(i)%camname) // trim(suffix)
long_name = trim(alist%aer(i)%camname)//' column burden'//long_name_description
call addfld
(trim(name), 'kg/m^2', 1, 'A', trim(long_name), phys_decomp)
! error check for name length
if (len_trim(name) > fieldname_len) then
write(iulog,*) 'rad_aer_diag_init: '//trim(name)//' longer than ', fieldname_len, ' characters'
call endrun
('rad_aer_diag_init: name too long: '//trim(name))
end if
end do
end subroutine rad_aer_diag_init
!================================================================================================
subroutine parse_rad_specifier(specifier, namelist_data) 11,4
!-----------------------------------------------------------------------------
! Private method for parsing the radiation namelist specifiers. The specifiers
! are of the form 'source_camname:radname' where:
! source -- either 'D' for data or 'P' for prognostic
! camname -- the name of a constituent that must be found in the constituent
! component of the state when source=P or in the physics buffer
! when source=D
! radname -- For gases this is a name that identifies the constituent to the
! radiative transfer codes. These names are contained in the
! radconstants module. For aerosols this is a filename, which is
! identified by a ".nc" suffix. The file contains optical and
! other physical properties of the aerosol.
!
! This code also identifies whether the constituent is a gas or an aerosol
! and adds that info to a structure that stores the parsed data.
!-----------------------------------------------------------------------------
character(len=*), dimension(:), intent(in) :: specifier
type(rad_cnst_namelist_t), intent(inout) :: namelist_data
! Local variables
character(len=1), dimension(N_RAD_CNST) :: source
character(len=64), dimension(N_RAD_CNST) :: camname
character(len=cs1), dimension(N_RAD_CNST) :: radname
character(len=1), dimension(N_RAD_CNST) :: type
integer :: number, i,j,k, astat
!-------------------------------------------------------------------------
number = 0
parse_loop: do i = 1, N_RAD_CNST
if ( len_trim(specifier(i)) == 0 ) then
exit parse_loop
endif
! Locate the '-' separating source from camname. This is the first
! occurance of '_' and allows for the possibility that camname or radname
! may also contain underscores.
j = scan( specifier(i),'_')
source(i) = trim(adjustl( specifier(i)(:j-1) ))
! locate the ':' separating camname from radname
k = scan( specifier(i),':')
camname(i) = trim(adjustl( specifier(i)(j+1:k-1) ))
radname(i) = trim(adjustl( specifier(i)(k+1:) ))
! determine the type of constituent
if (index(radname(i),".nc") .gt. 0) then
type(i) = 'A'
else
type(i) = 'G'
end if
number = number+1
end do parse_loop
namelist_data%ncnst = number
if (number == 0) return
allocate(namelist_data%source (number), stat=astat)
if( astat/= 0 ) call endrun
('parse_rad_specifier: not able to allocate namelist_data%source')
allocate(namelist_data%camname(number), stat=astat)
if( astat/= 0 ) call endrun
('parse_rad_specifier: not able to allocate namelist_data%camname')
allocate(namelist_data%radname(number), stat=astat)
if( astat/= 0 ) call endrun
('parse_rad_specifier: not able to allocate namelist_data%radname')
allocate(namelist_data%type(number), stat=astat)
if( astat/= 0 ) call endrun
('parse_rad_specifier: not able to allocate namelist_data%type')
namelist_data%source(:namelist_data%ncnst) = source (:namelist_data%ncnst)
namelist_data%camname(:namelist_data%ncnst) = camname(:namelist_data%ncnst)
namelist_data%radname(:namelist_data%ncnst) = radname(:namelist_data%ncnst)
namelist_data%type(:namelist_data%ncnst) = type(:namelist_data%ncnst)
end subroutine parse_rad_specifier
!================================================================================================
subroutine debug_nl(dgaslist,daerosollist) 2,3
use phys_prop
, only: physprop_get
type(aerlist_t), intent(in) :: daerosollist
type(gaslist_t), intent(in) :: dgaslist
integer :: iconst, id
character(len=256) :: filename
write(iulog,*) ' gaslist'
do iconst = 1,nradgas
if (dgaslist%gas(iconst)%source .eq. 'D') then
write(iulog,*) dgaslist%gas(iconst)%source//'_'//gaslist(iconst)//' has pbuf name:'//&
pbuf_get_fld_name
(dgaslist%gas(iconst)%idx)
else if (dgaslist%gas(iconst)%source .eq. 'P') then
write(iulog,*) dgaslist%gas(iconst)%source//'_'//gaslist(iconst)//' has constituents name:'//&
cnst_name(dgaslist%gas(iconst)%idx)
endif
enddo
write(iulog,*) ' aerosollist'
do iconst = 1,daerosollist%numaerosols
id = daerosollist%aer(iconst)%physprop_id
call physprop_get
(id, sourcefile=filename)
write(iulog,*) trim(daerosollist%aer(iconst)%source)//'_'//trim(daerosollist%aer(iconst)%camname)//&
' optics and phys props in :'//trim(filename)
enddo
end subroutine debug_nl
!================================================================================================
end module rad_constituents