!> \~japanese
!! \brief STD-grid を改良した STDGC-grid を作成するための手続きを提供するモジュール.
!!
!! - STDGCGrid_Builder モジュールについて
!!  - 本モジュールで提供される手続き construct_STDGCGrid によって生成される STD-GC-grid は, STD-grid の格子点の位置をコントールボリュームの重心に移動させて
!!    できる正二十面格子である.
!!  - この格子点位置の修正により, 格子点上で微分値を数値的に評価する際に数値誤差の減少が期待できる.
!!
!! \~english
!! \brief This module provides some subroutines to construct the STD-GC-grid which is obtained by modifying the STD-Grid.
!!
!! - About STDGCGrid_Builder module
!!  - 本モジュールで提供される手続き construct_STDGCGrid によって生成される STD-GC-grid は, STD-grid の格子点の位置をコントールボリュームの重心に移動させて
!!    できる正二十面格子である.
!!  - この格子点位置の修正により, 格子点上で微分値を数値的に評価する際に数値誤差の減少が期待できる.
!!
!! \~
!!
!! <br><br>
!! \b Copyright (C) GFD Dennou Club, 2011-2012. All rights reserved. <br>
!! \b license ?? <br>
!! \author Yuta Kawai
!!
module STDGCGrid_Builder

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

  ! 種類型パラメタ
  ! Kind type parameter
  !
  use dc_types, only: DP         ! 倍精度実数型. Double precision.

  ! 数学定数
  ! Mathematic
  !
  use igmcore_math, only: PI   ! 円周率

  ! 線形代数
  ! Linear algebra
  !
  use igmcore_linear_algebra, only: &
    & vec_length, vec_normalize, &
    & cross

  ! 球面三角法
  ! Spherical trigonometry
  !
  use igmcore_spherical_trigonometry, only: geodesic_arc_length

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


  ! STD-grid の構築
  ! STD-grid construction
  !
  use STDGrid_Builder, only: &
    & calc_STDGrid_GP_vertex, calc_CV_vertex, calc_CV_Area, &
    & split_rectangle_region, project_on_sphere

  ! 宣言文 ; Declaration statements
  !
  implicit none
  private

  ! 公開手続き
  ! Public procedures
  !
  public :: construct_STDGCGrid, move_GP_into_CVGravPt

  public :: calc_CV_vertex, calc_CV_Area, calc_STDGrid_GP_vertex, &   ! Cascade
       &    split_rectangle_region, project_on_sphere                 ! Cascade

contains

!> \~japanese
!! \brief STDGC-grid を構築する.
!!
!! @param[in,out] icgrid 構造型 IcGrid2D_FVM の変数.
!!
!! \~english
!! \brief Constructs the STD-GC-grid.
!!
!! @param[in,out] icgrid The variable of derived type IcGrid2D_FVM.
!!
subroutine construct_STDGCGrid( &
  & icgrid &  ! (inout)
  & )

  ! 宣言文 ; Declaration statements
  !
  type(IcGrid2D_FVM), intent(inout) :: icgrid

  ! 実行文 ; Executable statements
  !

  ! 最初に STD-GC-grid の格子点を生成する.
  call calc_STDGrid_GP_vertex(icgrid)

  ! コントロールボリュームの頂点の座標を計算する.
  call calc_CV_vertex(icgrid)

  ! 各格子点に付随するコントロールボリュームの重心に, 格子点を移動させる.
  call move_GP_into_CVGravPt(icgrid)

  ! 各格子点に付随するコントロールボリュームの面積を計算する.
  call calc_CV_Area(icgrid)

end subroutine construct_STDGCGrid

!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! モジュール外非公開手続き
!
!!!!!!!!!!!!!!!!!!!!!!!!!!

!
!> \~japanese
!! \brief 全球に分布する各格子点の位置を, それに付随するコントロールボリュームの重心に移動させる.
!!
!! \param[in,out] icgrid 構造体 IcGrid2D_FVM の変数.
!!
!! \~english
!! \brief 全球に分布する各格子点の位置を, それに付随するコントロールボリュームの重心に移動させる.
!!
!! \param[in,out] icgrid A variable of derived type IcGrid2D_FVM.
!!
subroutine move_GP_into_CVGravPt( &
  & icgrid &  ! (inout)
  & )

  ! 宣言文 ; Declaration statemnts
  !
  type(IcGrid2D_FVM), intent(inout) :: icgrid

  ! 作業変数
  ! Work variables
  !
  integer :: rcID, i, j
  integer :: EMin, EMax
  real(DP) :: ic_radius
  real(DP) :: mod_GP(3)
  type(IcGrid2D_FVM_CV), pointer :: cv_info
  integer :: CV_num, cvID

  ! 実行文 ; Executable statements
  !

  ! 格子点座標を保持する配列の境界インデックスに関する情報を取得する.
  EMin = get_EffSize_Min(icgrid)
  EMax = get_EffSize_Max(icgrid)
  ic_radius = get_IcRadius(icgrid)

  do rcID=1, RC_REGIONS_NUM
    do j=EMin, EMax
      do i=EMin, EMax

       cv_info => icgrid%rcs_CVInfo(i,j,rcID)
       
        ! インデックスに応じて, 格子点に付随するコントールボリュームの頂点数を設定.
        if ( ( i==EMin .and. j==EMin ) .or. ( i==EMax .and. j== EMin ) .or. &
          &  ( i==EMin .and. j== EMax ) .or. ( i==EMax .and. j== EMax ) ) then
          CV_num = 5
        else
          CV_num = 6
        end if

        ! 格子点の位置を, 近接の 3 個のコントールボリューム頂点の重心に移動させる.
        mod_GP(:) = 0.0d0
        do cvID=1, CV_num
          mod_GP(:) = mod_GP(:) + cv_info%cv_pts(:,cvID)
        end do

        icgrid%rcs_AGrid(:,i,j,rcID) = mod_GP(:) / CV_num

        ! 現在, コントールボリュームの 3 頂点で作られる平面三角形上に存在する格子点を,
        ! 球面上に投影する.
       call project_on_sphere(ic_radius, icgrid%rcs_AGrid(:,i,j,rcID))

      end do
    end do
  end do

  ! のりしろを貼り合わせる
  call paste_margin_width(icgrid)

end subroutine move_GP_into_CVGravPt

end module STDGCGrid_Builder
