!> \~japanese
!! \brief 各タイムレベルにおける速度場や高度場などの物理場データを管理するモジュール.
!! \~english
!! \brief This module provides some subroutines to manage the physical fields data of velocity or height, etc at each time level.
!!
!! <br><br>
!! \b Copyright (C) GFD Dennou Club, 2011-2012. All rights reserved. <br>
!! \b license ?? <br>
!! \author Yuta Kawai
!!
module output_field_data

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

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

  ! 座標変換
  ! Coordinate conversion
  !
  use igmcore_coordinate_conversion, only: &
    & orth_to_geo_pos, orth_to_geo_vec

  ! 正二十面体格子の管理
  ! Manager of icosahedral grid
  !
  use IcGrid2D_FVM_Manager, only: &
    & IcGrid2D_FVM, &
    & check_pole, get_EffSize_Min, get_EffSize_Max, &
    & RC_REGIONS_NUM, NOT_POLE_FLAG

  ! 正二十面体格子上の物理場の管理
  ! Manager of the physical field on icosahedral grid
  !
  use Field_IcGrid2D_Manager, only: &
    & Field_IcGrid2D, &
    & get_icgrid, &
    & Field_IcGrid2D_Init
  
  ! 正二十面体格子上の物理場データを NetCDF ファイルに書きだすクラス 
  ! Class to write the data of the physical fields on icosahedral grid into a NetCDF file
  !
  use IcGrid_ncWriter_mod, only: &
    & IcGrid_ncWriter, &
    & IcGrid_ncWriter_Init, open_ncFile, &
    & ncdef_simulation_parameter, ncdef_gridData, ncdef_FieldData, end_ncdef, &
    & write_GridData, write_FieldData, close_ncFile, &
    & increase_recorde_counter

  ! OpenMP
  !
  !
  use omp_lib

  ! 宣言文 ; Declaration statements
  !
  implicit none
  private

  ! 非公開変数
  ! Private variables
  !

  !> \~japanese シミュレーション結果を書きだす NetCDF ファイルの名前.
  !! \~english The name of the NetCDF file to write the simulation result to.
  character(Token) :: ncFileName
  
  !> \~japanese シミュレーション結果のデータを NetCDF ファイルに書き出すためのデータを管理する構造型 IcGrid_ncWriter の変数.
  !! \~english The variable of derived type IcGrid_ncWriter to output the data of the simulation result into a NetCDF file.
  type(IcGrid_ncWriter), save :: writer

  !> \~japanese 下部地形の高度データを NetCDF ファイルに書き出すためのデータを管理する構造型 IcGrid_ncWriter の変数.
  !! \~english The variable of derived type IcGrid_ncWriter to output the height data of underlying mountain into a NetCDF file.
  type(IcGrid_ncWriter), save :: hs_writer

  !> \~japanese 経度方向の速度場データを管理する構造型 Field_IcGrid2D の変数.
  !! \~english The variable of derived type Field_IcGrid2D to manage the field data of zonal velocity.
  type(Field_IcGrid2D), save :: UWind
  
  !> \~japanese 緯度方向の速度場データを管理する構造型 Field_IcGrid2D の変数.
  !! \~english The variable of derived type Field_IcGrid2D to manage the field data of meridional velocity.
  type(Field_IcGrid2D), save :: VWind
  
  !> \~japanese 鉛直速度場データを管理する構造型 Field_IcGrid2D の変数.
  !! \~english The variable of derived type Field_IcGrid2D to manage the field data of vertical velocity.
  type(Field_IcGrid2D), save :: WWind

  !> \~japanese 表面高度場データを管理する構造型 Field_IcGrid2D の変数.
  !! \~english The variable of derived type Field_IcGrid2D to manage the field data of surface height.
  type(Field_IcGrid2D), save :: Height

  !> \~japanese 下部境界の地形の高度場を管理する構造型 Field_IcGrid2D の変数.
  !! \~english The variable of derived type Field_IcGrid2D to manage the field data of the height of underlying mountain.
  type(Field_IcGrid2D), save :: HeightS

  !> \~japanese 変数名 UWind に対応する NetCDF 変数の ID.
  !! \~english The ID of the NetCDF variable coresponding to the variable name UWind.
  integer :: u_ncVarID
  
  !> \~japanese 変数名 VWind に対応する NetCDF 変数の ID.
  !! \~english The ID of the NetCDF variable coresponding to the variable name VWind.
  integer :: v_ncVarID
  
  !> \~japanese 変数名 WWind に対応する NetCDF 変数の ID.
  !! \~english The ID of the NetCDF variable coresponding to the variable name WWind.
  integer :: w_ncVarID

  !> \~japanese 変数名 Height に対応する NetCDF 変数の ID.
  !! \~english The ID of the NetCDF variable coresponding to the variable name Height.
  integer :: h_ncVarID

  !> \~japanese 変数名 HeightS に対応する NetCDF 変数の ID.
  !! \~english The ID of the NetCDF variable coresponding to the variable name HeightS.
  integer :: hs_ncVarID

  ! 公開関数
  ! Public procedures
  !
  public :: init_output_field_data, output_field, finalize_output_field_data

contains

!
!> \~japanese
!! \brief output_field_data モジュールの初期化を行う.
!!
!! @param[in] nc_filename  物理場データを書きだす NetCDF ファイルの名前.
!! @param[in] icgrid       構造型 IcGrid2D_FVM の変数.
!! @param[in] integration_time 積分時間 [s].
!! @param[in] time_step 時間ステップ [s].
!! @param[in] output_tick データ出力を行う時間刻み [s].
!!
!! \~english
!! \brief Initializes the output_field_data module.
!!
!! @param[in] nc_filename  The name of a NetCDF file to output the physical field data into.
!! @param[in] icgrid       The variable of derived type IcGrid2D_FVM.
!! @param[in] integration_time Integration time [s].
!! @param[in] time_step Time step [s].
!! @param[in] output_tick Time interval for outputing data.
!!
subroutine init_output_field_data( &
  & nc_filename, icgrid,           &            ! (in)
  & integration_time, time_step, output_tick )  ! (in)

  ! モジュール引用 ; Use statements
  !
  use dc_string, only: Replace

  ! 宣言文 ; Declaration statement
  !
  character(*), intent(in) :: nc_filename
  type(IcGrid2D_FVM), intent(in) :: icgrid
  real(DP), intent(in) :: integration_time
  real(DP), intent(in) :: time_step
  real(DP), intent(in) :: output_tick

  ! 作業変数
  ! Work variables
  !
  character(STRING) :: nc_hs_filename 

  ! 実行文 ; Executable statement
  !
  
  ncFileName = nc_filename

  ! IcGrid_ncWriter クラスのインスタンスを初期化. 
  call IcGrid_ncWriter_Init(writer, icgrid)
  call IcGrid_ncWriter_Init(hs_writer, icgrid)

  ! netCDF ファイルを開く. 
  call open_ncFile(writer, nc_filename)
  
  nc_hs_filename = trim(Replace(nc_filename, '.nc', '')) // '_hs.nc' 
  call open_ncFile(hs_writer, nc_hs_filename)

  ! netCDF ファイルへのアウトプットデータの定義
  !

  ! シミュレーションパラメータを NetCDF ファイルに書きだす. 
  call ncdef_Simulation_Parameter(writer, integration_time, time_step, output_tick)
  call ncdef_Simulation_Parameter(hs_writer, integration_time, time_step, output_tick)

  ! 格子点情報を NetCDF ファイルに定義する.  
  call ncdef_GridData(writer)
  call ncdef_GridData(hs_writer)

  ! 速度場と高度場の物理場データ情報を NetCDF ファイルに定義する.  
  call Field_IcGrid2D_Init(UWind, icgrid, 'u', 1, 'zonal_velocity', 'm/s')
  call Field_IcGrid2D_Init(VWind, icgrid, 'v', 1, 'meriodinal_velocity', 'm/s')
  call Field_IcGrid2D_Init(WWind, icgrid, 'w', 1, 'vertical_velocity', 'm/s')
  call Field_IcGrid2D_Init(Height, icgrid, 'h', 1, 'surface_height', 'm')
  call Field_IcGrid2D_Init(HeightS, icgrid, 'hs', 1, 'height_of_underlying_mountain', 'm')

  ! 各 Field_IcGrid2D クラスオブジェクトに対応付けられる NetCDF 内での変数管理 ID を取得する.
  u_ncVarID = ncdef_FieldData(writer, UWind)
  v_ncVarID = ncdef_FieldData(writer, VWind)
  w_ncVarID = ncdef_FieldData(writer, WWind)
  h_ncVarID = ncdef_FieldData(writer, Height)
  hs_ncVarID = ncdef_FieldData(hs_writer, HeightS)

  ! 物理場の定義を終了する. 
  call end_ncdef(writer)
  call end_ncdef(hs_writer)

  ! 格子情報を netCDF に書きこむ. 
  !
  call write_GridData(writer)
  call write_GridData(hs_writer)

end subroutine init_output_field_data

!
!> \~japanese
!! \brief  時間レベル n における速度場(v)と高度場(h, hs)の物理場データを NetCDF ファイルに書きだす.
!!
!! @param[in] tstep 現在の時間ステップ数.
!! @param[in] v_n   時間レベル n の速度場データを保持する構造型 Field_IcGrid2D の変数.
!! @param[in] h_n   時間レベル n の表面高度場データを保持する構造型 Field_IcGrid2D の変数.
!! @param[in] hs    下部境界における地形の高度場データを保持する構造型 Field_IcGrid2D の変数.
!!
!! \~english
!! \brief Outputs the physical fields data of velocity(v) and height(h, hs) at time level n into a NetCDF file.
!!
!! @param[in] tstep The number of current time step.
!! @param[in] v_n   The variable of derived type Field_IcGrid2D to manage the velocity field data at time level n.
!! @param[in] h_n   The variable of derived type Field_IcGrid2D to manage the surface height field data at time level n.
!! @param[in] hs    The variable of derived type Field_IcGrid2D to manage the height field of underlying mountain.
!!
subroutine output_field( &
  &  tstep, v_n, h_n, hs     &  ! (in)
  & )

  ! 宣言文 ; Declaration statement
  !
  integer, intent(in) :: tstep
  type(Field_IcGrid2D), intent(in) :: v_n
  type(Field_IcGrid2D), intent(in) :: h_n
  type(Field_IcGrid2D), intent(in), optional :: hs

  ! 作業変数 
  ! Work variables
  !
  type(IcGrid2D_FVM), pointer :: icgrid
  real(DP) :: s_v(3)
  integer :: rcID, i,j
  integer :: EMin, EMax

  ! 実行文 ; Executable statement
  !

  !write(*,*) 'ouput field: tstep=', tstep
  icgrid => get_icgrid(v_n)

  EMin = get_EffSize_Min(icgrid)
  EMax = get_EffSize_Max(icgrid)

  ! デカルト座標系で表されている速度場(ベクトル)データを, 地理座標系で表す. 
  do rcID=1, RC_REGIONS_NUM
    !$omp parallel do private(s_v)
    do j=EMin,EMax
      do i=EMin, EMax
        if ( check_pole(icgrid, rcID,i,j) == NOT_POLE_FLAG ) then
          s_v(:) = orth_to_geo_vec( v_n%val(rcID,i,j,:), orth_to_geo_pos(icgrid%rcs_AGrid(rcID,i,j,:)) )
          
          UWind%val(rcID,i,j,1) = s_v(1)
          VWind%val(rcID,i,j,1) = s_v(2)
          WWind%val(rcID,i,j,1) = s_v(3)
        end if
      end do
    end do
  end do

  Height%val(:,:,:,:) = h_n%val(:,:,:,:)

  ! 時間レベル n の速度場と高度場の情報を netCDF ファイルに書き出す. 
  call write_FieldData(writer, u_ncVarID, UWind)
  call write_FieldData(writer, v_ncVarID, VWind)
  call write_FieldData(writer, w_ncVarID, WWind)
  call write_FieldData(writer, h_ncVarID, Height)

  ! 地形の高度場を NetCDF ファイルに書きだす. 
  ! 地形の高度場については, 初期場に対してのみ書きだす. 
  if( tstep == 0 .and. present(hs) ) then
    HeightS%val(:,:,:,:) = hs%val(:,:,:,:)
    call write_FieldData(hs_writer, hs_ncVarID, HeightS)
    call close_ncFile(hs_writer)
  end if

  ! 時間レベル記録カウンタをインクリメントする. 
  call increase_recorde_counter(writer)

end subroutine output_field

!
!> \~japanese
!! \brief output_field_data モジュールを最終化する.
!! \~english
!! \brief Finalize the output_field_data module.
!!
subroutine finalize_output_field_data()

  ! 実行文 ; Executable statement
  !
  
  ! NetCDF ファイルの書き出しクラスのオブジェクトを最終化する. 
  call close_ncFile(writer)

end subroutine finalize_output_field_data

end module output_field_data
