module Derivate_Field_UnuniGrid1D_Manager

  ! モジュール引用 ; Use statements
  !

  !* gtool *****
  !*

  !
  !
  !
  use dc_types, only: DP

  use Derivate_Field_UniformGrid1D, only: &
    & delx_2ord_3pts_ufGrid, &
    & deldelx_2ord_3pts_ufGrid

  ! 宣言文 ; Declaration statements
  !
  implicit none
  private

  type, public :: Derivate_Field_UnuniGrid1D
    real(DP), pointer :: grid1D(:)
    real(DP), pointer :: delunigx_grid(:,:)
    real(DP), pointer :: deldelunigx_grid(:,:)
    real(DP) :: DelUniX
  end type Derivate_Field_UnuniGrid1D

  ! 公開手続き
  ! Public procedures
  !
  public :: Derivate_Field_UnuniGrid1D_Init, Derivate_Field_UnuniGrid1D_Final
  public :: delx_2ord_3pts_unufGrid, deldelx_2ord_3pts_unufGrid, &
    &       deldelx_2ord_3pts_unufGrid1, deldelx_2ord_3pts_unufGrid2

  interface deldelx_2ord_3pts_unufGrid
    module procedure deldelx_2ord_3pts_unufGrid1
    module procedure deldelx_2ord_3pts_unufGrid2
  end interface deldelx_2ord_3pts_unufGrid


contains
subroutine Derivate_Field_UnuniGrid1D_Init(self, grid1D)

  ! 宣言文 ; Declaration statements
  !
  type(Derivate_Field_UnuniGrid1D), intent(inout) :: self
  real(DP), target, intent(in) :: grid1D(:)

  ! 作業変数
  ! Work variables
  !
  integer :: gNum

  ! 実行文 ; Executable statements
  !

  self%DelUniX = 1.0d0
  gNum = size(grid1D)
  allocate(self%delunigx_grid(gNum, 1))
  allocate(self%deldelunigx_grid(gNum, 1))

  self%grid1D => grid1D
  self%delunigx_grid(:,:) = delx_2ord_3pts_ufGrid(reshape(grid1D, (/ gNum, 1/)), self%DelUniX)
  self%deldelunigx_grid(:,:) = deldelx_2ord_3pts_ufGrid(reshape(grid1D, (/ gNum, 1/)), self%DelUniX)

end subroutine Derivate_Field_UnuniGrid1D_Init

subroutine Derivate_Field_UnuniGrid1D_Final(self)

  ! 宣言文 ; Declaration statements
  !
  type(Derivate_Field_UnuniGrid1D), intent(inout) :: self

  ! 実行文 ; Executable statements
  !

  if ( associated(self%delunigx_grid) ) then
    deallocate(self%delunigx_grid)
    deallocate(self%deldelunigx_grid)
  end if

end subroutine Derivate_Field_UnuniGrid1D_Final

function delx_2ord_3pts_unufGrid(self, field1D) result(delununigx_field1D)

  ! 宣言文 ; Declaration statements
  !
  type(Derivate_Field_UnuniGrid1D), intent(in) :: self
  real(DP), intent(in) :: field1D(:,:)
  real(DP) :: delununigx_field1D(size(field1D,1), size(field1D,2))

  ! 作業変数
  ! Work variables
  !
  integer :: k
  integer :: kMax
  real(DP) :: delunigx_f(size(field1D,1), size(field1D,2))

  ! 実行文 ; Executable statements
  !

  kMax = size(field1D,1)
  delunigx_f(:,:) = delx_2ord_3pts_ufGrid(field1D, self%DelUniX)

  do k=1, kMax
  if (k==1 .or. k==kMax) then
    delununigx_field1D(k,:) = delunigx_f(k,:) / self%delunigx_grid(k,1)
  else
    delununigx_field1D(k,:) = ( field1D(k+1,:) - field1D(k-1,:) ) / ( self%grid1D(k+1) - self%grid1D(k-1) ) 
  end if
  end do

end function delx_2ord_3pts_unufGrid

function deldelx_2ord_3pts_unufGrid1(self, field1D) result(deldelununigx_field1D)

  ! 宣言文 ; Declaration statements
  !
  type(Derivate_Field_UnuniGrid1D), intent(in) :: self
  real(DP), intent(in) :: field1D(:,:)
  real(DP) :: deldelununigx_field1D(size(field1D,1), size(field1D,2))

  ! 作業変数
  ! Work variables
  !
  integer :: k
  integer :: kMax
  real(DP) :: delunigx_f(size(field1D,1), size(field1D,2))
  real(DP) :: deldelunigx_f(size(field1D,1), size(field1D,2))
  real(DP) :: G(3)
  
  ! 実行文 ; Executable statements
  !

  kMax = size(field1D,1)

  delunigx_f(:,:) = delx_2ord_3pts_ufGrid(field1D,self%DelUniX)
  deldelunigx_f(:,:) = deldelx_2ord_3pts_ufGrid(field1D, self%DelUniX)

  do k=1, kMax
    deldelununigx_field1D(k,:) = &
      & (    deldelunigx_f(k,:) &
      &    - delunigx_f(k,:) * self%deldelunigx_grid(k,1) / self%delunigx_grid(k,1) &
      & ) /  self%delunigx_grid(k,1)**2

!write(*,*) '   *', deldelunigx_f(k,:), - delunigx_f(k,:) * self%deldelunigx_grid(k,1) / self%delunigx_grid(k,1), &
!  & delunigx_f(k,:) * self%deldelunigx_grid(k,1), self%delunigx_grid(k,1)
  end do

end function deldelx_2ord_3pts_unufGrid1

function deldelx_2ord_3pts_unufGrid2(self, field1D, delununigx_f) result(deldelununigx_field1D)

  ! 宣言文 ; Declaration statements
  !
  type(Derivate_Field_UnuniGrid1D), intent(in) :: self
  real(DP), intent(in) :: field1D(:,:)
  real(DP), intent(in) :: delununigx_f(:,:)
  real(DP) :: deldelununigx_field1D(size(field1D,1), size(field1D,2))

  ! 作業変数
  ! Work variables
  !
  integer :: k
  integer :: kMax
  real(DP) :: deldelunigx_f(size(field1D,1), size(field1D,2))

  ! 実行文 ; Executable statements
  !

  kMax = size(field1D,1)

  deldelunigx_f(:,:) = deldelx_2ord_3pts_ufGrid(field1D, self%DelUniX)

  do k=1, kMax
    deldelununigx_field1D(k,:) = &
      & ( deldelunigx_f(k,:) - delununigx_f(k,:) * self%deldelunigx_grid(k,1)  ) &
      &  / self%delunigx_grid(k,1)**2
  end do

end function deldelx_2ord_3pts_unufGrid2

end module Derivate_Field_UnuniGrid1D_Manager
