!= 時系列データの読み込み
!
!= Reading time series
!
! Authors::   Yoshiyuki O. Takahashi, Satoshi NODA
! Version::   $Id: read_time_series.f90,v 1.19 2015/01/29 12:02:29 yot Exp $ 
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2008. All rights reserved.
! License::   See COPYRIGHT[link:../../../COPYRIGHT]
!

module read_time_series
  !
  != 時系列データの読み込み
  !
  != Reading time series
  !
  ! <b>Note that Japanese and English are described in parallel.</b>
  !
  ! 海表面温度, O3 量などの時系列データを NetCDF ファイルから読み込む. 
  !
  ! Reading time series data, such as sea surface temperature, O3, and so on, from 
  ! NetCDF file. 
  !
  !== Procedures List
!!$  ! GroundFileGet    :: 地表面データファイルの入力
!!$  !--
!!$  ! GroundFileOpen   :: 地表面データファイルのオープン
!!$  ! GroundFileOutput :: 地表面データファイルへのデータ出力
!!$  ! GroundFileClose  :: 地表面データファイルのクローズ
  !++
  ! ------------     :: ------------
!!$  ! GroundFileGet    :: Input ground data file
!!$  !--
!!$  ! GroundFileOpen   :: Open ground data file
!!$  ! GroundFileOutput :: Data output to ground data file
!!$  ! GroundFileClose  :: Close ground data file
  !++
  !
  !== NAMELIST
  !
!!$  ! NAMELIST#ground_file_io_nml
  !

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

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

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

  ! 格子点設定
  ! Grid points settings
  !
  use gridset, only: imax, & ! 経度格子点数. 
                             ! Number of grid points in longitude
    &                jmax, & ! 緯度格子点数. 
                             ! Number of grid points in latitude
    &                kmax    ! 鉛直層数. 
                             ! Number of vertical level

  ! 宣言文 ; Declaration statements
  !
  implicit none
  private

  ! 公開手続き
  ! Public procedure
  !
  public:: SetValuesFromTimeSeriesWrapper
!!$  public:: SetValuesFromTimeSeries
  public:: ReadTimeSeriesInit

  ! 公開変数
  ! Public variables
  !
  logical, save :: read_time_series_inited = .false.
                              ! 初期設定フラグ. 
                              ! Initialization flag


  ! 非公開変数
  ! Private variables
  !

  type time_series_data
    character(STRING):: Keyword
                              ! 
                              ! Keyword
    character(STRING):: FileName
                              ! ファイル名. 
                              ! File name
    character(STRING):: VarName
                              ! 変数名. 
                              ! Variable name
    integer          :: NDims
    integer          :: tmax
    integer          :: NVLevels
    real(DP), pointer:: z_VLevels(:)=>null()
    real(DP), pointer:: a_time(:)=>null()
    integer , pointer:: a_tindex(:)=>null()
    real(DP), pointer:: xyza_SavedData(:,:,:,:)=>null()
    real(DP), pointer:: xyz_VarTimeInterpolated(:,:,:)=>null()
    real(DP)         :: TimeFromOriginToInitialDate
  end type time_series_data

  integer, parameter :: NumMaxStructArr = 25
  integer, save      :: NumMaxStruct

  type(time_series_data), save :: a_TSDataInfo( NumMaxStructArr )

  logical, save :: FlagYearCyclic = .true.

  logical, save :: flag_mpi_split = .true.



  character(*), parameter:: module_name = 'read_time_series_from_file'
                              ! モジュールの名称. 
                              ! Module name
  character(*), parameter:: version = &
    & '$Name:  $' // &
    & '$Id: read_time_series.f90,v 1.19 2015/01/29 12:02:29 yot Exp $'
                              ! モジュールのバージョン
                              ! Module version

  ! INTERFACE 文 ; INTERFACE statements
  !
  interface SetValuesFromTimeSeriesWrapper
    module procedure SetValFromTimeSeriesWrapper0D, SetValFromTimeSeriesWrapper2D, SetValFromTimeSeriesWrapper3D
  end interface

contains

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

  subroutine SetValFromTimeSeriesWrapper0D( &
    & Keyword,           &
    & FileName, VarName, &
    & Var                &               ! (inout)
    & )


    ! 宣言文 ; Declaration statements
    !
    implicit none

    character(*), intent(in   ):: Keyword
    character(*), intent(in   ):: FileName
                              ! ファイル名. 
                              ! File name
    character(*), intent(in   ):: VarName
                              ! 変数名. 
                              ! Variable name
    real(DP)    , intent(inout):: Var
                              ! 地表面温度. 
                              ! Surface temperature


    integer :: Index


    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if


    call SetValFromTimeSeriesFindIndex( &
      & Keyword, & ! (in)
      & Index    & ! (out)
      & )
    call SetValuesFromTimeSeries( &
      & a_TSDataInfo( Index ),    &
      & FileName, VarName,        &
      & Var = Var                 & ! (inout)
      & )


  end subroutine SetValFromTimeSeriesWrapper0D

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

  subroutine SetValFromTimeSeriesWrapper2D( &
    & Keyword,           &
    & FileName, VarName, &
    & xy_Var             &               ! (inout)
    & )


    ! 宣言文 ; Declaration statements
    !
    implicit none

    character(*), intent(in   ):: Keyword
    character(*), intent(in   ):: FileName
                              ! ファイル名. 
                              ! File name
    character(*), intent(in   ):: VarName
                              ! 変数名. 
                              ! Variable name
    real(DP)    , intent(inout):: xy_Var(0:imax-1, 1:jmax)
                              ! 地表面温度. 
                              ! Surface temperature


    integer :: Index


    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if


    call SetValFromTimeSeriesFindIndex( &
      & Keyword, & ! (in)
      & Index    & ! (out)
      & )
    call SetValuesFromTimeSeries( &
      & a_TSDataInfo( Index ),    &
      & FileName, VarName,        &
      & xy_Var = xy_Var           & ! (inout)
      & )


  end subroutine SetValFromTimeSeriesWrapper2D

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

  subroutine SetValFromTimeSeriesWrapper3D( &
    & Keyword,                              & ! (in)
    & FileName, VarName,                    & ! (in)
    & xyz_Press,                            & ! (in)
    & xyz_Var,                              & ! (inout)
    & FlagLogVLev, FlagLog, FlagPositiveDef & ! (in)
    & )


    ! 宣言文 ; Declaration statements
    !
    implicit none

    character(*), intent(in   ):: Keyword
    character(*), intent(in   ):: FileName
                              ! ファイル名. 
                              ! File name
    character(*), intent(in   ):: VarName
                              ! 変数名. 
                              ! Variable name
    real(DP)    , intent(in   ):: xyz_Press(0:imax-1, 1:jmax, 1:kmax)
                              ! 地表面温度. 
                              ! Surface temperature
    real(DP)    , intent(inout):: xyz_Var(0:imax-1, 1:jmax, 1:kmax)
                              ! 地表面温度. 
                              ! Surface temperature
    logical     , intent(in   ):: FlagLogVLev
    logical     , intent(in   ):: FlagLog
    logical     , intent(in   ):: FlagPositiveDef


    integer :: Index


    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if


    call SetValFromTimeSeriesFindIndex( &
      & Keyword, & ! (in)
      & Index    & ! (out)
      & )
    call SetValuesFromTimeSeries( &
      & a_TSDataInfo(Index),      &
      & FileName, VarName,        &
      & xyz_Press = xyz_Press,    & ! (in)
      & xyz_Var = xyz_Var,        & ! (inout)
      & FlagLogVLev     = FlagLogVLev,     & ! (in ) optional
      & FlagLog         = FlagLog,         & ! (in ) optional
      & FlagPositiveDef = FlagPositiveDef  & ! (in ) optional
      & )



  end subroutine SetValFromTimeSeriesWrapper3D

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

  subroutine SetValFromTimeSeriesFindIndex( &
    & Keyword, & ! (in)
    & Index    & ! (out)
    & )


    ! 宣言文 ; Declaration statements
    !
    implicit none

    character(*), intent(in ):: Keyword
                              ! 
                              ! Keyword
    integer     , intent(out):: Index
                              ! 
                              ! Index

    integer :: l


    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if


    ! Search index of a_TSDataInfo with Keyword

    Index = 0

    search_index : do l = 1, NumMaxStruct
      if ( a_TSDataInfo( l ) % Keyword == Keyword ) then
        Index = l
        exit search_index
      end if
    end do search_index

    ! If an element of a_TSDataInfo with Keyword cannot be found, a new 
    ! element will be used. 
    if ( Index == 0 ) then
      NumMaxStruct = NumMaxStruct + 1
      Index        = NumMaxStruct
      a_TSDataInfo( Index ) % Keyword = Keyword
    end if


    if ( Index > NumMaxStructArr ) then
      call MessageNotify( 'E', module_name, 'Index is greater than NumMaxStructArr.' )
    end if


  end subroutine SetValFromTimeSeriesFindIndex

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

  subroutine SetValuesFromTimeSeries(          &
    & TSDataInfo,                              &
    & FileName, VarName,                       &
    & xyz_Press,                               & ! (in   ) optional
    & Var,                                     & ! (inout) optional
    & xy_Var,                                  & ! (inout) optional
    & xyz_Var,                                 & ! (inout) optional
    & FlagLogVLev, FlagLog, FlagPositiveDef    & ! (in   ) optional
    & )
    !
    ! 地表面の諸々のデータを設定します. 
    ! xy_SurfTemp 以外は一回目に呼ばれた時のみ設定されます. 
    !
    ! Get various data on ground. 
    ! Arguments excluding "xy_SurfTemp" are configured at first only. 
    !

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

    ! gtool4 データ入力
    ! Gtool4 data input
    !
    use gtool_history, only: HistoryGet

    ! 文字列操作
    ! Character handling
    !
    use dc_string, only: toChar

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_calendar, only: DCCalDateEvalSecOfYear

    ! 時刻管理
    ! Time control
    !
    use timeset, only: TimeN, InitialDate

    ! 宣言文 ; Declaration statements
    !
    implicit none

    type(time_series_data), intent(inout):: TSDataInfo
    character(*)          , intent(in   ):: FileName
                              ! ファイル名. 
                              ! File name
    character(*)          , intent(in   ):: VarName
                              ! 変数名. 
                              ! Variable name
    real(DP)    , optional, intent(in   ):: xyz_Press(0:imax-1, 1:jmax, 1:kmax)
                              ! 3 次元配列. 
                              ! 3D array
    real(DP)    , optional, intent(inout):: Var
                              ! 2 次元配列. 
                              ! 2D array
    real(DP)    , optional, intent(inout):: xy_Var (0:imax-1, 1:jmax)
                              ! 2 次元配列. 
                              ! 2D array
    real(DP)    , optional, intent(inout):: xyz_Var(0:imax-1, 1:jmax, 1:kmax)
                              ! 3 次元配列. 
                              ! 3D array
    logical     , optional, intent(in   ):: FlagLogVLev
    logical     , optional, intent(in   ):: FlagLog
    logical     , optional, intent(in   ):: FlagPositiveDef

    ! 作業変数
    ! Work variables
    !
    real(DP):: CurrentTimeInSec
    integer :: tindex

!!$    real(DP):: xyza_VarInterpolated(0:imax-1, 1:jmax, 1:kmax, 2)

    logical :: FlagReadData

    integer :: t


    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if


    if ( ( .not. present( Var ) ) .and. ( .not. present( xy_Var ) ) .and. ( .not. present( xyz_Var ) ) ) then
      call MessageNotify( 'E', module_name, 'Var or xy_Var or xyz_Var have to be given.' )
    end if

    if ( ( present( Var ) ) .and. ( present( xy_Var ) ) ) then
      call MessageNotify( 'E', module_name, 'Both Var and xy_Var are not given.' )
    end if

    if ( ( present( xy_Var ) ) .and. ( present( xyz_Var ) ) ) then
      call MessageNotify( 'E', module_name, 'Both xy_Var and xyz_Var are not given.' )
    end if

    if ( ( present( xyz_Var ) ) .and. ( present( Var ) ) ) then
      call MessageNotify( 'E', module_name, 'Both xyz_Var and Var are not be given.' )
    end if

    if ( ( present( xyz_Var ) ) .and. ( .not. present( xyz_Press ) ) ) then
      call MessageNotify( 'E', module_name, 'xyz_Press has to be given, when xyz_Var is given.' )
    end if

    ! 実行文 ; Executable statement
    !
    if ( .not. associated( TSDataInfo % a_time ) ) then
      if ( present( Var ) ) then
        call StructureInit(       &
          & FileName, VarName, 0, &
          & TSDataInfo            &
          & )
      else if ( present( xy_Var ) ) then
        call StructureInit(       &
          & FileName, VarName, 2, &
          & TSDataInfo            &
          & )
      else
        call StructureInit(       &
          & FileName, VarName, 3, &
          & TSDataInfo            &
          & )
      end if
    end if


    ! Update values of time paying attention to leap year
    ! This is not used, because this causes error when FlagYearCyclic = .true..
    !
!!$    call UpdateTime(     &
!!$      & TSDataInfo             & ! (inout)
!!$      & )


    if ( TSDataInfo % tmax >= 2 ) then

      if ( FlagYearCyclic ) then
        CurrentTimeInSec = DCCalDateEvalSecOfYear( TimeN, date = InitialDate )
      else
        CurrentTimeInSec = TimeN + TSDataInfo%TimeFromOriginToInitialDate
      end if

!!$      write( 6, * ) TSDataInfo%a_time(TSDataInfo%a_tindex(1)), &
!!$        & SecOfYear, TSDataInfo%a_time(TSDataInfo%a_tindex(2))


      ! Check whether the data have to be read or not
      if ( ( CurrentTimeInSec <  TSDataInfo%a_time(TSDataInfo%a_tindex(1)) ) .or. &
        &  ( CurrentTimeInSec >= TSDataInfo%a_time(TSDataInfo%a_tindex(2)) ) ) then
        FlagReadData = .true.
      else
        FlagReadData = .false.
      end if
      if ( .not. FlagYearCyclic ) then
        if ( ( CurrentTimeInSec <  TSDataInfo%a_time(1)               ) .or. &
          &  ( CurrentTimeInSec >= TSDataInfo%a_time(TSDataInfo%tmax) ) ) then
          FlagReadData = .false.
          CurrentTimeInSec = max( CurrentTimeInSec, TSDataInfo%a_time(1) )
          CurrentTimeInSec = min( CurrentTimeInSec, TSDataInfo%a_time(TSDataInfo%tmax) )
        end if
      end if

      if ( FlagReadData ) then
!!$      if ( ( CurrentTimeInSec <   TSDataInfo%a_time(TSDataInfo%a_tindex(1)) ) .or. &
!!$        &  ( CurrentTimeInSec >=  TSDataInfo%a_time(TSDataInfo%a_tindex(2)) ) ) then

        TSDataInfo % a_tindex(1) = 0
        TSDataInfo % a_tindex(2) = 1
        do t = 1, TSDataInfo%tmax
          if ( TSDataInfo % a_time(t) <= CurrentTimeInSec ) then
            TSDataInfo % a_tindex(1) = t
            TSDataInfo % a_tindex(2) = t+1
          end if
        end do

!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) 'in if', TSDataInfo % a_tindex(1), TSDataInfo % a_tindex(2)
!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) '##############################################'
!!$        write( 6, * ) '##############################################'

        ! set time index
        if ( FlagYearCyclic ) then
          tindex = TSDataInfo % a_tindex(1)
          if ( tindex == 0 ) then
            tindex = TSDataInfo % tmax
          else if ( tindex == TSDataInfo % tmax + 1 ) then
            tindex = 1
          else
            tindex = tindex
          end if
        else
          tindex = TSDataInfo % a_tindex(1)
          tindex = min( max( tindex, 1 ), TSDataInfo % tmax )
        end if


        if ( present( Var ) ) then
          call HistoryGet(                                       &
            & TSDataInfo%FileName,                               &
            & TSDataInfo%VarName,                                &
            & TSDataInfo%xyza_SavedData(0,1,1,1),                &
            & range = 'time=^'//toChar(tindex),                  &
            & flag_mpi_split = flag_mpi_split                    &
            & )
        else if ( present( xy_Var ) ) then
          call HistoryGet(                                       &
            & TSDataInfo%FileName,                               &
            & TSDataInfo%VarName,                                &
            & TSDataInfo%xyza_SavedData(:,:,1,1),                &
            & range = 'time=^'//toChar(tindex),                  &
            & flag_mpi_split = flag_mpi_split                    &
            & )
        else
          call HistoryGet(                                       &
            & TSDataInfo%FileName,                               &
            & TSDataInfo%VarName,                                &
            & TSDataInfo%xyza_SavedData(:,:,:,1),                &
            & range = 'time=^'//toChar(tindex),                  &
            & flag_mpi_split = flag_mpi_split                    &
            & )
        end if

        ! set time index
        if ( FlagYearCyclic ) then
          tindex = TSDataInfo % a_tindex(2)
          if ( tindex == 0 ) then
            tindex = TSDataInfo % tmax
          else if ( tindex == TSDataInfo % tmax + 1 ) then
            tindex = 1
          else
            tindex = tindex
          end if
        else
          tindex = TSDataInfo % a_tindex(2)
          tindex = min( max( tindex, 1 ), TSDataInfo % tmax )
        end if

        if ( present( Var ) ) then
          call HistoryGet(                                       &
            & TSDataInfo%FileName,                               &
            & TSDataInfo%VarName,                                &
            & TSDataInfo%xyza_SavedData(0,1,1,2),                &
            & range = 'time=^'//toChar(tindex),                  &
            & flag_mpi_split = flag_mpi_split                    &
            & )
        else if ( present( xy_Var ) ) then
          call HistoryGet(                                       &
            & TSDataInfo%FileName,                               &
            & TSDataInfo%VarName,                                &
            & TSDataInfo%xyza_SavedData(:,:,1,2),                &
            & range = 'time=^'//toChar(tindex),                  &
            & flag_mpi_split = flag_mpi_split                    &
            & )
        else
          call HistoryGet(                                       &
            & TSDataInfo%FileName,                               &
            & TSDataInfo%VarName,                                &
            & TSDataInfo%xyza_SavedData(:,:,:,2),                &
            & range = 'time=^'//toChar(tindex),                  &
            & flag_mpi_split = flag_mpi_split                    &
            & )
        end if

      end if

      if ( present( Var ) ) then
        Var =                                                 &
          &   ( TSDataInfo%xyza_SavedData(0,1,1,2)            &
          &   - TSDataInfo%xyza_SavedData(0,1,1,1)  )         &
          & / ( TSDataInfo%a_time(TSDataInfo%a_tindex(2))     &
          &   - TSDataInfo%a_time(TSDataInfo%a_tindex(1))  )  &
          & * ( CurrentTimeInSec                              &
          &    - TSDataInfo%a_time(TSDataInfo%a_tindex(1))  ) &
          & + TSDataInfo%xyza_SavedData(0,1,1,1)
      else if ( present( xy_Var ) ) then
        xy_Var =                                              &
          &   ( TSDataInfo%xyza_SavedData(:,:,1,2)            &
          &   - TSDataInfo%xyza_SavedData(:,:,1,1)  )         &
          & / ( TSDataInfo%a_time(TSDataInfo%a_tindex(2))     &
          &   - TSDataInfo%a_time(TSDataInfo%a_tindex(1))  )  &
          & * ( CurrentTimeInSec                              &
          &    - TSDataInfo%a_time(TSDataInfo%a_tindex(1))  ) &
          & + TSDataInfo%xyza_SavedData(:,:,1,1)
      else
        TSDataInfo%xyz_VarTimeInterpolated =                  &
          &   ( TSDataInfo%xyza_SavedData(:,:,:,2)            &
          &   - TSDataInfo%xyza_SavedData(:,:,:,1)  )         &
          & / ( TSDataInfo%a_time(TSDataInfo%a_tindex(2))     &
          &   - TSDataInfo%a_time(TSDataInfo%a_tindex(1))  )  &
          & * ( CurrentTimeInSec                              &
          &    - TSDataInfo%a_time(TSDataInfo%a_tindex(1))  ) &
          & + TSDataInfo%xyza_SavedData(:,:,:,1)

        call VerticalInterpolation(                    &
          & TSDataInfo%NVLevels, TSDataInfo%z_VLevels, & ! (in )
          & TSDataInfo%xyz_VarTimeInterpolated,        & ! (in )
          & xyz_Press,                                 & ! (in )
          & xyz_Var,                                   & ! (out)
          & FlagLogVLev, FlagLog, FlagPositiveDef      & ! (in ) optional
          & )
      end if

    else

      if ( present( Var ) ) then
        Var = TSDataInfo%xyza_SavedData(0,1,1,1)
      else if ( present( xy_Var ) ) then
        xy_Var = TSDataInfo%xyza_SavedData(:,:,1,1)
      else
        call VerticalInterpolation(                    &
          & TSDataInfo%NVLevels, TSDataInfo%z_VLevels, & ! (in )
          & TSDataInfo%xyza_SavedData(:,:,:,1),        & ! (in )
          & xyz_Press,                                 & ! (in )
          & xyz_Var,                                   & ! (out)
          & FlagLogVLev, FlagLog, FlagPositiveDef      & ! (in ) optional
          & )
      end if

    end if


  end subroutine SetValuesFromTimeSeries

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

  subroutine VerticalInterpolation(          &
    & NVLevels, z_VLevelsIn, xyz_VarIn,      & ! (in )
    & xyz_VLevelsOut,                        & ! (in )
    & xyz_VarOut,                            & ! (out)
    & FlagLogVLev, FlagLog, FlagPositiveDef  & ! (in ) optional
    & )

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

    ! 宣言文 ; Declaration statements
    !
    implicit none

    integer , intent(in ):: NVLevels
    real(DP), intent(in ):: z_VLevelsIn(1:NVLevels)
    real(DP), intent(in ):: xyz_VarIn  (0:imax-1, 1:jmax, 1:NVLevels)
    real(DP), intent(in ):: xyz_VlevelsOut(0:imax-1, 1:jmax, 1:kmax)
    real(DP), intent(out):: xyz_VarOut    (0:imax-1, 1:jmax, 1:kmax)
    logical , intent(in ), optional:: FlagLogVLev
    logical , intent(in ), optional:: FlagLog
    logical , intent(in ), optional:: FlagPositiveDef


    ! 作業変数
    ! Work variables
    !
    logical:: FlagLogVLevLV
    logical:: FlagLogLV
    logical:: FlagPositiveDefLV
    integer:: i
    integer:: j
    integer:: k
    integer:: kk
    integer:: xyz_kk(0:imax-1, 1:jmax, 1:kmax)


    ! 実行文 ; Executable statement
    !

    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if

    ! Check order of vertical levels
    !
    if ( z_VlevelsIn(1) < z_VlevelsIn(2) ) then
      call MessageNotify( 'E', module_name, 'The order of vertical levels is inappropriate.' )
    end if


    ! Flags are checked
    !
    if ( present( FlagLogVLev ) ) then
      FlagLogVLevLV = FlagLogVLev
    else
      FlagLogVLevLV = .false.
    end if
    if ( present( FlagLog ) ) then
      FlagLogLV = FlagLog
    else
      FlagLogLV = .false.
    end if
    if ( present( FlagPositiveDef ) ) then
      FlagPositiveDefLV = FlagPositiveDef
    else
      FlagPositiveDefLV = .false.
    end if


    xyz_kk = 1

    do kk = 1, NVLevels-1

      do k = 1, kmax
        do j = 1, jmax
          do i = 0, imax-1
            if ( xyz_VLevelsOut(i,j,k) < z_VLevelsIn(kk) ) then
              xyz_kk(i,j,k) = kk
            end if
          end do
        end do
      end do

    end do


    if ( FlagLogVLevLV ) then

      if ( FlagLogLV ) then
        ! log-log

        do k = 1, kmax
          do j = 1, jmax
            do i = 0, imax-1

!!$          if ( xyz_VLevelsOut(i,j,k) > z_VLevelsIn(1) ) then
!!$            xyz_VarOut(i,j,k) = xyz_VarIn(i,j,1)
!!$
!!$!          else if ( xyz_VLevelsOut(i,j,k) < z_VLevelsIn(NVLevels) ) then
!!$!            call MessageNotify( 'E', module_name, 'Vertical level is out of given range.' )
!!$!!            xyz_VarOut(i,j,k) = 0.0d0
!!$
!!$          else
!!$
!!$            xyz_VarOut(i,j,k) = &
!!$              &   ( xyz_VarIn(i,j,xyz_kk(i,j,k)+1)     - xyz_VarIn(i,j,xyz_kk(i,j,k)) ) &
!!$              & / log( z_VLevelsIn   (xyz_kk(i,j,k)+1) / z_VLevelsIn(xyz_kk(i,j,k))   ) &
!!$              & * log( xyz_VLevelsOut(i,j,k)           / z_VLevelsIn(xyz_kk(i,j,k))   ) &
!!$              & + xyz_VarIn(i,j,xyz_kk(i,j,k))
!!$
!!$          end if


              xyz_VarOut(i,j,k) = &
                &   log(   ( xyz_VarIn(i,j,xyz_kk(i,j,k)+1) + 1.0d-100 )    &
                &        / ( xyz_VarIn(i,j,xyz_kk(i,j,k)  ) + 1.0d-100 )  ) &
                & / log(   z_VLevelsIn   (xyz_kk(i,j,k)+1)                  &
                &        / z_VLevelsIn(xyz_kk(i,j,k))      )                &
                & * log(   xyz_VLevelsOut(i,j,k)                            &
                &        / z_VLevelsIn(xyz_kk(i,j,k))      )                &
                & + log( xyz_VarIn(i,j,xyz_kk(i,j,k)) + 1.0d-100 )
              xyz_VarOut(i,j,k) = exp( xyz_VarOut(i,j,k) )

            end do
          end do
        end do

      else
        ! log-linear

        do k = 1, kmax
          do j = 1, jmax
            do i = 0, imax-1

              xyz_VarOut(i,j,k) =                            &
                &   (   xyz_VarIn(i,j,xyz_kk(i,j,k)+1)       &
                &     - xyz_VarIn(i,j,xyz_kk(i,j,k)  )     ) &
                & / log(   z_VLevelsIn   (xyz_kk(i,j,k)+1)   &
                &        / z_VLevelsIn(xyz_kk(i,j,k))      ) &
                & * log(   xyz_VLevelsOut(i,j,k)             &
                &        / z_VLevelsIn(xyz_kk(i,j,k))      ) &
                & + xyz_VarIn(i,j,xyz_kk(i,j,k))

            end do
          end do
        end do

      end if

    else

      if ( FlagLogLV ) then
        ! linear-log

        do k = 1, kmax
          do j = 1, jmax
            do i = 0, imax-1

              xyz_VarOut(i,j,k) = &
                &   log(   ( xyz_VarIn(i,j,xyz_kk(i,j,k)+1) + 1.0d-100 )    &
                &        / ( xyz_VarIn(i,j,xyz_kk(i,j,k)  ) + 1.0d-100 )  ) &
                & / (   z_VLevelsIn(xyz_kk(i,j,k)+1)                        &
                &     - z_VLevelsIn(xyz_kk(i,j,k)  )    )                   &
                & * (   xyz_VLevelsOut(i,j,k)                               &
                &     - z_VLevelsIn(xyz_kk(i,j,k))      )                   &
                & + log( xyz_VarIn(i,j,xyz_kk(i,j,k)) + 1.0d-100 )
              xyz_VarOut(i,j,k) = exp( xyz_VarOut(i,j,k) )

            end do
          end do
        end do

      else
        ! linear-linear

        do k = 1, kmax
          do j = 1, jmax
            do i = 0, imax-1

              xyz_VarOut(i,j,k) = &
                &   (   xyz_VarIn(i,j,xyz_kk(i,j,k)+1)   &
                &     - xyz_VarIn(i,j,xyz_kk(i,j,k)  ) ) &
                & / (   z_VLevelsIn(xyz_kk(i,j,k)+1)     &
                &     - z_VLevelsIn(xyz_kk(i,j,k)  )   ) &
                & * (   xyz_VLevelsOut(i,j,k)            &
                &     - z_VLevelsIn(xyz_kk(i,j,k))     ) &
                & + xyz_VarIn(i,j,xyz_kk(i,j,k))

            end do
          end do
        end do

      end if

    end if


    if ( FlagPositiveDefLV ) then

      do k = 1, kmax
        do j = 1, jmax
          do i = 0, imax-1

            if ( xyz_VarOut(i,j,k) < 0.0_DP ) then
              xyz_VarOut(i,j,k) = 0.0_DP
            end if

          end do
        end do
      end do

    end if


!!$    i = 0
!!$    j = jmax / 2
!!$    do k = 1, NVLevels
!!$      write( 92, * ) z_VLevelsIn(k), xyz_VarIn(i,j,k)
!!$    end do
!!$    write( 92, * )
!!$    call flush( 92 )
!!$    do k = 1, kmax
!!$      write( 93, * ) xyz_VLevelsOut(i,j,k), xyz_VarOut(i,j,k)
!!$    end do
!!$    write( 93, * )
!!$    call flush( 93 )
!!$    stop


  end subroutine VerticalInterpolation

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

  subroutine UpdateTime(     &
    & TSDataInfo             & ! (inout)
    & )

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

    ! 暦と日時の取り扱い
    ! Calendar and Date handler
    !
    use dc_calendar, only: &
      & DC_CAL_DATE             ! 日時を表現するデータ型.
                                ! Data type for date and time

    ! 日付および時刻の取り扱い
    ! Date and time handler
    !
    use dc_calendar, only: DCCalInquire, DCCalDateCreate, DCCalDateInquire, DCCalDateChkLeapYear

    ! 時刻管理
    ! Time control
    !
    use timeset, only: TimeN, InitialDate

    ! 宣言文 ; Declaration statements
    !
    implicit none

    type(time_series_data), intent(inout):: TSDataInfo


    ! 作業変数
    ! Work variables
    !
    integer           :: hour_in_day, min_in_hour, day_in_year
    integer, pointer  :: day_in_month_ptr(:) => null()
    real(DP)          :: sec_in_min, sec_in_day

    integer           :: year
    type(DC_CAL_DATE) :: PreYearDate


    ! 実行文 ; Executable statement
    !

    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if


    if ( TSDataInfo % tmax >= 2 ) then

      call DCCalInquire( &
        & day_in_month_ptr = day_in_month_ptr , & ! (out)
        & hour_in_day      = hour_in_day  , &     ! (out)
        & min_in_hour      = min_in_hour  , &     ! (out)
        & sec_in_min       = sec_in_min )         ! (out)
      day_in_year = sum( day_in_month_ptr )
      deallocate( day_in_month_ptr )
      sec_in_day  = hour_in_day * min_in_hour * sec_in_min


      ! Set TSDataInfo % a_time(0)
      !

      call DCCalDateInquire(       &
        & year       = year,       & ! (out)
        & elapse_sec = TimeN,      & ! (in)
        & date       = InitialDate & ! (in)
        & )
      call DCCalDateCreate(        &
        & year       = year - 1,   & ! (in)
        & month      = 1,          & ! (in)
        & day        = 1,          & ! (in)
        & hour       = 0,          & ! (in)
        & min        = 0,          & ! (in)
        & sec        = 0.0_DP,     & ! (in)
        & date       = PreYearDate & ! (out)
        & )

      if ( DCCalDateChkLeapYear( 0.0_DP, PreYearDate ) ) then
        TSDataInfo % a_time(0                ) = &
          & - ( ( day_in_year + 1 ) * sec_in_day - TSDataInfo % a_time(TSDataInfo%tmax) )
      else
        TSDataInfo % a_time(0                ) = &
          & - (   day_in_year       * sec_in_day - TSDataInfo % a_time(TSDataInfo%tmax) )
      end if


      ! Set TSDataInfo % a_time(TSDataInfo%tmax+1)
      !

      if ( DCCalDateChkLeapYear( TimeN, InitialDate ) ) then
        TSDataInfo % a_time(TSDataInfo%tmax+1) = &
          &     ( day_in_year + 1 ) * sec_in_day + TSDataInfo % a_time(1              )
      else
        TSDataInfo % a_time(TSDataInfo%tmax+1) = &
          &       day_in_year       * sec_in_day + TSDataInfo % a_time(1              )
      end if


    end if


  end subroutine UpdateTime

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

  subroutine InterpretTimeUnitString( &
    & FileName, DateString,       & ! (in)
    & Yr, Mon, Day, Hr, Min, Sec  & ! (out)
    & )

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

    ! 宣言文 ; Declaration statements
    !
    implicit none

    character(*), intent(in ) :: FileName
    character(*), intent(in ) :: DateString
    integer     , intent(out) :: Yr
    integer     , intent(out) :: Mon
    integer     , intent(out) :: Day
    integer     , intent(out) :: Hr
    integer     , intent(out) :: Min
    real(DP)    , intent(out) :: Sec


    ! 作業変数
    ! Work variables
    !
    integer :: StrLen
    integer :: l
    integer :: ll

    ! 実行文 ; Executable statement
    !

    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if

    StrLen = len_trim( DateString )

    ! format of the DateString has to be "... since YYYY/MM/DD HH:MM:SS".

    search_since : do ll = 1, StrLen-5+1
      if ( DateString(ll:ll+5-1) == "since" ) exit search_since
    end do search_since
    if ( ll > StrLen-5+1 ) then
      call MessageNotify( 'E', module_name, 'Unable to find "since" in %c.', c1 = trim(FileName) )
    end if
    !
    l = ll + 5
    !
    if ( DateString(l:l) /= " " ) then
      call MessageNotify( 'E', module_name, 'Unable to find a space after "since" in %c.', c1 = trim(FileName) )
    end if
    !
    l = l + 1
    !
    search_yr : do ll = l, StrLen
      if ( DateString(ll:ll) == "-" ) exit search_yr
    end do search_yr
    if ( ll > StrLen ) then
      call MessageNotify( 'E', module_name, 'Unable to find "-" between year and month in %c.', c1 = trim(FileName) )
    end if
    read( DateString(l:ll-1), * ) Yr
    !
    l = ll + 1
    !
    search_mon : do ll = l, StrLen
      if ( DateString(ll:ll) == "-" ) exit search_mon
    end do search_mon
    if ( ll > StrLen ) then
      call MessageNotify( 'E', module_name, 'Unable to find "-" between month and day in %c.', c1 = trim(FileName) )
    end if
    read( DateString(l:ll-1), * ) Mon
    !
    l = ll + 1
    !
    search_day : do ll = l, StrLen
      if ( DateString(ll:ll) == " " ) exit search_day
    end do search_day
    if ( ll > StrLen ) then
      call MessageNotify( 'E', module_name, 'Unable to find a space between day and hour in %c.', c1 = trim(FileName) )
    end if
    read( DateString(l:ll-1), * ) Day
    !
    l = ll
    !
    if ( DateString(l:l) /= " " ) then
      call MessageNotify( 'E', module_name, 'Unable to confirm a space between day and hour in %c.', c1 = trim(FileName) )
    end if
    !
    l = l + 1
    !
    search_hr : do ll = l, StrLen
      if ( DateString(ll:ll) == ":" ) exit search_hr
    end do search_hr
    if ( ll > StrLen ) then
      call MessageNotify( 'E', module_name, 'Unable to find ":" between hour and minute in %c.', c1 = trim(FileName) )
    end if
    read( DateString(l:ll-1), * ) Hr
    !
    l = ll + 1
    !
    search_min : do ll = l, StrLen
      if ( DateString(ll:ll) == ":" ) exit search_min
    end do search_min
    if ( ll > StrLen ) then
      call MessageNotify( 'E', module_name, 'Unable to find ":" between minute and second in %c.', c1 = trim(FileName) )
    end if
    read( DateString(l:ll-1), * ) Min
    !
    l = ll + 1
    !
    search_sec : do ll = l, StrLen
      if ( ( DateString(ll:ll) == " " ) .or. ( DateString(ll:ll) == "." ) ) exit search_sec
    end do search_sec
!!$    if ( ll > StrLen ) then
!!$      call MessageNotify( 'E', module_name, 'Unable to find end of second in %c.', c1 = trim(FileName) )
!!$    end if
    read( DateString(l:ll-1), * ) Sec


  end subroutine InterpretTimeUnitString

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

  subroutine StructureInit(     &
    & FileName, VarName, NDims, &
    & TSDataInfo                &
    & )

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

    ! gtool4 データ入力
    ! Gtool4 data input
    !
    use gtool_history, only: HistoryGet, HistoryGetPointer

    ! 文字列操作
    ! Character handling
    !
    use dc_string, only: toChar

    ! 暦と日時の取り扱い
    ! Calendar and Date handler
    !
    use dc_calendar, only: &
      & DC_CAL_DATE,            & ! 日時を表現するデータ型.
                                  ! Data type for date and time
      & DCCalInquire,           &
      & DCCalDateEvalSecOfYear, &
      & DCCalDateCreate,        &
      & DCCalDateDifference

    ! 時刻管理
    ! Time control
    !
    use timeset, only: TimeN, InitialDate

    ! NetCDF wrapper
    !
    use netcdf_wrapper, only: NWGetAtt, NWInqDimLen


    ! 宣言文 ; Declaration statements
    !
    implicit none

    character(*)          , intent(in   ):: FileName
                              ! ファイル名. 
                              ! File name
    character(*)          , intent(in   ):: VarName
                              ! 変数名. 
                              ! Variable name
    integer               , intent(in   ):: NDims
                              ! 時間以外の変数の次元. 
                              ! Number of dimensions except for time dimension
    type(time_series_data), intent(inout):: TSDataInfo


    ! 作業変数
    ! Work variables
    !
    real(DP)         :: CurrentTimeInSec
!!$    real(DP), pointer:: a_time(:)
    integer          :: tindex
    integer          :: t

    character(STRING):: VLevelName

    character(STRING):: attchar

    integer:: hour_in_day, min_in_hour, day_in_year
    integer, pointer:: day_in_month_ptr(:) => null()
    real(DP):: sec_in_min, sec_in_day


    type(DC_CAL_DATE), save :: DataOriginDate
                              ! データ日時基準
                              ! Origin date of data
    integer  :: DataOriginYr
    integer  :: DataOriginMon
    integer  :: DataOriginDay
    integer  :: DataOriginHr
    integer  :: DataOriginMin
    real(DP) :: DataOriginSec


    ! 実行文 ; Executable statement
    !

    ! 初期化確認
    ! Initialization check
    !
    if ( .not. read_time_series_inited ) then
      call MessageNotify( 'E', module_name, 'This module has not been initialized.' )
    end if


!!$    nullify( a_time )


    call DCCalInquire( &
      & day_in_month_ptr = day_in_month_ptr , & ! (out)
      & hour_in_day      = hour_in_day  , &     ! (out)
      & min_in_hour      = min_in_hour  , &     ! (out)
      & sec_in_min       = sec_in_min )         ! (out)
    day_in_year = sum( day_in_month_ptr )
    deallocate( day_in_month_ptr )
    sec_in_day  = hour_in_day * min_in_hour * sec_in_min


    TSDataInfo % FileName = FileName
    TSDataInfo % VarName  = VarName
    TSDataInfo % NDims    = NDims


    if ( TSDataInfo % NDims == 0 ) then
      TSDataInfo % NVLevels = 1
    else if ( TSDataInfo % NDims == 2 ) then
      TSDataInfo % NVLevels = 1
    else
      VLevelName = "plev"

      call HistoryGetPointer(               &
        & TSDataInfo%FileName,              &
        & VLevelName,                       &
        & TSDataInfo % z_VLevels,           &
        & flag_mpi_split = flag_mpi_split   &
        & )
      TSDataInfo % NVLevels = size( TSDataInfo % z_Vlevels )
    end if


    call NWInqDimLen( &
      & TSDataInfo%FileName,    & ! (in )
      & 'time', & ! (in )
      & TSDataInfo%tmax      & ! (out)
      & )


    if ( ( FlagYearCyclic ) .or. ( TSDataInfo % tmax < 2 ) ) then
      ! case in which the data are cyclic

      TSDataInfo % TimeFromOriginToInitialDate = 0.0_DP

    else
      ! case in which the data are not cyclic

      call NWGetAtt( TSDataInfo%FileName, 'time', 'units', AttChar )

      call InterpretTimeUnitString( &
        & TSDataInfo%FileName,                        & ! (in)
        & AttChar,                                    & ! (in)
        & DataOriginYr, DataOriginMon, DataOriginDay, & ! (in)
        & DataOriginHr, DataOriginMin, DataOriginSec  & ! (out)
        & )

      ! Check time from data origin to start time of integration
      !
      call DCCalDateCreate(            &
        & year       = DataOriginYr,   & ! (in)
        & month      = DataOriginMon,  & ! (in)
        & day        = DataOriginDay,  & ! (in)
        & hour       = DataOriginHr  , & ! (in)
        & min        = DataOriginMin,  & ! (in)
        & sec        = DataOriginSec,  & ! (in)
        & date       = DataOriginDate  & ! (out)
        & )
      TSDataInfo % TimeFromOriginToInitialDate = &
        & DCCalDateDifference( DataOriginDate, InitialDate )

      call MessageNotify( 'M', module_name, 'Origin time for a variable %c is %d/%d/%d %d:%d:%f.', &
        & c1 = trim(TSDataInfo%VarName), &
        & i = (/ DataOriginYr, DataOriginMon, DataOriginDay, DataOriginHr, DataOriginMin /), &
        & d = (/ DataOriginSec /) )
      call MessageNotify( 'M', module_name, 'Time from origin to initial date is %f s.', &
        & d = (/ TSDataInfo % TimeFromOriginToInitialDate /) )

    end if



    !-----
!!$    call HistoryGetPointer(               &
!!$      & TSDataInfo%FileName,              &
!!$      & 'time',                           &
!!$      & a_time,                           &
!!$      & flag_mpi_split = flag_mpi_split   &
!!$      & )
!!$    TSDataInfo % tmax = size( a_time )
!!$
!!$    call NWGetAtt( TSDataInfo%FileName, 'time', 'units', attchar )
!!$    if ( ( attchar(1:3) == 'day' ) .or. &
!!$      &  ( attchar(1:3) == 'DAY' ) .or. &
!!$      &  ( attchar(1:3) == 'Day' ) ) then
!!$      a_time = a_time * DAY_SECONDS
!!$    else
!!$      call MessageNotify( 'E', module_name, 'Unit of time, %c, is not supported.', c1 = trim(attchar) )
!!$    end if
    !-----


    if ( TSDataInfo % tmax >= 2 ) then

      if ( FlagYearCyclic ) then
        CurrentTimeInSec = DCCalDateEvalSecOfYear( TimeN, date = InitialDate )
      else
        CurrentTimeInSec = TimeN + TSDataInfo%TimeFromOriginToInitialDate
      end if

      !-----
!!$      allocate( TSDataInfo % a_time(0:TSDataInfo%tmax+1) )
!!$      TSDataInfo % a_time(0) = - ( YEAR_DAYS * DAY_SECONDS - a_time(TSDataInfo%tmax) )
!!$      do t = 1, TSDataInfo%tmax
!!$        TSDataInfo % a_time(t) = a_time(t)
!!$      end do
!!$      TSDataInfo % a_time(TSDataInfo%tmax+1) = YEAR_DAYS * DAY_SECONDS + a_time(1)
!!$      deallocate( a_time )
      !-----


      allocate( TSDataInfo % a_time(0:TSDataInfo%tmax+1) )
      call HistoryGet(               &
        & TSDataInfo%FileName,              &
        & 'time',                           &
        & TSDataInfo%a_time(1:TSDataInfo%tmax),                           &
        & flag_mpi_split = flag_mpi_split   &
        & )
      call NWGetAtt( TSDataInfo%FileName, 'time', 'units', attchar )

      if ( ( attchar(1:3) == 'day' ) .or. &
        &  ( attchar(1:3) == 'DAY' ) .or. &
        &  ( attchar(1:3) == 'Day' ) ) then

        ! convert unit of time from day to sec
        TSDataInfo%a_time(1:TSDataInfo%tmax) = &
          & TSDataInfo%a_time(1:TSDataInfo%tmax) * sec_in_day
      else
        call MessageNotify( 'E', module_name, 'Unit of time, %c, is not supported.', &
          & c1 = trim(attchar) )
      end if

      ! set time in hallo regions
      if ( FlagYearCyclic ) then
        TSDataInfo % a_time(0                ) = &
          & - ( day_in_year * sec_in_day - TSDataInfo % a_time(TSDataInfo%tmax) )
        TSDataInfo % a_time(TSDataInfo%tmax+1) = &
          &     day_in_year * sec_in_day + TSDataInfo % a_time(1              )
      else
        TSDataInfo % a_time(0                ) = &
          & TSDataInfo % a_time(1                ) - 1.0_DP

        TSDataInfo % a_time(TSDataInfo%tmax+1) = &
          & TSDataInfo % a_time(TSDataInfo%tmax  ) + 1.0_DP
      end if


      allocate( TSDataInfo % a_tindex(1:2) )
      allocate( TSDataInfo % xyza_SavedData(0:imax-1,1:jmax,1:TSDataInfo%NVLevels,1:2) )

      TSDataInfo % a_tindex(1) = 0
      TSDataInfo % a_tindex(2) = 1
      do t = 1, TSDataInfo%tmax
        if ( TSDataInfo % a_time(t) <= CurrentTimeInSec ) then
          TSDataInfo % a_tindex(1) = t
          TSDataInfo % a_tindex(2) = t+1
        end if
      end do

      ! set time index
      if ( FlagYearCyclic ) then
        tindex = TSDataInfo % a_tindex(1)
        if ( tindex == 0 ) then
          tindex = TSDataInfo % tmax
        else if ( tindex == TSDataInfo % tmax + 1 ) then
          tindex = 1
        else
          tindex = tindex
        end if
      else
        tindex = TSDataInfo % a_tindex(1)
        tindex = min( max( tindex, 1 ), TSDataInfo % tmax )
      end if


      if ( TSDataInfo % NDims == 0 ) then
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(0,1,1,1),                &
          & range = 'time=^'//toChar(tindex),                  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      else if ( TSDataInfo % NDims == 2 ) then
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(:,:,1,1),                &
          & range = 'time=^'//toChar(tindex),                  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      else
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(:,:,:,1),                &
          & range = 'time=^'//toChar(tindex),                  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      end if

      ! set time index
      if ( FlagYearCyclic ) then
        tindex = TSDataInfo % a_tindex(2)
        if ( tindex == 0 ) then
          tindex = TSDataInfo % tmax
        else if ( tindex == TSDataInfo % tmax + 1 ) then
          tindex = 1
        else
          tindex = tindex
        end if
      else
        tindex = TSDataInfo % a_tindex(2)
        tindex = min( max( tindex, 1 ), TSDataInfo % tmax )
      end if

      if ( TSDataInfo % NDims == 0 ) then
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(0,1,1,2),                &
          & range = 'time=^'//toChar(tindex),                  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      else if ( TSDataInfo % NDims == 2 ) then
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(:,:,1,2),                &
          & range = 'time=^'//toChar(tindex),                  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      else
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(:,:,:,2),                &
          & range = 'time=^'//toChar(tindex),                  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      end if

      allocate( TSDataInfo%xyz_VarTimeInterpolated(0:imax-1, 1:jmax, 1:TSDataInfo%NVLevels) )

    else

      !-----
!!$      allocate( TSDataInfo % a_time(TSDataInfo%tmax) )
!!$      do t = 1, TSDataInfo%tmax
!!$        TSDataInfo % a_time(t) = a_time(t)
!!$      end do
      !-----


      allocate( TSDataInfo % a_time(TSDataInfo%tmax) )
      call HistoryGet(               &
        & TSDataInfo%FileName,              &
        & 'time',                           &
        & TSDataInfo%a_time(1:TSDataInfo%tmax),                           &
        & flag_mpi_split = flag_mpi_split   &
        & )
      call NWGetAtt( TSDataInfo%FileName, 'time', 'units', attchar )
      if ( ( attchar(1:3) == 'day' ) .or. &
        &  ( attchar(1:3) == 'DAY' ) .or. &
        &  ( attchar(1:3) == 'Day' ) ) then
        ! convert unit of time from day to sec
        TSDataInfo%a_time(1:TSDataInfo%tmax) = &
          & TSDataInfo%a_time(1:TSDataInfo%tmax) * sec_in_day
      else
        call MessageNotify( 'E', module_name, 'Unit of time, %c, is not supported.', &
          & c1 = trim(attchar) )
      end if

      allocate( TSDataInfo % a_tindex(1:1) )
      allocate( TSDataInfo % xyza_SavedData(0:imax-1,1:jmax,1:TSDataInfo%NVLevels,1:1) )

      TSDataInfo % a_tindex(1) = 1

      if ( TSDataInfo % NDims == 0 ) then
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(0,1,1,1),                &
          & range = 'time=^'//toChar(TSDataInfo%a_tindex(1)),  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      else if ( TSDataInfo % NDims == 2 ) then
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(:,:,1,1),                &
          & range = 'time=^'//toChar(TSDataInfo%a_tindex(1)),  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      else
        call HistoryGet(                                       &
          & TSDataInfo%FileName,                               &
          & TSDataInfo%VarName,                                &
          & TSDataInfo%xyza_SavedData(:,:,:,1),                &
          & range = 'time=^'//toChar(TSDataInfo%a_tindex(1)),  &
          & flag_mpi_split = flag_mpi_split                    &
          & )
      end if

    end if


  end subroutine StructureInit

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

  subroutine ReadTimeSeriesInit

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

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


    ! 宣言文 ; Declaration statements
    !

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

    ! NAMELIST 変数群
    ! NAMELIST group name
    !
    namelist /read_time_series_nml/ &
      & FlagYearCyclic
          !
          ! デフォルト値については初期化手続 "read_time_series#ReadTimeSeriesInit"
          ! のソースコードを参照のこと.
          !
          ! Refer to source codes in the initialization procedure
          ! "read_time_series#ReadTimeSeriesInit" for the default values.
          !

    if ( read_time_series_inited ) return


    ! デフォルト値の設定
    ! Default values settings
    !

    FlagYearCyclic = .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 = read_time_series_nml,       & ! (out)
        & iostat = iostat_nml )             ! (out)
      close( unit_nml )

      call NmlutilMsg( iostat_nml, module_name ) ! (in)
    end if


    ! Initialzation
    !
    NumMaxStruct = 0


    ! 印字 ; Print
    !
    call MessageNotify( 'M', module_name, '----- Initialization Messages -----' )
    call MessageNotify( 'M', module_name, 'FlagYearCyclic = %b', l = (/ FlagYearCyclic /) )
    call MessageNotify( 'M', module_name, '-- version = %c', c1 = trim(version) )


    read_time_series_inited = .true.


  end subroutine ReadTimeSeriesInit

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

end module read_time_series
