module modal_aer_opt 3,10

#ifdef MODAL_AERO
!     parameterizes aerosol coefficients using chebychev polynomial
!     parameterize aerosol radiative properties in terms of
!     surface mode wet radius and wet refractive index

!     Ghan and Zaveri, JGR 2007.

!     uses Wiscombe's (1979) mie scattering code


use shr_kind_mod,      only: r8 => shr_kind_r8
use ppgrid,            only: pcols, pver, pverp, begchunk, endchunk
use abortutils,        only: endrun
use constituents,      only: pcnst
use spmd_utils,        only: masterproc
use error_messages,    only: handle_ncerr
use modal_aero_data,   only: maxd_amode, maxd_aspectype, ntot_amode, ntot_aspectype, &
                             nspec_amode, lspectype_amode, lmassptr_amode, numptr_amode, alnsg_amode, &
                             specrefndxsw, specrefndxlw, specdens_amode,   &
!++xl added 11/24/2009, dust AOD
                             lptr_dust_a_amode, specdens_dust_amode, &
!--dust AOD
		             sigmag_amode, species_class, spec_class_aerosol
   use physconst,      only: rhoh2o
   use cam_history,    only: phys_decomp, addfld, add_default
   use perf_mod
   use radconstants,   only: nswbands, nlwbands
   use cam_logfile,    only: iulog

implicit none
private
save
      public :: modal_aer_opt_init, modal_size_parameters, modal_aero_sw, modal_aero_lw


      integer nrefr,nrefi,nr,ni
      integer, parameter :: prefr=7,prefi=10

      integer, parameter, public :: ncoef=5

!     coefficients for parameterizing aerosol radiative properties
!     in terms of refractive index and wet radius
      real(r8) extpsw(ncoef,prefr,prefi,maxd_amode,nswbands) ! specific extinction
      real(r8) abspsw(ncoef,prefr,prefi,maxd_amode,nswbands) ! specific absorption
      real(r8) asmpsw(ncoef,prefr,prefi,maxd_amode,nswbands) ! asymmetry factor
      real(r8) extplw(ncoef,prefr,prefi,maxd_amode,nlwbands) ! specific extinction
      real(r8) absplw(ncoef,prefr,prefi,maxd_amode,nlwbands) ! specific absorption
      real(r8) asmplw(ncoef,prefr,prefi,maxd_amode,nlwbands) ! asymmetry factor
#ifdef AEROCOM
      logical saveaerocom
      complex crefw_aerocom(naerocom)
      real(r8) extp_aerocom(ncoef,prefr,prefi,maxd_amode,naerocom)
      real(r8) absp_aerocom(ncoef,prefr,prefi,maxd_amode,naerocom)
      real(r8) asmp_aerocom(ncoef,prefr,prefi,maxd_amode,naerocom)
      real(r8) refrtab_aerocom(prefr,naerocom),refitab_aerocom(prefi,naerocom)
#endif
      integer, parameter :: pnangle=1

!     specabs = absorption coeff / unit dry mass
!     specscat = scattering coeff / unit dry mass
      complex crefin
      complex, public :: crefwsw(nswbands) ! complex refractive index for water visible
      complex, public :: crefwlw(nlwbands) ! complex refractive index for water infrared
      real(r8), pointer :: refrwsw(:),refiwsw(:) ! real, imaginary ref index for water visible
      real(r8), pointer :: refrwlw(:),refiwlw(:) ! real, imaginary ref index for water infrared
!      data refrwsw/19*1.33/
!      data refiwsw/8*1.e-9,1.5e-8,7*1.e-5,6.e-2,2*1.e-2/
      real(r8) pie

      real(r8) rmmin,rmmax ! min, max aerosol surface mode radius treated (m)
      real(r8) xrmin,xrmax

      real(r8) refrmin ! minimum of real part of refractive index
      real(r8) refrmax ! maximum of real part of refractive index
      real(r8) refimin ! minimum of imag part of refractive index
      real(r8) refimax ! maximum of imag part of refractive index
      real(r8) refrtabsw(prefr,nswbands) ! table of real refractive indices for aerosols visible
      real(r8) refitabsw(prefi,nswbands) ! table of imag refractive indices for aerosols visible
      real(r8) refrtablw(prefr,nlwbands) ! table of real refractive indices for aerosols infrared
      real(r8) refitablw(prefi,nlwbands) ! table of imag refractive indices for aerosols infrared
#if (defined BACKSCAT)
      real(r8)  angmin, angmax=3.14 ! minimum, maximum scattering angle
      real(r8)  ang(pnangle), xmu(pnangle)
#endif
!===============================================================================
CONTAINS
!===============================================================================

   subroutine modal_aer_opt_init(wavminsw,wavmaxsw,wavenumber1_longwave,wavenumber2_longwave),55

  use rad_constituents, only: rad_cnst_get_clim_aer_props
   use ioFileMod,    only: getfil
   use filenames,    only: modal_optics
#if ( defined SPMD )
   use mpishorthand,   only: mpicom, mpiint, mpir8, mpichar
#endif

implicit none

      real(r8), intent(in):: wavmaxsw(nswbands)
      real(r8), intent(in):: wavminsw(nswbands)
      real(r8), intent(in):: wavenumber1_longwave(nlwbands) ! (cm-1)
      real(r8), intent(in):: wavenumber2_longwave(nlwbands) ! (cm-1)
      real(r8) wavmidsw(nswbands) ! middle wavelength of shortwave band (m)
      real(r8) wavmidlw(nlwbands) ! middle wavelength of longwave band (m)
      real(r8) refr,refi
      integer lw_band_len
      integer  :: nc_id ! index to netcdf file
      character*256 outfilename,infilename
      logical, parameter :: calc_optics = .false.
      integer :: ierr ! error codes from pio


      integer ns, m, l, ltype

      call rad_cnst_get_clim_aer_props(1, &
                            refindex_real_water_sw=refrwsw,  &
                            refindex_im_water_sw=refiwsw,  &
			    refindex_real_water_lw=refrwlw,  &
			    refindex_im_water_lw=refiwlw)

      pie=4._r8*atan(1._r8)

      nrefr=prefr
      nrefi=prefi
      rmmin=0.01e-6
      rmmax=25.e-6
      xrmin=log(rmmin)
      xrmax=log(rmmax)

#if (defined BACKSCAT)
      angmin=1.1 ! minimum scattering angle between satellite and sun
      angmax=3.14 ! backscattering
      ang(1)=angmax ! backscatter angle only
      do i=1,pnangle
         xmu(i)=cos(ang(i))
      enddo
#endif

      if(calc_optics)then

!        wavelength loop

         do 200 ns=1,nswbands

!           wavelength (m)

            wavmidsw(ns) = 0.5e-6*(wavminsw(ns) + wavmaxsw(ns))
!            write(iulog,*)'wavelength=',wavmidsw(ns)

!           first find min,max of real and imaginary parts of refractive index

!           real and imaginary parts of water refractive index

            crefwsw(ns)=cmplx(refrwsw(ns),refiwsw(ns))

            refrmin=real(crefwsw(ns))
            refrmax=real(crefwsw(ns))
            refimin=aimag(crefwsw(ns))
            refimax=aimag(crefwsw(ns))

!           aerosol mode loop

            do m=1,ntot_amode

!              aerosol species loop

               do l=1,nspec_amode(m)

                  ltype=lspectype_amode(l,m)

!                 real and imaginary parts of aerosol refractive index

                  refr=real(specrefndxsw(ns,ltype))
                  refi=aimag(specrefndxsw(ns,ltype))

                  refrmin=min(refrmin,refr)
                  refrmax=max(refrmax,refr)
                  refimin=min(refimin,refi)
                  refimax=max(refimax,refi)

               enddo
            enddo

!	    write(iulog,*)'sw band ',ns
!            write(iulog,*)'refrmin=',refrmin
!            write(iulog,*)'refrmax=',refrmax
!            write(iulog,*)'refimin=',refimin
!            write(iulog,*)'refimax=',refimax
            if(refimin<-1.e-3)then
               write(iulog,*)'negative refractive indices not allowed'
               call endrun('error in modal_aer_opt_init')
            endif

	    call miefit(wavmidsw(ns),refrtabsw(1,ns),refitabsw(1,ns),   &
	       extpsw(1,1,1,1,ns),abspsw(1,1,1,1,ns),asmpsw(1,1,1,1,ns) )
  200    continue

         do 300 ns=1,nlwbands

!            wavmidir=10.e-6 ! wavelength (m) at 10 microns
            wavmidlw(ns) = 0.5e-2*(1._r8/wavenumber1_longwave(ns) + 1._r8/wavenumber1_longwave(ns))

!           first find min,max of real and imaginary parts of infrared (10 micron) refractive index

!           real and imaginary parts of water refractive index

!            refrwir=1.179 ! Kent et al., Applied Optics, 22, 1655-1665, 1983
!	    refiwir=0.6777 ! Kent et al., Applied Optics, 22, 1655-1665, 1983
            crefwlw(ns)=cmplx(refrwlw(ns),refiwlw(ns))

            refrmin=real(crefwlw(ns))
            refrmax=real(crefwlw(ns))
            refimin=aimag(crefwlw(ns))
            refimax=aimag(crefwlw(ns))

!           aerosol mode loop

            do m=1,ntot_amode

!              aerosol species loop

               do l=1,nspec_amode(m)

                  ltype=lspectype_amode(l,m)

!                 real and imaginary parts of aerosol refractive index

		  refr=real(specrefndxlw(ns,ltype))
		  refi=aimag(specrefndxlw(ns,ltype))
                  refrmin=min(refrmin,refr)
                  refrmax=max(refrmax,refr)
                  refimin=min(refimin,refi)
                  refimax=max(refimax,refi)

               enddo
            enddo

!	    write(iulog,*)'longwave band ',ns
!            write(iulog,*)'refrmin=',refrmin
!            write(iulog,*)'refrmax=',refrmax
!            write(iulog,*)'refimin=',refimin
!            write(iulog,*)'refimax=',refimax

	    call miefit(wavmidlw(ns),refrtablw(1,ns),refitablw(1,ns), &
	        extplw(1,1,1,1,ns),absplw(1,1,1,1,ns),asmplw(1,1,1,1,ns) )
  300    continue

            outfilename='modal_optics.nc'

            call write_modal_optics(outfilename,  maxd_amode, nlwbands, nswbands,  &
                 refrtabsw, refitabsw, refrtablw, refitablw, &
                 prefr, prefi, sigmag_amode, ncoef, extpsw, abspsw, asmpsw, absplw )

        
     else


            infilename='modal_optics.nc'
            call getfil(modal_optics, infilename)
	    write(iulog,*)'modal_optics filename=',infilename
            call read_modal_optics(infilename,  maxd_amode, nlwbands, nswbands,  &
	       refrtabsw, refitabsw, refrtablw, refitablw, &
	       prefr, prefi, ncoef, extpsw, abspsw, asmpsw, absplw )

	 do ns=1,nswbands

            wavmidsw(ns) = 0.5e-6*(wavminsw(ns) + wavmaxsw(ns))

            crefwsw(ns)=cmplx(refrwsw(ns),refiwsw(ns))

         end do

	 do ns=1,nlwbands
!            wavmidir=10.e-6 ! wavelength (m) at 10 microns
!            wavmidlw(ns) = 0.5e-6*(wavminlw(ns) + wavmaxlw(ns))
            wavmidlw(ns) = 0.5e-2*(1._r8/wavenumber1_longwave(ns) + 1._r8/wavenumber1_longwave(ns))

!           real and imaginary parts of water refractive index

           crefwlw(ns)=cmplx(refrwlw(ns),refiwlw(ns))
	 end do

    endif

     call addfld ('EXTINCT','/m  ',pver,    'A','Aerosol extinction',phys_decomp, flag_xyfill=.true.)
     call addfld ('ABSORB','/m  ',pver,    'A','Aerosol absorption',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODVIS','  ',1,    'A','Aerosol optical depth 550 nm',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODABS','  ',1,    'A','Aerosol absorption optical depth 550 nm',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODMODE1','  ',1,    'A','Aerosol optical depth 550 nm mode 1',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODMODE2','  ',1,    'A','Aerosol optical depth 550 nm mode 2',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODMODE3','  ',1,    'A','Aerosol optical depth 550 nm mode 3',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODMODE4','  ',1,    'A','Aerosol optical depth 550 nm mode 4',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODMODE5','  ',1,    'A','Aerosol optical depth 550 nm mode 5',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODMODE6','  ',1,    'A','Aerosol optical depth 550 nm mode 6',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODMODE7','  ',1,    'A','Aerosol optical depth 550 nm mode 7',phys_decomp, flag_xyfill=.true.)
!++xl added 11/24/2009, dust AOD
     call addfld ('AODDUST1','  ',1,    'A','Aerosol optical depth 550 nm model 1 from dust',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODDUST2','  ',1,    'A','Aerosol optical depth 550 nm model 2 from dust',phys_decomp, flag_xyfill=.true.)
     call addfld ('AODDUST3','  ',1,    'A','Aerosol optical depth 550 nm model 3 from dust',phys_decomp, flag_xyfill=.true.)
!--dust AOD
     call addfld ('BURDEN1','kg/m2',1,    'A','Aerosol burden mode 1',phys_decomp, flag_xyfill=.true.)
     call addfld ('BURDEN2','kg/m2',1,    'A','Aerosol burden mode 2',phys_decomp, flag_xyfill=.true.)
     call addfld ('BURDEN3','kg/m2',1,    'A','Aerosol burden mode 3',phys_decomp, flag_xyfill=.true.)
     call addfld ('BURDEN4','kg/m2',1,    'A','Aerosol burden mode 4',phys_decomp, flag_xyfill=.true.)
     call addfld ('BURDEN5','kg/m2',1,    'A','Aerosol burden mode 5',phys_decomp, flag_xyfill=.true.)
     call addfld ('BURDEN6','kg/m2',1,    'A','Aerosol burden mode 6',phys_decomp, flag_xyfill=.true.)
     call addfld ('BURDEN7','kg/m2',1,    'A','Aerosol burden mode 7',phys_decomp, flag_xyfill=.true.)
     call addfld ('SSAVIS','  ',1,    'A','Aerosol singel-scatter albedo',phys_decomp, flag_xyfill=.true.)
     call add_default ('EXTINCT', 1, ' ')
     call add_default ('ABSORB', 1, ' ')
     call add_default ('AODVIS', 1, ' ')
     call add_default ('AODABS', 1, ' ')
     call add_default ('AODMODE1', 1, ' ')
     call add_default ('AODMODE2', 1, ' ')
     call add_default ('AODMODE3', 1, ' ')
#if (defined MODAL_AERO_7MODE)
     call add_default ('AODMODE4', 1, ' ')
     call add_default ('AODMODE5', 1, ' ')
     call add_default ('AODMODE6', 1, ' ')
     call add_default ('AODMODE7', 1, ' ')
#endif
!++xl added 11/24/2009, dust AOD
     call add_default ('AODDUST1', 1, ' ')
     call add_default ('AODDUST2', 1, ' ')
     call add_default ('AODDUST3', 1, ' ')
!--dust AOD
     call add_default ('BURDEN1', 1, ' ')
     call add_default ('BURDEN2', 1, ' ')
     call add_default ('BURDEN3', 1, ' ')
#if (defined MODAL_AERO_7MODE)
     call add_default ('BURDEN4', 1, ' ')
     call add_default ('BURDEN5', 1, ' ')
     call add_default ('BURDEN6', 1, ' ')
     call add_default ('BURDEN7', 1, ' ')
#endif
     call add_default ('SSAVIS', 1, ' ')


   end subroutine modal_aer_opt_init


   subroutine modal_size_parameters(ncol, dgnumwet, radsurf, logradsurf, cheb) 1,1

   use phys_buffer,      only: pbuf_size_max, pbuf_fld,  pbuf_get_fld_idx

   implicit none

   integer, intent(in) :: ncol
   real(r8), intent(in) :: dgnumwet(pcols,pver,maxd_amode) ! aerosol wet number mode diameter (m)
   real(r8), intent(out) :: radsurf(pcols,pver,maxd_amode) ! aerosol surface mode radius
   real(r8), intent(out) :: logradsurf(pcols,pver,maxd_amode) ! log(aerosol surface mode radius)
   real(r8), intent(out) :: cheb(ncoef,maxd_amode,pcols,pver)

   integer m,l,lmass,lnum,i,k,nc,ifld,lwater
   real(r8) explnsigma
   real(r8) xrad(pcols) ! normalized aerosol radius

   do m=1,ntot_amode

      explnsigma=exp(2.0_r8*alnsg_amode(m)*alnsg_amode(m))

      do k=1,pver
      do i=1,ncol
!        convert from number mode diameter to surface area
         radsurf(i,k,m)=0.5*dgnumwet(i,k,m)*explnsigma
         logradsurf(i,k,m)=log(radsurf(i,k,m))
!        normalize size parameter
         xrad(i)=max(logradsurf(i,k,m),xrmin)
         xrad(i)=min(xrad(i),xrmax)
         xrad(i)=(2._r8*xrad(i)-xrmax-xrmin)/(xrmax-xrmin)
!        chebyshev polynomials
         cheb(1,m,i,k)=1._r8
         cheb(2,m,i,k)=xrad(i)
         do nc=3,ncoef
            cheb(nc,m,i,k)=2._r8*xrad(i)*cheb(nc-1,m,i,k)-cheb(nc-2,m,i,k)
         enddo
      end do
      end do

   end do

   end subroutine modal_size_parameters


      subroutine miefit(wavmid,refrtab,refitab, extparam,absparam,asmparam) 2,4

   implicit none

      integer nsiz ! number of wet particle sizes
      integer nlog ! number of log-normals modes to product mie fit
      parameter (nsiz=200,nlog=30)

      real(r8) rad(nsiz)
      real(r8) wavmid
      real(r8) extparam(ncoef,prefr,prefi,maxd_amode)
      real(r8) absparam(ncoef,prefr,prefi,maxd_amode)
      real(r8) asmparam(ncoef,prefr,prefi,maxd_amode)
      real(r8) refrtab(prefr),refitab(prefi)
      real(r8) size ! 2 pi radpart / waveleng = size parameter
      real(r8) qext(nsiz) ! array of extinction efficiencies
      real(r8) qsca(nsiz) ! array of scattering efficiencies
      real(r8) qabs(nsiz) ! array of absorption efficiencies
      real(r8) gqsc(nsiz) ! array of asymmetry factor * scattering efficiency
      real(r8) asymm(nsiz) ! array of asymmetry factor
      complex*16 sforw,sback,tforw(2),tback(2),refindx
      integer :: nmom,ipolzn,momdim,numang
      real(r8) pmom(0:1,1)
      logical :: perfct,prnt(2)
      complex*16 crefd
      real(r8) :: mimcut
      logical :: anyang

      real(r8) xmu
      complex*16 s1(1),s2(1)

      real(r8) dsdlogr(nsiz),dlogr
      real(r8) rmin,rmax ! min, max aerosol size bin
      real(r8) xr
      real(r8) drefr ! increment in real part of refractive index
      real(r8) drefi ! increment in imag part of refractive index
      integer m,n,nr,ni,nl

      real(r8) exparg
      real(r8) volwet ! sum of volume of wet aerosols
      real(r8) sumabs ! sum of specific absorption coefficients
      real(r8) sumsca ! sum of specific scattering coefficients
      real(r8) sumg   ! sum of asymmetry factors
      real(r8) rs(nlog) ! surface mode radius (cm)
      real(r8) specscat(nlog) ! specific scattering (m2/g)
      real(r8) specabs(nlog)  ! specific absorption (m2/g)
      real(r8) specext(nlog)  ! specfiic extinction (m2/g)
      real(r8) abs(nlog)      ! single scattering albedo
      real(r8) asym(nlog)     ! asymmetry factor
      real(r8) logr(nsiz)
      real(r8) bma,bpa
      real(r8) sq2pi

      sq2pi=2.5066283

      nmom=0
      ipolzn=0
      momdim=1
      perfct=.false.
      prnt(1)=.false.
      prnt(2)=.false.
      mimcut=0.0_r8

      anyang=.false.
      numang=0


        drefr=(refrmax-refrmin)/(nrefr-1)

!       size bins (m)

        rmin=0.001e-6
        rmax=100.e-6

        dlogr=log(rmax/rmin)/(nsiz-1)
        logr(1)=log(rmin)
        do n=2,nsiz
           logr(n)=logr(n-1)+dlogr
        enddo

        do n=1,nsiz
           rad(n)=exp(logr(n))
        enddo

!           calibrate parameterization with range of refractive indices

            do 120 nr=1,nrefr
            do 120 ni=1,nrefi

               refrtab(nr)=refrmin+(nr-1)*drefr
               refitab(ni)=refimax*0.3**(nrefi-ni)
	       if(ni.eq.1)refitab(ni)=0.
               crefd=dcmplx(refrtab(nr),refitab(ni))
!               write(iulog,*)'nr,ni,refr,refi=',nr,ni,refrtab(nr),refitab(ni)

!              mie calculations of optical efficiencies

               do n=1,nsiz

!                 size parameter and weighted refractive index

                  size=2.*pie*rad(n)/wavmid
                  size=min(size,400.d0)

                  call miev0(size,crefd,perfct,mimcut,anyang,          &
                     numang,xmu,nmom,ipolzn,momdim,prnt,               &
                     qext(n),qsca(n),gqsc(n),pmom,sforw,sback,s1,      &
                     s2,tforw,tback )

                  qsca(n)=min(qsca(n),qext(n))
                  qabs(n)=qext(n)-qsca(n)
                  asymm(n)=gqsc(n)/qsca(n)
!                 if(nr.eq.1.and.ni.eq.1)then
!                  write(iulog,*)'rad=',rad(n),' qsca,qabs=',qsca(n),qabs(n)
!                endif


               enddo

!            now consider a variety of lognormal size distributions
!            with surface mode radius rs (m) and log standard deviation alnsg_amode

!            aerosol mode loop

             do 110 m=1,ntot_amode

!              size units are m

!              bounds of surface mode radius

               bma=0.5*log(rmmax/rmmin)
               bpa=0.5*log(rmmax*rmmin)

               do 100 nl=1,nlog

!                 pick rs to match zeroes of chebychev

                  xr=cos(pie*(nl-0.5)/nlog)
                  rs(nl)=exp(xr*bma+bpa)

!                 define wet size distribution

!                 integrate over all size bins

                  volwet=0
                  sumsca=0
                  sumabs=0
                  sumg=0

                  do n=1,nsiz
                     exparg=log(rad(n)/rs(nl))/alnsg_amode(m)
                     dsdlogr(n)=exp(-0.5*exparg*exparg)
                     volwet=volwet+4./3.*rad(n)*dsdlogr(n)*dlogr
                     sumabs=sumabs+qabs(n)*dsdlogr(n)*dlogr
                     sumsca=sumsca+qsca(n)*dsdlogr(n)*dlogr
                     sumg=sumg+asymm(n)*qsca(n)*dsdlogr(n)*dlogr
                  enddo


!                 coefficients wrt wet mass, using water density
                  specscat(nl)=sumsca/(volwet*rhoh2o)
                  specabs(nl)=sumabs/(volwet*rhoh2o)
!                 coefficients wrt wet mass
                  specext(nl)=specscat(nl)+specabs(nl)
                  asym(nl)=sumg/sumsca

                 !if(nr.eq.1.and.ni.eq.1)then
                  if(m.eq.3.and.wavmid.gt.0.45e-6.and.wavmid.lt.0.6e-6)then
!                    write(98,*)'rs=',rs(nl),' cref=',refrtab(nr),refitab(ni),' specext=',specext(nl)
                  endif
                ! endif

  100          continue

               call fitcurv(rs,specext,extparam(1,nr,ni,m),ncoef,nlog)
               call fitcurvlin(rs,specabs,absparam(1,nr,ni,m),ncoef,nlog)
               call fitcurvlin(rs,asym,asmparam(1,nr,ni,m),ncoef,nlog)

  110         continue
  120       continue
!       write(iulog,*)'refitab=',(refitab(ni),ni=1,nrefi)
      return
      end subroutine miefit


      subroutine modal_aero_sw(ncol,lchnk,iswband, nnite, idxnite, tauxar,wa,ga,fa, raer, state, & 1,30
                               qaerwat, radsurf, logradsurf, cheb )

!  calculates aerosol radiative properties

   use ppgrid
   use physconst,        only: rga, rair
   use physics_types,    only: physics_state
   use radconstants,     only: idx_sw_diag
   use cam_history,      only: outfld, fillvalue

   implicit none

   integer, intent(in) :: ncol  ! number of columns
   integer, intent(in) :: lchnk  ! chunk index
   integer, intent(in) :: iswband  ! spectral interval
   integer, intent(in) :: nnite          ! number of night columns
   integer, intent(in) :: idxnite(nnite) ! local column indices of night columns
   real(r8), intent(in) :: raer(pcols, pver, pcnst)
   type(physics_state), intent(in) :: state
   real(r8), intent(in) :: qaerwat(pcols,pver,maxd_amode) ! aerosol water (g/g)
   real(r8), intent(in) :: radsurf(pcols,pver,maxd_amode) ! aerosol surface mode radius
   real(r8), intent(in) :: logradsurf(pcols,pver,maxd_amode) ! log(aerosol surface mode radius)
   real(r8), intent(in) :: cheb(ncoef,maxd_amode,pcols,pver)

         real(r8), intent(out) :: tauxar(pcols,0:pver) ! layer extinction optical depth
	 real(r8), intent(out) :: wa(pcols,0:pver) ! layer single-scatter albedo
	 real(r8), intent(out) :: ga(pcols,0:pver) ! asymmetry factor
	 real(r8), intent(out) :: fa(pcols,0:pver) ! forward scattered fraction

         integer i,k
         real(r8) pext(pcols) ! parameterized specific extinction (m2/kg)
         real(r8) specpext(pcols) ! specific extinction (m2/kg)
         real(r8) pabs(pcols) ! parameterized specific absorption (m2/kg)
         real(r8) palb(pcols) ! parameterized single scattering albedo
         real(r8) pasm(pcols) ! parameterized asymmetry factor
      real(r8) :: mass(pcols,pver) ! layer mass
      real(r8) totmass(pcols)
      real(r8) vol(pcols)      ! volume concentration of aerosol specie (m3/kg)
      real(r8) volsol(pcols)   ! volume concentration of soluble aerosol specie (m3/kg)
      real(r8) volinsol(pcols) ! volume concentration of insoluble aerosol specie (m3/kg)
      real(r8) dryvol(pcols)   ! volume concentration of aerosol mode (m3/kg)
      real(r8) dryvolsol(pcols)   ! volume concentration of soluble aerosol mode (m3/kg)
      real(r8) dryvolinsol(pcols) ! volume concentration of insoluble aerosol mode (m3/kg)
      real(r8) wetvol(pcols)   ! volume concentration of wet mode (m3/kg)
      real(r8) watervol(pcols) ! volume concentration of water in each mode (m3/kg)
      real(r8) volf            ! volume fraction of insoluble aerosol
      real(r8) refr(pcols)     ! real part of refractive index
      real(r8) refi(pcols)     ! imaginary part of refractive index
      real(r8) :: aodvis(pcols) ! extinction optical depth
      real(r8) :: aodabs(pcols) ! absorption optical depth
      real(r8) :: aodmode(pcols,maxd_amode)
      real(r8) :: burden(pcols,maxd_amode)
!++xl added 11/24/2009, dust AOD
      real(r8) :: dustvol(pcols)  ! volume concentration of dust in aerosol mode (m3/kg)
      real(r8) :: dustaodmode(pcols,maxd_amode)  ! dust aod in aerosol mode
!--dust AOD
      real(r8) :: ssavis(pcols)
      real(r8) :: extinct(pcols,pver)
      real(r8) :: absorb(pcols,pver)
   logical :: savaervis ! true if visible wavelength (0.55 micron)

      complex crefin(pcols), crefsol(pcols), crefinsol(pcols) ! complex refractive index
      complex crefinsq, crefsolsq, crefinsolsq
      complex crefa, crefb
      integer lmass,ltype
      integer itab(pcols),jtab(pcols)
      real(r8) ttab(pcols),utab(pcols)
      real(r8) cext(pcols,ncoef),cabs(pcols,ncoef),casm(pcols,ncoef)
      real(r8)  air_density(pcols,pver) ! (kg/m3)
      integer, parameter :: nerrmax_dopaer=1000
      integer nerr_dopaer
      save nerr_dopaer
      data nerr_dopaer/0/
      real(r8) dopaer(pcols) ! aerosol optical depth in layer
      real(r8) third
      real(r8) colext(pcols,maxd_amode)
	 integer m,l,nc,ns
	
                do i=1,ncol
                   extinct(i,:)=0.0_r8
                   absorb(i,:)=0.0_r8
                   aodvis(i)=0.0_r8
                   aodmode(i,:)=0.0_r8
                   aodabs(i)=0.0_r8
!++xl added 11/24/2009, dust AOD
                   dustaodmode(i,:)=0.0_r8
!--dust AOD
                   ssavis(i)=0.0_r8
		end do

      do k=1,pver
         tauxar(:ncol,k)=0._r8
         wa(:ncol,k)=0._r8
         ga(:ncol,k)=0._r8
	 fa(:ncol,k)=0._r8
	 mass(:ncol,k)=state%pdeldry(:ncol,k)*rga
	 air_density(:ncol,k)=state%pmid(:ncol,k)/(rair*state%t(:ncol,k))
      enddo
      burden(:ncol,:ntot_amode)=0._r8
      third=1./3.
      savaervis=iswband.eq.idx_sw_diag

! zero'th layer does not contain aerosol
!
   tauxar(1:ncol,0)  = 0._r8
   wa(1:ncol,0)      = 0.925_r8
   ga(1:ncol,0)      = 0.850_r8
   fa(1:ncol,0)      = 0.7225_r8

   do k=1,pver

!     loop over all aerosol modes

      do m=1,ntot_amode

!        form bulk refractive index
         crefin(:ncol)=0._r8
         dryvol(:ncol)=0._r8
!++xl added 11/24/2009, dust AOD
         dustvol(:ncol)=0._r8
!--dust AOD

!        aerosol species loop

         do l=1,nspec_amode(m)
            ltype=lspectype_amode(l,m)
            lmass=lmassptr_amode(l,m)
	    do i=1,ncol
	       burden(i,m)=burden(i,m) + raer(i,k,lmass)*mass(i,k)
               vol(i)=raer(i,k,lmass)/specdens_amode(ltype)
               dryvol(i)=dryvol(i)+vol(i)
               crefin(i)=crefin(i)+vol(i)*specrefndxsw(iswband,ltype)
	    end do
         enddo
!++xl added 11/24/2009, dust AOD
         do i=1,ncol
           if (lptr_dust_a_amode(m)>0) then
             dustvol(i)=raer(i,k,lptr_dust_a_amode(m))/specdens_dust_amode
           else
             dustvol(i)=0.0_r8
           endif
         enddo
!--dust AOD
         do i=1,ncol
       	    watervol(i)=qaerwat(i,k,m)/rhoh2o
	    wetvol(i)=watervol(i)+dryvol(i)
            if(watervol(i)<0._r8)then
               if(abs(watervol(i)).gt.1.e-1*wetvol(i))then
                  write(iulog,'(a,4e10.2,a)')'watervol,wetvol,dryvolsol,dryvolinsol=', &
		                   watervol(i),wetvol(i),dryvolsol(i),dryvolinsol(i) &
                         ,' in modal_aero_sw'
!               !  call endrun()
               endif
                 watervol(i)=0._r8
                 wetvol(i)=dryvol(i)
            endif
! volume mixing
            crefin(i)=crefin(i)+watervol(i)*crefwsw(iswband)
            crefin(i)=crefin(i)/max(wetvol(i),1.e-60_r8)
            refr(i)=real(crefin(i))
            refi(i)=abs(aimag(crefin(i)))
          end do ! ncol

!        call t_startf('binterp')

!        interpolate coefficients linear in refractive index
!        first call calcs itab,jtab,ttab,utab
         itab(:ncol)=0
         call binterp(extpsw(1,1,1,m,iswband),ncol,ncoef,nrefr,nrefi,   &
                          refr,refi,refrtabsw(1,iswband),refitabsw(1,iswband),itab,jtab,  &
                          ttab,utab,cext)

         call binterp(abspsw(1,1,1,m,iswband),ncol,ncoef,nrefr,nrefi,   &
                          refr,refi,refrtabsw(1,iswband),refitabsw(1,iswband),itab,jtab,  &
                          ttab,utab,cabs)
         call binterp(asmpsw(1,1,1,m,iswband),ncol,ncoef,nrefr,nrefi,   &
                          refr,refi,refrtabsw(1,iswband),refitabsw(1,iswband),itab,jtab,  &
                          ttab,utab,casm)

!       call t_stopf('binterp')

!        parameterized optical properties
         do i=1,ncol
            if(logradsurf(i,k,m).le.xrmax)then
               pext(i)=0.5_r8*cext(i,1)
               do nc=2,ncoef
                  pext(i)=pext(i)+cheb(nc,m,i,k)*cext(i,nc)
               enddo
               pext(i)=exp(pext(i))
            else
               pext(i)=1.5_r8/(radsurf(i,k,m)*rhoh2o) ! geometric optics
            endif
!           convert from m2/kg water to m2/kg aerosol
            specpext(i)=pext(i)
            pext(i)=pext(i)*wetvol(i)*rhoh2o
!           write(iulog,*)'pext=',pext(i)
            pabs(i)=0.5_r8*cabs(i,1)
            pasm(i)=0.5_r8*casm(i,1)
            do nc=2,ncoef
               pabs(i)=pabs(i)+cheb(nc,m,i,k)*cabs(i,nc)
               pasm(i)=pasm(i)+cheb(nc,m,i,k)*casm(i,nc)
            enddo
            pabs(i)=pabs(i)*wetvol(i)*rhoh2o
            pabs(i)=max(0._r8,pabs(i))
	    pabs(i)=min(pext(i),pabs(i))

	    palb(i)=1._r8-pabs(i)/max(pext(i),1.e-40_r8)
	    palb(i)=1._r8-pabs(i)/max(pext(i),1.e-40_r8)

            dopaer(i)=pext(i)*mass(i,k)
	 end do

!           Save aerosol optical depth at longest visible wavelength
!           sum over layers
            if(savaervis)then
!               aerosol extinction (/m)
                do i=1,ncol
                   extinct(i,k)=extinct(i,k) + dopaer(i)*air_density(i,k)/mass(i,k)
                   absorb(i,k)=absorb(i,k)+pabs(i)*air_density(i,k)
                   aodvis(i)=aodvis(i)+dopaer(i)
                   aodabs(i)=aodabs(i)+pabs(i)*mass(i,k)
                   aodmode(i,m)=aodmode(i,m)+dopaer(i)
!++xl added 11/24/2009, dust AOD
                   if (wetvol(i)>1.e-40_r8) then
                     dustaodmode(i,m)=dustaodmode(i,m)+dopaer(i)*dustvol(i)/wetvol(i)
 !                  else
 !                    dustaodmode(i,m)=0.0_r8
                   endif
!--dust AOD
                   ssavis(i)=ssavis(i)+dopaer(i)*palb(i)
	end do
             endif
             do i=1,ncol
                if ((dopaer(i)>-1.e-10) .and. (dopaer(i)<30.))goto 125

                    write(iulog,*)'dopaer(',i,',',k,',',m,',',lchnk,')=',dopaer(i)
!                    write(iulog,*)'itab,jtab,ttab,utab=',itab(i),jtab(i),ttab(i),utab(i)
                    write(iulog,*)'k=',k,' pext=',pext(i),' specext=',specpext(i)
                    write(iulog,*)'wetvol=',wetvol(i),' dryvol=',dryvol(i),' watervol=',watervol(i)
!                    write(iulog,*)'cext=',(cext(i,l),l=1,ncoef)
!                    write(iulog,*)'crefin=',crefin(i)
                    write(iulog,*)'nspec_amode(m)=',nspec_amode(m)
!                    write(iulog,*)'cheb=',(cheb(nc,m,i,k),nc=2,ncoef)
                     do l=1,nspec_amode(m)
                        lmass=lmassptr_amode(l,m)
                        ltype=lspectype_amode(l,m)
                        volf=raer(i,k,lmass)/specdens_amode(ltype)
                       write(iulog,*)'l=',l,'vol(l)=',volf
                       write(iulog,*)'specrefndxsw(l)=',specrefndxsw(iswband,ltype)
                       write(iulog,*)'specdens_amode(ltype)=',specdens_amode(ltype)
                     enddo

                     l=numptr_amode(m)
                     if ((l > 0) .and. (l .le. pcnst)) then
!                       write(iulog,*)'number=',raer(i,k,l)
                     else
!                       write(iulog,*)'number= ????, numptr=', l
                     endif

 !                    call endrun('exit from modal_aero_sw')
                     nerr_dopaer = nerr_dopaer + 1
                     if (nerr_dopaer >= nerrmax_dopaer) then
!                       write(iulog,*)'*** halting in modal_aero_sw after nerr_dopaer =', nerr_dopaer
!                       call endrun('exit from modal_aero_sw')
                     end if

125               continue
               end do
               do i=1,ncol
                  tauxar(i,k)=tauxar(i,k)+dopaer(i)
                  wa(i,k)=wa(i,k)+dopaer(i)*palb(i)
                  ga(i,k)=ga(i,k)+dopaer(i)*palb(i)*pasm(i)
                  fa(i,k)=fa(i,k)+dopaer(i)*palb(i)*pasm(i)*pasm(i)
	       end do
            end do ! ntot_amode
  end do ! pver
         if(savaervis)then
            do i=1,ncol
               if(aodvis(i)>1.e-10)then
                  ssavis(i)=ssavis(i)/aodvis(i)
               else
                  ssavis(i)=0.925_r8
               endif
			   do m=1,ntot_amode
			      colext(i,m)=0.001*aodmode(i,m)/burden(i,m)
!				  if(aodmode(i,m).gt.1.)write(iulog,*)'m,burden,tau,ext=',m, &
!                                                 burden(i,m),aodmode(i,m),colext(i,m)
			   end do
	    end do
            do i = 1, nnite
               extinct(idxnite(i),:) = fillvalue
               absorb(idxnite(i),:) = fillvalue
               aodvis(idxnite(i)) = fillvalue
               aodabs(idxnite(i)) = fillvalue
               aodmode(idxnite(i),:) = fillvalue
!++xl added 11/24/2009, dust AOD
               dustaodmode(idxnite(i),:) = fillvalue
!--xl
               burden(idxnite(i),:) = fillvalue
               ssavis(idxnite(i)) = fillvalue
            end do
            call outfld('EXTINCT',extinct ,pcols,lchnk)
            call outfld('ABSORB',absorb ,pcols,lchnk)
            call outfld('AODVIS',aodvis ,pcols,lchnk)
            call outfld('AODABS',aodabs ,pcols,lchnk)
            call outfld('AODMODE1',aodmode(1,1) ,pcols,lchnk)
            call outfld('AODMODE2',aodmode(1,2) ,pcols,lchnk)
            call outfld('AODMODE3',aodmode(1,3) ,pcols,lchnk)
#if (defined MODAL_AERO_7MODE)
            call outfld('AODMODE4',aodmode(1,4) ,pcols,lchnk)
            call outfld('AODMODE5',aodmode(1,5) ,pcols,lchnk)
            call outfld('AODMODE6',aodmode(1,6) ,pcols,lchnk)
            call outfld('AODMODE7',aodmode(1,7) ,pcols,lchnk)
#endif
!++xl added 11/24/2009, dust AOD
            call outfld('AODDUST1',dustaodmode(1,1) ,pcols,lchnk)
            call outfld('AODDUST2',dustaodmode(1,2) ,pcols,lchnk)
            call outfld('AODDUST3',dustaodmode(1,3) ,pcols,lchnk)
!--xl
            call outfld('BURDEN1',burden(1,1) ,pcols,lchnk)
            call outfld('BURDEN2',burden(1,2) ,pcols,lchnk)
            call outfld('BURDEN3',burden(1,3) ,pcols,lchnk)
#if (defined MODAL_AERO_7MODE)
            call outfld('BURDEN4',burden(1,4) ,pcols,lchnk)
            call outfld('BURDEN5',burden(1,5) ,pcols,lchnk)
            call outfld('BURDEN6',burden(1,6) ,pcols,lchnk)
            call outfld('BURDEN7',burden(1,7) ,pcols,lchnk)
#endif
            call outfld('SSAVIS',ssavis ,pcols,lchnk)
         endif

      return
      end subroutine modal_aero_sw


      subroutine modal_aero_lw(ncol,lchnk, pbuf, raer, tauxar, pdeldry) 1,9

!  calculates aerosol radiative properties

   use ppgrid
   use constituents,  only: pcnst
   use physconst, only: rga
   use phys_buffer,      only: pbuf_size_max, pbuf_fld,  pbuf_get_fld_idx

   implicit none

   integer, intent(in) :: ncol  ! number of columns
   integer, intent(in) :: lchnk  ! chunk index
   real(r8), intent(in) :: raer(pcols, pver, pcnst)
      real(r8), intent(out) :: tauxar(pcols,pver,nlwbands) ! layer absorption optical depth
      real(r8), intent(in) :: pdeldry(pcols,pver) ! pressure thickness (Pa)
    type(pbuf_fld),      intent(in), dimension(pbuf_size_max) :: pbuf


      integer i,k
      real(r8) pabs(pcols) ! parameterized specific absorption (m2/kg)
      real(r8) :: mass(pcols,pver) ! layer mass
      real(r8) totmass(pcols)
      real(r8) vol(pcols)      ! volume concentration of aerosol specie (m3/kg)
      real(r8) dryvol(pcols)   ! volume concentration of aerosol mode (m3/kg)
      real(r8) wetvol(pcols)   ! volume concentration of wet mode (m3/kg)
      real(r8) watervol(pcols) ! volume concentration of water in each mode (m3/kg)
      real(r8) volf            ! volume fraction of insoluble aerosol
      real(r8) refr(pcols)     ! real part of refractive index
      real(r8) refi(pcols)     ! imaginary part of refractive index
      complex crefin(pcols)    ! complex refractive index
      integer lmass,ltype
      integer itab(pcols),jtab(pcols)
      real(r8) ttab(pcols),utab(pcols)
      real(r8) cext(pcols,ncoef),cabs(pcols,ncoef),casm(pcols,ncoef)
      real(r8) xrad(pcols)
      real(r8) cheby(ncoef,pcols,pver,maxd_amode) ! chebychef polynomials
      integer, parameter ::  nerrmax_dopaer=1000
      integer nerr_dopaer
      save nerr_dopaer
      data nerr_dopaer/0/
      real(r8) dopaer(pcols) ! aerosol optical depth in layer
      real(r8) third
	 integer m,l,nc,ns,ifld
      real(r8), pointer, dimension(:,:,:) ::  dgnumwet  ! wet number mode diameter (m)
      real(r8), pointer, dimension(:,:,:) ::  qaerwat  ! aerosol water (g/g)
      integer ilwband

      ifld = pbuf_get_fld_idx('DGNUMWET')
      dgnumwet  => pbuf(ifld)%fld_ptr(1,1:pcols,1:pver,lchnk,1:maxd_amode)
      ifld  = pbuf_get_fld_idx( 'QAERWAT' )
      if ( associated(pbuf(ifld)%fld_ptr) ) then
         qaerwat => pbuf(ifld)%fld_ptr( 1, 1:pcols, 1:pver, lchnk, 1:maxd_amode )
      else
         call endrun( 'pbuf for QAERWAT not allocated in modal_aer_day' )
      end if


      do k=1,pver
	 mass(:ncol,k)=pdeldry(:ncol,k)*rga !
      enddo
      third=1./3.

!     calc size parameter for all columns
      do k=1,pver
      do m=1,ntot_amode
         do i=1,ncol
!           convert from number diameter to surface area
            xrad(i)=log(0.5*dgnumwet(i,k,m))+2.0_r8*alnsg_amode(m)*alnsg_amode(m)
!           normalize size parameter
            xrad(i)=max(xrad(i),xrmin)
            xrad(i)=min(xrad(i),xrmax)
            xrad(i)=(2*xrad(i)-xrmax-xrmin)/(xrmax-xrmin)
!           chebyshev polynomials
            cheby(1,i,k,m)=1.0_r8
            cheby(2,i,k,m)=xrad(i)
            do nc=3,ncoef
               cheby(nc,i,k,m)=2.0_r8*xrad(i)*cheby(nc-1,i,k,m)-cheby(nc-2,i,k,m)
            enddo
         enddo
      enddo
      enddo


   do 1000 ilwband=1,nlwbands


   do k=1,pver

      tauxar(:ncol,k,ilwband)=0._r8

!     loop over all aerosol modes

      do m=1,ntot_amode

!        form bulk refractive index. Use volume mixing for infrared

         do i=1,ncol
            crefin(i)=0._r8
            dryvol(i)=0._r8
	 end do

!        aerosol species loop

         do l=1,nspec_amode(m)
            ltype=lspectype_amode(l,m)
            lmass=lmassptr_amode(l,m)
	    do i=1,ncol
               vol(i)=raer(i,k,lmass)/specdens_amode(ltype)
               crefin(i)=crefin(i)+vol(i)*specrefndxlw(ilwband,ltype)
               dryvol(i)=dryvol(i)+vol(i)
	    end do
         enddo
         do i=1,ncol
       	    watervol(i)=qaerwat(i,k,m)/rhoh2o
	    wetvol(i)=watervol(i)+dryvol(i)
            if(watervol(i)<0.0_r8)then
               if(abs(watervol(i)).gt.1.e-1*wetvol(i))then
                  write(iulog,*)'watervol,wetvol,dryvol=',watervol(i),wetvol(i),dryvol(i),' in modal_aero_lw'
              !   call endrun()
               endif
               watervol(i)=0._r8
               wetvol(i)=dryvol(i)
            endif
            crefin(i)=crefin(i)+watervol(i)*crefwlw(ilwband)
            if(wetvol(i)>1.e-40)crefin(i)=crefin(i)/wetvol(i)
            refr(i)=real(crefin(i))
            refi(i)=aimag(crefin(i))

         end do ! ncol

!        interpolate coefficients linear in refractive index
!        first call calcs itab,jtab,ttab,utab
         itab(:ncol)=0
         call binterp(absplw(1,1,1,m,ilwband),ncol,ncoef,nrefr,nrefi,   &
            refr,refi,refrtablw(1,ilwband),refitablw(1,ilwband),itab,jtab,  &
            ttab,utab,cabs)

!        parameterized optical properties
         do i=1,ncol
            pabs(i)=0.5*cabs(i,1)
            do nc=2,ncoef
               pabs(i)=pabs(i)+cheby(nc,i,k,m)*cabs(i,nc)
            enddo
            pabs(i)=pabs(i)*wetvol(i)*rhoh2o
            pabs(i)=max(0._r8,pabs(i))
            dopaer(i)=pabs(i)*mass(i,k)
	 end do

             do i=1,ncol
                  if ((dopaer(i)>-1.e-10) .and. (dopaer(i)<20.))goto 225

                     write(iulog,*)'dopaer(',i,',',k,',',m,',',lchnk,')=',dopaer(i)
                     write(iulog,*)'k=',k,' pabs=',pabs(i)
                     write(iulog,*)'wetvol=',wetvol(i),' dryvol=',dryvol(i),     &
                             ' watervol=',watervol(i)
                     write(iulog,*)'cabs=',(cabs(i,l),l=1,ncoef)
                     write(iulog,*)'crefin=',crefin(i)
                     write(iulog,*)'nspec_amode(m)=',nspec_amode(m)
                     do l=1,nspec_amode(m)
                        lmass=lmassptr_amode(l,m)
                        ltype=lspectype_amode(l,m)
                        vol=raer(i,k,lmass)/specdens_amode(ltype)
                        write(iulog,*)'l=',l,'vol(l)=',vol
                        write(iulog,*)'specrefndxlw(l)=',specrefndxlw(ilwband,ltype)
                        write(iulog,*)'specdens_amode(ltype)=',specdens_amode(ltype)
                     enddo

                     l=numptr_amode(m)
                     if ((l > 0) .and. (l .le. pcnst)) then
                        write(iulog,*)'number=',raer(i,k,l)
                     else
                        write(iulog,*)'number= ????, numptr=', l
                     endif

!                    call endrun()
                     nerr_dopaer = nerr_dopaer + 1
                     if (nerr_dopaer >= nerrmax_dopaer) then
                        write(iulog,*)'*** halting in modal_aero_lw after nerr_dopaer =', nerr_dopaer
                        call endrun()
                     end if

225               continue
               end do
               do i=1,ncol
                  tauxar(i,k,ilwband)=tauxar(i,k,ilwband)+dopaer(i)
	       end do
            end do ! ntot_amode
  end do ! pver

  1000 continue

      return
      end subroutine modal_aero_lw


      subroutine fitcurv(rs,yin,coef,ncoef,maxm) 1,2

!     fit y(x) using Chebyshev polynomials

      implicit none
      integer nmodes,maxm,m,ncoef
      parameter (nmodes=300)

      real(r8) rs(maxm) ! surface mode radius (cm)
      real(r8) yin(maxm),coef(ncoef)
      real(r8) x(nmodes),y(nmodes)
      real(r8) xmin,xmax

      if(maxm.gt.nmodes)then
        write(iulog,*)'nmodes too small in fitcurv',maxm
        call endrun()
      endif

      xmin=1.e20
      xmax=-1.e20
      do 100 m=1,maxm
        x(m)=log(rs(m))
        xmin=min(xmin,x(m))
        xmax=max(xmax,x(m))
        y(m)=log(yin(m))
  100 continue

      do 110 m=1,maxm
      x(m)=(2*x(m)-xmax-xmin)/(xmax-xmin)
  110 continue

      call chebft(coef,ncoef,y,maxm)

      return
      end subroutine fitcurv


      subroutine fitcurvlin(rs,yin,coef,ncoef,maxm) 2,2

!     fit y(x) using Chebychev polynomials
!     calculates ncoef coefficients coef

      implicit none
      integer nmodes,m,ncoef
      parameter (nmodes=300)

      integer,intent(in) :: maxm
      real(r8),intent(in) :: rs(maxm),yin(maxm)
      real(r8) x(nmodes),y(nmodes)
      real(r8),intent(out) :: coef(ncoef)
      real(r8) xmin,xmax

      if(maxm.gt.nmodes)then
        write(iulog,*)'nmodes too small in fitcurv',maxm
        call endrun
      endif

      do 100 m=1,maxm
      x(m)=log(rs(m))
      y(m)=(yin(m))
  100 continue

      call chebft(coef,ncoef,y,maxm)

      return
      end subroutine fitcurvlin


      subroutine chebft(c,m,f,n) 2
!     given a function f with values at zeroes x_k of Chebychef polynomial
!     T_n(x), calculate coefficients c_j such that
!     f(x)=sum(k=1,n) c_k t_(k-1)(y) - 0.5*c_1
!     where y=(x-0.5*(xmax+xmin))/(0.5*(xmax-xmin))
!     See Numerical Recipes, pp. 148-150.

      implicit none
      real(r8) pi
      parameter (pi=3.14159265)
      real(r8) c(m),f(n),fac,sum
      integer n,j,k,m

      fac=2./n
      do j=1,m
         sum=0
         do k=1,n
            sum=sum+f(k)*cos((pi*(j-1))*((k-0.5)/n))
         enddo
         c(j)=fac*sum
      enddo
      return
      end subroutine chebft


      subroutine binterp(table,ncol,km,im,jm,x,y,xtab,ytab,ix,jy,t,u,out) 4,11

!     bilinear interpolation of table
!
      implicit none
      integer im,jm,km,ncol
      real(r8) table(km,im,jm),xtab(im),ytab(jm),out(pcols,km)
      integer i,ix(pcols),ip1,j,jy(pcols),jp1,k,ic
      real(r8) x(pcols),dx,t(pcols),y(pcols),dy,u(pcols), &
             tu(pcols),tuc(pcols),tcu(pcols),tcuc(pcols)

      if(ix(1).gt.0)go to 30
      if(im.gt.1)then
        do ic=1,ncol
          do i=1,im
            if(x(ic).lt.xtab(i))go to 10
          enddo
   10     ix(ic)=max0(i-1,1)
          ip1=min(ix(ic)+1,im)
          dx=(xtab(ip1)-xtab(ix(ic)))
          if(abs(dx).gt.1.e-20_r8)then
             t(ic)=(x(ic)-xtab(ix(ic)))/dx
          else
             t(ic)=0._r8
          endif
	end do
      else
        ix(:ncol)=1
        t(:ncol)=0._r8
      endif
      if(jm.gt.1)then
        do ic=1,ncol
          do j=1,jm
            if(y(ic).lt.ytab(j))go to 20
          enddo
   20     jy(ic)=max0(j-1,1)
          jp1=min(jy(ic)+1,jm)
          dy=(ytab(jp1)-ytab(jy(ic)))
          if(abs(dy).gt.1.e-20_r8)then
             u(ic)=(y(ic)-ytab(jy(ic)))/dy
             if(u(ic).lt.0._r8.or.u(ic).gt.1._r8)then
                write(iulog,*)'u,y,jy,ytab,dy=',u(ic),y(ic),jy(ic),ytab(jy(ic)),dy
             endif
          else
            u(ic)=0._r8
          endif
	end do
      else
        jy(:ncol)=1
        u(:ncol)=0._r8
      endif
   30 continue
      do ic=1,ncol
         tu(ic)=t(ic)*u(ic)
         tuc(ic)=t(ic)-tu(ic)
         tcuc(ic)=1._r8-tuc(ic)-u(ic)
         tcu(ic)=u(ic)-tu(ic)
         jp1=min(jy(ic)+1,jm)
         ip1=min(ix(ic)+1,im)
         do k=1,km
            out(ic,k)=tcuc(ic)*table(k,ix(ic),jy(ic))+tuc(ic)*table(k,ip1,jy(ic))   &
               +tu(ic)*table(k,ip1,jp1)+tcu(ic)*table(k,ix(ic),jp1)
	 end do
      enddo
      return
      end subroutine binterp


      subroutine  write_modal_optics(outfilename,  modes, lw_band_len, sw_band_len,  & 1
	 refindex_real_sw,refindex_im_sw, refindex_real_lw, refindex_im_lw, &
	 nrefr, nrefi, sigma_logr_aer, ncoef, extpsw, abspsw, asmpsw, absplw )
        use pio, only : pio_def_var, pio_def_dim, pio_put_var, pio_clobber, pio_put_att, pio_double, &
             file_desc_T, var_desc_t, pio_global, pio_enddef, pio_closefile
        use cam_pio_utils, only : cam_pio_createfile
        implicit none

      character*(*) outfilename
! error status return
      integer  ierr
! netCDF id
      type(file_desc_t) ::  ncid
! dimension ids
      integer  lw_band_dim
      integer  sw_band_dim
      integer  refindex_real_dim
      integer  refindex_im_dim
      integer  mode_dim
      integer  ncoef_dim
! dimension lengths
      integer, intent(in) :: nrefr,nrefi ! number of refractive indices
      integer, intent(in) :: ncoef ! number of coefficients in polynomial expressions
      integer, intent(in) :: sw_band_len ! number of solar wavelengths
      integer, intent(in) :: lw_band_len ! number of infrared wavelengths
      integer, intent(in) :: modes ! number of aerosol modes

! variable ids
      type(var_desc_t) ::   lw_abs_id
      type(var_desc_t) ::   sw_asm_id
      type(var_desc_t) ::   sw_ext_id
      type(var_desc_t) ::   sw_abs_id
      type(var_desc_t) ::   sigma_logr_aer_id
      type(var_desc_t) ::   refindex_real_lw_id
      type(var_desc_t) ::   refindex_im_lw_id
      type(var_desc_t) ::   refindex_real_sw_id
      type(var_desc_t) ::   refindex_im_sw_id
! rank (number of dimensions) for each variable
      integer  lw_abs_rank
      integer  sw_asm_rank
      integer  sw_ext_rank
      integer  sw_abs_rank
      integer  sigma_logr_aer_rank
      integer refindex_rank
      parameter (lw_abs_rank = 5)
      parameter (sw_asm_rank = 5)
      parameter (sw_ext_rank = 5)
      parameter (sw_abs_rank = 5)
      parameter (refindex_rank=2)
      parameter (sigma_logr_aer_rank = 1)
! variable shapes
      integer  lw_abs_dims(lw_abs_rank)
      integer  sw_asm_dims(sw_asm_rank)
      integer  sw_ext_dims(sw_ext_rank)
      integer  sw_abs_dims(sw_abs_rank)
      integer refindex_dims(refindex_rank)
      integer coef_dim
      integer sigma_logr_aer_dims(sigma_logr_aer_rank)
! data variables

!     coefficients for parameterizing aerosol radiative properties
!     in terms of refractive index and wet radius
      real(r8), intent(in) :: extpsw(ncoef,nrefr,nrefi,modes,sw_band_len) ! specific extinction
      real(r8), intent(in) :: abspsw(ncoef,nrefr,nrefi,modes,sw_band_len) ! specific absorption
      real(r8), intent(in) :: asmpsw(ncoef,nrefr,nrefi,modes,sw_band_len) ! asymmetry factor
      real(r8), intent(in) :: absplw(ncoef,nrefr,nrefi,modes,lw_band_len) ! specific absorption

      real(r8), intent(in) ::  sigma_logr_aer(maxd_amode) ! geometric standard deviation of size distribution

!     tables of real refractive indices for aerosols
      real(r8), intent(in) :: refindex_real_sw(nrefr,sw_band_len) !
      real(r8), intent(in) :: refindex_im_sw(nrefi,sw_band_len) !
      real(r8), intent(in) :: refindex_real_lw(nrefr,lw_band_len) !
      real(r8), intent(in) :: refindex_im_lw(nrefi,lw_band_len) !

      integer lenchr


      integer len
! attribute vectors
! enter define mode
      call cam_pio_createfile(ncid, outfilename, PIO_CLOBBER)
! define dimensions
      ierr = pio_def_dim(ncid, 'lw_band', lw_band_len, lw_band_dim) 
      ierr = pio_def_dim(ncid, 'sw_band', sw_band_len, sw_band_dim)
      ierr = pio_def_dim(ncid, 'refindex_real', nrefr, refindex_real_dim)
      ierr = pio_def_dim(ncid, 'refindex_im', nrefi, refindex_im_dim)
      ierr = pio_def_dim(ncid, 'mode', modes, mode_dim)
      ierr = pio_def_dim(ncid, 'coef_number', ncoef, coef_dim)

! define variables

      lw_abs_dims(5) = lw_band_dim
      lw_abs_dims(4) = mode_dim
      lw_abs_dims(3) = refindex_im_dim
      lw_abs_dims(2) = refindex_real_dim
      lw_abs_dims(1) = coef_dim
      ierr = pio_def_var(ncid, 'absplw', PIO_DOUBLE, lw_abs_dims, lw_abs_id )
             
      sw_asm_dims(5) = sw_band_dim
      sw_asm_dims(4) = mode_dim
      sw_asm_dims(3) = refindex_im_dim
      sw_asm_dims(2) = refindex_real_dim
      sw_asm_dims(1) = coef_dim
      ierr = pio_def_var(ncid, 'asmpsw', PIO_DOUBLE, sw_asm_dims, sw_asm_id )

      sw_ext_dims(5) = sw_band_dim
      sw_ext_dims(4) = mode_dim
      sw_ext_dims(3) = refindex_im_dim
      sw_ext_dims(2) = refindex_real_dim
      sw_ext_dims(1) = coef_dim
      ierr = pio_def_var(ncid, 'extpsw', PIO_DOUBLE, sw_ext_dims, sw_ext_id )

      sw_abs_dims(5) = sw_band_dim
      sw_abs_dims(4) = mode_dim
      sw_abs_dims(3) = refindex_im_dim
      sw_abs_dims(2) = refindex_real_dim
      sw_abs_dims(1) = coef_dim
      ierr = pio_def_var(ncid, 'abspsw', PIO_DOUBLE, sw_abs_dims, sw_abs_id )

      refindex_dims(2) = sw_band_dim
      refindex_dims(1) = refindex_real_dim
      ierr = pio_def_var(ncid, 'refindex_real_sw', PIO_DOUBLE,  refindex_dims, &
          refindex_real_sw_id)
      refindex_dims(2) = sw_band_dim
      refindex_dims(1) = refindex_im_dim
      ierr = pio_def_var(ncid, 'refindex_im_sw', PIO_DOUBLE, refindex_dims, &
          refindex_im_sw_id)
      refindex_dims(2) = lw_band_dim
      refindex_dims(1) = refindex_real_dim
      ierr = pio_def_var(ncid, 'refindex_real_lw', PIO_DOUBLE, refindex_dims, &
          refindex_real_lw_id)
      refindex_dims(2) = lw_band_dim
      refindex_dims(1) = refindex_im_dim
      ierr = pio_def_var(ncid, 'refindex_im_lw', PIO_DOUBLE,  refindex_dims, &
          refindex_im_lw_id)
      sigma_logr_aer_dims(1) = mode_dim
      ierr = pio_def_var(ncid, 'sigma_logr_aer', PIO_DOUBLE, sigma_logr_aer_dims, &
          sigma_logr_aer_id)
! assign attributes
      ierr = pio_put_att(ncid, lw_abs_id, 'long_name',   &
         'coefficients of polynomial expression for longwave absorption')
      ierr = pio_put_att(ncid, lw_abs_id, 'units',  'meter^2 kilogram^-1')
      ierr = pio_put_att(ncid, sw_ext_id, 'long_name',  &
         'coefficients of polynomial expression for shortwave extinction') 
      ierr = pio_put_att(ncid, sw_ext_id, 'units',  'meter^2 kilogram^-1')
      ierr = pio_put_att(ncid, sw_asm_id, 'long_name',  &
         'coefficients of polynomial expression for shortwave asymmetry parameter')
      ierr = pio_put_att(ncid, sw_asm_id, 'units',  'fraction')
      ierr = pio_put_att(ncid, sw_abs_id, 'long_name',  &
         'coefficients of polynomial expression for shortwave absorption')
      ierr = pio_put_att(ncid, sw_abs_id, 'units',  'meter^2 kilogram^-1')
      ierr = pio_put_att(ncid, refindex_real_lw_id, 'long_name',  &
            'real refractive index of aerosol - longwave')
      ierr = pio_put_att(ncid, refindex_im_lw_id,   'long_name',  &
            'imaginary refractive index of aerosol - longwave')
      ierr = pio_put_att(ncid, refindex_real_sw_id, 'long_name',  &
            'real refractive index of aerosol - shortwave')
      ierr = pio_put_att(ncid, refindex_im_sw_id,   'long_name',  &
            'imaginary refractive index of aerosol - shortwave')
      ierr = pio_put_att(ncid, sigma_logr_aer_id, 'long_name',  &
            'geometric standard deviation of aerosol')
      ierr = pio_put_att(ncid, sigma_logr_aer_id, 'units',  '-')

      ierr = pio_put_att(ncid, PIO_GLOBAL, 'source',  'OPAC + miev0')
      ierr = pio_put_att(ncid, PIO_GLOBAL, 'history',  'Ghan and Zaveri, JGR 2007')

! leave define mode

      ierr = pio_enddef(ncid)

      ierr = pio_put_var(ncid,  sigma_logr_aer_id,  sigma_logr_aer)

      ierr = pio_put_var(ncid, refindex_real_lw_id, refindex_real_lw)

      ierr = pio_put_var(ncid, refindex_im_lw_id, refindex_im_lw)

      ierr = pio_put_var(ncid, refindex_real_sw_id, refindex_real_sw)

      ierr = pio_put_var(ncid, refindex_im_sw_id, refindex_im_sw)

      ierr = pio_put_var(ncid, lw_abs_id, absplw)

       ierr = pio_put_var(ncid, sw_ext_id, extpsw)

       ierr = pio_put_var(ncid, sw_abs_id, abspsw)

      ierr = pio_put_var(ncid, sw_asm_id, asmpsw)

      call pio_closefile(ncid)

      end subroutine write_modal_optics


      subroutine  read_modal_optics(infilename,  modes, lw_band_len, sw_band_len,  & 1
	 refindex_real_sw,refindex_im_sw, refindex_real_lw, refindex_im_lw, &
	 nrefr, nrefi, ncoef, extpsw, abspsw, asmpsw, absplw )

      use pio, only : pio_inq_dimlen, pio_inq_dimid, pio_get_var, pio_inq_varid, file_desc_t, var_desc_t, &
           pio_nowrite, pio_closefile
      use cam_pio_utils, only : cam_pio_openfile

      implicit none

      character*(*), intent(in) :: infilename

! netCDF id
      type(file_desc_t) ::  ncid
! dimension ids
      integer  lw_band_dim
      integer  sw_band_dim
      integer  refindex_real_dim
      integer  refindex_im_dim
      integer  mode_dim
      integer  ncoef_dim
! dimension lengths
      integer, intent(in) :: nrefr,nrefi ! number of refractive indices
      integer, intent(in) :: ncoef ! number of coefficients in polynomial expressions
      integer, intent(in) :: sw_band_len ! number of solar wavelengths
      integer, intent(in) :: lw_band_len ! number of infrared wavelengths
      integer, intent(in) :: modes ! number of aerosol modes

! variable ids
      type(var_desc_t) ::  lw_abs_id
      type(var_desc_t) ::  sw_asm_id
      type(var_desc_t) ::  sw_ext_id
      type(var_desc_t) ::  sw_abs_id
      type(var_desc_t) ::  sigma_logr_aer_id
      type(var_desc_t) ::  refindex_real_lw_id
      type(var_desc_t) ::  refindex_im_lw_id
      type(var_desc_t) ::  refindex_real_sw_id
      type(var_desc_t) ::  refindex_im_sw_id
! rank (number of dimensions) for each variable
      integer  lw_abs_rank
      integer  sw_asm_rank
      integer  sw_ext_rank
      integer  sw_abs_rank
      integer  sigma_logr_aer_rank
      integer refindex_rank
      parameter (lw_abs_rank = 5)
      parameter (sw_asm_rank = 5)
      parameter (sw_ext_rank = 5)
      parameter (sw_abs_rank = 5)
      parameter (refindex_rank=2)
      parameter (sigma_logr_aer_rank = 1)
! variable shapes
      integer  lw_abs_dims(lw_abs_rank)
      integer  sw_asm_dims(sw_asm_rank)
      integer  sw_ext_dims(sw_ext_rank)
      integer  sw_abs_dims(sw_abs_rank)
      integer refindex_dims(refindex_rank)
      integer coef_dim
      integer sigma_logr_aer_dims(sigma_logr_aer_rank)
! data variables

!     coefficients for parameterizing aerosol radiative properties
!     in terms of refractive index and wet radius
      real(r8), intent(out) :: extpsw(ncoef,nrefr,nrefi,modes,sw_band_len) ! specific extinction
      real(r8), intent(out) :: abspsw(ncoef,nrefr,nrefi,modes,sw_band_len) ! specific absorption
      real(r8), intent(out) :: asmpsw(ncoef,nrefr,nrefi,modes,sw_band_len) ! asymmetry factor
      real(r8), intent(out) :: absplw(ncoef,nrefr,nrefi,modes,lw_band_len) ! specific absorption

      real(r8) ::  sigma_logr_aer(maxd_amode) ! geometric standard deviation of size distribution

!     tables of real refractive indices for aerosols
      real(r8), intent(out) :: refindex_real_sw(nrefr,sw_band_len) !
      real(r8), intent(out) :: refindex_im_sw(nrefi,sw_band_len) !
      real(r8), intent(out) :: refindex_real_lw(nrefr,lw_band_len) !
      real(r8), intent(out) :: refindex_im_lw(nrefi,lw_band_len) !

      integer lenchr
      integer dimread
      integer start(5),count(5)
      integer m, ierr

      integer len
! open file
       call cam_pio_openfile(ncid, infilename, PIO_NOWRITE)
! inquire dimensions
      ierr = pio_inq_dimid(ncid,'lw_band',lw_band_dim)
      ierr = pio_inq_dimlen(ncid, lw_band_dim, dimread)
      if(dimread.ne.lw_band_len)then
         write(iulog,*)'lw_band_len=',dimread,' from ',infilename,' ne lw_band_len=',lw_band_len
	 call endrun
      endif
      ierr = pio_inq_dimid(ncid,'sw_band',sw_band_dim)
      ierr = pio_inq_dimlen(ncid, sw_band_dim, dimread)
      if(dimread.ne.sw_band_len)then
         write(iulog,*)'sw_band_len=',dimread,' from ',infilename,' ne sw_band_len=',sw_band_len
	 call endrun
      endif
      ierr = pio_inq_dimid(ncid,'refindex_real',refindex_real_dim)
      ierr = pio_inq_dimlen(ncid, refindex_real_dim, dimread)
      if(dimread.ne.nrefr)then
         write(iulog,*)'refindex_real=',dimread,' from ',infilename,' ne nrefr=',nrefr
	 call endrun
      endif
      ierr = pio_inq_dimid(ncid,'refindex_im',refindex_im_dim)
      ierr = pio_inq_dimlen(ncid, refindex_im_dim, dimread)
      if(dimread.ne.nrefi)then
         write(iulog,*)'refindex_im=',dimread,' from ',infilename,' ne nrefi=',nrefi
	 call endrun
      endif
      ierr = pio_inq_dimid(ncid,'mode',mode_dim)
      ierr = pio_inq_dimlen(ncid, mode_dim, dimread)
      if(dimread.ne.modes)then
         write(iulog,*)'mode=',dimread,' from ',infilename,' ne modes=',modes
	 call endrun
      endif
      ierr = pio_inq_dimid(ncid,'coef_number',coef_dim)
      ierr = pio_inq_dimlen(ncid, coef_dim, dimread)
      if(dimread.ne.ncoef)then
         write(iulog,*)'coef_number=',dimread,' from ',infilename,' ne ncoef=',ncoef
	 call endrun
      endif

! read variables
      ierr = pio_inq_varid(ncid,'absplw',lw_abs_id)
      ierr = pio_get_var(ncid, lw_abs_id, absplw)

      ierr = pio_inq_varid(ncid,'extpsw',sw_ext_id)
      ierr = pio_get_var(ncid, sw_ext_id, extpsw)

      ierr = pio_inq_varid(ncid,'abspsw',sw_abs_id)
      ierr = pio_get_var(ncid, sw_abs_id, abspsw)

      ierr = pio_inq_varid(ncid,'asmpsw',sw_asm_id)
      ierr = pio_get_var(ncid, sw_asm_id, asmpsw)

      ierr = pio_inq_varid(ncid, 'refindex_real_sw', refindex_real_sw_id)
      ierr = pio_get_var(ncid, refindex_real_sw_id, refindex_real_sw)

      ierr = pio_inq_varid(ncid, 'refindex_im_sw', refindex_im_sw_id)
      ierr = pio_get_var(ncid, refindex_im_sw_id, refindex_im_sw)

      ierr = pio_inq_varid(ncid, 'refindex_real_lw', refindex_real_lw_id)
      ierr = pio_get_var(ncid, refindex_real_lw_id, refindex_real_lw)

      ierr = pio_inq_varid(ncid, 'refindex_im_lw', refindex_im_lw_id)
      ierr = pio_get_var(ncid, refindex_im_lw_id, refindex_im_lw)

      ierr = pio_inq_varid(ncid, 'sigma_logr_aer', sigma_logr_aer_id)
      ierr = pio_get_var(ncid, sigma_logr_aer_id, sigma_logr_aer)
      do m=1,modes
         if(sigma_logr_aer(m)/sigmag_amode(m).lt.0.99.or. &
            sigma_logr_aer(m)/sigmag_amode(m).gt.1.01)then
	    write(iulog,*)'sigma_logr_aer,sigmag_amode=',sigma_logr_aer(m),sigmag_amode(m)
	    call endrun
	 end if
      end do

      call pio_closefile(ncid)

      end subroutine read_modal_optics
#endif
!MODAL_AERO
end module modal_aer_opt