!---------------------------------------------------------------------
!     Copyright (C) GFD Dennou Club, 2006. All rights reserved.
!---------------------------------------------------------------------
!
!= 1 次元 (x 方向) 等間隔交互格子 有限差分モデル用 基本モジュール
!
!* 履歴
!  * 2007/07/15 (小高正嗣) : 3D deepconv へ移植, dc_types を Use.
!  * 2006/12/26 (小高正嗣) : p_X を復活, x_p, p_x の名前を元に戻す
!  * 2006/06/17 (小高正嗣) : IntX_*, AvrX_* を追加
!  * 2006/05/26 (小高正嗣) : モジュール名称変更
!  * 2006/02/02 (小高正嗣) : 新規作成
!
module x_base_module
  != 1 次元 (x 方向) 等間隔交互格子 有限差分モデル用 基本モジュール
  !
  !== 概要
  !
  ! x_base_module は, 1 次元 (x 方向) 等間隔交互格子を用いた有限差分
  ! 法に基づく数値モデルのための, 基本的な Fortran90 副プログラムおよび
  ! 関数を提供する. 
  !
  ! このモジュールは x_module の下位モジュールである. 下請けモジュール
  ! として data_type モジュールを用いている. 
  ! 
  !== 備考
  !
  ! * 例外処理がない
  ! * その場合のメッセージ表示がない
  ! * 初期化の値はマシンイプシロン値としておくべき

  use dc_types, only : DBKIND => DP
  implicit none

  private
  public :: im, xmargin, imin, imax, x_X, p_X, x_dx, p_dx
  public :: x_axis_init, x_avr_p, p_avr_x, IntX_p, IntX_x, AvrX_p, AvrX_x

  integer         :: im      = 10 ! 格子点数
  integer         :: xmargin = 2  ! 糊代格子点数
  integer         :: imin         ! 配列添字の下限
  integer         :: imax         ! 配列添字の上限

  real(DBKIND),allocatable :: x_X(:)       ! 半整数格子点座標
  real(DBKIND),allocatable :: p_X(:)       ! 整数格子点座標
  real(DBKIND),allocatable :: x_dx(:)       ! 半整数格子点座標
  real(DBKIND),allocatable :: p_dx(:)       ! 整数格子点座標

  save im, xmargin, imin, imax, x_X, p_X, x_dx, p_dx

  contains
!--------------------------------------------------------------------
    subroutine x_axis_init(i, xmg, xmin, xmax)
      ! 配列の上下限の値と格子点座標値, 格子点間隔を設定する

      integer,intent(in)  :: i    ! x 方向格子点数
      integer,intent(in)  :: xmg  ! x 方向糊代格子点数
      real(DBKIND),intent(in) :: xmin ! x 座標最小値     
      real(DBKIND),intent(in) :: xmax ! x 座標最大値  
      integer             :: ix   ! do ループ添字
      real(DBKIND)            :: dx   ! 格子間隔

      im = i
      xmargin = xmg

      imin = 1  - xmargin
      imax = im + xmargin

      allocate(x_X(imin:imax))
      allocate(p_X(imin:imax))
      allocate(x_dx(imin:imax))
      allocate(p_dx(imin:imax))

      dx = (xmax - xmin)/im

      do ix = imin, imax
        p_X(ix) = dx * ix
        x_X(ix) = dx * (ix - 0.5)
        x_dx(ix) = dx
        p_dx(ix) = dx
      end do

    end subroutine x_axis_init  
!--------------------------------------------------------------------
    function x_avr_p(p_Var)
      ! 平均操作を行い整数格子点の配列値を半整数格子点上へ返す
  
      real(DBKIND),intent(in) :: p_Var(imin:imax)  ! 入力
      real(DBKIND)            :: x_avr_p(imin:imax) ! 出力
      integer             :: ix                ! ループ添字

      ! 初期化
      ! * 0 割りを防ぐためにはマシンイプシロン値を用いるべき
      !
      x_avr_p = 0.0d0

      ! 平均操作
      ! * 平均がとれない imin 格子上の値は計算しない.
      !
      do ix = imin+1, imax
        x_avr_p(ix) = (p_Var(ix) + p_Var(ix-1))*0.5d0 
      end do

    end function x_avr_p

!--------------------------------------------------------------------
    function p_avr_x(x_Var)
      ! 平均操作を行い半整数格子点の配列値を整数格子点上へ返す
  
      real(DBKIND),intent(in) :: x_Var(imin:imax)  ! 入力
      real(DBKIND)            :: p_avr_x(imin:imax) ! 出力
      integer             :: ix                ! ループ添字

      ! 初期化
      ! * 0 割りを防ぐためにはマシンイプシロン値を用いるべき
      !
      p_avr_x = 0.0d0

      ! 平均操作
      ! * 平均がとれない imax 格子上の値は計算しない.
      ! * 不等間隔格子なので重みをつけて平均する.
      !   点 P, Q を a:b に内分する点の X の値は, a*X(Q) + b*X(P) 
      !   (a+b=1 を仮定) であることから, 
      !
      !     p_Var(ix) = [0.5*x_dx(ix)  /p_dx(ix)]*x_Var(ix+1) +    
      !                 [0.5*x_dx(ix+1)/p_dx(ix)]*x_Var(ix)     
      !   
      !   変形すると
      !
      !     p_Var(ix) = [x_dx(ix)*x_Var(ix+1) + x_dx(ix+1)*x_Var(ix)]
      !                 *0.5/p_dx(ix)
      ! 
      do ix = imin, imax-1
        p_avr_x(ix) = &
          &  (x_dx(ix)*x_Var(ix+1) + x_dx(ix+1)*x_Var(ix))*0.5d0/p_dx(ix)
      end do

    end function p_avr_x
!--------------------------------------------------------------------
    function IntX_p(p_Var)
      ! 整数格子上の配列に対し x 方向に重み付きの積分を行う

      real(DBKIND), intent(in) :: p_Var(imin:imax)  ! 入力
      real(DBKIND)             :: IntX_p            ! 出力

      ! 初期化
      IntX_p = 0.0d0

      ! 積分
      IntX_p = sum(p_Var(1:im)*p_dx(1:im))

    end function IntX_p
!--------------------------------------------------------------------
    function IntX_x(x_Var)
      ! 半整数格子上の配列に対し x 方向に重み付きの積分を行う

      real(DBKIND), intent(in) :: x_Var(imin:imax)  ! 入力
      real(DBKIND)             :: IntX_x            ! 出力

      ! 初期化
      IntX_x = 0.0d0

      ! 積分
      IntX_x = sum(x_Var(1:im)*x_dx(1:im))

    end function IntX_x
!--------------------------------------------------------------------
    function AvrX_p(p_Var)
      ! 整数格子上の配列に対し x 方向の平均操作を行う

      real(DBKIND), intent(in) :: p_Var(imin:imax)  ! 入力
      real(DBKIND)             :: AvrX_p            ! 出力

      AvrX_p = IntX_p(p_Var)/sum(p_dx(1:im))

    end function AvrX_p
!--------------------------------------------------------------------
    function AvrX_x(x_Var)
      ! 半整数格子上の配列に対し x 方向の平均操作を行う

      real(DBKIND), intent(in) :: x_Var(imin:imax)  ! 入力
      real(DBKIND)             :: AvrX_x            ! 出力

      AvrX_x = IntX_x(x_Var)/sum(x_dx(1:im))

    end function AvrX_x
!--------------------------------------------------------------------
end module x_base_module
