program test_IcGrid3D_field

  ! モジュール引用 ; Use statements
  !
  use dc_types, only: &
    & DP, TOKEN, STRING

  use dc_test, only: AssertLessThan, AssertEqual

  use dc_message, only: MessageNotify
  
  use IcGrid2D_FVM_Manager, only: &
    & IcGrid2D_FVM, &
    & IcGrid2D_FVM_Init, IcGrid2D_FVM_Final, &
    & get_EffSize_Min, get_EffSize_Max, &
    & RC_REGIONS_NUM


  use IcGrid2D_FVM_Builder, only: &
    & construct_icosahedral_grid, GTYPE_STDGCGRID

  use IcGrid3D_FVM_Manager, only: &
    & IcGrid3D_FVM, &
    & IcGrid3D_FVM_init, IcGrid3D_FVM_Final, &
    & get_icgrid2D, get_vertical_level_num, &
    & redistribute_verticalGrid

  use Field_IcGrid2D_Manager, only: &
    & Field_IcGrid2D, &
    & Field_IcGrid2D_Init, Field_IcGrid2D_Final, &
    & get_field2D_name, get_long_field2D_name, get_field2D_units

  use Field_IcGrid3D_Manager, only: &
    & Field_IcGrid3D, &
    & Field_IcGrid3D_Init, Field_IcGrid3D_Final, &
    & get_field3D_name, get_long_field3D_name, get_field3D_units, &
    & set_field3D_name, set_long_field3D_name, set_field3D_units, &
    & get_field_layer, &
    & paste_field3D_margin, fill_value, copy_field3D

  implicit none

  type(IcGrid2D_FVM), pointer :: icgrid2D
  integer :: glevel = 5
  real(DP) :: ic_radius = 1.0d0

  type(IcGrid3D_FVM) :: icgrid3D
  integer, parameter :: vertical_lv_num = 4

  type(Field_IcGrid3D) :: field3D, copied_field3D
  integer :: field_rank = 3
  character(TOKEN) :: name = 'velocity'
  character(STRING) :: long_name = 'velocity'
  character(STRING) :: units = 'm/s'

  real(DP) :: vertGrid_interval_ratio(vertical_lv_num-1) = (/ 1.0d0, 2.0d0, 1.0d0 /)
  real(DP) :: VMax = 10.0d0
  real(DP) :: VMin = 0.0d0

  type(Field_IcGrid2D), pointer :: field2D
  integer :: vtID, rcID, i, j
  integer :: glEMin, glEMax, vertLv_num

  ! Unit test 3.1
  !
  ! icgrid3D の生成
  write(*,*) '= Unit Test 3.1 [ IcGrid3D_FVM_Manager]'
  write(*,*) '* Constructs IcGrid3D'

  allocate(icgrid2D)
  call construct_icosahedral_grid(GTYPE_STDGCGRID, glevel, ic_radius, icgrid2D)
  call IcGrid3D_FVM_Init(icgrid3D, icgrid2D, vertical_lv_num)

  !
  vertLv_num = get_vertical_level_num(icgrid3D)
  glEMin = get_EffSize_Min(icgrid2D)
  glEMax = get_EffSize_Min(icgrid2D)  

  write(*,*) 'Output defalut vertcies of vertical grid:'
  write(*,*) ( icgrid3D%verticalGrid(i), i=1, vertLv_num )
  
  call AssertEqual( &
    & message='IcGrid3D_FVM_Init', &
    & answer=icgrid3D%verticalGrid(1:vertLv_num), &
    & check=(/ 0.0d0, 1.0d0/3.0d0, 2.0/3.0d0, 1.0d0 /) &
    & )
  write(*,*) '---------------------------------------'


  ! Unit test 3.2
  !
  ! 鉛直格子の再配置
  !
  write(*,*) '= Unit Test 3.2 [ Field_IcGrid3D_Manager]'
  write(*,*) '* Redistribute vertical grid IcGrid3D'

  call redistribute_verticalGrid(icgrid3D, VMin, VMax, vertGrid_interval_ratio)

  write(*,*) 'Output vertcies of redistributed vertical grid:'
  write(*,*) icgrid3D%verticalGrid
  call AssertEqual( &
    & message='redistribute_verticalGrid', &
    & answer=icgrid3D%verticalGrid(1:vertLv_num), &
    & check=(/ 0.0d0, 2.5d0, 7.5d0, 10.0d0 /) &
    & )
    
  write(*,*) '---------------------------------------'

  ! Unit test 3.3
  !
  write(*,*) '= Unit Test 3.3 [ Field_IcGrid3D_Manager]'
  write(*,*) '* Generates Field_IcGrid3D object'
  write(*,*) '* Tests getters/setters of Field_IcGrid3D.' 

  !
  call Field_IcGrid3D_Init(field3D, icgrid3D, name, field_rank, long_name, units)

  call set_field3D_name(field3D, name)
  call AssertEqual( message='Test of Field_IcGrid3D::set_field3D_name', & 
    &               answer=trim(name), check=trim(get_field3D_name(field3D)) )

  call set_long_field3D_name(field3D, long_name)
  call AssertEqual( message='Test of Field_IcGrid3D::set_field3D_long_name', & 
    &               answer=trim(long_name), check=trim(get_long_field3D_name(field3D)) )

  call set_field3D_units(field3D, units)
  call AssertEqual( message='Test of Field_IcGrid3D::set_field3D_units', & 
    &               answer=trim(units), check=trim(get_field3D_units(field3D)) )

  write(*,*) '* Test of IcGrid3D_FVM::get_field_layer'

  do vtID=1, vertLv_num
    field2D => get_field_layer(field3D, vtID)
    write(*,'(a,i2,a,a,a,a)') '* vtID=', vtID, ', name=',  trim(get_field2D_name(field2D)), &
      & ', units=', trim(get_field2D_units(field2D))
  end do
  
  if ( ( .not. associated(get_field_layer(field3D, -1)) )   .and.      &
    &  ( .not. associated( get_field_layer(field3D, vertLv_num + 1)) ) & 
    & ) then
    
  else
    call MessageNotify('E', 'Unit Test 3.3', 'Test of Field_IcGrid3D::get_field_layer is failed !!')
    stop
  end if
  
  call MessageNotify('M', 'Unit Test 3.3', 'Test of Field_IcGrid3D::get_field_layer is succeed!!')

  write(*,*) '---------------------------------------'

  ! Unit test 3.4
  !
  write(*,*) '= Unit Test 3.4 [ Field_IcGrid3D_Manager]'
  write(*,*) '* Tests some procedures in Field_IcGrid3D_Manager module.' 

  write(*,*) '* Test of IcGrid3D_FVM::fill_value'
  call fill_value(field3D, -1d0)
  
  do vtID=1, vertLv_num
    field2D => get_field_layer(field3D, vtID)

    do rcID=1, RC_REGIONS_NUM
      do j=glEMin, glEMax
        do i=glEMin, glEMax
          if( field2D%val(1, i,j,rcID) /= -1d0 ) then
            call MessageNotify('E', 'Unit Test 3.4', 'Test of Field_IcGrid3D::fill_value is failed !!')
            stop
          end if
        end do
      end do
    end do
    
  end do
  
  call MessageNotify('M', 'Unit Test 3.4', 'Test of Field_IcGrid3D::fill_value is succeed!!')

  write(*,*) '* Test of IcGrid3D_FVM::copy_field3D'
  call Field_IcGrid3D_Init(copied_field3D, icgrid3D, 'copied_field3D', 1)
  call fill_value(copied_field3D, +1.0d0)
  
  call copy_field3D(copied_field3D, field3D)
  
  do vtID=1, vertLv_num
    field2D => get_field_layer(copied_field3D, vtID)

    do rcID=1, RC_REGIONS_NUM
      do j=glEMin, glEMax
        do i=glEMin, glEMax
          if( field2D%val(1, i,j,rcID) /= -1d0 ) then
            call MessageNotify('E', 'Unit Test 3.4', 'Test of IcGrid3D_FVM::copy_field3D is failed !!')
            stop
          end if
        end do
      end do
    end do
    
  end do
  
  call Field_IcGrid3D_Final(copied_field3D)
  call MessageNotify('M', 'Unit Test 3.4', 'Test of IcGrid3D_FVM::copy_field3D is succeed!!')
  
  ! 後片付け
  !
  write(*,*) '---------------------------------------'

  call Field_IcGrid3D_Final(field3D)
  call IcGrid3D_FVM_Final(icgrid3D)
  call IcGrid2D_FVM_Final(icgrid2D)
  deallocate(icgrid2D)

end program test_IcGrid3D_field
