module Output_EnergyAnalysis

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

  use, intrinsic :: iso_c_binding

#ifdef LIB_MPI
  use mpi
#endif

  !* gtool ***********
  !*

  ! 種類型パラメータ
  ! kind type parameter
  !
  use dc_types, only: &
    & DP, STRING

  use dc_string, only: &
    & StoA

  use gtool_history, only: &
    & GT_HISTORY, &
    & HistoryCreate, &
    & HistoryAddVariable, HistoryPut, &
    & HistoryClose

  !* IGMBaseLib ***********
  !*

  !
  !
  !
  use Field_IcGrid3D_Manager, only: &
    & Field_IcGrid3D

  !
  !
  !
  use TFCoord_IcGrid3D_helper, only: &
    & TFCoord_IcGrid3D, &
    & global_mean_Field_TFIcGrid3Dz

  ! C との相互利用のためのユーティリティ
  ! Utility for interoperability with C
  !
  use CBinding_Utility, only: &
    & c_f_string

  !* DIGMO **********
  !

  !
  !
  !
  use EnergyAnalysis, only: &
    & Analize_SystemEnergy

  ! 宣言文 ; Declaration statements
  !
  implicit none
  private

  ! 公開手続き
  ! Public procedures
  !
  public :: output_EnergyAnalysis_Init, output_EnergyAnalysis_Final
  public :: output_EnergyAnalysis_Data

  logical :: mpi_EnabledFlag = .false.
  logical :: mpi_IOEnabledFlag = .false.

real(DP) :: e_check

contains
subroutine output_EnergyAnalysis_Init( &
  & cfileName, EnergyAnalysisOutputTick, &
  & cptr_gthistory, mpi_flag &
  ) bind(C, name='output_EnergyAnalysis_Init')

  ! 宣言文 ; Declaration statements
  !
  character(len=1, kind=c_char), intent(in) :: cfileName(*)
  real(DP), value :: EnergyAnalysisOutputTick
  type(c_ptr), intent(out) :: cptr_gthistory
  logical(c_bool), value :: mpi_flag

	! 作業変数
	! Work variables
	!
  type(GT_HISTORY), pointer :: ptr_gthistory
	character(STRING) :: fileName
	integer :: my_rank, ierr
	
	! 実行文 ; Executable statements
	!

  if ( mpi_flag ) then
    mpi_EnabledFlag = .true.

#ifdef LIB_MPI
    call MPI_Comm_rank(MPI_COMM_WORLD, my_rank, ierr)
    if ( my_rank /= 0 ) then
      mpi_IOEnabledFlag = .false.
      return
    end if

    mpi_IOEnabledFlag = .true.
#endif
  end if

  allocate(ptr_gthistory)
	cptr_gthistory = c_loc(ptr_gthistory)
	
	call c_f_string(cfileName, fileName)
	
  call HistoryCreate( &
    & file=fileName, title='Energy Analysis', &
    & source=' ', institution='GFD Dennou Club IGModel Project', &
    & dims=StoA('time'), dimsizes=(/ 0 /), &
    & longnames=StoA('time'), units=StoA('s'), &
    & origin=real(0d0), interval=real(EnergyAnalysisOutputTick), &
    & history=ptr_gthistory )

  call HistoryAddVariable( &                  
    & varname='TotalE', dims=(/'time'/), &
    & longname='total energy (per unit volume)', units='J/m^3', xtype='double', &
    & history=ptr_gthistory )


  call HistoryAddVariable( &                  
    & varname='InternalE', dims=(/'time'/), &
    & longname='internal energy (per unit volume)', units='J/m^3', xtype='double', &
    & history=ptr_gthistory )


  call HistoryAddVariable( &                  
    & varname='KineticE', dims=(/'time'/), &
    & longname='kinetic energy (per unit volume)', units='J/m^3', xtype='double', &
    & history=ptr_gthistory )

  call HistoryAddVariable( &                  
    & varname='PotentialE', dims=(/'time'/), &
    & longname='potential energy (per unit volume)', units='J/m^3', xtype='double', &
    & history=ptr_gthistory )

  call HistoryAddVariable( &                  
    & varname='Mass', dims=(/'time'/), &
    & longname='Total mass (per unit volume)', units='kg/m^3', xtype='double', &
    & history=ptr_gthistory )
    
end subroutine output_EnergyAnalysis_Init

subroutine output_EnergyAnalysis_Data( &
  & cptr_gthistory, &
  & cptr_xyz_TENs, cptr_xyz_VhNl, cptr_xyr_WNl, &
  & cptr_xyz_RhoBasic, cptr_xyz_RNl, cptr_xyz_ENl, &
  & cptr_tfcoordz, cptr_tfcoordr, Grav &
  & ) bind(C, name='output_EnergyAnalysis_Data')

  ! 宣言文 ; Declaration statements
  !	
  type(c_ptr), value :: cptr_gthistory
	type(c_ptr), value :: cptr_xyz_TENs
	type(c_ptr), value :: cptr_xyz_VhNl
	type(c_ptr), value :: cptr_xyr_WNl
	type(c_ptr), value :: cptr_xyz_RhoBasic
	type(c_ptr), value :: cptr_xyz_RNl	
	type(c_ptr), value :: cptr_xyz_ENl
	type(c_ptr), value :: cptr_tfcoordz
	type(c_ptr), value :: cptr_tfcoordr
	real(DP), value :: Grav

  ! 作業変数
  ! Work variables
  !
  type(GT_HISTORY), pointer :: ptr_gthistory
	type(Field_IcGrid3D), pointer :: ptr_xyz_TENs
	type(Field_IcGrid3D), pointer :: ptr_xyz_VhNl
	type(Field_IcGrid3D), pointer :: ptr_xyr_WNl
	type(Field_IcGrid3D), pointer :: ptr_xyz_RhoBasic
	type(Field_IcGrid3D), pointer :: ptr_xyz_RNl
	type(Field_IcGrid3D), pointer :: ptr_xyz_ENl
	
	type(TFCoord_IcGrid3D), pointer :: ptr_tfcoordz
	type(TFCoord_IcGrid3D), pointer :: ptr_tfcoordr
	
	real(DP) :: gm_TotalE
	real(DP) :: gm_InternalE
	real(DP) :: gm_KineticE
	real(DP) :: gm_PotentialE
	real(DP) :: gm_mass
	
	real(DP) :: te_error
  
  ! 実行文 ; Executable statements
  !
	
	call c_f_pointer(cptr_gthistory, ptr_gthistory)
	call c_f_pointer(cptr_xyz_TENs, ptr_xyz_TENs)
	call c_f_pointer(cptr_xyz_VhNl, ptr_xyz_VhNl)
	call c_f_pointer(cptr_xyr_WNl, ptr_xyr_WNl)
	call c_f_pointer(cptr_xyz_RhoBasic, ptr_xyz_RhoBasic)
	call c_f_pointer(cptr_xyz_RNl, ptr_xyz_RNl)
	call c_f_pointer(cptr_xyz_ENl, ptr_xyz_ENl)
	call c_f_pointer(cptr_tfcoordz, ptr_tfcoordz)
	call c_f_pointer(cptr_tfcoordr, ptr_tfcoordr)
	
	call 	Analize_SystemEnergy( &
		& gm_TotalE, gm_KineticE, gm_InternalE, gm_PotentialE, gm_mass, &
		& ptr_xyz_TENs, ptr_xyz_VhNl, ptr_xyr_WNl, &
		& ptr_xyz_RhoBasic, ptr_xyz_RNl, ptr_xyz_ENl, &
		& ptr_tfcoordz,  ptr_tfcoordr, Grav &
		& )	
  
  if ( ( .not. mpi_EnabledFlag ) .or. mpi_IOEnabledFlag ) then
!    write(*,*) gm_TotalE - e_check
    e_check = gm_TotalE
    
	  call HistoryPut('TotalE', gm_TotalE, ptr_gthistory)
	  call HistoryPut('InternalE', gm_InternalE, ptr_gthistory)
	  call HistoryPut('KineticE', gm_KineticE, ptr_gthistory)
	  call HistoryPut('PotentialE', gm_PotentialE, ptr_gthistory)
	  call HistoryPut('Mass', gm_mass, ptr_gthistory)
	end if
	
end subroutine output_EnergyAnalysis_Data

subroutine output_EnergyAnalysis_Final( &
  & cptr_gthistory &
  ) bind(C, name='output_EnergyAnalysis_Final')

  ! 宣言文 ; Declaration statements
  !	
 type(c_ptr), intent(inout) :: cptr_gthistory

  ! 作業変数
  ! Work variables
  !
  type(GT_HISTORY), pointer :: ptr_gthistory
  logical :: err

  ! 実行文 ; Executable statements
  !

  if ( ( .not. mpi_EnabledFlag ) .or. mpi_IOEnabledFlag ) then
    call c_f_pointer(cptr_gthistory, ptr_gthistory)

    call HistoryClose(ptr_gthistory)
    deallocate(ptr_gthistory)

	  cptr_gthistory = c_null_ptr

	end if
end subroutine output_EnergyAnalysis_Final

end module Output_EnergyAnalysis
