!--
!----------------------------------------------------------------------
! Copyright (c) 2020 SPMODEL Development Group. All rights reserved.
!----------------------------------------------------------------------
!表題  w_wave_module
!
!   spml/w_wave_module モジュールは球面上での 2 次元流体運動を
!   球面調和函数を用いたスペクトル法によって 1 東西波数数値計算するための
!   Fortran90 関数を提供する. 
!
!   w_wave_module は実際には基本変換, 微分計算をそれぞれ担っている
!   下部モジュール w_wave_module_base, w_wave_module_deriv, 
!   w_wave_module_interpolate からなっている.
!
!   内部で ISPACK3 の LXPACK(SXPACK) の Fortran サブルーチンを呼んでいる.
!   スペクトルデータおよび格子点データの格納方法や変換の詳しい計算法に
!   ついては ISPACK3/LXPACK のマニュアルを参照されたい.
!
!   w_wave_modulde で提供される関数・サブルーチンは 2 次元的
!   流体運動を扱う w_module モジュールで用いられているものと
!   名前およびインターフェースが共通になるように設計してある. 
!   したがって, w_module を用いて構成された 2 次元モデルを
!   経度方向に 1 波数成分のモデルへと改造するには次の手順が必要となる.
!
!      * use 文での w_module の引用を w_wave_module に変更する.
!      * 配列の大きさを経度方向格子点数 im -> 2 に,
!        水平波数を (nm+1)**2 -> 2*(nm-m+1) に変更する.
!      * DO 文で水平波数に関してループを回しているところを
!        (nm+1)**2 -> 2*(nm-m+1) に変更する.
!      * gtool 出力の次元変数を変更する.
!
!履歴  2020/11/24  竹広真一  w_wave_module_svpack より改造
!
!++
module w_wave_module
  !
  != w_wave_module
  !
  ! Authors:: Shin-ichi Takehiro, Youhei SASAKI
  ! Version:: $Id: w_wave_module.f90 586 2013-05-23 17:42:12Z uwabami $
  ! Copyright&License:: See COPYRIGHT[link:../COPYRIGHT]
  !
  !== 概要
  !
  !   spml/w_wave_module モジュールは球面上での 2 次元流体運動を
  !   球面調和函数を用いたスペクトル法によって 1 東西波数数値計算するための
  !   Fortran90 関数を提供する. 
  !
  !   w_wave_module は実際には基本変換, 微分計算をそれぞれ担っている
  !   下部モジュール w_wave_module_base, w_wave_module_deriv, 
  !   w_wave_module_interpolate からなっている.
  !
  !   内部で ISPACK3 の LXPACK(SXPACK) の Fortran サブルーチンを呼んでいる.
  !   スペクトルデータおよび格子点データの格納方法や変換の詳しい計算法に
  !   ついては ISPACK3/LXPACK のマニュアルを参照されたい.
  !
  !   w_wave_modulde で提供される関数・サブルーチンは 2 次元的
  !   流体運動を扱う w_module モジュールで用いられているものと
  !   名前およびインターフェースが共通になるように設計してある. 
  !   したがって, w_module を用いて構成された 2 次元モデルを
  !   経度方向に 1 波数成分のモデルへと改造するには次の手順が必要となる.
  !
  !      * use 文での w_module の引用を w_wave_module に変更する.
  !      * 配列の大きさを経度方向格子点数 im -> 2 に,
  !        水平波数を (nm+1)**2 -> 2*(nm-m+1) に変更する.
  !      * DO 文で水平波数に関してループを回しているところを
  !        (nm+1)**2 -> 2*(nm-m+1) に変更する.
  !      * gtool 出力の次元変数を変更する.
  !
  !== 関数・変数の名前と型について
  !
  !=== 命名法
  !
  ! * 関数名の先頭 (w_, nm_, n_, xy_, x_, y_) は, 返す値の形を示している.
  !   w_  :: スペクトルデータ
  !   xy_ :: 2 次元格子点データ(y 方向緯度座標, x 方向スペクトルデータ実数虚数)
  !
  ! * 関数名の間の文字列(DLon, GradLat, GradLat, DivLon, DivLat, Lapla, 
  !   LaplaInv, Jacobian)は, その関数の作用を表している.
  !
  ! * 関数名の最後 (_w_w, _w, _xy, _x, _y) は, 入力変数の形スペクトルデータ
  !   および格子点データであることを示している.
  !   _w   :: スペクトルデータ
  !   _w_w :: 2 つのスペクトルデータ
  !   _xy  :: 2 次元格子点データ(y 方向緯度座標, x 方向スペクトルデータ実数虚数)
  !
  !=== 各データの種類の説明
  !
  ! * xy : 2 次元格子点データ(y 方向緯度座標, x 方向スペクトルデータ実数虚数).
  !   * 変数の種類と次元は real(8), dimension(0:im-1,1:jm). 
  !   * im(=2), jm はそれぞれ経度, 緯度座標の格子点数であり, サブルーチン
  !     w_Initial にてあらかじめ設定しておく.
  !
  ! * w : スペクトルデータ.
  !   * 変数の種類と次元は real(8), dimension(2(nm-m+1))
  !   * nm は球面調和函数の最大全波数, m は東西破数であり, 
  !     サブルーチン w_Initial にてあらかじめ設定しておく. 
  !   * スペクトルデータの格納のされ方は関数 l_nm, nm_l によって
  !     調べることができる.
  !
  ! * y : 緯度方向 1 次元格子点データ.
  !   * 変数の種類と次元は real(8), dimension(1:jm).
  !
  ! * w_ で始まる関数が返す値はスペクトルデータに同じ.
  !
  ! * xy_ で始まる関数が返す値は 2 次元格子点データに同じ.
  !
  ! * y_ で始まる関数が返す値は 1 次元格子点データに同じ.
  !
  ! * スペクトルデータに対する微分等の作用とは, 対応する格子点データに
  !   微分などを作用させたデータをスペクトル変換したものことである.
  !
  !
  !== 変数・手続き群の要約
  !
  !==== 初期化 
  !
  ! w_Initial :: スペクトル変換の格子点数, 波数, 領域の大きさの設定
  ! 
  !==== 終了処理 
  !
  ! w_Finalize :: モジュールの終了処理(割り付け配列の解放)をおこなう. 
  !
  !==== 座標変数
  !
  ! y_Lat        :: 格子点座標(経度座標)を格納した 1 次元配列
  ! y_Lat_Weight :: 重み座標を格納した 1 次元配列
  ! xy_Lat       :: 格子点データの緯度座標(格子点データ型 2 次元配列)
  !
  !==== 基本変換
  !
  ! xy_w :: スペクトルデータから格子データへの変換
  ! w_xy :: 格子データからスペクトルデータへの変換
  ! l_nm, nm_l :: スペクトルデータの格納位置と全波数・帯状波数の変換 
  !
  !==== 微分
  !
  ! w_Lapla_w       :: スペクトルデータにラプラシアンを作用させる
  ! rn              :: スペクトルデータのラプラシアンを計算するための係数. 
  ! irm             :: 経度微分演算用配列(未定義)
  ! w_LaplaInv_w    :: スペクトルデータにラプラシアンの逆変換を作用させる
  ! w_DLon_w        :: スペクトルデータに経度微分∂/∂λを作用させる
  ! xy_GradLon_w    :: スペクトルデータに
  !                    勾配型経度微分 1/cosφ・∂/∂λを作用させる
  ! xy_GradLat_w    :: スペクトルデータに勾配型緯度微分∂/∂φを作用させる
  ! w_DivLon_xy     :: 格子データに発散型経度微分 1/cosφ・∂/∂λを作用させる
  ! w_DivLat_xy     :: 格子データに
  !                    発散型緯度微分 1/cosφ・∂(g cosφ)/∂φを作用させる
  ! w_Div_xy_xy     :: ベクトル成分である 2 つの格子データに発散を作用させる
  !
  !
  !==== 微分(λ,μ=sinφ 座標)
  !
  ! xy_GradLambda_w :: スペクトルデータに勾配型経度微分∂/∂λを作用させる
  ! xy_GradMu_w     :: スペクトルデータに
  !                    勾配型緯度微分 (1-μ^2)∂/∂μを作用させる
  ! w_DivLambda_xy  :: 格子データに
  !                    発散型経度微分 1/(1-μ^2)・∂/∂λを作用させる
  ! w_DivMu_xy      :: 格子データに発散型緯度微分∂/∂μを作用させる
  !
  !
  !==== 補間
  !
  ! Interpolate_w :: スペクトルデータから任意の点での値を求める.
  !
  use dc_message, only : MessageNotify
  use w_wave_module_base
  use w_wave_module_deriv
  use w_wave_module_interpolate

  private

  public w_Initial                            ! 初期化
  public w_Finalize                           ! 終了処理

  public y_Lat                                ! 格子座標
  public y_Lat_Weight                         ! 格子座標重み
  public xy_Lat                               ! 格子座標(im,jm)
  public xy_w, w_xy, l_nm, nm_l               ! 変換関数

  public w_Lapla_w, w_LaplaInv_w              ! ラプラシアンと逆演算
  public rn                                   ! ラプラシアン演算用配列
  public w_DLon_w                             ! 経度微分
  public xy_GradLon_w, xy_GradLat_w           ! 勾配型微分
  public w_DivLon_xy, w_DivLat_xy             ! 発散型微分
  public w_Div_xy_xy                          ! 発散型微分
  public xy_GradLambda_w, xy_GradMu_w         ! 勾配型微分(λ,μ座標)
  public w_DivLambda_xy, w_DivMu_xy           ! 発散型微分(λ,μ座標)

  public Interpolate_w                        ! 補間関数
 
contains

  !--------------- 初期化 -----------------
  subroutine w_initial(n_in,m_in,i_in,j_in)
    !
    ! スペクトル変換の格子点数, 波数を設定する.
    !
    ! 他の関数を呼ぶ前に, 最初にこのサブルーチンを呼んで初期設定を
    ! しなければならない. 
    !
    integer,intent(in) :: i_in              !(in) 格子点数(東西)
    integer,intent(in) :: j_in              !(in) 格子点数(南北)
    integer,intent(in) :: n_in              !(in) 切断波数の設定
    integer,intent(in) :: m_in              !(in) 東西波数

    call w_base_initial(n_in,m_in,i_in,j_in)

    call w_deriv_initial

    call MessageNotify('M','w_initial',&
         'w_wave_module (2020/11/24) is initialized')

  end subroutine w_initial


  !--------------- 終了処理 -----------------
  subroutine w_Finalize
    !
    ! モジュールの終了処理(割り付け配列の解放)をおこなう. 
    !
    ! 解像度を変更する際にはこのサブルーチンを呼んで終了処理を
    ! おこなったのちに再度 w_Initial で初期設定しなければ
    ! ならない. 
    !
    call w_base_Finalize
    call w_deriv_Finalize

    call MessageNotify('M','w_Finalize',&
         'w_module (2020/11/24) is finalized')

  end subroutine w_Finalize

end module w_wave_module
