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