module opt_prop

  use vtype_module

  implicit none

  private

  public :: OptPropInit
  public :: OptPropFinalize
  public :: OptPropGetNWN
  public :: OptPropGetNPress
  public :: OptPropGetNMol
  public :: OptPropGetNBand
  public :: OptPropGetDelWN
  public :: OptPropGetWN
  public :: OptPropGetBandWNBnds
  public :: OptPropGetBandBinIndexBnds
  public :: OptPropGetAbsCoefProf
  public :: OptPropGetPFInted
  public :: OptPropGetPFIntedRatio


  integer, save               :: IDMethod
  integer, parameter          :: IDMethodLBL        =  1
  integer, parameter          :: IDMethodLBLConstPF =  2
  integer, parameter          :: IDMethodKDDevelop  = 10
  integer, parameter          :: IDMethodKD         = 11


  ! Common
  character(128)       , save :: OptPropNcFNSave
  !
  character(128)       , save :: PressAxisName
  character(128)       , save :: MolAxisName
  !
  integer              , save :: NPressSave
  integer              , save :: NMolSave
  !
  real(DP), allocatable, save :: p_PressSave(:)
  real(DP), allocatable, save :: m_MolNumSave(:)

  ! LBL
  integer              , save :: NWaveNumSave
  real(DP), allocatable, save :: w_WaveNumSave(:)

  ! KDDevelop
  integer , parameter         :: NBndSave = 2
  integer              , save :: NBinSave
  integer              , save :: NBandSave
  integer , allocatable, save :: a_BinNumSave(:)
  real(DP), allocatable, save :: aa_BandWaveNumBndsSave     (:,:)
!!$  integer , allocatable, save :: aa_BandWaveNumIndexBndsSave(:,:)
  integer , allocatable, save :: aa_BandBinIndexBndsSave    (:,:)
  !
  character(128), save :: WaveNumAxisName
  character(128), save :: AbsCoefVarName
  character(128), save :: PFRatioVarName
  !
  real(DP), allocatable, save :: a_DelWaveNum(:)
  !
  ! KDDevelop only
  real(DP), allocatable, save :: za_PFRatio  (:,:)
  real(DP), allocatable, save :: zma_AbsCoef (:,:,:)


  character(128), save :: ModuleName = 'opt_prop'

  logical, save :: FlagInited = .false.

contains

  !----------------------------------------------------------------------------

  subroutine OptPropInit( &
    & Type, &
    & OptPropNcFN &
    & )

    use opt_prop_kd, only : OptPropKDInit

    character(*), intent(in) :: Type
    character(*), intent(in) :: OptPropNcFN

    if ( FlagInited ) return


    select case ( Type )
    case ( 'LBL' )
      IDMethod = IDMethodLBL
    case ( 'LBLConstPF' )
      IDMethod = IDMethodLBLConstPF
    case ( 'KDDevelop' )
      IDMethod = IDMethodKDDevelop
    case ( 'KD' )
      IDMethod = IDMethodKD
    case default
      write( 6, * ) 'In module, ', trim( ModuleName )
      write( 6, * ) 'Unexpected type: ', trim( Type )
      stop
    end select


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      call OptPropInitCore( &
        & OptPropNcFN &
        & )
    case ( IDMethodKD )
      call OptPropKDInit( &
        & OptPropNcFN &
        & )
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


    FlagInited = .true.

  end subroutine OptPropInit

  !----------------------------------------------------------------------------

  subroutine OptPropFinalize

    use opt_prop_kd, only : OptPropKDFinalize

    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      call OptPropFinalizeCore
    case ( IDMethodKD )
      call OptPropKDFinalize
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


    FlagInited = .false.

  end subroutine OptPropFinalize

  !----------------------------------------------------------------------------

  function OptPropGetNWN() result( NWN )

    use opt_prop_kd, only : OptPropKDGetNWN

    integer :: NWN

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      NWN = OptPropGetNWNCore()
    case ( IDMethodKD )
      NWN = OptPropKDGetNWN()
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end function OptPropGetNWN

  !----------------------------------------------------------------------------

  function OptPropGetNPress() result( NPress )

    use opt_prop_kd, only : OptPropKDGetNPress

    integer :: NPress

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      NPress = OptPropGetNPressCore()
    case ( IDMethodKD )
      NPress = OptPropKDGetNPress()
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end function OptPropGetNPress

  !----------------------------------------------------------------------------

  function OptPropGetNMol() result( NMol )

    use opt_prop_kd, only : OptPropKDGetNMol

    integer :: NMol

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      NMol = OptPropGetNMolCore()
    case ( IDMethodKD )
      NMol = OptPropKDGetNMol()
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end function OptPropGetNMol

  !----------------------------------------------------------------------------

  function OptPropGetNBand() result( NBand )

    use opt_prop_kd, only : OptPropKDGetNBand

    integer :: NBand

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      NBand = OptPropGetNBandCore()
    case ( IDMethodKD )
      NBand = OptPropKDGetNBand()
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end function OptPropGetNBand

  !----------------------------------------------------------------------------

  function OptPropGetDelWN( iWaveNum ) result( DelWaveNum )

    use opt_prop_kd, only : OptPropKDGetDelWN

    integer, intent(in) :: iWaveNum


    real(DP) :: DelWaveNum

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      DelWaveNum = OptPropGetDelWNCore( iWaveNum )
    case ( IDMethodKD )
      DelWaveNum = OptPropKDGetDelWN( iWaveNum )
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select



  end function OptPropGetDelWN

  !----------------------------------------------------------------------------

  function OptPropGetWN( iWaveNum ) result( WaveNum )

    integer, intent(in) :: iWaveNum

    real(DP) :: WaveNum

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      WaveNum = OptPropGetWNCore( iWaveNum )
    case ( IDMethodKD )
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  function OptPropGetWN cannot be used when IDMethod is IDMethodKD'
      stop
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end function OptPropGetWN

  !----------------------------------------------------------------------------

  subroutine OptPropGetBandWNBnds( &
    & NBand, &
    & aa_BandWNBnds &
    & )

    use opt_prop_kd, only : OptPropKDGetBandWNBnds

    integer , intent(in ) :: NBand
    real(DP), intent(out) :: aa_BandWNBnds(2,NBand)


    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      call OptPropGetBandWNBndsCore( &
        & NBand, &
        & aa_BandWNBnds &
        & )
    case ( IDMethodKD )
      call OptPropKDGetBandWNBnds( &
        & NBand, &
        & aa_BandWNBnds &
        & )
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end subroutine OptPropGetBandWNBnds

  !----------------------------------------------------------------------------

  subroutine OptPropGetBandBinIndexBnds( &
    & NBand, &
    & aa_BandBinIndexBnds &
    & )

    use opt_prop_kd, only : OptPropKDGetBandBinIndexBnds

    integer, intent(in ) :: NBand
    integer, intent(out) :: aa_BandBinIndexBnds(2,NBand)


    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      call OptPropGetBandBinIndexBndsCore( &
        & NBand, &
        & aa_BandBinIndexBnds &
        & )
    case ( IDMethodKD )
      call OptPropKDGetBandBinIndexBnds( &
        & NBand, &
        & aa_BandBinIndexBnds &
        & )
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end subroutine OptPropGetBandBinIndexBnds

  !----------------------------------------------------------------------------

  subroutine OptPropGetAbsCoefProf( &
    & iWaveNum, kmax, NMol, r_Press, r_Temp, r_VMRH2O, &
    & rm_AbsCoef &
    & )

    use opt_prop_kd, only : OptPropKDGetAbsCoefProf

    integer     , intent(in ) :: iWaveNum
    integer     , intent(in ) :: kmax
    integer     , intent(in ) :: NMol
    real(DP)    , intent(in ) :: r_Press   (1:kmax)
    real(DP)    , intent(in ) :: r_Temp    (1:kmax)
    real(DP)    , intent(in ) :: r_VMRH2O  (1:kmax)
    real(DP)    , intent(out) :: rm_AbsCoef(1:kmax,1:NMol)


    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      call OptPropGetAbsCoefProfCore( &
        & iWaveNum, kmax, NMol, &
        & rm_AbsCoef &
        & )
    case ( IDMethodKD )
      call OptPropKDGetAbsCoefProf( &
        & iWaveNum, kmax, NMol, r_Press, r_Temp, r_VMRH2O, &
        & rm_AbsCoef &
        & )
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end subroutine OptPropGetAbsCoefProf

  !----------------------------------------------------------------------------

  subroutine OptPropGetPFInted( &
    & iWaveNum, &
    & kmax, &
    & r_Temp, SurfTemp, &
    & r_PFInted, SurfPFInted, SurfDPFDTInted &
    & )

    integer , intent(in ) :: iWaveNum
    integer , intent(in ) :: kmax
    real(DP), intent(in ) :: r_Temp   (1:kmax)
    real(DP), intent(in ) :: SurfTemp
    real(DP), intent(out) :: r_PFInted(1:kmax)
    real(DP), intent(out) :: SurfPFInted
    real(DP), intent(out) :: SurfDPFDTInted


    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      call OptPropGetPFIntedCore( &
        & iWaveNum, &
        & kmax, &
        & r_Temp, SurfTemp, &
        & r_PFInted, SurfPFInted, SurfDPFDTInted &
        & )
    case ( IDMethodKD )
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  function OptPropGetPFInted cannot be used when IDMethod is IDMethodKD'
      stop
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end subroutine OptPropGetPFInted

  !----------------------------------------------------------------------------

  subroutine OptPropGetPFIntedRatio( &
    & iWaveNum, kmax, r_Temp, SurfTemp, &
    & r_PFRatio, SurfPFRatio &
    & )

    use opt_prop_kd, only : OptPropKDGetPFIntedRatio

    integer     , intent(in ) :: iWaveNum
    integer     , intent(in ) :: kmax
    real(DP)    , intent(in ) :: r_Temp   (1:kmax)
    real(DP)    , intent(in ) :: SurfTemp
    real(DP)    , intent(out) :: r_PFRatio(1:kmax)
    real(DP)    , intent(out) :: SurfPFRatio


    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL )
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  function OptPropGetPFIntedRatio cannot be used when IDMethod is IDMethodLBL'
      stop
    end select


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF, IDMethodKDDevelop )
      call OptPropGetPFIntedRatioCore( &
        & iWaveNum, kmax, &
        & r_PFRatio, SurfPFRatio &
        & )
    case ( IDMethodKD )
      call OptPropKDGetPFIntedRatio( &
        & iWaveNum, kmax, r_Temp, SurfTemp, &
        & r_PFRatio, SurfPFRatio &
        & )
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end subroutine OptPropGetPFIntedRatio

  !----------------------------------------------------------------------------
  !----------------------------------------------------------------------------
  !----------------------------------------------------------------------------

  subroutine OptPropInitCore( &
    & OptPropNcFN &
    & )

    use ni3_module


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


    ! local variables
    !
    character(stdstr) :: Mode
    integer           :: NcID


!!$    if ( .not. FlagInited ) then
!!$      write( 6, * ) trim( ModuleName ), " is not initialized."
!!$      stop
!!$    end if


    NPressSave   = -1
    NMolSave     = -1
    NWaveNumSave = -1
    NBinSave     = -1
    NBandSave    = -1


    OptPropNcFNSave = OptPropNcFN

    PressAxisName = "Press"
    MolAxisName   = "MolNum"

    Mode = "read"
    call ni3_open( OptPropNcFNSave, Mode, NcID )
    call ni3_inq_dimlen( NcID, PressAxisName, NPressSave )
    call ni3_inq_dimlen( NcID, MolAxisName  , NMolSave   )
    allocate( p_PressSave (1:NPressSave) )
    allocate( m_MolNumSave(1:NMolSave  ) )
    call ni3_get_var( NcID, PressAxisName, p_PressSave  )
    call ni3_get_var( NcID, MolAxisName  , m_MolNumSave )


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      WaveNumAxisName = 'WaveNum'
      AbsCoefVarName  = 'AbsCoef'
      PFRatioVarName  = 'PFRatio'
      !
      call ni3_inq_dimlen( NcID, WaveNumAxisName, NWaveNumSave )
      allocate( w_WaveNumSave( 1:NWaveNumSave ) )
      call ni3_get_var( NcID, WaveNumAxisName, w_WaveNumSave )
    case ( IDMethodKDDevelop )
      WaveNumAxisName = 'BinNum'
      !
      call ni3_inq_dimlen( NcID, WaveNumAxisName, NBinSave  )
      call ni3_inq_dimlen( NcID, "BandNum"      , NBandSave )
      allocate( a_BinNumSave               (NBinSave) )
      allocate( aa_BandWaveNumBndsSave     (NBndSave,NBandSave) )
      allocate( aa_BandBinIndexBndsSave    (NBndSave,NBandSave) )

      call ni3_get_var( NcID, WaveNumAxisName   , a_BinNumSave            )
      call ni3_get_var( NcID, 'BandWaveNumBnds' , aa_BandWaveNumBndsSave  )
      call ni3_get_var( NcID, 'BandBinIndexBnds', aa_BandBinIndexBndsSave )
      !
      AbsCoefVarName  = 'BinAbsCoef'
      PFRatioVarName  = 'BinPFRatio'
    end select

    select case ( IDMethod )
    case ( IDMethodKDDevelop )
      allocate( a_DelWaveNum(NBinSave) )
      call ni3_get_var( NcID, "BinWeight", a_DelWaveNum )
    end select
    !
    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      allocate( zma_AbsCoef (NPressSave,NMolSave,NWaveNumSave) )
      call ni3_get_var( NcID, AbsCoefVarName, zma_AbsCoef )
    case ( IDMethodKDDevelop )
      allocate( zma_AbsCoef (NPressSave,NMolSave,NBinSave) )
      call ni3_get_var( NcID, AbsCoefVarName, zma_AbsCoef )
    end select

    select case ( IDMethod )
    case ( IDMethodLBL )
    case ( IDMethodLBLConstPF )
      allocate( za_PFRatio(NPressSave,NWaveNumSave) )
      call ni3_get_var( NcID, PFRatioVarName, za_PFRatio )
    case ( IDMethodKDDevelop )
      allocate( za_PFRatio(NPressSave,NBinSave) )
      call ni3_get_var( NcID, PFRatioVarName, za_PFRatio )
    end select

    call ni3_close( NcID )


  end subroutine OptPropInitCore

  !----------------------------------------------------------------------------

  subroutine OptPropFinalizeCore


    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    NPressSave   = -1
    NMolSave     = -1
    NWaveNumSave = -1
    NBinSave     = -1
    NBandSave    = -1


    deallocate( p_PressSave  )
    deallocate( m_MolNumSave )

    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      NWaveNumSave    = 0
      deallocate( w_WaveNumSave )
    case ( IDMethodKDDevelop )
      NBinSave    = 0
      deallocate( a_BinNumSave                )
      deallocate( aa_BandWaveNumBndsSave      )
!!$      deallocate( aa_BandWaveNumIndexBndsSave )
      deallocate( aa_BandBinIndexBndsSave     )
    end select
    !
    select case ( IDMethod )
    case ( IDMethodKDDevelop )
      deallocate( a_DelWaveNum )
    end select
    !
    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      deallocate( zma_AbsCoef )
    case ( IDMethodKDDevelop )
      deallocate( zma_AbsCoef )
    end select

    select case ( IDMethod )
    case ( IDMethodLBL )
    case ( IDMethodLBLConstPF )
      deallocate( za_PFRatio )
    case ( IDMethodKDDevelop )
      deallocate( za_PFRatio )
    end select


  end subroutine OptPropFinalizeCore

  !----------------------------------------------------------------------------

  function OptPropGetNWNCore() result( NWN )


    integer :: NWN

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      NWN = NWaveNumSave
    case ( IDMethodKDDevelop )
      NWN = NBinSave
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end function OptPropGetNWNCore

  !----------------------------------------------------------------------------

  function OptPropGetNPressCore() result( NPress )


    integer :: NPress

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    NPress = NPressSave


  end function OptPropGetNPressCore

  !----------------------------------------------------------------------------

  function OptPropGetNMolCore() result( NMol )


    integer :: NMol

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    NMol = NMolSave


  end function OptPropGetNMolCore

  !----------------------------------------------------------------------------

  function OptPropGetNBandCore() result( NBand )


    integer :: NBand

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  function OptPropGetNBandCore cannot be used when IDMethod is IDMethodLBL or IDMethodLBLConstPF'
      stop
    case ( IDMethodKDDevelop )
      NBand = NBandSave
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end function OptPropGetNBandCore

  !----------------------------------------------------------------------------

  function OptPropGetDelWNCore( iWaveNum ) result( DelWaveNum )


    integer, intent(in) :: iWaveNum

    real(DP) :: DelWaveNum

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      DelWaveNum = w_WaveNumSave( 2 ) - w_WaveNumSave( 1 )
    case ( IDMethodKDDevelop )
      DelWaveNum = a_DelWaveNum(iWaveNum)
    end select


  end function OptPropGetDelWNCore

  !----------------------------------------------------------------------------

  function OptPropGetWNCore( iWaveNum ) result( WaveNum )


    integer, intent(in) :: iWaveNum

    real(DP) :: WaveNum

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      WaveNum = w_WaveNumSave( iWaveNum )
    case ( IDMethodKDDevelop )
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  function OptPropGetWNCore cannot be used when IDMethod is IDMethodKDDevelop'
      stop
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end function OptPropGetWNCore

  !----------------------------------------------------------------------------

  subroutine OptPropGetBandWNBndsCore( &
    & NBand, &
    & aa_BandWNBnds &
    & )


    integer , intent(in ) :: NBand
    real(DP), intent(out) :: aa_BandWNBnds(2,NBand)

    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  function OptPropGetBandWNBndsCore cannot be used when IDMethod is IDMethodLBL'
      stop
    case ( IDMethodKDDevelop )
      ! check
      if ( NBand /= NBandSave ) then
        write( 6, * ) 'Number of bands is inappropriate: ', NBand, NBandSave
        stop
      end if
      aa_BandWNBnds = aa_BandWaveNumBndsSave
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select


  end subroutine OptPropGetBandWNBndsCore

  !----------------------------------------------------------------------------

  subroutine OptPropGetBandBinIndexBndsCore( &
    & NBand, &
    & aa_BandBinIndexBnds &
    & )

    integer, intent(in ) :: NBand
    integer, intent(out) :: aa_BandBinIndexBnds(2,NBand)


    ! local variables
    !


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  function OptPropGetBandBinIndexBndsCore cannot be used when IDMethod is IDMethodLBL or IDMethodLBLConstPF'
      stop
    case ( IDMethodKDDevelop )
      ! check
      if ( NBand /= NBandSave ) then
        write( 6, * ) 'Number of bands is appropriate: ', NBand, NBandSave
        stop
      end if
      aa_BandBinIndexBnds = aa_BandBinIndexBndsSave
    end select


  end subroutine OptPropGetBandBinIndexBndsCore

  !----------------------------------------------------------------------------

  subroutine OptPropGetAbsCoefProfCore( &
    & iWaveNum, kmax, NMol, &
    & pm_AbsCoef &
    & )


    integer     , intent(in ) :: iWaveNum
    integer     , intent(in ) :: kmax
    integer     , intent(in ) :: NMol
    real(DP)    , intent(out) :: pm_AbsCoef(1:kmax,1:NMol)


    ! local variables
    !
!!$    integer        :: k


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    ! check
    if ( kmax /= NPressSave ) then
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Number of layers does not match with number of pressure levels in optical properties: ', &
        & kmax, NPressSave
      stop
    end if
!!$      do k = 1, kmax
!!$        if ( abs( p_Press(k) - p_PressSave(k) ) > p_PressSave(k) * 1.0d-6 ) then
!!$          write( 6, * ) 'In ', trim( ModuleName )
!!$          write( 6, * ) '  Pressure is inappropriate: ', p_PressSave(k), p_Press(k)
!!$          stop
!!$        end if
!!$      end do


    pm_AbsCoef = zma_AbsCoef(:,:,iWaveNum)


  end subroutine OptPropGetAbsCoefProfCore

  !----------------------------------------------------------------------------

  subroutine OptPropGetPFIntedCore( &
    & iWaveNum, &
    & kmax, &
    & r_Temp, SurfTemp, &
    & r_PFInted, SurfPFInted, SurfDPFDTInted &
    & )

    use constants0, only : PI

    use planck_func_wrapper

    integer , intent(in ) :: iWaveNum
    integer , intent(in ) :: kmax
    real(DP), intent(in ) :: r_Temp   (1:kmax)
    real(DP), intent(in ) :: SurfTemp
    real(DP), intent(out) :: r_PFInted(1:kmax)
    real(DP), intent(out) :: SurfPFInted
    real(DP), intent(out) :: SurfDPFDTInted


    ! local variables
    !
    real(DP) :: WaveNum
    real(DP) :: DelWaveNum
    real(DP) :: WNs
    real(DP) :: WNe
    integer  :: GQNum


    select case ( IDMethod )
    case ( IDMethodLBL, IDMethodLBLConstPF )
      WaveNum    = OptPropGetWNCore( iWaveNum )
      DelWaveNum = OptPropGetDelWNCore( iWaveNum )
      WNs = WaveNum - DelWaveNum / 2.0d0
      WNe = WaveNum + DelWaveNum / 2.0d0
    case ( IDMethodKDDevelop )
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  function OptPropGetPFIntedCore cannot be used when IDMethod is IDMethodKDDevelop, IDMethodKD'
      stop
    case default
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Unexpected case default'
      stop
    end select

!!$    GQNum = 1
    GQNum = int( DelWaveNum / 10.0d0 ) + 1

    call Integ_PF_GQ_Array1D( &
      & WNs, WNe, GQNum, &
      & 1, kmax, &
      & r_Temp, &
      & r_PFInted &
      & )
    r_PFInted = PI * r_PFInted
    call Integ_PF_GQ_Array0D( &
      & WNs, WNe, GQNum, &
      & SurfTemp, &
      & SurfPFInted &
      & )
    SurfPFInted = PI * SurfPFInted
    call Integ_DPFDT_GQ_Array0D( &
      & WNs, WNe, GQNum,                 & ! (in )
      & SurfTemp,                & ! (in )
      & SurfDPFDTInted                  & ! (out)
      & )
    SurfDPFDTInted = PI * SurfDPFDTInted


  end subroutine OptPropGetPFIntedCore

  !----------------------------------------------------------------------------

  subroutine OptPropGetPFIntedRatioCore( &
    & iWaveNum, kmax, &
    & r_PFRatio, SurfPFRatio &
    & )


    integer     , intent(in ) :: iWaveNum
    integer     , intent(in ) :: kmax
    real(DP)    , intent(out) :: r_PFRatio(1:kmax)
    real(DP)    , intent(out) :: SurfPFRatio


    ! local variables
    !

!!$    real(DP), allocatable :: za_PFRatio(:,:)


    if ( .not. FlagInited ) then
      write( 6, * ) trim( ModuleName ), " is not initialized."
      stop
    end if


    ! check
    if ( kmax /= NPressSave ) then
      write( 6, * ) 'In ', trim( ModuleName )
      write( 6, * ) '  Number of layers does not match with number of pressure levels in optical properties: ', &
        & kmax, NPressSave
      stop
    end if


    r_PFRatio = za_PFRatio(:,iWaveNum)


!!$    allocate( za_PFRatio( NPressSave, NWaveNumSave ) )
!!$    call HistoryGet( OptPropNcFNSave, PFRatioVarName, za_PFRatio, &
!!$      & quiet = .true. )
!!$    z_PFRatio = za_PFRatio(:,iWaveNum)
!!$    deallocate( za_PFRatio )


    SurfPFRatio = r_PFRatio(1)


  end subroutine OptPropGetPFIntedRatioCore

  !----------------------------------------------------------------------------

end module opt_prop

