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