!fpx3_header(0.13_3a)
!
!dependencies
!   dir: ~/devel/gyre-4/src/utils 
!   sources: -
!   includes: ../extern/core/core.inc
!   uses: core_kinds gyre_cocache
!   provides: gyre_model
!end dependencies
!
!end fpx3_header
! Module   : gyre_model
! Purpose  : stellar model (interface)
!
! Copyright 2013-2014 Rich Townsend
!
! This file is part of GYRE. GYRE is free software: you can
! redistribute it and/or modify it under the terms of the GNU General
! Public License as published by the Free Software Foundation, version 3.
!
! GYRE is distributed in the hope that it will be useful, but WITHOUT
! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
! License for more details.
!
! You should have received a copy of the GNU General Public License
! along with this program.  If not, see <http://www.gnu.org/licenses/>.

! Incfile  : core
! Purpose  : fpx3 macros

!****

!****

!****

!****

!****

!****

!****

!****

!****

module gyre_model

  ! Uses

  use core_kinds

  ! No implicit typing

  implicit none

  ! Derived-type definitions

  type, abstract :: model_t
   contains
     private

    procedure(y_1_), deferred :: V_1_
    procedure(y_v_), deferred :: V_v_
    generic, public           :: V => V_1_, V_v_

    procedure(y_1_), deferred :: As_1_
    procedure(y_v_), deferred :: As_v_
    generic, public           :: As => As_1_, As_v_

    procedure(y_1_), deferred :: U_1_
    procedure(y_v_), deferred :: U_v_
    generic, public           :: U => U_1_, U_v_

    procedure(y_1_), deferred :: c_1_1_
    procedure(y_v_), deferred :: c_1_v_
    generic, public           :: c_1 => c_1_1_, c_1_v_

    procedure(y_1_), deferred :: Gamma_1_1_
    procedure(y_v_), deferred :: Gamma_1_v_
    generic, public           :: Gamma_1 => Gamma_1_1_, Gamma_1_v_

    procedure(y_1_), deferred :: nabla_ad_1_
    procedure(y_v_), deferred :: nabla_ad_v_
    generic, public           :: nabla_ad => nabla_ad_1_, nabla_ad_v_

    procedure(y_1_), deferred :: delta_1_
    procedure(y_v_), deferred :: delta_v_
    generic, public           :: delta => delta_1_, delta_v_

    procedure(y_1_), deferred :: c_rad_1_
    procedure(y_v_), deferred :: c_rad_v_
    generic, public           :: c_rad => c_rad_1_, c_rad_v_

    procedure(y_1_), deferred :: dc_rad_1_
    procedure(y_v_), deferred :: dc_rad_v_
    generic, public           :: dc_rad => dc_rad_1_, dc_rad_v_

    procedure(y_1_), deferred :: c_thm_1_
    procedure(y_v_), deferred :: c_thm_v_
    generic, public           :: c_thm => c_thm_1_, c_thm_v_

    procedure(y_1_), deferred :: c_dif_1_
    procedure(y_v_), deferred :: c_dif_v_
    generic, public           :: c_dif => c_dif_1_, c_dif_v_

    procedure(y_1_), deferred :: c_eps_ad_1_
    procedure(y_v_), deferred :: c_eps_ad_v_
    generic, public           :: c_eps_ad => c_eps_ad_1_, c_eps_ad_v_

    procedure(y_1_), deferred :: c_eps_S_1_
    procedure(y_v_), deferred :: c_eps_S_v_
    generic, public           :: c_eps_S => c_eps_S_1_, c_eps_S_v_

    procedure(y_1_), deferred :: nabla_1_
    procedure(y_v_), deferred :: nabla_v_
    generic, public           :: nabla => nabla_1_, nabla_v_

    procedure(y_1_), deferred :: kappa_ad_1_
    procedure(y_v_), deferred :: kappa_ad_v_
    generic, public           :: kappa_ad => kappa_ad_1_, kappa_ad_v_

    procedure(y_1_), deferred :: kappa_S_1_
    procedure(y_v_), deferred :: kappa_S_v_
    generic, public           :: kappa_S => kappa_S_1_, kappa_S_v_

    procedure(y_1_), deferred :: tau_thm_1_
    procedure(y_v_), deferred :: tau_thm_v_
    generic, public           :: tau_thm => tau_thm_1_, tau_thm_v_

    procedure(y_1_), deferred :: Omega_rot_1_
    procedure(y_v_), deferred :: Omega_rot_v_
    generic, public           :: Omega_rot => Omega_rot_1_, Omega_rot_v_

     procedure(pi_c_), deferred, public         :: pi_c
     procedure(is_zero_), deferred, public      :: is_zero
     procedure(attach_cache_), deferred, public :: attach_cache
     procedure(detach_cache_), deferred, public :: detach_cache
     procedure(fill_cache_), deferred, public   :: fill_cache
  end type model_t

  ! Interfaces

  abstract interface

     function y_1_ (this, x) result (y)
       use core_kinds
       import model_t
       class(model_t), intent(in) :: this
       real(WP), intent(in)       :: x
       real(WP)                   :: y
     end function y_1_

     function y_v_ (this, x) result (y)
       use core_kinds
       import model_t
       class(model_t), intent(in) :: this
       real(WP), intent(in)       :: x(:)
       real(WP)                   :: y(SIZE(x))
     end function y_v_

     function pi_c_ (this) result (pi_c)
       use core_kinds
       import model_t
       class(model_t), intent(in) :: this
       real(WP)                   :: pi_c
     end function pi_c_

     function is_zero_ (this, x) result (is_zero)
       use core_kinds
       import model_t
       class(model_t), intent(in) :: this
       real(WP), intent(in)       :: x
       logical                    :: is_zero
     end function is_zero_

     subroutine attach_cache_ (this, cc)
       use gyre_cocache
       import model_t
       class(model_t), intent(inout)         :: this
       class(cocache_t), pointer, intent(in) :: cc
     end subroutine attach_cache_

     subroutine detach_cache_ (this)
       import model_t
       class(model_t), intent(inout) :: this
     end subroutine detach_cache_

     subroutine fill_cache_ (this, x)
       use core_kinds
       import model_t
       class(model_t), intent(inout) :: this
       real(WP), intent(in)          :: x(:)
     end subroutine fill_cache_

  end interface

 ! Access specifiers

  private

  public :: model_t

end module gyre_model
