!--
!----------------------------------------------------------------------
! Copyright(c) 2009-2013 SPMDODEL Development Group. All rights reserved.
!----------------------------------------------------------------------
!
!表題  wt_galerkin_module_sjpack
!
!      3 次元球殻領域
!      球面調和函数展開 + チェビシェフ−ガラーキン法(sjpack 版)
!
!      spml/wt_galerkin_module モジュールは球面上および球殻内での流体運動を
!      スペクトル法によって数値計算するための Fortran90 関数を提供する
!      ものである. 
!
!      水平方向に球面調和函数変換および上下にチェビシェフガラーキン法
!      を用いる場合のスペクトル計算のためのさまざまな関数を提供する. 
!
!      内部で wt_module_sjpack および上下境界条件を解くための
!      チェビシェフーガラーキン法のモジュール群
!      (at_ab_galerkin_ND, at_ad_galerkin_DD, at_af_galerkin_MM,
!       at_ah_galerkin_MMex, at_ap_galerkin_DN, at_aq_galerkin_RRFF,
!       at_av_galerkin_NN) を用いている.
!
!      最下部では球面調和変換およびチェビシェフ変換のエンジンとして 
!      ISPACK の Fortran77 サブルーチン(sjpack, ftack)を用いている.
!
!      関数, サブルーチンの名前と機能は wt_galerkin_module のものと同じである. 
!      したがって use 文を wt_galerkin_module から wt_galerkin_module_sjpack に
!      変更するだけで SJPACK の機能が使えるようになる. 
! 
!      ただし l_nm, nm_l の使い方には注意されたい. wt_galerkin_module の
!      l_nm, nm_l は wt_galerkin_Initial で初期化しなくとも用いることが
!      できる(結果が切断波数に依らない)が, wt_galerkin_module_sjpack の
!      ものは初期化したのちにしか使うことができない. 
!
!
!履歴  2009/09/18  竹広 真一 wt_galerkin_module より sjpack 用に改造
!      2009/09/20  竹広真一  使用上の注意を追加
!      2010/03/10  佐々木洋平  threadprivate 削除(コンパイラ依存)
!      2013/08/24  竹広 真一  gfortran 対応
!
!++
module wt_galerkin_module_sjpack
  !
  != wt_galerkin_module_sjpack
  !
  ! Authors:: Youhei SASAKI, Shin-Ichi Takehiro
  ! Version:: $Id$
  ! Copyright&License:: See COPYRIGHT[link:../COPYRIGHT]
  !
  !== 概要
  !
  !      3 次元球殻領域
  !      球面調和函数展開 + チェビシェフ−ガラーキン法(sjpack 版)
  !
  !      spml/wt_galerkin_module モジュールは球面上および球殻内での流体運動を
  !      スペクトル法によって数値計算するための Fortran90 関数を提供する
  !      ものである. 
  !
  !      水平方向に球面調和函数変換および上下にチェビシェフガラーキン法
  !      を用いる場合のスペクトル計算のためのさまざまな関数を提供する. 
  !
  !      内部で wt_module_sjpack および上下境界条件を解くための
  !      チェビシェフーガラーキン法のモジュール群
  !      (at_ab_galerkin_ND, at_ad_galerkin_DD, at_af_galerkin_MM,
  !       at_ah_galerkin_MMex, at_ap_galerkin_DN, at_aq_galerkin_RRFF,
  !       at_av_galerkin_NN) を用いている.
  !
  !      最下部では球面調和変換およびチェビシェフ変換のエンジンとして 
  !      ISPACK の Fortran77 サブルーチン(sjpack, ftack)を用いている.
  !
  !      関数, サブルーチンの名前と機能は wt_galerkin_module のものと同じである. 
  !      したがって use 文を wt_galerkin_module から wt_galerkin_module_sjpack に
  !      変更するだけで SJPACK の機能が使えるようになる. 
  ! 
  !      ただし l_nm, nm_l の使い方には注意されたい. wt_galerkin_module の
  !      l_nm, nm_l は wt_galerkin_Initial で初期化しなくとも用いることが
  !      できる(結果が切断波数に依らない)が, wt_galerkin_module_sjpack の
  !      ものは初期化したのちにしか使うことができない. 
  !
  use dc_message
  use lumatrix
  use wt_module_sjpack
  use at_ad_galerkin_DD, only: at_ad_galerkin_DD_Initial,      &
                               ad_at, at_ad, ad_ag, ag_ad,     &
                               ad_Dx_ad,                       &
                               d_t, t_d, d_z=>d_g, z_d=>g_d,   &
                               d_DRad_d => d_Dx_d
  use at_av_galerkin_NN, only: at_av_galerkin_NN_Initial,      &
                               av_at, at_av, av_ag, ag_av,     &
                               av_Dx_av,                       &
                               v_t, t_v, v_z=>v_g, z_v=>g_v,   &
                               v_DRad_v => v_Dx_V
  use at_ab_galerkin_ND, only: at_ab_galerkin_ND_Initial,      &
                               ab_at, at_ab, ab_ag, ag_ab,     &
                               ab_Dx_ab,                       &
                               b_t, t_b, b_z=>b_g, z_b=>g_b,   &
                               b_DRad_b => b_Dx_b
  use at_ap_galerkin_DN, only: at_ap_galerkin_DN_Initial,      &
                               ap_at, at_ap, ap_ag, ag_ap,     &
                               ap_Dx_ap,                       &
                               p_t, t_p, p_z=>p_g, z_p=>g_p,   &
                               p_DRad_p => p_Dx_p
  use at_af_galerkin_MM, only: at_af_galerkin_MM_Initial,      &
                               af_at, at_af, af_ag, ag_af,     &
                               af_Dx_af,                       &
                               f_t, t_f, f_z=>f_g, z_f=>g_f,   &
                               f_DRad_f => f_Dx_f
  use at_ah_galerkin_MMex, only: at_ah_galerkin_MMex_Initial,  &
                                 ah_at, at_ah, ah_ag, ag_ah,   &
                                 ah_Dx_ah
  use at_aq_galerkin_RRFF, only: at_aq_galerkin_RRFF_Initial,  &
                                 aq_at, at_aq, aq_ag, ag_aq,   &
                                 aq_Dx_aq,                     &
                                 q_t, t_q, q_z=>q_g, z_q=>g_q, &
                                 q_DRad_q => q_Dx_q,           &
                                 TQ, QT, alpha, beta

  implicit none
  private

  public wt_galerkin_Initial       ! 初期化
  public wq_LaplaPol2Pol_wt        ! ポロイダル速度場ポテンシャル φ <= ▽^2φ

  !-- wt_module 
  public x_Lon, x_Lon_Weight
  public y_Lat, y_Lat_Weight
  public z_Rad, z_Rad_Weight
  public l_nm, nm_l
  public xy_Lon, xy_Lat
  public xyz_Lon, xyz_Lat, xyz_Rad
  public wz_Rad
  public wt_VMiss

  public w_xy, xy_w
  public at_Dr_at, t_Dr_t, az_at, at_az
  public xyz_wt, wt_xyz, xyz_wz, wz_xyz, wz_wt, wt_wz
  public wt_DRad_wt, wt_DivRad_wt, wt_RotRad_wt, wt_Lapla_wt
  public xyz_GradLon_wt, xyz_gradlat_wt
  public wt_DivLon_xyz, wt_DivLat_xyz
  public wt_Div_xyz_xyz_xyz, xyz_Div_xyz_xyz_xyz
  public xyz_RotLon_wt_wt, xyz_RotLat_wt_wt, wt_RotRad_xyz_xyz

  public yz_IntLon_xyz, xz_IntLat_xyz, xy_IntRad_xyz
  public x_IntLatRad_xyz, y_IntLonRad_xyz, z_IntLonLat_xyz
  public IntLonLatRad_xyz

  public x_IntLat_xy, y_IntLon_xy, IntLonLat_xy
  public z_IntLat_yz, y_IntRad_yz, IntLatRad_yz
  public z_IntLon_xz, x_IntRad_xz, IntLonRad_xz
  public IntLon_x, IntLat_y, IntRad_z

  public yz_AvrLon_xyz, xz_AvrLat_xyz, xy_AvrRad_xyz
  public x_AvrLatRad_xyz, y_AvrLonRad_xyz, z_AvrLonLat_xyz
  public AvrLonLatRad_xyz

  public x_AvrLat_xy, y_AvrLon_xy, AvrLonLat_xy
  public z_AvrLat_yz, y_AvrRad_yz, AvrLatRad_yz
  public z_AvrLon_xz, x_AvrRad_xz, AvrLonRad_xz
  public AvrLon_x, AvrLat_y, AvrRad_z

  public wt_KxRGrad_wt, xyz_KGrad_wt, wt_L2_wt, wt_L2Inv_wt, wt_QOperator_wt
  public wt_RadRot_xyz_xyz, wt_RadRotRot_xyz_xyz_xyz
  public wt_Potential2vector, wt_Potential2Rotation
  public wt_VGradV

  public nmz_ToroidalEnergySpectrum_wt, nz_ToroidalEnergySpectrum_wt
  public nmz_PoloidalEnergySpectrum_wt, nz_PoloidalEnergySpectrum_wt

  public wt_Boundaries, wt_TorBoundaries, wz_LaplaPol2Pol_wz
  public wt_TormagBoundaries, wt_PolmagBoundaries

  public wt_BoundariesTau, wt_TorBoundariesTau
  public wt_TormagBoundariesTau, wt_PolmagBoundariesTau

  public wt_BoundariesGrid, wt_TorBoundariesGrid, wt_LaplaPol2PolGrid_wt
  public wt_TormagBoundariesGrid, wt_PolmagBoundariesGrid

  !-- at_ad_galerkin_DD
  public :: wd_wt, d_t                 ! チェビシェフ->ガラーキン変換
  public :: wd_wz, d_z                 ! 格子点->ガラーキンデータ変換
  public :: wt_wd, t_d                 ! ガラーキン->チェビシェフ変換
  public :: wz_wd, z_d                 ! ガラーキン->格子点データ変換
  public :: wd_DRad_wd, d_DRad_d       ! 動径微分

  !-- at_av_galerkin_NN
  public :: wv_wt, v_t                 ! チェビシェフ->ガラーキン変換
  public :: wv_wz, v_z                 ! 格子点->ガラーキンデータ変換
  public :: wt_wv, t_v                 ! ガラーキン->チェビシェフ変換
  public :: wz_wv, z_v                 ! ガラーキン->格子点データ変換
  public :: wv_DRad_wv, v_DRad_v       ! 動径微分

  !-- at_ab_galerkin_ND
  public :: wb_wt, b_t                 ! チェビシェフ->ガラーキン変換
  public :: wb_wz, b_z                 ! 格子点->ガラーキンデータ変換
  public :: wt_wb, t_b                 ! ガラーキン->チェビシェフ変換
  public :: wz_wb, z_b                 ! ガラーキン->格子点データ変換
  public :: wb_DRad_wb, b_DRad_b       ! 動径微分

  !-- at_ap_galerkin_DN
  public :: wp_wt, p_t                 ! チェビシェフ->ガラーキン変換
  public :: wp_wz, p_z                 ! 格子点->ガラーキンデータ変換
  public :: wt_wp, t_p                 ! ガラーキン->チェビシェフ変換
  public :: wz_wp, z_p                 ! ガラーキン->格子点データ変換
  public :: wp_DRad_wp, p_DRad_p       ! 動径微分

  !-- at_af_galerkin_MM
  public :: wf_wt, f_t                 ! チェビシェフ->ガラーキン変換
  public :: wf_wz, f_z                 ! 格子点->ガラーキンデータ変換
  public :: wt_wf, t_f                 ! ガラーキン->チェビシェフ変換
  public :: wz_wf, z_f                 ! ガラーキン->格子点データ変換
  public :: wf_DRad_wf, f_DRad_f       ! 動径微分

  !-- at_ab_galerkin_MMex
  public :: wh_wt                      ! チェビシェフ->ガラーキン変換
  public :: wh_wz                      ! 格子点->ガラーキンデータ変換
  public :: wt_wh                      ! ガラーキン->チェビシェフ変換
  public :: wz_wh                      ! ガラーキン->格子点データ変換
  public :: wh_DRad_wh                 ! 動径微分

  !-- at_aq_galerkin_RRFF
  public :: wq_wt, q_t                 ! チェビシェフ->ガラーキン変換
  public :: wq_wz, q_z                 ! 格子点->ガラーキンデータ変換
  public :: wt_wq, t_q                 ! ガラーキン->チェビシェフ変換
  public :: wz_wq, z_q                 ! ガラーキン->格子点データ変換
  public :: wq_DRad_wq, q_DRad_q       ! 動径微分


  !-- 内部変数--
  integer :: im=64, jm=32, km=16       ! 格子点の設定(経度, 緯度, 動径)
  integer :: nm=21, lm=16              ! 切断波数の設定(水平, 動径)

  logical :: Set_DD    =.false.        ! モジュール読み込みスイッチ
  logical :: Set_NN    =.false.        ! モジュール読み込みスイッチ
  logical :: Set_DN    =.false.        ! モジュール読み込みスイッチ
  logical :: Set_ND    =.false.        ! モジュール読み込みスイッチ
  logical :: Set_MM    =.false.        ! モジュール読み込みスイッチ
  logical :: Set_MMex  =.false.        ! モジュール読み込みスイッチ
  logical :: Set_RRFF  =.false.        ! モジュール読み込みスイッチ

  save im, jm, km, nm, lm, &
       Set_DD, Set_NN, Set_DN, Set_ND, Set_MM, Set_MMex, Set_RRFF

  contains
  !--------------- 初期化 -----------------
    subroutine wt_galerkin_Initial(i,j,k,n,l,r_in,r_out,&
         DD,NN,DN,ND,velBC,&
         MM_cfdx0_ri, MM_cfdx1_ri, MM_cfdx0_ro, MM_cfdx1_ro,&
         MMex_cfdx0_ri, MMex_cfdx1_ri, MMex_cfdx0_ro, MMex_cfdx1_ro, np)
      !
      !  3 次元球殻領域
      !  球面調和函数展開 + チェビシェフ−ガラーキン法
      !
      !  初期化サブルーチン
      !
      integer,intent(in) :: i, j, k        ! 格子点の設定(経度, 緯度, 動径)
      integer,intent(in) :: n, l           ! 切断波数の設定(水平, 動径)
      integer,intent(in),optional :: np    ! OPENMP での最大スレッド数

      real(8),intent(in) :: r_in, r_out    ! 球殻内外半径

      logical,intent(in),optional :: DD  ! モジュール読み込みスイッチ
      logical,intent(in),optional :: NN  ! モジュール読み込みスイッチ
      logical,intent(in),optional :: DN  ! モジュール読み込みスイッチ
      logical,intent(in),optional :: ND  ! モジュール読み込みスイッチ

      ! at_af_galerkin_MM_module 境界条件係数
      real(8),intent(in),optional :: MM_cfdx0_ri ! (0階微分@x=xmin)
      real(8),intent(In),optional :: MM_cfdx1_ri ! (1階微分@x=xmin)
      real(8),intent(in),optional :: MM_cfdx0_ro ! (0階微分@x=xmax)
      real(8),intent(in),optional :: MM_cfdx1_ro ! (1階微分@x=xmax)

      ! at_ah_galerkin_MMex_module 境界条件係数
      real(8),intent(in),optional :: MMex_cfdx0_ri((n+1)*(n+1)) ! (0階微分@r=ri)
      real(8),intent(in),optional :: MMex_cfdx1_ri((n+1)*(n+1)) ! (1階微分@r=ri)
      real(8),intent(in),optional :: MMex_cfdx0_ro((n+1)*(n+1)) ! (0階微分@r=ro)
      real(8),intent(in),optional :: MMex_cfdx1_ro((n+1)*(n+1)) ! (1階微分@r=ro)

      ! at_aq_galerkin_RRFF_module 速度場境界条件
      character(LEN=2),intent(in),optional :: velBC  ! 境界条件(RR/FF/RF/FR)

      !--------------- 引数処理 -----------------
      im=i ; jm = j ; km=k ; nm=n ; lm=l

      if ( present(DD) ) Set_DD = DD
      if ( present(NN) ) Set_NN = NN
      if ( present(DN) ) Set_DN = DN
      if ( present(ND) ) Set_ND = ND

      if ( present(MM_cfdx0_ri) .AND.present(MM_cfdx1_ri) .AND.&
           present(MM_cfdx0_ro) .AND.present(MM_cfdx1_ro) ) &
           Set_MM=.true.

      if ( present(MMex_cfdx0_ri) .AND.present(MMex_cfdx1_ri) .AND.&
           present(MMex_cfdx0_ro) .AND.present(MMex_cfdx1_ro) ) &
           Set_MMex=.true.

      if ( present(velBC) ) Set_RRFF = .true.

      !--------------- モジュール初期化 -----------------
      if ( present(np) ) then
        call wt_Initial(i,j,k,n,l,r_in,r_out, np)
      else
        call wt_Initial(i,j,k,n,l,r_in,r_out)
      endif

      if ( Set_DD ) call at_ad_galerkin_DD_Initial(km,lm)
      if ( Set_NN ) call at_av_galerkin_NN_Initial(km,lm)
      if ( Set_DN ) call at_ap_galerkin_DN_Initial(km,lm)
      if ( Set_ND ) call at_ab_galerkin_ND_Initial(km,lm)
      if ( Set_MM ) call at_af_galerkin_MM_Initial      &
                               (km,lm, MM_cfdx0_ro, MM_cfdx1_ro,&
                                       MM_cfdx0_ri, MM_cfdx1_ri   )
      if ( Set_MMex ) call at_ah_galerkin_MMex_Initial      &
                               (km,lm,(nm+1)*(nm+1), &
                                MMex_cfdx0_ro, MMex_cfdx1_ro,&
                                MMex_cfdx0_ri, MMex_cfdx1_ri   )

      if ( Set_RRFF ) call at_aq_galerkin_RRFF_Initial(km,lm,velBC)

      call MessageNotify('M','wt_galerkin_initial','wt_galerkin_module_sjpack (2013/08/24) is initialized')
    end subroutine wt_galerkin_initial

    !-- at_ad_galerkin_DD --
    function wd_wt(wt)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ディリクレ境界条件
      !
      ! 動径チェビシェフ係数 -> 動径ガラーキン係数変換
      !
      real(8), intent(IN) :: wt((nm+1)**2,0:lm)       !(in)  チェビシェフデータ
      real(8)             :: wd_wt((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wd_wt = ad_at(wt)

    end function wd_wt

    function wt_wd(wd)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ディリクレ境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径チェビシェフ係数
      !
      real(8), intent(IN) :: wd((nm+1)**2,2:lm)
      real(8)             :: wt_wd((nm+1)**2,0:lm)

      wt_wd = at_ad(wd)

    end function wt_wd

    function wd_wz(wz)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ディリクレ境界条件
      !
      ! 動径格子点データ -> 動径ガラーキン係数変換
      !

      real(8), intent(IN)  :: wz((nm+1)**2,0:km)       !(in)  格子点データ
      real(8)              :: wd_wz((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wd_wz = ad_ag(wz)

    end function wd_wz

    function wz_wd(wd)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ディリクレ境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径格子点データ
      !

      real(8), intent(IN) :: wd((nm+1)**2,2:lm)        !(in) ガラーキン係数
      real(8)             :: wz_wd((nm+1)**2,0:km)     !(out)  格子点データ

      wz_wd = ag_ad(wd)

    end function wz_wd

    function wd_DRad_wd(wd)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ディリクレ境界条件
      !
      ! 動径微分計算(2 次元データ)
      !
      real(8), intent(IN) :: wd((nm+1)**2,2:lm)         !(in) ガラーキン係数
      real(8)             :: wd_DRad_wd((nm+1)**2,2:lm) !(out) 微分ガラーキン

      wd_DRad_wd = wd_wt(wt_DRad_wt(wt_wd(wd)))

    end function wd_DRad_wd

    !-- at_av_galerkin_NN --
    function wv_wt(wt)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ノイマン境界条件
      !
      ! 動径チェビシェフ係数 -> 動径ガラーキン係数変換
      !
      real(8), intent(IN) :: wt((nm+1)**2,0:lm)       !(in)  チェビシェフデータ
      real(8)             :: wv_wt((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wv_wt = av_at(wt)

    end function wv_wt

    function wt_wv(wv)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ノイマン境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径チェビシェフ係数
      !
      real(8), intent(IN) :: wv((nm+1)**2,2:lm)
      real(8)             :: wt_wv((nm+1)**2,0:lm)

      wt_wv = at_av(wv)

    end function wt_wv

    function wv_wz(wz)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ノイマン境界条件
      !
      ! 動径格子点データ -> 動径ガラーキン係数変換
      !

      real(8), intent(IN)  :: wz((nm+1)**2,0:km)       !(in)  格子点データ
      real(8)              :: wv_wz((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wv_wz = av_ag(wz)

    end function wv_wz

    function wz_wv(wv)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ノイマン境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径格子点データ
      !

      real(8), intent(IN) :: wv((nm+1)**2,2:lm)        !(in) ガラーキン係数
      real(8)             :: wz_wv((nm+1)**2,0:km)     !(out)  格子点データ

      wz_wv = ag_av(wv)

    end function wz_wv

    function wv_DRad_wv(wv)
      !
      ! チェビシェフ−ガラーキン法
      ! 両端ノイマン境界条件
      !
      ! 動径微分計算(2 次元データ)
      !
      real(8), intent(IN) :: wv((nm+1)**2,2:lm)         !(in) ガラーキン係数
      real(8)             :: wv_DRad_wv((nm+1)**2,2:lm) !(out) 微分ガラーキン

      wv_DRad_wv = wv_wt(wt_DRad_wt(wt_wv(wv)))

    end function wv_DRad_wv

    !-- at_ab_galerkin_ND --
    function wb_wt(wt)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ノイマン下端ディリクレ境界条件
      !
      ! 動径チェビシェフ係数 -> 動径ガラーキン係数変換
      !
      real(8), intent(IN) :: wt((nm+1)**2,0:lm)       !(in)  チェビシェフデータ
      real(8)             :: wb_wt((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wb_wt = ab_at(wt)

    end function wb_wt

    function wt_wb(wb)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ノイマン下端ディリクレ境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径チェビシェフ係数
      !
      real(8), intent(IN) :: wb((nm+1)**2,2:lm)
      real(8)             :: wt_wb((nm+1)**2,0:lm)

      wt_wb = at_ab(wb)

    end function wt_wb

    function wb_wz(wz)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ノイマン下端ディリクレ境界条件
      !
      ! 動径格子点データ -> 動径ガラーキン係数変換
      !

      real(8), intent(IN)  :: wz((nm+1)**2,0:km)       !(in)  格子点データ
      real(8)              :: wb_wz((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wb_wz = ab_ag(wz)

    end function wb_wz

    function wz_wb(wb)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ノイマン下端ディリクレ境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径格子点データ
      !

      real(8), intent(IN) :: wb((nm+1)**2,2:lm)        !(in) ガラーキン係数
      real(8)             :: wz_wb((nm+1)**2,0:km)     !(out)  格子点データ

      wz_wb = ag_ab(wb)

    end function wz_wb

    function wb_DRad_wb(wb)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ノイマン下端ディリクレ境界条件
      !
      ! 動径微分計算(2 次元データ)
      !
      real(8), intent(IN) :: wb((nm+1)**2,2:lm)         !(in) ガラーキン係数
      real(8)             :: wb_DRad_wb((nm+1)**2,2:lm) !(out) 微分ガラーキン

      wb_DRad_wb = wb_wt(wt_DRad_wt(wt_wb(wb)))

    end function wb_DRad_wb

    !-- at_ap_galerkin_DN --
    function wp_wt(wt)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ディリクレ下端ノイマン境界条件
      !
      ! 動径チェビシェフ係数 -> 動径ガラーキン係数変換
      !
      real(8), intent(IN) :: wt((nm+1)**2,0:lm)       !(in)  チェビシェフデータ
      real(8)             :: wp_wt((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wp_wt = ap_at(wt)

    end function wp_wt

    function wt_wp(wp)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ディリクレ下端ノイマン境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径チェビシェフ係数
      !
      real(8), intent(IN) :: wp((nm+1)**2,2:lm)
      real(8)             :: wt_wp((nm+1)**2,0:lm)

      wt_wp = at_ap(wp)

    end function wt_wp

    function wp_wz(wz)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ディリクレ下端ノイマン境界条件
      !
      ! 動径格子点データ -> 動径ガラーキン係数変換
      !

      real(8), intent(IN)  :: wz((nm+1)**2,0:km)       !(in)  格子点データ
      real(8)              :: wp_wz((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wp_wz = ap_ag(wz)

    end function wp_wz

    function wz_wp(wp)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ディリクレ下端ノイマン境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径格子点データ
      !

      real(8), intent(IN) :: wp((nm+1)**2,2:lm)        !(in) ガラーキン係数
      real(8)             :: wz_wp((nm+1)**2,0:km)     !(out)  格子点データ

      wz_wp = ag_ap(wp)

    end function wz_wp

    function wp_DRad_wp(wp)
      !
      ! チェビシェフ−ガラーキン法
      ! 上端ディリクレ下端ノイマン境界条件
      !
      ! 動径微分計算(2 次元データ)
      !
      real(8), intent(IN) :: wp((nm+1)**2,2:lm)         !(in) ガラーキン係数
      real(8)             :: wp_DRad_wp((nm+1)**2,2:lm) !(out) 微分ガラーキン

      wp_DRad_wp = wp_wt(wt_DRad_wt(wt_wp(wp)))

    end function wp_DRad_wp

    !-- at_af_galerkin_MM --
    function wf_wt(wt)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレノイマン混合型境界条件
      !
      ! 動径チェビシェフ係数 -> 動径ガラーキン係数変換
      !
      real(8), intent(IN) :: wt((nm+1)**2,0:lm)       !(in)  チェビシェフデータ
      real(8)             :: wf_wt((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wf_wt = af_at(wt)

    end function wf_wt

    function wt_wf(wf)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレノイマン混合型境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径チェビシェフ係数
      !
      real(8), intent(IN) :: wf((nm+1)**2,2:lm)
      real(8)             :: wt_wf((nm+1)**2,0:lm)

      wt_wf = at_af(wf)

    end function wt_wf

    function wf_wz(wz)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレノイマン混合型境界条件
      !
      ! 動径格子点データ -> 動径ガラーキン係数変換
      !

      real(8), intent(IN)  :: wz((nm+1)**2,0:km)       !(in)  格子点データ
      real(8)              :: wf_wz((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wf_wz = af_ag(wz)

    end function wf_wz

    function wz_wf(wf)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレノイマン混合型境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径格子点データ
      !

      real(8), intent(IN) :: wf((nm+1)**2,2:lm)        !(in) ガラーキン係数
      real(8)             :: wz_wf((nm+1)**2,0:km)     !(out)  格子点データ

      wz_wf = ag_af(wf)

    end function wz_wf

    function wf_DRad_wf(wf)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレノイマン混合型境界条件
      !
      ! 動径微分計算(2 次元データ)
      !
      real(8), intent(IN) :: wf((nm+1)**2,2:lm)         !(in) ガラーキン係数
      real(8)             :: wf_DRad_wf((nm+1)**2,2:lm) !(out) 微分ガラーキン

      wf_DRad_wf = wf_wt(wt_DRad_wt(wt_wf(wf)))

    end function wf_DRad_wf

    !-- at_ah_galerkin_MMex --
    function wh_wt(wt)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレ・ノイマン混合境界条件(可変係数)境界条件
      !
      ! 動径チェビシェフ係数 -> 動径ガラーキン係数変換
      !
      real(8), intent(IN) :: wt((nm+1)**2,0:lm)       !(in)  チェビシェフデータ
      real(8)             :: wh_wt((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wh_wt = ah_at(wt)

    end function wh_wt

    function wt_wh(wh)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレ・ノイマン混合境界条件(可変係数)
      !
      ! 動径ガラーキン係数変換 -> 動径チェビシェフ係数
      !
      real(8), intent(IN) :: wh((nm+1)**2,2:lm)
      real(8)             :: wt_wh((nm+1)**2,0:lm)

      wt_wh = at_ah(wh)

    end function wt_wh

    function wh_wz(wz)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレ・ノイマン混合境界条件(可変係数)
      !
      ! 動径格子点データ -> 動径ガラーキン係数変換
      !

      real(8), intent(IN)  :: wz((nm+1)**2,0:km)       !(in)  格子点データ
      real(8)              :: wh_wz((nm+1)**2,2:lm)    !(out) ガラーキン係数

      wh_wz = ah_ag(wz)

    end function wh_wz

    function wz_wh(wh)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレ・ノイマン混合境界条件(可変係数)
      !
      ! 動径ガラーキン係数変換 -> 動径格子点データ
      !

      real(8), intent(IN) :: wh((nm+1)**2,2:lm)        !(in) ガラーキン係数
      real(8)             :: wz_wh((nm+1)**2,0:km)     !(out)  格子点データ

      wz_wh = ag_ah(wh)

    end function wz_wh

    function wh_DRad_wh(wh)
      !
      ! チェビシェフ−ガラーキン法
      ! ディリクレ・ノイマン混合境界条件(可変係数)
      !
      ! 動径微分計算
      !
      real(8), intent(IN) :: wh((nm+1)**2,2:lm)         !(in) ガラーキン係数
      real(8)             :: wh_DRad_wh((nm+1)**2,2:lm) !(out) 微分ガラーキン

      wh_DRad_wh = wh_wt(wt_DRad_wt(wt_wh(wh)))

    end function wh_DRad_wh

    !-- at_aq_galerkin_RRFF --
    function wq_wt(wt)
      !
      ! チェビシェフ−ガラーキン法
      ! 非圧縮流体の流線関数・流れポテンシャル用境界条件
      !
      ! 動径チェビシェフ係数 -> 動径ガラーキン係数変換
      !
      real(8), intent(IN) :: wt((nm+1)**2,0:lm)       !(in)  チェビシェフデータ
      real(8)             :: wq_wt((nm+1)**2,4:lm)    !(out) ガラーキン係数

      wq_wt = aq_at(wt)

    end function wq_wt

    function wt_wq(wq)
      !
      ! チェビシェフ−ガラーキン法
      ! 非圧縮流体の流線関数・流れポテンシャル用境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径チェビシェフ係数
      !
      real(8), intent(IN) :: wq((nm+1)**2,4:lm)
      real(8)             :: wt_wq((nm+1)**2,0:lm)

      wt_wq = at_aq(wq)

    end function wt_wq

    function wq_wz(wz)
      !
      ! チェビシェフ−ガラーキン法
      ! 非圧縮流体の流線関数・流れポテンシャル用境界条件
      !
      ! 動径格子点データ -> 動径ガラーキン係数変換
      !

      real(8), intent(IN)  :: wz((nm+1)**2,0:km)       !(in)  格子点データ
      real(8)              :: wq_wz((nm+1)**2,4:lm)    !(out) ガラーキン係数

      wq_wz = aq_ag(wz)

    end function wq_wz

    function wz_wq(wq)
      !
      ! チェビシェフ−ガラーキン法
      ! 非圧縮流体の流線関数・流れポテンシャル用境界条件
      !
      ! 動径ガラーキン係数変換 -> 動径格子点データ
      !

      real(8), intent(IN) :: wq((nm+1)**2,4:lm)        !(in) ガラーキン係数
      real(8)             :: wz_wq((nm+1)**2,0:km)     !(out)  格子点データ

      wz_wq = ag_aq(wq)

    end function wz_wq

    function wq_DRad_wq(wq)
      !
      ! チェビシェフ−ガラーキン法
      ! 非圧縮流体の流線関数・流れポテンシャル用境界条件
      !
      ! X 微分計算(2 次元データ)
      !
      real(8), intent(IN) :: wq((nm+1)**2,4:lm)         !(in) ガラーキン係数
      real(8)             :: wq_DRad_wq((nm+1)**2,4:lm) !(out) 微分ガラーキン

      wq_DRad_wq = wq_wt(wt_DRad_wt(wt_wq(wq)))

    end function wq_DRad_wq

   !----- ポロイダル速度場ポテンシャル φを ▽^2φ から求める ------
    function wq_LaplaPol2Pol_wt(wt_LaplaPolvel)
      !
      !  3 次元球殻領域
      !  球面調和函数展開 + チェビシェフ−ガラーキン法
      !
      !  ポロイダル速度場ポテンシャル φを ▽^2φ から求める
      !
      real(8), intent(IN) :: wt_LaplaPolvel((nm+1)*(nm+1),0:lm)
        !(in) ポロイダル速度場ポテンシャルのラプラシアン ▽^2φ
      real(8)             :: wq_LaplaPol2Pol_wt((nm+1)*(nm+1),4:lm) 
        !(out) ポロイダル速度場ポテンシャル φ

      real(8), allocatable :: LaplaMT(:,:,:)
      real(8), allocatable :: LaplaInvMT(:,:,:)
      integer, allocatable :: kpvot(:,:)

      integer, parameter :: ls=4

      real(8) :: wq_work((nm+1)*(nm+1),ls:lm)
      real(8) :: wt_work((nm+1)*(nm+1),0:lm)

      integer :: k, m, n, l, p
      logical :: first = .true.
      save LaplaInvMT, kpvot, first

      if ( .not. Set_RRFF ) &
           call MessageNotify('E','wq_LaplaPol2Pol_wt',&
                    'at_aq_galerkin_RRFF_module not initialized.')

      if ( first ) then
         first = .false.
         allocate(LaplaMT((nm+1)*(nm+1),0:lm,0:lm))
         allocate(LaplaInvMT((nm+1)*(nm+1),ls:lm,ls:lm))
         allocate(kpvot((nm+1)*(nm+1),ls:lm))

         LaplaMT=0.0D0
         do l=0,lm
            wt_work = 0.0D0 ; wt_work(:,l) = 1.0D0
            wt_work = wt_Lapla_wt(wt_work)
            LaplaMT(:,:,l) = wt_work
         enddo

         LaplaInvMT=0.0D0
         do n=ls,lm
            do m=ls,lm
               do l=0,lm
                  do p=0,lm
                     LaplaInvMT(:,n,m)=LaplaInvMT(:,n,m) &
                          +TQ(l,n)*LaplaMT(:,l,p)*alpha(p)*TQ(p,m)
                  enddo
               enddo
            enddo
         enddo

         call LUDecomp(LaplaInvMT,kpvot)
         deallocate(LaplaMT)
      endif

      wq_work=0.0D0
      do m=ls,lm
         do k=0,lm
            wq_work(:,m)=wq_work(:,m) &
                 + alpha(k) * beta(k) * wt_LaplaPolvel(:,k)* TQ(k,m) 
         enddo
      enddo

      wq_LaplaPol2Pol_wt = LUSolve(LaplaInvMT,kpvot,wq_work)

    end function wq_LaplaPol2Pol_wt

end module wt_galerkin_module_sjpack

