!= 時刻管理
!
!= Time control
!
! Authors::   Yasuhiro MORIKAWA
! Version::   $Id: gridset.f90,v 1.5 2007/06/09 13:12:30 sugiyama Exp $ 
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2008. All rights reserved.
! License::   See COPYRIGHT[link:../../../COPYRIGHT]
!

module timeset
  !
  != 時刻管理
  !
  != Time control
  !
  ! <b>Note that Japanese and English are described in parallel.</b>
  !
  ! 時刻情報の管理を行います. 
  !
  ! Information of time is controlled. 
  !
  !== Variables List
  !
  ! Nstep        :: 総ステップ数
  ! Cstep        :: 現在のステップ数
  ! DelTime      :: $ \Delta t $ [s]
  ! ------------ :: ------------
  ! Nstep        :: Number of full steps
  ! Cstep        :: Current steps
  ! DelTime      :: $ \Delta t $ [s]
  !
  !== Procedures List
  !
  ! TimesetInit           :: timeset モジュールの初期化
  ! TimesetClose          :: timeset モジュールの終了処理
  ! TimesetProgress       :: 時刻の進行
  ! TimesetClockStart     :: 計算時間計測開始
  ! TimesetClockStop      :: 計算時間計一時停止
  ! TimesetIntStepEval    :: ステップ間隔見積り
  ! TimesetGetStartTime   :: 計算開始時刻の取得
  ! TimesetGetEndTime     :: 計算終了時刻の取得
  ! TimesetGetDelTime     :: $ \Delta t $ の取得
  ! TimesetGetCurrentTime :: 現在時刻の取得
  ! ------------          :: ------------
  ! TimesetInit           :: Initialize "timeset" module
  ! TimesetClose          :: Terminate "timeset" module
  ! TimesetProgress       :: Progress time
  ! TimesetClockStart     :: Start measurement of computation time
  ! TimesetClockStop      :: Pause measurement of computation time
  ! TimesetIntStepEval    :: Eval interval of step
  ! TimesetGetStartTime   :: Get start time of calculation
  ! TimesetGetEndTime     :: Get end time of calculation
  ! TimesetGetDelTime     :: Get $ \Delta t $
  ! TimesetGetCurrentTime :: Get current time
  !
  !== NAMELIST
  !
  ! NAMELIST#timeset_nml
  !

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

  ! 種別型パラメタ
  ! Kind type parameter
  !
  use dc_types, only: DP, &  ! 倍精度実数型. Double precision. 
    &                 TOKEN  ! キーワード.   Keywords. 

  ! メッセージ出力
  ! Message output
  !
  use dc_message, only: MessageNotify

  ! 日付および時刻の取り扱い
  ! Date and time handler
  !
  use dc_date_types, only: DC_DIFFTIME
                              ! 日時の差を表現するデータ型. 
                              ! Data type for difference about date and time

  ! CPU 時間計測
  ! CPU time monitor
  !
  use dc_clock, only: CLOCK

  ! 宣言文 ; Declaration statements
  !
  implicit none
  private

  ! 公開手続き
  ! Public procedure
  !
  public:: TimesetInit, TimesetClose, TimesetProgress
  public:: TimesetClockStart, TimesetClockStop
  public:: TimesetIntStepEval
  public:: TimesetGetStartTime, TimesetGetEndTime, TimesetGetDelTime
  public:: TimesetGetCurrentTime

  ! 公開変数
  ! Public variables
  !
  logical, save, public:: timeset_inited = .false.
                              ! 初期設定フラグ. 
                              ! Initialization flag
  integer, save, public:: Nstep
                              ! 総ステップ数. Number of full steps
  integer, save, public:: Cstep
                              ! 現在のステップ数. Current steps
  real(DP), save, public:: DelTime
                              ! $ \Delta t $ [s]

  ! 非公開変数
  ! Private variables
  !
  real(DP), save:: StartTimeValue
                              ! 計算開始時刻. 
                              ! Start time of calculation
  character(TOKEN), save:: StartTimeUnit
                              ! 計算開始時刻の単位. 
                              ! Unit of start time of calculation

  real(DP), save:: EndTimeValue
                              ! 計算終了時刻. 
                              ! End time of calculation
  character(TOKEN), save:: EndTimeUnit
                              ! 計算開始時刻の単位. 
                              ! Unit of end time of calculation

  real(DP), save:: DelTimeValue
                              ! $ \Delta t $ .  単位は DelTimeUnit にて指定.
                              ! Unit is specified by "DelTimeUnit". 
  character(TOKEN), save:: DelTimeUnit
                              ! $ \Delta t $ の単位. 
                              ! Unit of $ \Delta t $ 

  integer, save:: PredictIntStep
                              ! 終了予測日時表示間隔ステップ数. 
                              ! Interval steps of predicted end time output
  real(DP), save:: PredictIntValue
                              ! 終了予測日時表示間隔. 
                              ! Interval of predicted end time output
  character(TOKEN), save:: PredictIntUnit
                              ! 終了予測日時表示間隔 (単位). 
                              ! Unit for interval of predicted end time output

  type(DC_DIFFTIME), save:: DCdiffCurrentTime
                              ! 現在の日時. 
                              ! Current date and time
  type(DC_DIFFTIME), save:: DCdiffDelTime
                              ! $ \Delta t $ 

  logical, save:: CpuTimeMoniter
                              ! CPU 時間計測のオンオフ
                              ! On/off of CPU time monitoring

  integer, parameter:: clkmax = 64
                              ! CPU 時間計測を行うプロセスの最大数. 
                              ! Maximum number of processes monitored CPU time
  integer, save:: clk_proc_num = 0
                              ! CPU 時間計測を行っているプロセスの数. 
                              ! Number of processes monitored CPU time
  type(CLOCK), save:: clocks(1:clkmax)
                              ! CPU 時間計測用構造体
                              ! Derived type for monitoring CPU time
  character(TOKEN), save:: clocks_name(1:clkmax) = ''
                              ! CPU 時間計測を行っているプロセスの名称
                              ! Names of processes monitored CPU time

  character(*), parameter:: module_name = 'timeset'
                              ! モジュールの名称. 
                              ! Module name
  character(*), parameter:: version = &
    & '$Name:  $' // &
    & '$Id:  $'
                              ! モジュールのバージョン
                              ! Module version

  ! INTERFACE 文 ; INTERFACE statements
  !
  interface TimesetInit
    module procedure TimesetInit
  end interface

  interface TimesetClose
    module procedure TimesetClose
  end interface

  interface TimesetProgress
    module procedure TimesetProgress
  end interface

  interface TimesetIntStepEval
    module procedure TimesetIntStepEval
  end interface

  interface TimesetClockStart
    module procedure TimesetClockStart
  end interface

  interface TimesetClockStop
    module procedure TimesetClockStop
  end interface

contains

  !-------------------------------------------------------------------

  subroutine TimesetInit
    !
    ! timeset モジュールの初期化を行います. 
    ! NAMELIST#timeset_nml の読み込みはこの手続きで行われます. 
    !
    ! "timeset" module is initialized. 
    ! NAMELIST#timeset_nml is loaded in this procedure. 
    !

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

    ! NAMELIST ファイル入力に関するユーティリティ
    ! Utilities for NAMELIST file input
    !
    use namelist_util, only: namelist_filename, NmlutilMsg

    ! ファイル入出力補助
    ! File I/O support
    !
    use dc_iounit, only: FileOpen

    ! 種別型パラメタ
    ! Kind type parameter
    !
    use dc_types, only: STDOUT ! 標準出力の装置番号. Unit number of standard output

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_date_types, only: DC_DIFFTIME
                              ! 日時の差を表現するデータ型. 
                              ! Data type for difference about date and time
    use dc_date, only: DCDiffTimeCreate, EvalSec, EvalByUnit, mod, toChar, &
      & operator(*), operator(==), operator(<), operator(>), &
      & operator(/), operator(+), operator(-)

    ! CPU 時間計測
    ! CPU time monitor
    !
    use dc_clock, only: DCClockCreate, DCClockStart

    ! 宣言文 ; Declaration statements
    !
    implicit none

    ! 作業変数
    ! Work variables
    !
    integer:: unit_nml        ! NAMELIST ファイルオープン用装置番号. 
                              ! Unit number for NAMELIST file open
    integer:: iostat_nml      ! NAMELIST 読み込み時の IOSTAT. 
                              ! IOSTAT of NAMELIST read

    type(DC_DIFFTIME):: dcdiff_start
                              ! 計算開始時刻. 
                              ! Start time of calculation
    type(DC_DIFFTIME):: dcdiff_end
                              ! 計算終了時刻. 
                              ! End time of calculation
    type(DC_DIFFTIME):: dcdiff_delt
                              ! $ \Delta t $
    type(DC_DIFFTIME):: dcdiff_predict
                              ! 終了予測日時表示間隔. 
                              ! Interval of predicted end time output

    ! NAMELIST 変数群
    ! NAMELIST group name
    !
    namelist /timeset_nml/ &
      & StartTimeValue,  StartTimeUnit, &
      & EndTimeValue,    EndTimeUnit, &
      & DelTimeValue,    DelTimeUnit, &
      & PredictIntValue, PredictIntUnit, &
      & CpuTimeMoniter
          !
          ! デフォルト値については初期化手続 "timeset#TimesetInit" 
          ! のソースコードを参照のこと. 
          !
          ! Refer to source codes in the initialization procedure
          ! "timeset#TimesetInit" for the default values. 
          !

    ! 実行文 ; Executable statement
    !

    if ( timeset_inited ) return
    call InitCheck

    ! デフォルト値の設定
    ! Default values settings
    !
    Nstep = 0
    Cstep = 0

    StartTimeValue = 0.0_DP
    StartTimeUnit = 'day'

    EndTimeValue = 7.0_DP
    EndTimeUnit = 'day'

    DelTime = 180.0_DP
    DelTimeValue = 30.0_DP
    DelTimeUnit = 'min'

    PredictIntStep = 1
    PredictIntValue = 1.0_DP
    PredictIntUnit = 'day'

    CpuTimeMoniter = .true.

    ! NAMELIST の読み込み
    ! NAMELIST is input
    !
    if ( trim(namelist_filename) /= '' ) then
      call FileOpen( unit_nml, &          ! (out)
        & namelist_filename, mode = 'r' ) ! (in)

      rewind( unit_nml )
      read( unit_nml, &         ! (in)
        & nml = timeset_nml, &  ! (out)
        & iostat = iostat_nml ) ! (out)
      close( unit_nml )

      call NmlutilMsg( iostat_nml, module_name ) ! (in)
      if ( iostat_nml == 0 ) write( STDOUT, nml = timeset_nml )
    end if

    ! DC_DIFFTIME 型変数の設定
    ! Configure DC_DIFFTIME type variables
    !
    call DCDiffTimeCreate( dcdiff_start, &    ! (out)
      & StartTimeValue, StartTimeUnit )       ! (in)
    call DCDiffTimeCreate( dcdiff_end, &      ! (out)
      & EndTimeValue, EndTimeUnit )           ! (in)
    call DCDiffTimeCreate( dcdiff_delt, &     ! (out)
      & DelTimeValue, DelTimeUnit )           ! (in)
    call DCDiffTimeCreate( dcdiff_predict, &  ! (out)
      & PredictIntValue, PredictIntUnit)      ! (in)

    ! 時刻の正当性のチェック
    ! Check validation of time
    !
    call TimeValidCheck( &
      & dcdiff_start, dcdiff_end, dcdiff_delt, dcdiff_predict & ! (in)
      & )

    ! 総ステップ数算出
    ! Calculate number of full steps
    !
    Nstep = int( ( dcdiff_end - dcdiff_start ) / dcdiff_delt )
    Nstep = Nstep + 1

    ! $ \Delta t $ [s] 算出
    ! Calculate $ \Delta t $ [s] 
    !
    DelTime = EvalSec( dcdiff_delt )

    ! 終了予測日時表示間隔ステップ数算出
    ! Calculate interval steps of predicted end time output
    PredictIntStep = int( dcdiff_predict / dcdiff_delt )
    PredictIntStep = max( PredictIntStep, 1 )

    ! DC_DIFFTIME 型変数の設定
    ! Configure DC_DIFFTIME type variables
    !
    call DCDiffTimeCreate( DCdiffCurrentTime, &    ! (out)
      & StartTimeValue, StartTimeUnit )            ! (in)
    call DCDiffTimeCreate( DCdiffDelTime, &    ! (out)
      & DelTimeValue, DelTimeUnit )            ! (in)

    ! CPU 時間計測開始 (モデル全体)
    ! Start CPU time monitoring (for entire model)
    !
    if ( CpuTimeMoniter ) then
      call DCClockCreate( clocks(clk_proc_num + 1), 'total' ) ! (in)
      call DCClockStart( clocks(clk_proc_num + 1) ) ! (in)
      clocks_name(clk_proc_num + 1) = 'total'
      clk_proc_num = clk_proc_num + 1
    end if

    ! 印字 ; Print
    !
    call MessageNotify( 'M', module_name, '----- Initialization Messages -----' )
    call MessageNotify( 'M', module_name, '  Nstep = %d', i = (/ Nstep /) )
    call MessageNotify( 'M', module_name, '  StartTime  = %f [%c]', &
      & d = (/ StartTimeValue /), c1 = trim(StartTimeUnit) )
    call MessageNotify( 'M', module_name, '  EndTime    = %f [%c]', &
      & d = (/ EndTimeValue /), c1 = trim(EndTimeUnit) )
    call MessageNotify( 'M', module_name, '  DelTime    = %f [%c]', &
      & d = (/ DelTimeValue /), c1 = trim(DelTimeUnit) )
    call MessageNotify( 'M', module_name, '             = %f [%c]', &
      & d = (/ DelTime /), c1 = 'sec' )
    call MessageNotify( 'M', module_name, '  PredictInt = %f [%c]', &
      & d = (/ PredictIntValue /), c1 = trim(PredictIntUnit) )
    call MessageNotify( 'M', module_name, '  PredictIntStep = %d', &
      & i = (/ PredictIntStep /) )
    call MessageNotify( 'M', module_name, '  CpuTimeMoniter = %b', &
      & l = (/ CpuTimeMoniter /) )
    call MessageNotify( 'M', module_name, '-- version = %c', c1 = trim(version) )

    Cstep = 1
    timeset_inited = .true.
  end subroutine TimesetInit

  !-------------------------------------------------------------------

  subroutine TimesetProgress
    !
    ! timeset モジュール内の時刻を進めます. 
    ! また, TimesetProgress#PredictIntStep で設定された値に応じて, 
    ! 現在までの計算時間と計算終了予測時刻を表示します. 
    !
    ! Progress time configured in "timeset" module. 
    ! And, computation time until now and 
    ! predicted end of computation time are printed 
    ! according to configured "TimesetProgress#PredictIntStep"
    !

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

    ! CPU 時間計測
    ! CPU time monitor
    !
    use dc_clock, only: DCClockPredict, DCClockStop, DCClockClose, &
      & operator(+), operator(-)

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_date, only: operator(==), operator(+)

    ! 宣言文 ; Declaration statements
    !
    implicit none

    ! 作業変数
    ! Work variables
    !
    type(CLOCK):: clock_tmp

    ! 実行文 ; Executable statement
    !

    ! 終了予測日時表示
    ! Print predicted end time
    !
    if ( mod( Cstep, PredictIntStep ) == 0 ) then
      if ( CpuTimeMoniter ) then
        clock_tmp = clocks(1)
        call DCClockStop( clock_tmp ) ! (in)
        call DCClockPredict( &
          & clock_tmp, real(Cstep) / real(Nstep) ) ! (in)
        call DCClockClose( clock_tmp ) ! (in)
      else
        call MessageNotify( 'M', module_name, &
          & ' Current/Total = [ %d / %d ]', i = (/ Cstep, Nstep /) )
      end if
    end if

    ! 時刻の進行
    ! Progress time
    !
    Cstep = Cstep + 1
    DCdiffCurrentTime = DCdiffCurrentTime + DCdiffDelTime
  end subroutine TimesetProgress

  !-------------------------------------------------------------------

  subroutine TimesetClose
    !
    ! 計算時間の総計を表示します. 
    !
    ! Total computation time is printed. 

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

    ! CPU 時間計測
    ! CPU time monitor
    !
    use dc_clock, only: DCClockStop, DCClockResult, DCClockSetName, &
      & operator(+), operator(-)

    ! 宣言文 ; Declaration statements
    !
    implicit none
    integer:: i               ! clocks, clocks_name 用 DO ループ用作業変数
                              ! Work variables for DO loop for "clocks", "clocks_name"

    ! 作業変数
    ! Work variables
    !

    ! 実行文 ; Executable statement
    !

    if ( .not. CpuTimeMoniter ) return

    ! CPU 時間計測終了 (モデル全体)
    ! Stop CPU time monitoring (for entire model)
    !
    call DCClockStop( clocks(1) ) ! (in)

    ! 「その他」の CPU 時間を算出
    ! Calculate CPU time of "Others"
    !
    clocks(clk_proc_num + 1) = clocks(1)
    do i = 2, clk_proc_num
      clocks(clk_proc_num + 1) = clocks(clk_proc_num + 1) - clocks(i)
    end do
    call DCClockSetName( clocks(clk_proc_num + 1), 'others' )

    ! CPU 時間の総計を表示
    ! Print total CPU time
    !
    call DCClockResult( &
      & clocks(2:clk_proc_num + 1), total_auto = .true. ) ! (in)

  end subroutine TimesetClose

  !-------------------------------------------------------------------

  subroutine TimesetClockStart( name & ! (in)
    & )
    !
    ! プログラム単位 (主にモジュールを想定) ごとの時間計測を開始します. 
    !
    ! Start measurement of computation time by program unit
    ! (expected modules). 

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

    ! CPU 時間計測
    ! CPU time monitor
    !
    use dc_clock, only: DCClockCreate, DCClockStart

    ! 宣言文 ; Declaration statements
    !
    implicit none
    character(*), intent(in):: name
                              ! モジュールの名称. 
                              ! Name of module

    ! 作業変数
    ! Work variables
    !
    integer:: i               ! clocks, clocks_name 用 DO ループ用作業変数
                              ! Work variables for DO loop for "clocks", "clocks_name"

    ! 実行文 ; Executable statement
    !

    if ( .not. CpuTimeMoniter ) return

    do i = 1, clk_proc_num
      if ( trim(clocks_name(i)) == trim(name) ) then
        call DCClockStart( clocks(i) ) ! (in)
        return
      end if
    end do

    call DCClockCreate( clocks(clk_proc_num + 1), name ) ! (in)
    call DCClockStart( clocks(clk_proc_num + 1) ) ! (in)
    clocks_name(clk_proc_num + 1) = name
    clk_proc_num = clk_proc_num + 1

  end subroutine TimesetClockStart

  !-------------------------------------------------------------------

  subroutine TimesetClockStop( name & ! (in)
    & )
    !
    ! プログラム単位 (主にモジュールを想定) ごとの時間計測を一時停止します.
    !
    ! Pause measurement of computation time by program unit
    ! (expected modules). 

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

    ! CPU 時間計測
    ! CPU time monitor
    !
    use dc_clock, only: DCClockStop

    ! 宣言文 ; Declaration statements
    !
    implicit none
    character(*), intent(in):: name
                              ! モジュールの名称. 
                              ! Name of module

    ! 作業変数
    ! Work variables
    !
    integer:: i               ! clocks, clocks_name 用 DO ループ用作業変数
                              ! Work variables for DO loop for "clocks", "clocks_name"

    ! 実行文 ; Executable statement
    !

    if ( .not. CpuTimeMoniter ) return

    do i = 1, clk_proc_num
      if ( trim(clocks_name(i)) == trim(name) ) then
        call DCClockStop( clocks(i) ) ! (in)
        return
      end if
    end do

    call MessageNotify( 'W', module_name, ' name "%c" is not found in "TimesetClockStop"', c1 = trim(name) )

  end subroutine TimesetClockStop

  !-------------------------------------------------------------------

  subroutine TimesetIntStepEval( &
    & DelTime_Value, DelTime_Unit, & ! (in)
    & IntStep &                      ! (out)
    & )
    !
    ! 与えられた DelTime_Value と DelTime_Unit を
    ! timeset モジュール内で保存している $ \Delta t $ で割り, その結果を
    ! ステップ間隔として IntStep に返します. 
    !
    ! 1 以下になる場合には 1 を返します. 
    !
    ! Given "DelTime_Value" and "DelTime_Unit" are
    ! divided by $ \Delta t $ stored in "timeset" module, 
    ! and the result are returned to "IntStep" as interval of step.
    !
    ! If the result is less than 1, 1 is returned.
    !

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

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_date_types, only: DC_DIFFTIME
                              ! 日時の差を表現するデータ型. 
                              ! Data type for difference about date and time
    use dc_date, only: DCDiffTimeCreate, EvalSec, EvalByUnit, mod, toChar, &
      & operator(*), operator(==), operator(<), operator(>), &
      & operator(/), operator(+), operator(-)

    ! 宣言文 ; Declaration statements
    !
    implicit none
    real(DP), intent(in):: DelTime_Value
                              ! $ \Delta t $ .  単位は DelTimeUnit にて指定.
                              ! Unit is specified by "DelTimeUnit". 
    character(*), intent(in):: DelTime_Unit
                              ! $ \Delta t $ の単位. 
                              ! Unit of $ \Delta t $ 
    integer, intent(out):: IntStep
                              ! ステップ間隔. 
                              ! Interval of steps

    ! 作業変数
    ! Work variables
    !
    type(DC_DIFFTIME):: dcdiff_delt_ext
                              ! $ \Delta t $
    type(DC_DIFFTIME):: dcdiff_delt_int
                              ! $ \Delta t $

    ! 実行文 ; Executable statement
    !

    ! DC_DIFFTIME 型変数の設定
    ! Configure DC_DIFFTIME type variables
    !
    call DCDiffTimeCreate( dcdiff_delt_ext, &  ! (out)
      & DelTime_Value, DelTime_Unit )          ! (in)
    call DCDiffTimeCreate( dcdiff_delt_int, &  ! (out)
      & DelTimeValue, DelTimeUnit )            ! (in)

    ! IntStep の算出
    ! Calculate IntStep
    !
    IntStep = int( dcdiff_delt_ext / dcdiff_delt_int )
    IntStep = max( IntStep, 1 )

  end subroutine TimesetIntStepEval

  !-------------------------------------------------------------------

  subroutine TimesetGetStartTime( &
    & time, & ! (out)
    & unit  & ! (in) optional
    & )
    !
    ! 計算開始時刻を time に返します. 
    ! デフォルトでは, NAMELIST#timeset_nml の
    ! StartTimeUnit に指定されるものがその時刻の単位です. 
    ! オプショナル引数 unit に単位を指定することでその単位に
    ! 応じた時刻が返ります. 
    !
    ! Start time of calculation is returned to "time". 
    ! By default, "StartTimeUnit"in "NAMELIST#timeset_nml" is units of 
    ! the time. 
    ! If a unit is specified to an optional argument "unit", 
    ! a time according to the unit is returned. 
    !

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

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_date_types, only: DC_DIFFTIME
                              ! 日時の差を表現するデータ型. 
                              ! Data type for difference about date and time
    use dc_date, only: DCDiffTimeCreate, EvalByUnit

    ! 宣言文 ; Declaration statements
    !
    implicit none
    real(DP), intent(out):: time
                              ! 計算開始時刻. 
                              ! Start time of calculation
    character(*), intent(in), optional:: unit
                              ! 計算開始時刻の単位. 
                              ! Unit of start time of calculation

    ! 作業変数
    ! Work variables
    !
    type(DC_DIFFTIME):: dcdiff_time

    ! 実行文 ; Executable statement
    !

    if ( .not. present(unit) ) then
      time = StartTimeValue
    else
      call DCDiffTimeCreate( dcdiff_time, &  ! (out)
        & StartTimeValue, StartTimeUnit )    ! (in)
      time = EvalByUnit( dcdiff_time, unit )
    end if

  end subroutine TimesetGetStartTime

  !-------------------------------------------------------------------

  subroutine TimesetGetEndTime( &
    & time, & ! (out)
    & unit  & ! (in) optional
    & )
    !
    ! 計算終了時刻を time に返します. 
    ! デフォルトでは, NAMELIST#timeset_nml の
    ! EndTimeUnit に指定されるものがその時刻の単位です. 
    ! オプショナル引数 unit に単位を指定することでその単位に
    ! 応じた時刻が返ります. 
    !
    ! End time of calculation is returned to "time". 
    ! By default, "EndTimeUnit"in "NAMELIST#timeset_nml" is units of 
    ! the time. 
    ! If a unit is specified to an optional argument "unit", 
    ! a time according to the unit is returned. 
    !

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

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_date_types, only: DC_DIFFTIME
                              ! 日時の差を表現するデータ型. 
                              ! Data type for difference about date and time
    use dc_date, only: DCDiffTimeCreate, EvalByUnit

    ! 宣言文 ; Declaration statements
    !
    implicit none
    real(DP), intent(out):: time
                              ! 計算終了時刻. 
                              ! End time of calculation
    character(*), intent(in), optional:: unit
                              ! 計算終了時刻の単位. 
                              ! Unit of end time of calculation

    ! 作業変数
    ! Work variables
    !
    type(DC_DIFFTIME):: dcdiff_time

    ! 実行文 ; Executable statement
    !

    if ( .not. present(unit) ) then
      time = EndTimeValue
    else
      call DCDiffTimeCreate( dcdiff_time, &  ! (out)
        & EndTimeValue, EndTimeUnit )        ! (in)
      time = EvalByUnit( dcdiff_time, unit )
    end if

  end subroutine TimesetGetEndTime

  !-------------------------------------------------------------------

  subroutine TimesetGetDelTime( &
    & time, & ! (out)
    & unit  & ! (in) optional
    & )
    !
    ! $ \Delta t $ を time に返します. 
    ! デフォルトでは, NAMELIST#timeset_nml の
    ! DelTimeUnit に指定されるものがその時刻の単位です. 
    ! オプショナル引数 unit に単位を指定することでその単位に
    ! 応じた時刻が返ります. 
    !
    ! $ \Delta t $  is returned to "time". 
    ! By default, "DelTimeUnit"in "NAMELIST#timeset_nml" is units of 
    ! the time. 
    ! If a unit is specified to an optional argument "unit", 
    ! a time according to the unit is returned. 
    !

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

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_date_types, only: DC_DIFFTIME
                              ! 日時の差を表現するデータ型. 
                              ! Data type for difference about date and time
    use dc_date, only: DCDiffTimeCreate, EvalByUnit

    ! 宣言文 ; Declaration statements
    !
    implicit none
    real(DP), intent(out):: time
                              ! $ \Delta t $ 
    character(*), intent(in), optional:: unit
                              ! $ \Delta t $ の単位. 
                              ! Unit of $ \Delta t $ 

    ! 作業変数
    ! Work variables
    !
    type(DC_DIFFTIME):: dcdiff_time

    ! 実行文 ; Executable statement
    !

    if ( .not. present(unit) ) then
      time = DelTimeValue
    else
      call DCDiffTimeCreate( dcdiff_time, &  ! (out)
        & DelTimeValue, DelTimeUnit )        ! (in)
      time = EvalByUnit( dcdiff_time, unit )
    end if

  end subroutine TimesetGetDelTime

  !-------------------------------------------------------------------

  subroutine TimesetGetCurrentTime( &
    & time, & ! (out)
    & unit  & ! (in) optional
    & )
    !
    ! 現在時刻 time に返します. 
    ! デフォルトでは, NAMELIST#timeset_nml の
    ! DelTimeUnit に指定されるものがその時刻の単位です. 
    ! オプショナル引数 unit に単位を指定することでその単位に
    ! 応じた時刻が返ります. 
    !
    ! Current time is returned to "time". 
    ! By default, "DelTimeUnit"in "NAMELIST#timeset_nml" is units of 
    ! the time. 
    ! If a unit is specified to an optional argument "unit", 
    ! a time according to the unit is returned. 
    !

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

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_date_types, only: DC_DIFFTIME
                              ! 日時の差を表現するデータ型. 
                              ! Data type for difference about date and time
    use dc_date, only: DCDiffTimeCreate, EvalSec, EvalByUnit, mod, toChar, &
      & operator(*), operator(==), operator(<), operator(>), &
      & operator(/), operator(+), operator(-)

    ! 宣言文 ; Declaration statements
    !
    implicit none
    real(DP), intent(out):: time
                              ! 現在時刻. Current time
    character(*), intent(in), optional:: unit
                              ! 現在時刻の単位. 
                              ! Unit of current time

    ! 作業変数
    ! Work variables
    !

    ! 実行文 ; Executable statement
    !
    if ( .not. present(unit) ) then
      time = EvalByUnit( DCdiffCurrentTime, DelTimeUnit )
    else
      time = EvalByUnit( DCdiffCurrentTime, unit )
    end if

  end subroutine TimesetGetCurrentTime

  !-------------------------------------------------------------------

  subroutine TimeValidCheck( &
    & dcdiff_start, dcdiff_end, dcdiff_delt, dcdiff_predict & ! (in)
    & )
    !
    ! 時刻情報についての有効性をチェックします. 
    !
    ! Check validation about infomation time
    !

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

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_date_types, only: DC_DIFFTIME
                              ! 日時の差を表現するデータ型. 
                              ! Data type for difference about date and time
    use dc_date, only: DCDiffTimeCreate, EvalSec, EvalByUnit, mod, toChar, &
      & operator(*), operator(==), operator(<), operator(>), &
      & operator(/), operator(+), operator(-)

    implicit none

    ! 作業変数
    ! Work variables
    !
    type(DC_DIFFTIME):: dcdiff_start
                              ! 計算開始時刻. 
                              ! Start time of calculation
    type(DC_DIFFTIME):: dcdiff_end
                              ! 計算終了時刻. 
                              ! End time of calculation
    type(DC_DIFFTIME):: dcdiff_delt
                              ! $ \Delta t $ [s]
    type(DC_DIFFTIME):: dcdiff_predict
                              ! 終了予測日時表示間隔. 
                              ! Interval of predicted end time output

    ! 実行文 ; Executable statement
    !

    if ( .not. 0.0_DP < EvalSec( dcdiff_end - dcdiff_start )  ) then
      call MessageNotify( 'E', module_name, &
        & 'StartTime=<%f[%c]> is later than EndTime=<%f[%c]>', &
        & d = (/ StartTimeValue, EndTimeValue /), &
        & c1 = trim(StartTimeUnit), c2 = trim(EndTimeUnit) )
    end if

    if ( dcdiff_delt > ( dcdiff_end - dcdiff_start ) ) then
      call MessageNotify( 'E', module_name, &
        & 'DelTime=<%f[%c]> is larger than ' // &
        & 'EndTime=<%f[%c]> - StartTime=<%f[%c]>.', &
        & d = (/ DelTimeValue, EndTimeValue, StartTimeValue /), &
        & c1 = trim(DelTimeUnit), &
        & c2 = trim(EndTimeUnit), c3 = trim(StartTimeUnit) )
    end if

    if ( .not. EvalSec( dcdiff_delt ) > 0.0_DP ) then
      call MessageNotify( 'E', module_name, &
        & 'DelTime=<%f[%c]> must be more than 0.', &
        & d = (/ DelTimeValue /), &
        & c1 = trim(DelTimeUnit) )
    end if

    if ( .not. EvalSec( dcdiff_predict ) > 0.0_DP ) then
      call MessageNotify( 'E', module_name, &
        & 'PredictInt=<%f[%c]> must be more than 0.', &
        & d = (/ PredictIntValue /), &
        & c1 = trim(PredictIntUnit) )
    end if

  end subroutine TimeValidCheck

  !-------------------------------------------------------------------

  subroutine InitCheck
    !
    ! 依存モジュールの初期化チェック
    !
    ! Check initialization of dependency modules

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

    ! NAMELIST ファイル入力に関するユーティリティ
    ! Utilities for NAMELIST file input
    !
    use namelist_util, only: namelist_util_inited

    ! 実行文 ; Executable statement
    !

    if ( .not. namelist_util_inited ) &
      & call MessageNotify( 'E', module_name, '"namelist_util" module is not initialized.' )

  end subroutine InitCheck

end module timeset
