module phys_prop 4,5 ! Properties of aerosols that are used by radiation and other parameterizations. ! *****N.B.***** ! This module is a utility used by the rad_constituents module. The properties stored ! here are meant to be accessed via that module. This module knows nothing about how ! this data is associated with the constituents that are radiatively active or those that ! are being used for diagnostic calculations. That is the responsibility of the ! rad_constituents module. use shr_kind_mod, only: r8 => shr_kind_r8 use pio, only: file_desc_t, var_desc_t, pio_get_var, pio_inq_varid, & pio_inq_dimlen, pio_inq_dimid , pio_nowrite, pio_closefile use cam_logfile, only: iulog use abortutils, only: endrun use spmd_utils, only: masterproc use radconstants, only: nrh, nlwbands, nswbands, idx_sw_diag implicit none private save integer, parameter, public :: ot_length = 32 public :: & physprop_accum_unique_files, &! Make a list of the unique set of files that contain properties ! This is an initialization step that must be done before calling physprop_init physprop_init, &! Initialization -- read the input datasets physprop_get_id, &! Return ID used to access the property data from the input files physprop_get ! Return data for specified ID type :: waterprop_type real(r8), pointer :: refindex_real_water_sw(:) real(r8), pointer :: refindex_im_water_sw(:) real(r8), pointer :: refindex_real_water_lw(:) real(r8), pointer :: refindex_im_water_lw(:) endtype waterprop_type ! Data from one input dataset is stored in a structure of type(physprop_type). type :: physprop_type character(len=256) :: sourcefile ! Absolute pathname of data file. character(len=ot_length) :: opticsmethod ! one of {hygro,nonhygro} ! for hygroscopic species of externally mixed aerosols real(r8), pointer :: sw_hygro_ext(:,:) real(r8), pointer :: sw_hygro_ssa(:,:) real(r8), pointer :: sw_hygro_asm(:,:) real(r8), pointer :: lw_hygro_abs(:,:) ! for nonhygroscopic species of externally mixed aerosols real(r8), pointer :: sw_nonhygro_ext(:) real(r8), pointer :: sw_nonhygro_ssa(:) real(r8), pointer :: sw_nonhygro_asm(:) real(r8), pointer :: sw_nonhygro_scat(:) real(r8), pointer :: sw_nonhygro_ascat(:) real(r8), pointer :: lw_abs(:) real(r8), pointer :: refindex_real_aer_sw(:) real(r8), pointer :: refindex_im_aer_sw(:) real(r8), pointer :: refindex_real_aer_lw(:) real(r8), pointer :: refindex_im_aer_lw(:) ! for radius-dependent mass-specific quantities real(r8), pointer :: r_sw_ext(:,:) real(r8), pointer :: r_sw_scat(:,:) real(r8), pointer :: r_sw_ascat(:,:) real(r8), pointer :: r_lw_abs(:,:) real(r8), pointer :: mu(:) ! microphysics parameters. character(len=32) :: aername ! for output of number concentration real(r8) :: density_aer ! density of aerosol (kg/m3) real(r8) :: hygro_aer ! hygroscopicity of aerosol real(r8) :: dryrad_aer ! number mode radius (m) of aerosol size distribution real(r8) :: dispersion_aer ! geometric standard deviation of aerosol size distribution real(r8) :: num_to_mass_aer ! ratio of number concentration to mass concentration (#/kg) ! *** Is this actually (kg/#) ??? endtype physprop_type ! This module stores data in an array of physprop_type structures. The way this data ! is accessed outside the module is via a physprop ID, which is an index into the array. integer :: numphysprops = 0 ! an incremental total across ALL clim and diag constituents type (physprop_type), pointer :: physprop(:) type (waterprop_type) :: waterprop ! Temporary storage location for filenames in namelist, and construction of dynamic index ! to properties. The unique filenames specified in the namelist are the identifiers of ! the properties. Searching the uniquefilenames array provides the index into the physprop ! array. integer, parameter :: maxuniquefiles = 50 character(len=256) :: uniquefilenames(maxuniquefiles) !================================================================================================ contains !================================================================================================ subroutine physprop_accum_unique_files(radname, type, numaerosols) 2,2 ! Count number of aerosols in input radname array. Aerosols are identified ! as strings with a ".nc" suffix. ! Construct a cumulative list of unique filenames containing physical property data. character(len=*), intent(in) :: radname(:) character(len=1), intent(in) :: type(:) integer, intent(out) :: numaerosols integer :: ncnst, i character(len=*), parameter :: subname = 'physprop_accum_unique_files' !------------------------------------------------------------------------------------ ncnst = ubound(radname, 1) numaerosols = 0 do i = 1, ncnst ! check if radname is an aerosol if (type(i) == 'A') then numaerosols = numaerosols + 1 ! check if this filename has been used by another aerosol. If not ! then add it to the list of unique names. if (physprop_get_id(radname(i)) < 0) then numphysprops = numphysprops + 1 if (numphysprops > maxuniquefiles) then write(iulog,*) subname//': request for more than ',maxuniquefiles, ' values' call endrun(subname//': need to increase maxuniquefiles value') end if uniquefilenames(numphysprops) = trim(radname(i)) endif endif enddo end subroutine physprop_accum_unique_files !================================================================================================ subroutine physprop_init() 1,7 ! Read physical properties from the aerosol data files. The optical properties ! are read by the aerosol_optics module. ! ***N.B.*** The calls to physprop_accum_unique_files must be made before calling ! this init routine. physprop_accum_unique_files is responsible for building ! the list of files to be read here. use ioFileMod, only: getfil use cam_pio_utils, only: cam_pio_openfile ! Local variables integer :: fileindex type(file_desc_t) :: nc_id ! index to netcdf file character(len=256) :: locfn ! path to actual file used character(len=32) :: aername_str ! string read from netCDF file -- may contain trailing ! nulls which aren't dealt with by trim() type(var_desc_T) :: aername_id, density_aer_id, dispersion_aer_id, dryrad_aer_id, hygro_aer_id, num_to_mass_aer_id integer :: ierr ! error codes from mpi logical :: debug = .true. !------------------------------------------------------------------------------------ allocate(physprop(numphysprops)) do fileindex = 1, numphysprops nullify(physprop(fileindex)%sw_hygro_ext) nullify(physprop(fileindex)%sw_hygro_ssa) nullify(physprop(fileindex)%sw_hygro_asm) nullify(physprop(fileindex)%lw_hygro_abs) nullify(physprop(fileindex)%sw_nonhygro_ext) nullify(physprop(fileindex)%sw_nonhygro_ssa) nullify(physprop(fileindex)%sw_nonhygro_asm) nullify(physprop(fileindex)%sw_nonhygro_scat) nullify(physprop(fileindex)%sw_nonhygro_ascat) nullify(physprop(fileindex)%lw_abs) nullify(physprop(fileindex)%refindex_real_aer_sw) nullify(physprop(fileindex)%refindex_im_aer_sw) nullify(physprop(fileindex)%refindex_real_aer_lw) nullify(physprop(fileindex)%refindex_im_aer_lw) nullify(physprop(fileindex)%r_sw_ext) nullify(physprop(fileindex)%r_sw_scat) nullify(physprop(fileindex)%r_sw_ascat) nullify(physprop(fileindex)%r_lw_abs) nullify(physprop(fileindex)%mu) call getfil(uniquefilenames(fileindex), locfn, 0) physprop(fileindex)%sourcefile = locfn call cam_pio_openfile(nc_id, locfn, PIO_NOWRITE) call aerosol_optics_init(physprop(fileindex), nc_id) if(fileindex==1) call refindex_water_init(physprop(fileindex), waterprop, nc_id) ! read microphys ierr = pio_inq_varid(nc_id, 'name', aername_id) ierr = pio_get_var(nc_id, aername_id, physprop(fileindex)%aername) ! use GLC function to remove trailing nulls and blanks. ! physprop(fileindex)%aername = aername_str(:GLC(aername_str)) ierr = pio_inq_varid(nc_id, 'density', density_aer_id) ierr = pio_get_var(nc_id, density_aer_id, physprop(fileindex)%density_aer) ierr = pio_inq_varid(nc_id, 'sigma_logr', dispersion_aer_id) ierr = pio_get_var(nc_id, dispersion_aer_id, physprop(fileindex)%dispersion_aer) ierr = pio_inq_varid(nc_id, 'dryrad', dryrad_aer_id) ierr = pio_get_var(nc_id, dryrad_aer_id, physprop(fileindex)%dryrad_aer) ierr = pio_inq_varid(nc_id, 'hygroscopicity', hygro_aer_id) ierr = pio_get_var(nc_id, hygro_aer_id, physprop(fileindex)%hygro_aer) ierr = pio_inq_varid(nc_id, 'num_to_mass_ratio', num_to_mass_aer_id) ierr = pio_get_var(nc_id, num_to_mass_aer_id, physprop(fileindex)%num_to_mass_aer) ! Output select data to log file if (debug .and. masterproc) then if (trim(physprop(fileindex)%aername) == 'SULFATE') then write(iulog, '(2x, a)') '_______ hygroscopic growth in visible band _______' call aer_optics_log_rh('SO4', physprop(fileindex)%sw_hygro_ext(:,idx_sw_diag), & physprop(fileindex)%sw_hygro_ssa(:,idx_sw_diag), physprop(fileindex)%sw_hygro_asm(:,idx_sw_diag)) end if write(iulog, *) ' physprop_init finished for ', trim(physprop(fileindex)%aername) end if call pio_closefile(nc_id) enddo ! fileindex end subroutine physprop_init !================================================================================================ integer function physprop_get_id(filename) 2 ! Look for filename in the global list of unique filenames (module data uniquefilenames). ! If found, return it's index in the list. Otherwise return -1. character(len=*), intent(in) :: filename integer iphysprop physprop_get_id = -1 do iphysprop = 1, numphysprops if(trim(uniquefilenames(iphysprop)) == trim(filename) ) then physprop_get_id = iphysprop return endif enddo end function physprop_get_id !================================================================================================ subroutine physprop_get(id, sourcefile, opticstype, sw_hygro_ext, sw_hygro_ssa, & 31,1 sw_hygro_asm, sw_nonhygro_ext, sw_nonhygro_ssa, sw_nonhygro_asm, & sw_nonhygro_scat, sw_nonhygro_ascat, lw_abs, & aername, density_aer, hygro_aer, dryrad_aer, dispersion_aer, lw_hygro_abs, & 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, & num_to_mass_aer) ! Return requested properties for specified ID. ! Arguments integer, intent(in) :: id character(len=256),optional, intent(out) :: sourcefile ! Absolute pathname of data file. 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_abs(:,:) 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_abs(:) 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 character(len=*), parameter :: subname = 'physprop_get' !------------------------------------------------------------------------------------ if (id <= 0 .or. id > numphysprops) then write(iulog,*) subname//': illegal ID value: ', id call endrun('physprop_get: ID out of range') end if if (present(sourcefile)) sourcefile = physprop(id)%sourcefile if (present(opticstype)) opticstype = physprop(id)%opticsmethod if (present(sw_hygro_ext)) sw_hygro_ext => physprop(id)%sw_hygro_ext if (present(sw_hygro_ssa)) sw_hygro_ssa => physprop(id)%sw_hygro_ssa if (present(sw_hygro_asm)) sw_hygro_asm => physprop(id)%sw_hygro_asm if (present(lw_hygro_abs)) lw_hygro_abs => physprop(id)%lw_hygro_abs if (present(sw_nonhygro_ext)) sw_nonhygro_ext => physprop(id)%sw_nonhygro_ext if (present(sw_nonhygro_ssa)) sw_nonhygro_ssa => physprop(id)%sw_nonhygro_ssa if (present(sw_nonhygro_asm)) sw_nonhygro_asm => physprop(id)%sw_nonhygro_asm if (present(sw_nonhygro_scat)) sw_nonhygro_scat => physprop(id)%sw_nonhygro_scat if (present(sw_nonhygro_ascat)) sw_nonhygro_ascat => physprop(id)%sw_nonhygro_ascat if (present(lw_abs)) lw_abs => physprop(id)%lw_abs if (present(refindex_real_aer_sw)) refindex_real_aer_sw => physprop(id)%refindex_real_aer_sw if (present(refindex_im_aer_sw)) refindex_im_aer_sw => physprop(id)%refindex_im_aer_sw if (present(refindex_real_aer_lw)) refindex_real_aer_lw => physprop(id)%refindex_real_aer_lw if (present(refindex_im_aer_lw)) refindex_im_aer_lw => physprop(id)%refindex_im_aer_lw if (present(refindex_real_water_sw)) refindex_real_water_sw => waterprop%refindex_real_water_sw if (present(refindex_im_water_sw)) refindex_im_water_sw => waterprop%refindex_im_water_sw if (present(refindex_real_water_lw)) refindex_real_water_lw => waterprop%refindex_real_water_lw if (present(refindex_im_water_lw)) refindex_im_water_lw => waterprop%refindex_im_water_lw if (present(aername)) aername = physprop(id)%aername if (present(density_aer)) density_aer = physprop(id)%density_aer if (present(hygro_aer)) hygro_aer = physprop(id)%hygro_aer if (present(dryrad_aer)) dryrad_aer = physprop(id)%dryrad_aer if (present(dispersion_aer)) dispersion_aer = physprop(id)%dispersion_aer if (present(num_to_mass_aer)) num_to_mass_aer = physprop(id)%num_to_mass_aer ! radius-dependent optics if (present(r_sw_ext)) r_sw_ext => physprop(id)%r_sw_ext if (present(r_sw_scat)) r_sw_scat => physprop(id)%r_sw_scat if (present(r_sw_ascat)) r_sw_ascat => physprop(id)%r_sw_ascat if (present(r_lw_abs)) r_lw_abs => physprop(id)%r_lw_abs if (present(mu)) mu => physprop(id)%mu end subroutine physprop_get !================================================================================================ ! Private methods !================================================================================================ subroutine aerosol_optics_init(phys_prop, nc_id) 1,14 ! Determine the opticstype, then call the ! appropriate routine to read the data. type (physprop_type), intent(inout) :: phys_prop ! data after interp onto cam rh mesh type (file_desc_t), intent(in) :: nc_id ! indentifier for netcdf file integer :: opticslength_id, opticslength type(var_desc_t) :: op_type_id integer :: ierr ! mpi error codes character(len=ot_length) :: opticstype_str ! string read from netCDF file -- may contain trailing ! nulls which aren't dealt with by trim() !------------------------------------------------------------------------------------ ierr = pio_inq_dimid(nc_id, 'opticsmethod_len', opticslength_id) ierr = pio_inq_dimlen(nc_id, opticslength_id, opticslength) if ( opticslength .gt. ot_length ) then call endrun(" optics type length in "//phys_prop%sourcefile//" excedes maximum length of 32") endif ierr = pio_inq_varid(nc_id, 'opticsmethod', op_type_id) ierr = pio_get_var(nc_id, op_type_id,phys_prop%opticsmethod ) select case (phys_prop%opticsmethod) case ('zero') call refindex_aer_init(phys_prop, nc_id) call zero_optics_init(phys_prop, nc_id) case ('hygro') call refindex_aer_init(phys_prop, nc_id) call hygro_optics_init(phys_prop, nc_id) case ('hygroscopic') call refindex_aer_init(phys_prop, nc_id) call hygroscopic_optics_init(phys_prop, nc_id) case ('nonhygro') call refindex_aer_init(phys_prop, nc_id) call nonhygro_optics_init(phys_prop, nc_id) case ('insoluble') call refindex_aer_init(phys_prop, nc_id) call insoluble_optics_init(phys_prop, nc_id) case ('volcanic_radius') call volcanic_radius_optics_init(phys_prop, nc_id) case ('volcanic') call volcanic_optics_init(phys_prop, nc_id) ! other types of optics can be added here case default call endrun('aerosol_optics_init: unsupported optics type '//& phys_prop%opticsmethod//' in file '//phys_prop%sourcefile) end select end subroutine aerosol_optics_init !================================================================================================ subroutine hygro_optics_init(phys_prop, nc_id) 1,5 ! Read optics data of type 'hygro' and interpolate it to CAM's rh mesh. type (physprop_type), intent(inout) :: phys_prop ! data after interp onto cam rh mesh type (file_desc_t), intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: ierr ! error flag integer :: rh_idx_id, lw_band_id, sw_band_id integer :: kbnd, krh integer :: rh_id, sw_ext_id, sw_ssa_id, sw_asm_id, lw_ext_id integer :: nbnd, swbands ! temp data from hygroscopic file before interpolation onto cam-rh-mesh integer :: nfilerh ! number of rh values in file real(r8), allocatable, dimension(:) :: frh real(r8), allocatable, dimension(:,:) :: fsw_ext real(r8), allocatable, dimension(:,:) :: fsw_ssa real(r8), allocatable, dimension(:,:) :: fsw_asm real(r8) :: rh ! real rh value on cam rh mesh (indexvalue) !------------------------------------------------------------------------------------ allocate(phys_prop%sw_hygro_ext(nrh,nswbands)) allocate(phys_prop%sw_hygro_ssa(nrh,nswbands)) allocate(phys_prop%sw_hygro_asm(nrh,nswbands)) allocate(phys_prop%lw_abs(nlwbands)) ierr = pio_inq_dimid(nc_id, 'rh_idx', rh_idx_id) ierr = pio_inq_dimlen(nc_id, rh_idx_id, nfilerh) ierr = pio_inq_dimid(nc_id, 'lw_band', lw_band_id) ierr = pio_inq_dimid(nc_id, 'sw_band', sw_band_id) ierr = pio_inq_dimlen(nc_id, lw_band_id, nbnd) if (nbnd .ne. nlwbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of lwbands') ierr = pio_inq_dimlen(nc_id, sw_band_id, swbands) if(swbands .ne. nswbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of sw bands') ierr = pio_inq_varid(nc_id, 'rh', rh_id) ierr = pio_inq_varid(nc_id, 'ext_sw', sw_ext_id) ierr = pio_inq_varid(nc_id, 'ssa_sw', sw_ssa_id) ierr = pio_inq_varid(nc_id, 'asm_sw', sw_asm_id) ierr = pio_inq_varid(nc_id, 'abs_lw', lw_ext_id) ! specific optical properties on file's rh mesh allocate(fsw_ext(nfilerh,nswbands)) allocate(fsw_asm(nfilerh,nswbands)) allocate(fsw_ssa(nfilerh,nswbands)) allocate(frh(nfilerh)) ierr = pio_get_var(nc_id, rh_id, frh) ierr = pio_get_var(nc_id, sw_ext_id, fsw_ext) ierr = pio_get_var(nc_id, sw_ssa_id, fsw_ssa) ierr = pio_get_var(nc_id, sw_asm_id, fsw_asm) ierr = pio_get_var(nc_id, lw_ext_id, phys_prop%lw_abs) ! interpolate onto cam's rh mesh do kbnd = 1,nswbands do krh = 1, nrh rh = 1.0_r8 / nrh * (krh - 1) phys_prop%sw_hygro_ext(krh,kbnd) = & exp_interpol( frh, fsw_ext(:,kbnd) / fsw_ext(1,kbnd), rh ) & * fsw_ext(1, kbnd) phys_prop%sw_hygro_ssa(krh,kbnd) = & lin_interpol( frh, fsw_ssa(:,kbnd) / fsw_ssa(1,kbnd), rh ) & * fsw_ssa(1, kbnd) phys_prop%sw_hygro_asm(krh,kbnd) = & lin_interpol( frh, fsw_asm(:,kbnd) / fsw_asm(1,kbnd), rh ) & * fsw_asm(1, kbnd) enddo enddo deallocate (fsw_ext, fsw_asm, fsw_ssa, frh) end subroutine hygro_optics_init !================================================================================================ subroutine zero_optics_init(phys_prop, nc_id) 1 ! Read optics data of type 'nonhygro' type (physprop_type), intent(inout) :: phys_prop ! storage for file data type (file_desc_t), intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: lw_band_id, sw_band_id integer :: sw_ext_id, sw_ssa_id, sw_asm_id, lw_ext_id integer :: swbands, nbnd integer :: ierr ! error flag !------------------------------------------------------------------------------------ ! perhaps this doesn't even need allocated. allocate (phys_prop%sw_nonhygro_ext(nswbands)) allocate (phys_prop%sw_nonhygro_ssa(nswbands)) allocate (phys_prop%sw_nonhygro_asm(nswbands)) allocate (phys_prop%lw_abs(nlwbands)) phys_prop%sw_nonhygro_ext = 0._r8 phys_prop%sw_nonhygro_ssa = 0._r8 phys_prop%sw_nonhygro_asm = 0._r8 phys_prop%lw_abs = 0._r8 end subroutine zero_optics_init !================================================================================================ subroutine insoluble_optics_init(phys_prop, nc_id) 1,2 ! Read optics data of type 'nonhygro' type (physprop_type), intent(inout) :: phys_prop ! storage for file data type (file_desc_t), intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: lw_band_id, sw_band_id integer :: sw_ext_id, sw_ssa_id, sw_asm_id, lw_ext_id integer :: swbands, nbnd integer :: ierr ! error flag integer :: start(2), count(2) !------------------------------------------------------------------------------------ allocate (phys_prop%sw_nonhygro_ext(nswbands)) allocate (phys_prop%sw_nonhygro_ssa(nswbands)) allocate (phys_prop%sw_nonhygro_asm(nswbands)) allocate (phys_prop%lw_abs(nlwbands)) ierr = pio_inq_dimid(nc_id, 'lw_band', lw_band_id) ierr = pio_inq_dimid(nc_id, 'sw_band', sw_band_id) ierr = pio_inq_dimlen(nc_id, lw_band_id, nbnd) if (nbnd .ne. nlwbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of lwbands') ierr = pio_inq_dimlen(nc_id, sw_band_id, swbands) if (swbands .ne. nswbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of sw bands') ! read file data ierr = pio_inq_varid(nc_id, 'ext_sw', sw_ext_id) ierr = pio_inq_varid(nc_id, 'ssa_sw', sw_ssa_id) ierr = pio_inq_varid(nc_id, 'asm_sw', sw_asm_id) ierr = pio_inq_varid(nc_id, 'abs_lw', lw_ext_id) start = 1 count=(/1,swbands/) ierr = pio_get_var(nc_id, sw_ext_id, start, count, phys_prop%sw_nonhygro_ext) ierr = pio_get_var(nc_id, sw_ssa_id, start, count, phys_prop%sw_nonhygro_ssa) ierr = pio_get_var(nc_id, sw_asm_id, start, count, phys_prop%sw_nonhygro_asm) count = (/1,nbnd/) ierr = pio_get_var(nc_id, lw_ext_id, start, count, phys_prop%lw_abs) end subroutine insoluble_optics_init subroutine volcanic_radius_optics_init(phys_prop, nc_id) 1,2 ! Read optics data of type 'volcanic_radius' type (physprop_type), intent(inout) :: phys_prop ! storage for file data type (file_desc_t), intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: lw_band_id, sw_band_id, mu_id, mu_did integer :: sw_ext_id, sw_scat_id, sw_ascat_id, lw_abs_id integer :: swbands, nbnd, n_mu_samples integer :: ierr ! error flag !------------------------------------------------------------------------------------ ierr = pio_inq_dimid(nc_id, 'mu_samples', mu_did) ierr = pio_inq_dimlen(nc_id, mu_did, n_mu_samples) allocate (phys_prop%r_sw_ext(nswbands,n_mu_samples)) allocate (phys_prop%r_sw_scat(nswbands,n_mu_samples)) allocate (phys_prop%r_sw_ascat(nswbands,n_mu_samples)) allocate (phys_prop%r_lw_abs(nlwbands,n_mu_samples)) allocate (phys_prop%mu(n_mu_samples)) ierr = pio_inq_dimid(nc_id, 'lw_band', lw_band_id) ierr = pio_inq_dimid(nc_id, 'sw_band', sw_band_id) ierr = pio_inq_dimlen(nc_id, lw_band_id, nbnd) if (nbnd .ne. nlwbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of lwbands') ierr = pio_inq_dimlen(nc_id, sw_band_id, swbands) if (swbands .ne. nswbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of sw bands') ! read file data ierr = pio_inq_varid(nc_id, 'bext_sw', sw_ext_id) ierr = pio_inq_varid(nc_id, 'bsca_sw', sw_scat_id) ierr = pio_inq_varid(nc_id, 'basc_sw', sw_ascat_id) ierr = pio_inq_varid(nc_id, 'babs_lw', lw_abs_id) ierr = pio_inq_varid(nc_id, 'mu_samples', mu_id) ierr = pio_get_var(nc_id, sw_ext_id, phys_prop%r_sw_ext) ierr = pio_get_var(nc_id, sw_scat_id, phys_prop%r_sw_scat) ierr = pio_get_var(nc_id, sw_ascat_id, phys_prop%r_sw_ascat) ierr = pio_get_var(nc_id, lw_abs_id, phys_prop%r_lw_abs) ierr = pio_get_var(nc_id, mu_id, phys_prop%mu) end subroutine volcanic_radius_optics_init subroutine volcanic_optics_init(phys_prop, nc_id) 1,2 ! Read optics data of type 'volcanic' type (physprop_type), intent(inout) :: phys_prop ! storage for file data type (file_desc_t) , intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: lw_band_id, sw_band_id integer :: sw_ext_id, sw_scat_id, sw_ascat_id, lw_abs_id integer :: swbands, nbnd integer :: ierr ! error flag !------------------------------------------------------------------------------------ allocate (phys_prop%sw_nonhygro_ext(nswbands)) allocate (phys_prop%sw_nonhygro_scat(nswbands)) allocate (phys_prop%sw_nonhygro_ascat(nswbands)) allocate (phys_prop%lw_abs(nlwbands)) ierr = pio_inq_dimid(nc_id, 'lw_band', lw_band_id) ierr = pio_inq_dimid(nc_id, 'sw_band', sw_band_id) ierr = pio_inq_dimlen(nc_id, lw_band_id, nbnd) if (nbnd .ne. nlwbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of lwbands') ierr = pio_inq_dimlen(nc_id, sw_band_id, swbands) if(masterproc) write(iulog,*) 'swbands',swbands if (swbands .ne. nswbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of sw bands') ! read file data ierr = pio_inq_varid(nc_id, 'bext_sw', sw_ext_id) ierr = pio_inq_varid(nc_id, 'bsca_sw', sw_scat_id) ierr = pio_inq_varid(nc_id, 'basc_sw', sw_ascat_id) ierr = pio_inq_varid(nc_id, 'babs_lw', lw_abs_id) ierr = pio_get_var(nc_id, sw_ext_id, phys_prop%sw_nonhygro_ext) ierr = pio_get_var(nc_id, sw_scat_id, phys_prop%sw_nonhygro_scat) ierr = pio_get_var(nc_id, sw_ascat_id, phys_prop%sw_nonhygro_ascat) ierr = pio_get_var(nc_id, lw_abs_id, phys_prop%lw_abs) end subroutine volcanic_optics_init subroutine hygroscopic_optics_init(phys_prop, nc_id) 1,6 ! Read optics data of type 'hygroscopic' and interpolate it to CAM's rh mesh. type (physprop_type), intent(inout) :: phys_prop ! data after interp onto cam rh mesh type (file_desc_T), intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: ierr ! error flag integer :: rh_idx_id, lw_band_id, sw_band_id integer :: kbnd, krh integer :: rh_id, sw_ext_id, sw_ssa_id, sw_asm_id, lw_ext_id integer :: nbnd, swbands ! temp data from hygroscopic file before interpolation onto cam-rh-mesh integer :: nfilerh ! number of rh values in file real(r8), allocatable, dimension(:) :: frh real(r8), allocatable, dimension(:,:) :: fsw_ext real(r8), allocatable, dimension(:,:) :: fsw_ssa real(r8), allocatable, dimension(:,:) :: fsw_asm real(r8), allocatable, dimension(:,:) :: flw_abs real(r8) :: rh ! real rh value on cam rh mesh (indexvalue) character(len=*), parameter :: sub = 'hygroscopic_optics_init' !------------------------------------------------------------------------------------ allocate(phys_prop%sw_hygro_ext(nrh,nswbands)) allocate(phys_prop%sw_hygro_ssa(nrh,nswbands)) allocate(phys_prop%sw_hygro_asm(nrh,nswbands)) allocate(phys_prop%lw_hygro_abs(nrh,nlwbands)) ierr = pio_inq_dimid(nc_id, 'rh_idx', rh_idx_id) ierr = pio_inq_dimlen(nc_id, rh_idx_id, nfilerh) ierr = pio_inq_dimid(nc_id, 'lw_band', lw_band_id) ierr = pio_inq_dimid(nc_id, 'sw_band', sw_band_id) ierr = pio_inq_dimlen(nc_id, lw_band_id, nbnd) if (nbnd .ne. nlwbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of lwbands') ierr = pio_inq_dimlen(nc_id, sw_band_id, swbands) if(swbands .ne. nswbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of sw bands') ierr = pio_inq_varid(nc_id, 'rh', rh_id) ierr = pio_inq_varid(nc_id, 'ext_sw', sw_ext_id) ierr = pio_inq_varid(nc_id, 'ssa_sw', sw_ssa_id) ierr = pio_inq_varid(nc_id, 'asm_sw', sw_asm_id) ierr = pio_inq_varid(nc_id, 'abs_lw', lw_ext_id) ! specific optical properties on file's rh mesh allocate(fsw_ext(nfilerh,nswbands)) allocate(fsw_asm(nfilerh,nswbands)) allocate(fsw_ssa(nfilerh,nswbands)) allocate(flw_abs(nfilerh,nlwbands)) allocate(frh(nfilerh)) ierr = pio_get_var(nc_id, rh_id, frh) ierr = pio_get_var(nc_id, sw_ext_id, fsw_ext) ierr = pio_get_var(nc_id, sw_ssa_id, fsw_ssa) ierr = pio_get_var(nc_id, sw_asm_id, fsw_asm) ierr = pio_get_var(nc_id, lw_ext_id, flw_abs) ! interpolate onto cam's rh mesh do kbnd = 1,nswbands do krh = 1, nrh rh = 1.0_r8 / nrh * (krh - 1) phys_prop%sw_hygro_ext(krh,kbnd) = & exp_interpol( frh, fsw_ext(:,kbnd) / fsw_ext(1,kbnd), rh ) & * fsw_ext(1, kbnd) phys_prop%sw_hygro_ssa(krh,kbnd) = & lin_interpol( frh, fsw_ssa(:,kbnd) / fsw_ssa(1,kbnd), rh ) & * fsw_ssa(1, kbnd) phys_prop%sw_hygro_asm(krh,kbnd) = & lin_interpol( frh, fsw_asm(:,kbnd) / fsw_asm(1,kbnd), rh ) & * fsw_asm(1, kbnd) enddo enddo do kbnd = 1,nlwbands do krh = 1, nrh rh = 1.0_r8 / nrh * (krh - 1) phys_prop%lw_hygro_abs(krh,kbnd) = & exp_interpol( frh, flw_abs(:,kbnd) / flw_abs(1,kbnd), rh ) & * flw_abs(1, kbnd) enddo enddo deallocate (fsw_ext, fsw_asm, fsw_ssa, flw_abs, frh) end subroutine hygroscopic_optics_init !================================================================================================ subroutine nonhygro_optics_init(phys_prop, nc_id) 1,2 ! Read optics data of type 'nonhygro' type (physprop_type), intent(inout) :: phys_prop ! storage for file data type (file_desc_t) , intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: lw_band_id, sw_band_id integer :: sw_ext_id, sw_ssa_id, sw_asm_id, lw_ext_id integer :: swbands, nbnd integer :: ierr ! error flag !------------------------------------------------------------------------------------ allocate (phys_prop%sw_nonhygro_ext(nswbands)) allocate (phys_prop%sw_nonhygro_ssa(nswbands)) allocate (phys_prop%sw_nonhygro_asm(nswbands)) allocate (phys_prop%lw_abs(nlwbands)) ierr = pio_inq_dimid(nc_id, 'lw_band', lw_band_id) ierr = pio_inq_dimid(nc_id, 'sw_band', sw_band_id) ierr = pio_inq_dimlen(nc_id, lw_band_id, nbnd) if (nbnd .ne. nlwbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of lwbands') ierr = pio_inq_dimlen(nc_id, sw_band_id, swbands) if (swbands .ne. nswbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of sw bands') ! read file data ierr = pio_inq_varid(nc_id, 'ext_sw', sw_ext_id) ierr = pio_inq_varid(nc_id, 'ssa_sw', sw_ssa_id) ierr = pio_inq_varid(nc_id, 'asm_sw', sw_asm_id) ierr = pio_inq_varid(nc_id, 'abs_lw', lw_ext_id) ierr = pio_get_var(nc_id, sw_ext_id, phys_prop%sw_nonhygro_ext) ierr = pio_get_var(nc_id, sw_ssa_id, phys_prop%sw_nonhygro_ssa) ierr = pio_get_var(nc_id, sw_asm_id, phys_prop%sw_nonhygro_asm) ierr = pio_get_var(nc_id, lw_ext_id, phys_prop%lw_abs) end subroutine nonhygro_optics_init subroutine refindex_aer_init(phys_prop, nc_id) 5,2 ! Read refractive indices of aerosol type (physprop_type), intent(inout) :: phys_prop ! storage for file data type (file_desc_T), intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: lw_band_id, sw_band_id integer :: refindex_real_aer_sw_id, refindex_im_aer_sw_id, refindex_real_aer_lw_id, refindex_im_aer_lw_id integer :: swbands, lwbands, i integer :: ierr ! error flag !------------------------------------------------------------------------------------ allocate (phys_prop%refindex_real_aer_sw(nswbands)) allocate (phys_prop%refindex_im_aer_sw(nswbands)) allocate (phys_prop%refindex_real_aer_lw(nlwbands)) allocate (phys_prop%refindex_im_aer_lw(nlwbands)) ierr = pio_inq_dimid(nc_id, 'lw_band', lw_band_id) ierr = pio_inq_dimid(nc_id, 'sw_band', sw_band_id) ierr = pio_inq_dimlen(nc_id, lw_band_id, lwbands) if (lwbands .ne. nlwbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of lwbands') ierr = pio_inq_dimlen(nc_id, sw_band_id, swbands) if (swbands .ne. nswbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of sw bands') ! read file data #ifdef MODAL_AERO ! refindex only needed for MODAL_AERO ierr = pio_inq_varid(nc_id, 'refindex_real_aer_sw', refindex_real_aer_sw_id) ierr = pio_inq_varid(nc_id, 'refindex_im_aer_sw', refindex_im_aer_sw_id) ierr = pio_inq_varid(nc_id, 'refindex_real_aer_lw', refindex_real_aer_lw_id) ierr = pio_inq_varid(nc_id, 'refindex_im_aer_lw', refindex_im_aer_lw_id) ierr = pio_get_var(nc_id, refindex_real_aer_sw_id, phys_prop%refindex_real_aer_sw) ierr = pio_get_var(nc_id, refindex_im_aer_sw_id, phys_prop%refindex_im_aer_sw) ierr = pio_get_var(nc_id, refindex_real_aer_lw_id, phys_prop%refindex_real_aer_lw) ierr = pio_get_var(nc_id, refindex_im_aer_lw_id, phys_prop%refindex_im_aer_lw) ! make sure imaginary component is positive phys_prop%refindex_im_aer_sw(:)=abs(phys_prop%refindex_im_aer_sw(:)) phys_prop%refindex_im_aer_lw(:)=abs(phys_prop%refindex_im_aer_lw(:)) #endif end subroutine refindex_aer_init subroutine refindex_water_init(phys_prop, water_prop, nc_id) 1,2 ! Read refractive indices of water type (physprop_type), intent(inout) :: phys_prop ! storage for file data type (waterprop_type), intent(inout) :: water_prop ! storage for file data type (file_desc_t), intent(in) :: nc_id ! indentifier for netcdf file ! Local variables integer :: lw_band_id, sw_band_id integer :: refindex_real_water_sw_id, refindex_im_water_sw_id, & refindex_real_water_lw_id, refindex_im_water_lw_id integer :: swbands, lwbands integer :: ierr ! error flag !------------------------------------------------------------------------------------ allocate (water_prop%refindex_real_water_sw(nswbands)) allocate (water_prop%refindex_im_water_sw(nswbands)) allocate (water_prop%refindex_real_water_lw(nlwbands)) allocate (water_prop%refindex_im_water_lw(nlwbands)) ierr = pio_inq_dimid(nc_id, 'lw_band', lw_band_id) ierr = pio_inq_dimid(nc_id, 'sw_band', sw_band_id) ierr = pio_inq_dimlen(nc_id, lw_band_id, lwbands) if (lwbands .ne. nlwbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of lwbands') ierr = pio_inq_dimlen(nc_id, sw_band_id, swbands) if (swbands .ne. nswbands) call endrun(phys_prop%sourcefile// & ' has the wrong number of sw bands') #ifdef MODAL_AERO ! refindex only needed for MODAL_AERO ierr = pio_inq_varid(nc_id, 'refindex_real_water_sw', refindex_real_water_sw_id) ierr = pio_inq_varid(nc_id, 'refindex_im_water_sw', refindex_im_water_sw_id) ierr = pio_inq_varid(nc_id, 'refindex_real_water_lw', refindex_real_water_lw_id) ierr = pio_inq_varid(nc_id, 'refindex_im_water_lw', refindex_im_water_lw_id) ierr = pio_get_var(nc_id, refindex_real_water_sw_id, water_prop%refindex_real_water_sw) ierr = pio_get_var(nc_id, refindex_im_water_sw_id, water_prop%refindex_im_water_sw) ierr = pio_get_var(nc_id, refindex_real_water_lw_id, water_prop%refindex_real_water_lw) ierr = pio_get_var(nc_id, refindex_im_water_lw_id, water_prop%refindex_im_water_lw) ! make sure imaginary component is positive water_prop%refindex_im_water_sw(:)=abs(water_prop%refindex_im_water_sw(:)) water_prop%refindex_im_water_lw(:)=abs(water_prop%refindex_im_water_lw(:)) #endif end subroutine refindex_water_init !================================================================================================ function exp_interpol(x, f, y) result(g) 3 ! Purpose: ! interpolates f(x) to point y ! assuming f(x) = f(x0) exp a(x - x0) ! where a = ( ln f(x1) - ln f(x0) ) / (x1 - x0) ! x0 <= x <= x1 ! assumes x is monotonically increasing ! Author: D. Fillmore implicit none real(r8), intent(in), dimension(:) :: x ! grid points real(r8), intent(in), dimension(:) :: f ! grid function values real(r8), intent(in) :: y ! interpolation point real(r8) :: g ! interpolated function value integer :: k ! interpolation point index integer :: n ! length of x real(r8) :: a n = size(x) ! find k such that x(k) < y =< x(k+1) ! set k = 1 if y <= x(1) and k = n-1 if y > x(n) if (y <= x(1)) then k = 1 else if (y >= x(n)) then k = n - 1 else k = 1 do while (y > x(k+1) .and. k < n) k = k + 1 end do end if ! interpolate a = ( log( f(k+1) / f(k) ) ) / ( x(k+1) - x(k) ) g = f(k) * exp( a * (y - x(k)) ) return end function exp_interpol !================================================================================================ function lin_interpol(x, f, y) result(g) 4 ! Purpose: ! interpolates f(x) to point y ! assuming f(x) = f(x0) + a * (x - x0) ! where a = ( f(x1) - f(x0) ) / (x1 - x0) ! x0 <= x <= x1 ! assumes x is monotonically increasing ! Author: D. Fillmore implicit none real(r8), intent(in), dimension(:) :: x ! grid points real(r8), intent(in), dimension(:) :: f ! grid function values real(r8), intent(in) :: y ! interpolation point real(r8) :: g ! interpolated function value integer :: k ! interpolation point index integer :: n ! length of x real(r8) :: a n = size(x) ! find k such that x(k) < y =< x(k+1) ! set k = 1 if y <= x(1) and k = n-1 if y > x(n) if (y <= x(1)) then k = 1 else if (y >= x(n)) then k = n - 1 else k = 1 do while (y > x(k+1) .and. k < n) k = k + 1 end do end if ! interpolate a = ( f(k+1) - f(k) ) / ( x(k+1) - x(k) ) g = f(k) + a * (y - x(k)) return end function lin_interpol !================================================================================================ subroutine aer_optics_log(name, ext, ssa, asm) ! Purpose: ! write aerosol optical constants to log file ! Author: D. Fillmore character(len=*), intent(in) :: name real(r8), intent(in) :: ext(:) real(r8), intent(in) :: ssa(:) real(r8), intent(in) :: asm(:) integer :: kbnd, nbnd !------------------------------------------------------------------------------------ nbnd = ubound(ext, 1) write(iulog, '(2x, a)') name write(iulog, '(2x, a, 4x, a, 4x, a, 4x, a)') 'SW band', 'ext (m^2 kg^-1)', ' ssa', ' asm' do kbnd = 1, nbnd write(iulog, '(2x, i7, 4x, f13.2, 4x, f4.2, 4x, f4.2)') kbnd, ext(kbnd), ssa(kbnd), asm(kbnd) end do end subroutine aer_optics_log !================================================================================================ subroutine aer_optics_log_rh(name, ext, ssa, asm) 1 ! Purpose: ! write out aerosol optical properties ! for a set of test rh values ! to test hygroscopic growth interpolation ! Author: D. Fillmore character(len=*), intent(in) :: name real(r8), intent(in) :: ext(nrh) real(r8), intent(in) :: ssa(nrh) real(r8), intent(in) :: asm(nrh) integer :: krh_test integer, parameter :: nrh_test = 36 integer :: krh real(r8) :: rh real(r8) :: rh_test(nrh_test) real(r8) :: exti real(r8) :: ssai real(r8) :: asmi real(r8) :: wrh !------------------------------------------------------------------------------------ do krh_test = 1, nrh_test rh_test(krh_test) = sqrt(sqrt(sqrt(sqrt(((krh_test - 1.0_r8) / (nrh_test - 1)))))) enddo write(iulog, '(2x, a)') name write(iulog, '(2x, a, 4x, a, 4x, a, 4x, a)') ' rh', 'ext (m^2 kg^-1)', ' ssa', ' asm' ! loop through test rh values do krh_test = 1, nrh_test ! find corresponding rh index rh = rh_test(krh_test) krh = min(floor( (rh) * nrh ) + 1, nrh - 1) wrh = (rh) *nrh - krh exti = ext(krh + 1) * (wrh + 1) - ext(krh) * wrh ssai = ssa(krh + 1) * (wrh + 1) - ssa(krh) * wrh asmi = asm(krh + 1) * (wrh + 1) - asm(krh) * wrh write(iulog, '(2x, f5.3, 4x, f13.3, 4x, f5.3, 4x, f5.3)') rh_test(krh_test), exti, ssai, asmi end do end subroutine aer_optics_log_rh !================================================================================================ end module phys_prop