!
!
!
module VDerivate_Field_IcGrid3D_Manager

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

  !* gtool *****
  !*

  !
  !
  !
  use dc_types, only: &
    & DP

  !* IGMBaseLib *****
  !*

  !
  !
  !
  use Derivate_Field_UnuniGrid1D_Manager, only: &
    & Derivate_Field_UnuniGrid1D, &
    & Derivate_Field_UnuniGrid1D_Init, Derivate_Field_UnuniGrid1D_Final, &
    & delx_2ord_3pts_unufGrid, &
    & deldelx_2ord_3pts_unufGrid1

  ! 正二十面体格子データの管理
  ! Manager of icosahedral grid data
  !
  use IcGrid2D_FVM_Manager, only: &
    & IcGrid2D_FVM, &
    & get_EffSize_Min, get_EffSize_Max, &
    & get_LocalProcRectInfo, &
    & RC_REGIONS_NUM

  ! 正二十面格子における広域矩形領域のサブドメインである局所矩形領域(各 MPI プロセスと対応)の情報管理
  ! Manager of information about a local rectangle region (corresponding to each MPI process)
  !
  use LocalProcRect_Manager, only: &
    & LocalProcRectInfo, &
    & get_InteriorRegion_IndexInfo

  ! 3 次元正二十面格子データの管理
  ! Manager of 3D icosahedral grid data
  !
  use IcGrid3D_FVM_Manager, only: &
    & IcGrid3D_FVM , &
    & get_icgrid2D, get_vertical_level_num

  ! 正二十面体格子上の物理場データの管理
  ! Manager of the physical field data on icosahedral grid
  !
  use Field_IcGrid2D_Manager, only: &
    & Field_IcGrid2D

  ! 3 次元正二十面体格子上の物理場データの管理
  ! Manager of the physical field data on 3D icosahedral grid
  !
  use Field_IcGrid3D_Manager, only: &
    & Field_IcGrid3D, &
    & get_icgrid3D, get_field_layer, get_field3D_rank, &
    & paste_field3D_margin

	use omp_lib
	
  ! 宣言文 ; Declaration statements
  !
  implicit none
  private

  type, public :: VDerivate_Field_IcGrid3D
    type(Derivate_Field_UnuniGrid1D) :: vderivateTool
  end type VDerivate_Field_IcGrid3D

  ! 公開手続き
  ! Public procedures
  !
  public :: VDerivate_Field_IcGrid3D_Init, VDerivate_Field_IcGrid3D_Final
  public :: d_dVCoord, dd_dVCoord

contains

subroutine  VDerivate_Field_IcGrid3D_Init(self, icgrid3d)

  ! 宣言文 ; Declaration statements
  !
  type(VDerivate_Field_IcGrid3D), intent(inout) :: self
  type(IcGrid3D_FVM), intent(in) :: icgrid3D

  ! 実行文 ; Executable statements
  !

  call Derivate_Field_UnuniGrid1D_Init(self%vderivateTool, icgrid3D%verticalGrid)

end subroutine  VDerivate_Field_IcGrid3D_Init

subroutine VDerivate_Field_IcGrid3D_Final(self)

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

  ! 実行文 ; Executable statements
  !

  call Derivate_Field_UnuniGrid1D_Final(self%vderivateTool)

end subroutine VDerivate_Field_IcGrid3D_Final

subroutine d_dVCoord( &
  & self, field3D,  &  ! (in)
  & ret_del_field3D &  ! (inout)
  & )
  
  ! 宣言文 ; Declaration statements
  !
  type(VDerivate_Field_IcGrid3D), intent(in) :: self
  type(Field_IcGrid3D), intent(in) :: field3D
  type(Field_IcGrid3D), intent(out) :: ret_del_field3D

  call delOptr_dVCoord( &
    & self, delx_2ord_3pts_unufGrid, field3D, &
    & ret_del_field3D )
  
end subroutine d_dVCoord

subroutine dd_dVCoord( &
  & self, field3D,  &  ! (in)
  & ret_del_field3D &  ! (inout)
  & )
  
  ! 宣言文 ; Declaration statements
  !
  type(VDerivate_Field_IcGrid3D), intent(in) :: self
  type(Field_IcGrid3D), intent(in) :: field3D
  type(Field_IcGrid3D), intent(out) :: ret_del_field3D

  call delOptr_dVCoord( &
    & self, deldelx_2ord_3pts_unufGrid1, field3D, &
    & ret_del_field3D )
  
end subroutine dd_dVCoord


subroutine delOptr_dVCoord( &
  & self, & 
  & delOptr_2ord, field3D,  &  ! (in)
  & ret_del_field3D         &  ! (inout)
  & )

  ! 宣言文 ; Declaration statements
  !
  type(VDerivate_Field_IcGrid3D), intent(in) :: self
  type(Field_IcGrid3D), intent(in) :: field3D
  type(Field_IcGrid3D), intent(out) :: ret_del_field3D

  interface 
    function delOptr_2ord(derivateTool, field1D) result(dfield1D)
      use dc_types, only: DP
      use Derivate_Field_UnuniGrid1D_Manager
      
      type(Derivate_Field_UnuniGrid1D), intent(in) :: derivateTool
      real(DP), intent(in) :: field1D(:,:)
      real(DP) :: dfield1D(size(field1D,1), size(field1D,2))
    end function delOptr_2ord
  end interface
  
  ! 作業変数
  ! Work variables
  !
  integer :: rcID, k, i, j, valDimID
  integer :: iEMin, iEMax, jEMin, jEMax, KMax, rcIDMin, rcIDMax
  type(LocalProcRectInfo), pointer :: lcRCInfo

  integer :: fieldRank
  real(DP), allocatable :: z_field1D(:,:,:,:)
  real(DP), allocatable :: z_delfield1D(:,:,:,:)

  type(IcGrid3D_FVM), pointer :: icgrid3D
  type(Field_IcGrid2D), pointer :: field2D_k

  ! 実行文 ; Executable statements
  !

  icgrid3D => get_icgrid3D(field3D)
  lcRCInfo => get_LocalProcRectInfo(get_icgrid2D(icgrid3D))

  call get_InteriorRegion_IndexInfo( &
    & lcRCInfo,            &                         ! (in)
    & iEMin, iEMax, jEMin, jEMax, rcIDMin, rcIDMax ) ! (out)

  kMax = get_vertical_level_num(icgrid3D)
  fieldRank = get_field3D_rank(field3D)

  allocate(z_field1D(kMax, fieldRank, iEMin:iEMax, jEMin:jEMax))
  allocate(z_delfield1D(kMax, fieldRank, iEMin:iEMax, jEMin:jEMax))

  do rcID=rcIDMin, rcIDMax

    do valDimID=1, fieldRank
      !$omp parallel do
      do k=1, KMax
        z_field1D(k, valDimID, iEMin:iEMax,jEMin:jEMax) = field3D%field2Ds(k)%val(valDimID, iEMin:iEMax,jEMin:jEMax,rcID)
      end do
    end do

    !$omp parallel do private(i)
    do j=jEMin, jEMax
      do i=iEMin, iEMax
        
        z_delfield1D(1:KMax,1:fieldRank, i,j) = delOptr_2ord(self%vderivateTool, z_field1D(:,:, i,j))

      end do
    end do

    do valDimID=1, fieldRank
      !$omp parallel do
      do k=1, KMax
        ret_del_field3D%field2Ds(k)%val(valDimID, iEMin:iEMax,jEMin:jEMax,rcID) = &
          & z_delfield1D(k,valDimID, iEMin:iEMax,jEMin:jEMax)
      end do
    end do

  end do

end subroutine delOptr_dVCoord

end module VDerivate_Field_IcGrid3D_Manager
