!----------------------------------------------------------------------
!     Copyright (c) 2020 Shin-ichi Takehiro. All rights reserved.
!----------------------------------------------------------------------
!
!表題  wb_deriv_mpi_module_sypack テストプログラム :: 微分関数のテスト
!
!履歴  2020/08/01  竹広真一
!
program wb_deriv_mpi_module_sypack_test

  use dc_types, only: DP
  use dc_message, only : MessageNotify
  use dc_test, only : AssertEqual
  use wb_mpi_module
!!$  use ua_base_mpi_module_sypack, only : ua_base_mpi_Initial, kp_kl, &
!!$       xvb_ua, ua_xvb, jc, kc, xv_Lon, xv_Lat
!!$  use ua_deriv_mpi_module_sypack
  use mpi
  implicit none

  integer, parameter :: im=128, jm=64, nm=42, km=2, npv=2
!!$  integer, parameter :: im=64, jm=32, nm=21, km=2, npv=2

  real(DP), allocatable  ::  pva_data1(:,:,:)              ! 元の関数
  real(DP), allocatable  ::  pva_data2(:,:,:)              ! 元の関数
  real(DP), allocatable  ::  pva_ddata(:,:,:)              ! 微分の正解
  real(DP), allocatable  ::  pv_data1(:,:)                 ! 元の関数
  real(DP), allocatable  ::  pv_data2(:,:)                 ! 元の関数
  real(DP), allocatable  ::  pv_ddata(:,:)                 ! 微分の正解
  real(DP), allocatable  ::  pv_mu(:,:)                    ! μ=sinφ

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

  integer :: ip, np, ierr


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

  call MessageNotify('M','wb_deriv_mpi_module_sypack_test', &
                         'wb_deriv_mpi_module_sypack function tests')

!!$  call wb_base_mpi_Initial( nm, im, jm, km, npv=npv )
!!$  call wb_deriv_mpi_Initial
  call wb_mpi_Initial( nm, im, jm, km, npv=npv )

  allocate(pva_data1(ic,jc,km))
  allocate(pva_data2(ic,jc,km))
  allocate(pva_ddata(ic,jc,km))
  allocate(pv_data1(ic,jc))
  allocate(pv_data2(ic,jc))
  allocate(pv_ddata(ic,jc))
  allocate(pv_mu(ic,jc))

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

  !---- Y_1^-1 Y_2^1 のテスト ----
  pva_data1(:,:,1) = -cos(pv_Lat)*sin(pv_Lon)               ! Y_1^{-1}
  pva_data1(:,:,2)  = sin(pv_Lat)*cos(pv_Lat) * cos(pv_Lon) ! Y_2^1

  pva_ddata(:,:,1) = 2*cos(pv_Lat)*sin(pv_Lon)                ! wb_Lapla_wb
  pva_ddata(:,:,2) = -6*sin(pv_Lat)*cos(pv_Lat) * cos(pv_Lon) ! wb_Lapla_wb

  call AssertEqual(&
    message='wb_Lapla_wb with Y_1^-1 and Y^2_1',                  &
    answer = pva_wb(wb_Lapla_wb(wb_pva(pva_data1))),              &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )


  pva_ddata(:,:,1) = 1.0/2.0*cos(pv_Lat)*sin(pv_Lon)      ! wb_LaplaInv_wb
  pva_ddata(:,:,2) = -1.0D0/6.0*sin(pv_Lat)*cos(pv_Lat) * cos(pv_Lon)
  call AssertEqual(&
    message='wb_LaplaInv_wb with Y_1^-1 and Y^2_1',               &
    answer = pva_wb(wb_LaplaInv_wb(wb_pva(pva_data1))),           &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pva_ddata(:,:,1) = -cos(pv_Lat)*cos(pv_Lon)         ! wb_DLon_wb
  pva_ddata(:,:,2) = -sin(pv_Lat)*cos(pv_Lat) * sin(pv_Lon)
  call AssertEqual(&
    message='wb_DLon_wb with Y_1^-1 and Y^2_1',                   &
    answer = pva_wb(wb_DLon_wb(wb_pva(pva_data1))),               &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pva_ddata(:,:,1) = -cos(pv_Lon)                     ! pva_GradLon_wb
  pva_ddata(:,:,2) = -sin(pv_Lat) * sin(pv_Lon)
  call AssertEqual(&
    message='pva_GradLon_wb with Y_1^-1 and Y^2_1',               &
    answer = pva_GradLon_wb(wb_pva(pva_data1)),                   &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pva_ddata(:,:,1) = sin(pv_Lat)*sin(pv_Lon)         ! pva_GradLat_wb
  pva_ddata(:,:,2) = cos(2*pv_Lat) * cos(pv_Lon)
  call AssertEqual(&
    message='pva_GradLat_wb with Y_1^-1 and Y^2_1',               &
    answer = pva_GradLat_wb(wb_pva(pva_data1)),                   &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pv_data1 = -cos(pv_Lat)*sin(pv_Lon)                 ! Y_1^{-1}
  pv_ddata = 2*cos(pv_Lat)*sin(pv_Lon)                ! wb_Lapla_wb
  call AssertEqual(&
    message='w_Lapla_w with Y_1^-1',                              &
    answer = pv_w(w_Lapla_w(w_pv(pv_data1))),                     &
    check = pv_ddata,                                             &
    significant_digits = check_digits, ignore_digits = ignore     &
    )
  pv_ddata = 1.0/2.0*cos(pv_Lat)*sin(pv_Lon)          ! wb_LaplaInv_wb
  call AssertEqual(&
    message='w_LaplaInv_w with Y_1^-1',                           &
    answer = pv_w(w_LaplaInv_w(w_pv(pv_data1))),                  &
    check = pv_ddata,                                             &
    significant_digits = check_digits, ignore_digits = ignore     &
    )
  pv_ddata = sin(pv_Lat)*sin(pv_Lon)                  ! pva_GradLat_wb
  call AssertEqual(&
    message='pv_GradLat_w with Y_1^-1',                           &
    answer = pv_GradLat_w(w_pv(pv_data1)),                        &
    check = pv_ddata,                                             &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pv_data1 = sin(pv_Lat)*cos(pv_Lat) * cos(pv_Lon)    ! Y_2^1
  pv_ddata = -6*sin(pv_Lat)*cos(pv_Lat) * cos(pv_Lon) ! wb_Lapla_wb
  call AssertEqual(&
    message='w_Lapla_w with Y_2^1',                               &
    answer = pv_w(w_Lapla_w(w_pv(pv_data1))),                     &
    check = pv_ddata,                                             &
    significant_digits = check_digits, ignore_digits = ignore     &
    )
  pv_ddata = -1.0D0/6.0*sin(pv_Lat)*cos(pv_Lat) * cos(pv_Lon) ! wb_LaplaInv_wb
  call AssertEqual(&
    message='w_LaplaInv_w with Y_2^1',                            &
    answer = pv_w(w_LaplaInv_w(w_pv(pv_data1))),                  &
    check = pv_ddata,                                             &
    significant_digits = check_digits, ignore_digits = ignore     &
    )
  pv_ddata = cos(2*pv_Lat) * cos(pv_Lon)                      ! pva_GradLat_wb
  call AssertEqual(&
    message='pv_GradLat_w with Y_2^1',                            &
    answer = pv_GradLat_w(w_pv(pv_data1)),                        &
    check = pv_ddata,                                             &
    significant_digits = check_digits, ignore_digits = ignore     &
    )


  !---- Y_1^-1 cosφ, Y_2^1 cosφ のテスト ----
  pva_data1(:,:,1) = -cos(pv_Lat)**2*sin(pv_Lon)              ! Y_1^-1 cosφ
  pva_data1(:,:,2) = sin(pv_Lat)*cos(pv_Lat)**2 * cos(pv_Lon) ! Y_2^1 cosφ

  pva_ddata(:,:,1) = -cos(pv_Lat)*cos(pv_Lon)                ! wb_DivLon_pv
  pva_ddata(:,:,2) = -sin(pv_Lat)*cos(pv_Lat)*sin(pv_Lon)    ! wb_DivLon_pv
  call AssertEqual(&
    message='wb_DivLon_pva with Y_1^-1 cosφ and Y^2_1 cosφ',    &
    answer = pva_wb(wb_DivLon_pva(pva_data1)),                    &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pva_ddata(:,:,1) = 3*sin(pv_Lat)*cos(pv_Lat)*sin(pv_Lon)        !wb_DivLat_wb
  pva_ddata(:,:,2) = cos(pv_Lat)*(1-4*sin(pv_Lat)**2)*cos(pv_Lon) !wb_DivLat_wb
  call AssertEqual(&
    message='wb_DivLat_pva with Y_1^-1 cosφ and Y^2_1 cosφ',    &
    answer = pva_wb(wb_DivLat_pva(pva_data1)),                    &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pv_data1 = -cos(pv_Lat)**2*sin(pv_Lon)              ! Y_1^-1 cosφ
  pv_ddata = -cos(pv_Lat)*cos(pv_Lon)                ! w_DivLon_pv
  call Assertequal(&
    message='w_DivLon_pv with Y_1^-1 cosφ and Y^2_1 cosφ',    &
    answer = pv_w(w_DivLon_pv(pv_data1)),                       &
    check = pv_ddata,                                           &
    significant_digits = check_digits, ignore_digits = ignore   &
    )
  pv_ddata = 3*sin(pv_Lat)*cos(pv_Lat)*sin(pv_Lon)        !w_DivLat_w
  call Assertequal(&
    message='w_DivLat_pv with Y_1^-1 cosφ and Y^2_1 cosφ',    &
    answer = pv_w(w_DivLat_pv(pv_data1)),                       &
    check = pv_ddata,                                           &
    significant_digits = check_digits, ignore_digits = ignore   &
    )

  pv_data1 = sin(pv_Lat)*cos(pv_Lat)**2 * cos(pv_Lon) ! Y_2^1 cosφ
  pv_ddata = -sin(pv_Lat)*cos(pv_Lat)*sin(pv_Lon)    ! w_DivLon_pv
  call Assertequal(&
    message='w_DivLon_pv with Y_1^-1 cosφ and Y^2_1 cosφ',    &
    answer = pv_w(w_DivLon_pv(pv_data1)),                       &
    check = pv_ddata,                                           &
    significant_digits = check_digits, ignore_digits = ignore   &
    )
  pv_ddata = cos(pv_Lat)*(1-4*sin(pv_Lat)**2)*cos(pv_Lon)     !w_DivLat_w
  call Assertequal(&
    message='w_DivLat_pv with Y_1^-1 cosφ and Y^2_1 cosφ',    &
    answer = pv_w(w_DivLat_pv(pv_data1)),                       &
    check = pv_ddata,                                           &
    significant_digits = check_digits, ignore_digits = ignore   &
    )


  !---- Jacobian のテスト ----
  pva_data1(:,:,1) = -cos(pv_Lat)*sin(pv_Lon)          ! Y_1^{-1}
  pva_data1(:,:,2) = -cos(pv_Lat)*sin(pv_Lon)          ! Y_1^{-1}

  pva_data2(:,:,1) = -cos(pv_Lat)*sin(pv_Lon)         ! Y_1^{-1}
  pva_data2(:,:,2) = sin(pv_Lat)*cos(pv_Lat) * cos(pv_Lon)   ! Y_2^1

  pva_ddata(:,:,1) = 0.0
  pva_ddata(:,:,2) = sin(pv_Lat)**2 - cos(pv_Lat)**2*cos(pv_Lon)**2

  call AssertEqual(&
    message='wb_JacobianMPI_wb_wb Y_1^-1 and Y^2_1',              &
    answer = pva_wb(wb_JacobianMPI_wb_wb(wb_pva(pva_data1),wb_pva(pva_data2))), &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pv_data1 = -cos(pv_Lat)*sin(pv_Lon)         ! Y_1^{-1}
  pv_data2 = -cos(pv_Lat)*sin(pv_Lon)         ! Y_1^{-1}
  pv_ddata = 0.0
  call AssertEqual(&
    message='w_JacobianMPI_w_w Y_1^-1 and Y^2_1',                    &
    answer = pv_w(w_JacobianMPI_w_w(w_pv(pv_data1),w_pv(pv_data2))), &
    check = pv_ddata,                                                &
    significant_digits = check_digits, ignore_digits = ignore        &
    )

  pv_data1 = -cos(pv_Lat)*sin(pv_Lon)                ! Y_1^{-1}
  pv_data2 = sin(pv_Lat)*cos(pv_Lat) * cos(pv_Lon)   ! Y_2^1
  pv_ddata = sin(pv_Lat)**2 - cos(pv_Lat)**2*cos(pv_Lon)**2
  call AssertEqual(&
    message='w_JacobianMPI_w_w Y_1^-1 and Y^2_1',                    &
    answer = pv_w(w_JacobianMPI_w_w(w_pv(pv_data1),w_pv(pv_data2))), &
    check = pv_ddata,                                                &
    significant_digits = check_digits, ignore_digits = ignore        &
    )


  !============== 微分計算 (λ,μ座標系用) のテスト ==============
  pv_mu = sin(pv_Lat)

  !----- Y_2^0, Y_1^1 のテスト -----
  pva_data1(:,:,1) = 3*pv_mu**2-1                              ! Y_2^0
  pva_data1(:,:,2) = sqrt(1-pv_mu**2)*cos(pv_Lon)              ! Y_1^1

  pva_ddata(:,:,1) = 0.0
  pva_ddata(:,:,2) = -sqrt(1-pv_mu**2)*sin(pv_Lon)
  call AssertEqual(&
    message='pva_GradLambda_wb with Y_2^0 and Y^1_1',             &
    answer = pva_GradLambda_wb(wb_pva(pva_data1)),                &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )
  pva_ddata(:,:,1) = 6*pv_mu*(1-pv_mu**2)
  pva_ddata(:,:,2) = -pv_mu*sqrt(1-pv_mu**2)*cos(pv_Lon)
  call AssertEqual(&
    message='pva_GradMu_wb with Y_2^0 and Y^1_1',                 &
    answer = pva_GradMu_wb(wb_pva(pva_data1)),                    &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pv_data1 = 3*pv_mu**2-1                              ! Y_2^0
  pv_ddata = 0.0
  call AssertEqual(&
    message='pv_GradLambda_w with Y_2^0',                        &
    answer = pv_GradLambda_w(w_pv(pv_data1)),                    &
    check = pv_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore    &
    )
  pv_ddata = 6*pv_mu*(1-pv_mu**2)
  call AssertEqual(&
    message='pv_GradMu_w with Y_2^0',                             &
    answer = pv_GradMu_w(w_pv(pv_data1)),                         &
    check = pv_ddata,                                             &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pv_data1 = sqrt(1-pv_mu**2)*cos(pv_Lon)              ! Y_1^1
  pv_ddata = -sqrt(1-pv_mu**2)*sin(pv_Lon)
  call AssertEqual(&
    message='pv_GradLambda_w with Y^1_1',                        &
    answer = pv_GradLambda_w(w_pv(pv_data1)),                    &
    check = pv_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore    &
    )
  pv_ddata = -pv_mu*sqrt(1-pv_mu**2)*cos(pv_Lon)
  call AssertEqual(&
    message='pv_GradMu_w with Y_1^1',                             &
    answer = pv_GradMu_w(w_pv(pv_data1)),                         &
    check = pv_ddata,                                             &
    significant_digits = check_digits, ignore_digits = ignore     &
    )


  !----- Y_2^0(1-μ^2), Y_1^1 (1-μ^2) のテスト -----
  pva_data1(:,:,1) = (3*pv_mu**2-1)*(1-pv_mu**2)       ! Y_2^0 (1-μ^2)
  pva_data1(:,:,2) = (1-pv_mu**2)**(3.0/2)*cos(pv_Lon) ! Y_1^1 (1-μ^2)

  pva_ddata(:,:,1) = 0.0
  pva_ddata(:,:,2) = -(1-pv_mu**2)**(1.0d0/2)*sin(pv_Lon)
  call AssertEqual(&
    message='wb_DivLambda_pva with Y_2^0 (1-μ^2) and Y^1_1 √(1-μ^2)',&
    answer = pva_wb(wb_DivLambda_pva(pva_data1)),                 &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )

  pva_ddata(:,:,1) = (2-3*pv_mu**2)*4*pv_mu
  pva_ddata(:,:,2) = -3.0D0*pv_mu*(1-pv_mu**2)**(1.0D0/2)*cos(pv_Lon)
  call AssertEqual(&
    message='wb_DivMu_pva with Y_2^0 (1-μ^2) and Y^1_1 √(1-μ^2)',&
    answer = pva_wb(wb_DivMu_pva(pva_data1)),                     &
    check = pva_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore     &
    )


  pv_data1 = (3*pv_mu**2-1)*(1-pv_mu**2)       ! Y_2^0 (1-μ^2)
  pv_ddata = 0.0
  call AssertEqual(&
    message='w_DivLambda_pv with Y_2^0 (1-μ^2)',                &
    answer = pv_w(w_DivLambda_pv(pv_data1)),                     &
    check = pv_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore    &
    )
  pv_ddata = (2-3*pv_mu**2)*4*pv_mu
  call AssertEqual(&
    message='w_DivMu_pv with Y_2^0 (1-μ^2)',                    &
    answer = pv_w(w_DivMu_pv(pv_data1)),                         &
    check = pv_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore    &
    )

  pv_data1 = (1-pv_mu**2)**(3.0/2)*cos(pv_Lon) ! Y_1^1 (1-μ^2)
  pv_ddata = -(1-pv_mu**2)**(1.0d0/2)*sin(pv_Lon)
  call AssertEqual(&
    message='w_DivLambda_pv with Y^1_1 √(1-μ^2)',              &
    answer = pv_w(w_DivLambda_pv(pv_data1)),                     &
    check = pv_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore    &
    )
  pv_ddata = -3.0D0*pv_mu*(1-pv_mu**2)**(1.0D0/2)*cos(pv_Lon)
  call AssertEqual(&
    message='w_DivMu_pv with  Y^1_1 √(1-μ^2)',                 &
    answer = pv_w(w_DivMu_pv(pv_data1)),                         &
    check = pv_ddata,                                            &
    significant_digits = check_digits, ignore_digits = ignore    &
    )


  call MessageNotify('M','wb_deriv_mpi_module_sypack_test', &
                         'wb_deriv_mpi_module_sypack function tests succeeded!')

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

  call MPI_FINALIZE(IERR)

end program wb_deriv_mpi_module_sypack_test
