!----------------------------------------------------------------------
!     Copyright (c) 2012-2017 Shin-ichi Takehiro. All rights reserved.
!----------------------------------------------------------------------
!
!表題  w_deriv_mpi_module テストプログラム :: 微分関数のテスト
!
!履歴  2012/04/03  竹広真一
!      2017/07/13  竹広真一 JacobianMPI テスト
!
program w_deriv_mpi_module_test

  use dc_message, only : MessageNotify
  use dc_test, only : AssertEqual
  use w_mpi_module
  use mpi

  implicit none

  integer, parameter :: im=128, jm=64, nm=42

  real(8), allocatable  ::  xv_data1(:,:)              ! 元の関数
  real(8), allocatable  ::  xv_data2(:,:)              ! 元の関数
  real(8), allocatable  ::  xv_ddata(:,:)              ! 微分の正解
  real(8), allocatable  ::  xv_mu(:,:)                 ! μ=sinφ

  real(8), allocatable  ::  xy_data1(:,:)              ! 元の関数
  real(8), allocatable  ::  xy_data2(:,:)              ! 元の関数
  real(8), allocatable  ::  xy_ddata(:,:)              ! 微分の正解
  real(8), allocatable  ::  xy_mu(:,:)                 ! μ=sinφ

  ! 判定誤差設定
  integer, parameter :: check_digits = 10
  integer, parameter :: ignore = -11

  integer :: iproc, np, ierr

 !---------------- MPI スタート ---------------------
  call MPI_INIT(IERR)
  call MPI_COMM_RANK(MPI_COMM_WORLD,IPROC,IERR)
  call MPI_COMM_SIZE(MPI_COMM_WORLD,NP,IERR)

  call MessageNotify('M','w_deriv_mpi_module_test', &
                         'w_deriv_mpi_module function tests') 

  call w_mpi_Initial( nm, im, jm )

  !------------ 変数割付け -------------
  allocate(xv_data1(0:im-1,jc))
  allocate(xv_data2(0:im-1,jc))
  allocate(xv_ddata(0:im-1,jc))
  allocate(xv_mu(0:im-1,jc))


  !========== 微分計算 (lon,lat座標系用) のテスト(領域分割) ==========

  !---- Y_1^{-1} のテスト ----
  xv_data1 = -cos(xv_Lat)*sin(xv_Lon)         ! Y_1^{-1}

  xv_ddata = -cos(xv_Lon)                     ! xv_GradLon_w
  call AssertEqual(&
    message='Y_1^0 test of xv_GradLon_w',                         &
    answer = xv_ddata,                                            &
    check = xv_GradLon_w(w_xv(xv_data1)),                         &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xv_ddata = sin(xv_Lat)*sin(xv_Lon)         ! xv_GradLat_w
  call AssertEqual(&
    message='Y_1^0 test of xv_GradLat_w',                         &
    answer = xv_ddata,                                            &
    check = xv_GradLat_w(w_xv(xv_data1)),                         &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  !---- Y_2^1 cosφ のテスト ----
  xv_data1 = sin(xv_Lat)*cos(xv_Lat)**2 * cos(xv_Lon) ! Y_2^1 cosφ

  xv_ddata = -sin(xv_Lat)*cos(xv_Lat)*sin(xv_Lon)    ! w_DivLon_xv
  call AssertEqual(&
    message='Y_2^1 cosφ test of xv_DivLon_w',                    &
    answer = xv_ddata,                                            &
    check = xv_w(w_DivLon_xv(xv_data1)),                          &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xv_ddata = cos(xv_Lat)*(1-4*sin(xv_Lat)**2)*cos(xv_Lon)      ! xv_DivLat_w
  call AssertEqual(&
    message='Y_2^1 cosφ test of xv_DivLat_w',                    &
    answer = xv_ddata,                                            &
    check = xv_w(w_DivLat_xv(xv_data1)),                          &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  !---- Jacobian (MPI) のテスト ----
  xv_data1 = -cos(xv_Lat)*sin(xv_Lon)                ! Y_1^{-1}
  xv_data2 = sin(xv_Lat)*cos(xv_Lat) * cos(xv_Lon)   ! Y_2^1

  xv_ddata = 0.0
  call AssertEqual(&
    message='Y_1^-1 test of w_JacobianMPI_w_w',                      &
    answer = xv_ddata,                                               &
    check = xv_w(w_JacobianMPI_w_w(w_xv(xv_data1),w_xv(xv_data1))),  &
    significant_digits = check_digits, ignore_digits = ignore        &
    )

  xv_ddata = sin(xv_Lat)**2 - cos(xv_Lat)**2*cos(xv_Lon)**2
  call AssertEqual(&
    message='Y_1^-1 and Y_2^1 test of w_JacobianMPI_w_w',            &
    answer = xv_ddata,                                               &
    check = xv_w(w_JacobianMPI_w_w(w_xv(xv_data1),w_xv(xv_data2))),  &
    significant_digits = check_digits, ignore_digits = ignore        &
    )

  !========== 微分計算 (λ,μ座標系用) のテスト(領域分割) ==========
  xv_mu = sin(xv_Lat)

  !----- Y_2^0 のテスト -----
  xv_data1 = 3*xv_mu**2-1                              ! Y_2^0

  xv_ddata = 0.0
  call AssertEqual(&
    message='Y_2^0 test of xv_GradLambda_w',                      &
    answer = xv_ddata,                                            &
    check = xv_GradLambda_w(w_xv(xv_data1)),                      &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xv_ddata = 6*xv_mu*(1-xv_mu**2)
  call AssertEqual(&
    message='Y_2^0 test of xv_GradMu_w',                          &
    answer = xv_ddata,                                            &
    check = xv_GradMu_w(w_xv(xv_data1)),                          &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  !----- Y_2^0 cosφ のテスト -----
  xv_data1 = (3*xv_mu**2-1)*(1-xv_mu**2)                ! Y_2^0 (1-μ^2)

  xv_ddata = 0.0
  call AssertEqual(&
    message='Y_2^0 (1-μ^2) test of xv_DivLambda_w',                 &
    answer = xv_ddata,                                            &
    check = xv_w(w_DivLambda_xv(xv_data1)),                       &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xv_ddata = (2-3*xv_mu**2)*4*xv_mu
  call AssertEqual(&
    message='Y_2^0 (1-μ^2) test of xv_DivMu_w',                  &
    answer = xv_ddata,                                            &
    check = xv_w(w_DivMu_xv(xv_data1)),                           &
    significant_digits = check_digits, ignore_digits = ignore     &
    )


  !========== 微分計算 (lon,lat座標系用) のテスト(領域非分割) ==========

  !------------ 変数割付け -------------
  allocate(xy_data1(0:im-1,jm))
  allocate(xy_data2(0:im-1,jm))
  allocate(xy_ddata(0:im-1,jm))
  allocate(xy_mu(0:im-1,jm))

  xy_mu = sin(xy_Lat)

  !---- Y_1^{-1} のテスト ----
  xy_data1 = -cos(xy_Lat)*sin(xy_Lon)         ! Y_1^{-1}

  xy_ddata = 2*cos(xy_Lat)*sin(xy_Lon)       ! w_Lapla_w
  call AssertEqual(&
    message='Y_1^0 test of w_Lapla_w',                            &
    answer = xy_ddata,                                            &
    check = xy_w(w_Lapla_w(w_xy(xy_data1))),                      &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xy_ddata = 1.0/2.0*cos(xy_Lat)*sin(xy_Lon)      ! w_LaplaInv_w
  call AssertEqual(&
    message='Y_1^0 test of w_LaplaInv_w',                         &
    answer = xy_ddata,                                            &
    check = xy_w(w_LaplaInv_w(w_xy(xy_data1))),                   &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xy_ddata = -cos(xy_Lat)*cos(xy_Lon)         ! w_DLon_w
  call AssertEqual(&
    message='Y_1^0 test of w_DLon_w',                             &
    answer = xy_ddata,                                            &
    check = xy_w(w_DLon_w(w_xy(xy_data1))),                       &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xy_ddata = -cos(xy_Lon)                     ! xy_GradLon_w
  call AssertEqual(&
    message='Y_1^0 test of xy_GradLon_w',                         &
    answer = xy_ddata,                                            &
    check = xy_GradLon_w(w_xy(xy_data1)),                         &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xy_ddata = sin(xy_Lat)*sin(xy_Lon)         ! xy_GradLat_w
  call AssertEqual(&
    message='Y_1^0 test of xy_GradLat_w',                         &
    answer = xy_ddata,                                            &
    check = xy_GradLat_w(w_xy(xy_data1)),                         &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  !---- Y_2^1 cosφ のテスト ----
  xy_data1 = sin(xy_Lat)*cos(xy_Lat)**2 * cos(xy_Lon) ! Y_2^1 cosφ

  xy_ddata = -sin(xy_Lat)*cos(xy_Lat)*sin(xy_Lon)    ! w_DivLon_xy
  call AssertEqual(&
    message='Y_2^1 cosφ test of xy_DivLon_w',                    &
    answer = xy_ddata,                                            &
    check = xy_w(w_DivLon_xy(xy_data1)),                          &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xy_ddata = cos(xy_Lat)*(1-4*sin(xy_Lat)**2)*cos(xy_Lon)      ! w_DivLat_w
  call AssertEqual(&
    message='Y_2^1 cosφ test of xy_DivLat_w',                    &
    answer = xy_ddata,                                            &
    check = xy_w(w_DivLat_xy(xy_data1)),                          &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  !---- Jacobian のテスト ----
  xy_data1 = -cos(xy_Lat)*sin(xy_Lon)                ! Y_1^{-1}
  xy_data2 = sin(xy_Lat)*cos(xy_Lat) * cos(xy_Lon)   ! Y_2^1

  xy_ddata = 0.0
  call AssertEqual(&
    message='Y_1^-1 test of w_Jacobian_w_w',                      &
    answer = xy_ddata,                                            &
    check = xy_w(w_Jacobian_w_w(w_xy(xy_data1),w_xy(xy_data1))),  &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xy_ddata = sin(xy_Lat)**2 - cos(xy_Lat)**2*cos(xy_Lon)**2
  call AssertEqual(&
    message='Y_1^-1 and Y_2^1 test of w_Jacobian_w_w',            &
    answer = xy_ddata,                                            &
    check = xy_w(w_Jacobian_w_w(w_xy(xy_data1),w_xy(xy_data2))),  &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  !========== 微分計算 (λ,μ座標系用) のテスト(領域非分割) ==========

  !----- Y_2^0 のテスト -----
  xy_data1 = 3*xy_mu**2-1                              ! Y_2^0

  xy_ddata = 0.0
  call AssertEqual(&
    message='Y_2^0 test of xy_GradLambda_w',                      &
    answer = xy_ddata,                                            &
    check = xy_GradLambda_w(w_xy(xy_data1)),                      &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xy_ddata = 6*xy_mu*(1-xy_mu**2)
  call AssertEqual(&
    message='Y_2^0 test of xy_GradMu_w',                          &
    answer = xy_ddata,                                            &
    check = xy_GradMu_w(w_xy(xy_data1)),                          &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  !----- Y_2^0 cosφ のテスト -----
  xy_data1 = (3*xy_mu**2-1)*(1-xy_mu**2)                ! Y_2^0 (1-μ^2)

  xy_ddata = 0.0
  call AssertEqual(&
    message='Y_2^0 (1-μ^2) test of xy_DivLambda_w',                 &
    answer = xy_ddata,                                            &
    check = xy_w(w_DivLambda_xy(xy_data1)),                       &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  xy_ddata = (2-3*xy_mu**2)*4*xy_mu
  call AssertEqual(&
    message='Y_2^0 (1-μ^2) test of xy_DivMu_w',                  &
    answer = xy_ddata,                                            &
    check = xy_w(w_DivMu_xy(xy_data1)),                           &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  call MessageNotify('M','w_deriv_mpi_module_test', &
                         'w_deriv_module function tests succeeded!') 

 !------ MPIの終了 ------

  call MPI_FINALIZE(IERR)      

end program w_deriv_mpi_module_test
