opticalProperties.f90 Source File


Source Code

module opticalProperties
    !! module implments the optical property abstract type and the types that inheirt from it
    use constants, only : wp
    use piecewiseMod

    implicit none
    !! abstract optical property type
    type, abstract :: opticalProp_base
        !> scattering coeff. \[cm^{-1}\]    
        real(kind=wp) :: mus
        !> absoprtion coeff. \[cm^{-1}\]    
        real(kind=wp) :: mua
        !> g factor
        real(kind=wp) :: hgg
        !> g factor squared
        real(kind=wp) :: g2
        !> refractive index
        real(kind=wp) :: n
        !> \[\kappa = \mu_s + \mu_a\]
        real(kind=wp) :: kappa
        !> \[a = \frac{\mu_s}{\mu_s + \mu_a}\]
        real(kind=wp) :: albedo
        contains
            procedure(updateInterface), deferred :: update
    end type opticalProp_base

    abstract interface
        subroutine updateInterface(this, wavelength)
            use constants, only : wp
            use piecewiseMod
            import opticalProp_base
            implicit none
            class(opticalProp_base), intent(inout) :: this
            real(kind=wp),           intent(out)   :: wavelength
        end subroutine updateInterface
    end interface

    type, extends(opticalProp_base) :: opticalProp_t
        class(opticalProp_base), allocatable :: value
        contains
            procedure :: update => update_opticalProp_t
            procedure, private :: opticalProp_t_assign
            generic :: assignment(=) => opticalProp_t_assign
    end type opticalProp_t

    type, extends(opticalProp_base) :: mono
        contains
            procedure :: update => updateMono
    end type mono

    type, extends(opticalProp_base) :: spectral
        type(piecewise1D), private :: mus_a, mua_a, hgg_a, n_a, flux
        contains
            procedure :: update => updateSpectral
    end type spectral

    interface opticalProp_t
        module procedure opticaProp_new
    end interface

    interface spectral
        module procedure init_spectral
    end interface spectral

    interface mono
        module procedure init_mono
    end interface mono

    private
    public :: spectral, mono, opticalProp_base, opticalProp_t

    contains

    subroutine opticalProp_t_assign(lhs, rhs)

        class(opticalProp_t),    intent(inout) :: lhs
        class(opticalProp_base), intent(in)    :: rhs

        if (allocated(lhs%value))deallocate(lhs%value)
        ! Prevent nested derived type
        select type (rhsT=>rhs)
            class is (opticalProp_t)
                if(allocated(rhsT%value))allocate(lhs%value,source=rhsT%value)
            class default
                allocate(lhs%value,source=rhsT)
        end select

    end subroutine opticalProp_t_assign

    ! optical_property initializer
    type(opticalProp_t) function opticaProp_new(rhs) result(lhs)

        class(opticalProp_base), intent(in) :: rhs
        allocate(lhs%value,source=rhs)

    end function opticaProp_new

    subroutine update_opticalProp_t(this, wavelength)

        class(opticalProp_t), intent(inout) :: this
        real(kind=wp),        intent(out)   :: wavelength

        call this%value%update(wavelength)

    end subroutine update_opticalProp_t

    type(mono) function init_mono(mus, mua, hgg, n) result(res)

        real(kind=wp), intent(in) :: mus, mua, hgg, n

        res%mus = mus
        res%mua = mua

        res%kappa = mus + mua
        if(res%mua < 1e-9_wp)then          
            res%albedo = 1.
        else
            res%albedo = res%mus / res%kappa
        end if

        res%hgg = hgg
        res%g2 = hgg**2
        res%n = n

    end function init_mono

    type(spectral) function init_spectral(mus, mua, hgg, n, flux) result(res)

        real(kind=wp), allocatable, intent(in) :: mus(:, :), mua(:, :), hgg(:, :), n(:, :), flux(:, :)
        
        real(kind=wp) :: wave, tmp

        !setup cdfs
        res%flux = piecewise1D(flux)

        res%mus_a = piecewise1D(mus)
        res%mua_a = piecewise1D(mua)
        res%hgg_a = piecewise1D(hgg)
        res%n_a = piecewise1D(n)

        !sample wavelength so we can sample from other optical properties at the correct points
        call res%flux%sample(wave,  tmp)
        ! sample optical properties
        call res%mus_a%sample(res%mus, wave)
        call res%mua_a%sample(res%mua, wave)
        call res%hgg_a%sample(res%hgg, wave)
        res%g2 = res%hgg**2
        call res%n_a%sample(res%n, wave)

        res%kappa =  res%mus + res%mua
        if(res%mua < 1e-9_wp)then          
            res%albedo = 1.
        else
            res%albedo = res%mus / res%kappa
        end if
    end function init_spectral

    subroutine updateMono(this, wavelength)

        implicit none

        class(Mono),   intent(inout) :: this
        real(kind=wp), intent(out)   :: wavelength

        ! don't do anything as wavelength will not change
        wavelength = 0.0_wp

    end subroutine updateMono


    subroutine updateSpectral(this, wavelength)

        implicit none

        class(spectral), intent(inout) :: this
        real(kind=wp),   intent(out)   :: wavelength

        real(kind=wp) :: tmp

        !get wavelength
        call this%flux%sample(wavelength, tmp)

        !update mus
        call this%mus_a%sample(this%mus, tmp, wavelength)

        !update mua
        call this%mua_a%sample(this%mua, tmp, wavelength)

        !update hgg
        call this%hgg_a%sample(this%hgg, tmp, wavelength)

        this%g2 = this%hgg**2

        !update n
        call this%n_a%sample(this%n, tmp, wavelength)

        !update kappa and albedo
        this%kappa =  this%mus + this%mua
        this%albedo = this%mus / this%kappa

    end subroutine updateSpectral
end module opticalProperties