!= 初期値生成モジュール
!
!= Initial data generation module
!
! Authors::   Yasuhiro MORIKAWA
! Version::   $Id: initial_data.f90,v 1.2 2007/07/09 11:02:50 morikawa Exp $
! Tag Name::  $Name: dcpam4-20070731 $
! Copyright:: Copyright (C) GFD Dennou Club, 2007. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]
!


module initial_data
  !
  != 初期値生成モジュール
  !
  != Initial data generation module
  !
  ! GCM の初期値となるデータを生成します.
  ! ファイルへの出力は主プログラムで行うことを想定しています.
  !
  ! Initial data for GCM is generated.
  ! File output is expected to done by a main program.
  !
  !== Procedures List
  !
  ! Create        :: INIDAT 型変数の初期設定
  ! Get           :: 初期値データの取得
  ! Close         :: INIDAT 型変数の終了処理
  ! PutLine       :: INIDAT 型変数に格納されている情報の印字
  !
  ! Create        :: Constructor of "INIDAT"
  ! Get           :: Get initial data
  ! Close         :: Deconstructor of "INIDAT"
  ! PutLine       :: Print information of "INIDAT"
  !
  !== Usage
  !
  ! 始めに, INIDAT 型の変数を定義し, Create で初期設定を行います.
  ! 初期設定後, Get によって初期値を読み込んでください.
  ! 最後に, INIDAT 型の変数の終了処理を Close にて行います.
  !
  ! First, initialize "INIDAT" by Create.
  ! Then, get initial data by Get.
  ! Finally, terminate "INIDAT" by Close.
  !

  implicit none
  private
  public:: INIDAT, Create, Get, Close, PutLine

  type INIDAT
    !
    ! まず, Create で "INIDAT" 型の変数を初期設定して下さい.
    ! 初期化された "INIDAT" 型の変数を再度利用する際には,
    ! Close によって終了処理を行ってください.
    !
    ! Initialize "INIDAT" variable by "Create" before usage.
    ! If you reuse "INIDAT" variable again for another application, 
    ! terminate by "Close".
    !
    logical:: initialized = .false.    ! initialization flag
    integer:: imax ! 経度格子点数. 
                   ! Number of grid points in longitude
    integer:: jmax ! 緯度格子点数. 
                   ! Number of grid points in latitude
    integer:: kmax ! 鉛直層数. 
                   ! Number of vertical level
  end type INIDAT

  character(*), parameter:: version = &
    & '$Name: dcpam4-20070731 $' // &
    & '$Id: initial_data.f90,v 1.2 2007/07/09 11:02:50 morikawa Exp $'

  interface Create
    module procedure InitialDataCreate
  end interface

  interface Close
    module procedure InitialDataClose
  end interface

  interface PutLine
    module procedure InitialDataPutLine
  end interface

  interface Get
    module procedure InitialDataGet
  end interface

contains

  subroutine InitialDataCreate( ini_dat, &
    & imax, jmax, kmax, &
    & err )
    !
    ! INIDAT 型の変数の初期設定を行います.
    ! 他のサブルーチンを使用する前に必ずこのサブルーチンによって
    ! INIDAT 型の変数を初期設定してください.
    ! なお, 与えられた *ini_dat* が既に初期設定されている場合,
    ! プログラムはエラーを発生させます.
    !
    ! Constructor of "INIDAT".
    ! Initialize *ini_dat* by this subroutine, 
    ! before other procedures are used, 
    ! Note that if *ini_dat* is already initialized 
    ! by this procedure, error is occurred.
    !
    use dc_trace, only: BeginSub, EndSub
    use dc_types, only: STRING, STDOUT
    use dcpam_error, only: StoreError, DC_NOERR, DCPAM_EALREADYINIT, &
      & DCPAM_ENEGATIVE
    implicit none
    type(INIDAT), intent(inout):: ini_dat
    integer, intent(in):: imax ! 経度格子点数. 
                               ! Number of grid points in longitude
    integer, intent(in):: jmax ! 緯度格子点数. 
                               ! Number of grid points in latitude
    integer, intent(in):: kmax ! 鉛直層数. 
                               ! Number of vertical level
    logical, intent(out), optional:: err
                              ! 例外処理用フラグ.
                              ! デフォルトでは, この手続き内でエラーが
                              ! 生じた場合, プログラムは強制終了します.
                              ! 引数 *err* が与えられる場合,
                              ! プログラムは強制終了せず, 代わりに
                              ! *err* に .true. が代入されます.
                              !
                              ! Exception handling flag. 
                              ! By default, when error occur in 
                              ! this procedure, the program aborts. 
                              ! If this *err* argument is given, 
                              ! .true. is substituted to *err* and 
                              ! the program does not abort. 
    integer:: stat
    character(STRING):: cause_c
    character(*), parameter:: subname = 'InitialDataCreate'
  continue
    call BeginSub(subname, version)
    stat = DC_NOERR
    cause_c = ''

    !-----------------------------------------------------------------
    !  初期設定のチェック
    !  Check initialization
    !-----------------------------------------------------------------
    if (ini_dat % initialized) then
      stat = DCPAM_EALREADYINIT
      cause_c = 'INIDAT'
      goto 999
    end if

    !-----------------------------------------------------------------
    !  引数の正当性のチェック
    !  Validation of arguments
    !-----------------------------------------------------------------
    if (imax < 1) then
      stat = DCPAM_ENEGATIVE
      cause_c = 'imax'
      goto 999
    end if
    if (jmax < 1) then
      stat = DCPAM_ENEGATIVE
      cause_c = 'jmax'
      goto 999
    end if
    if (kmax < 1) then
      stat = DCPAM_ENEGATIVE
      cause_c = 'kmax'
      goto 999
    end if

    !-----------------------------------------------------------------
    !  格子点の設定
    !  Configure grid point
    !-----------------------------------------------------------------
    ini_dat % imax = imax
    ini_dat % jmax = jmax
    ini_dat % kmax = kmax

    !-----------------------------------------------------------------
    !  終了処理, 例外処理
    !  Termination and Exception handling
    !-----------------------------------------------------------------
    ini_dat % initialized = .true.
999 continue
    call StoreError(stat, subname, err, cause_c)
    call EndSub(subname)
  end subroutine InitialDataCreate

  subroutine InitialDataClose( ini_dat, err )
    !
    ! INIDAT 型の変数の終了処理を行います.
    ! なお, 与えられた *ini_dat* が Create によって初期設定
    ! されていない場合, プログラムはエラーを発生させます.
    !
    ! Deconstructor of "INIDAT".
    ! Note that if *ini_dat* is not initialized by Create yet,
    ! error is occurred.
    !
    use dc_trace, only: BeginSub, EndSub
    use dc_types, only: STRING, STDOUT
    use dcpam_error, only: StoreError, DC_NOERR, DCPAM_ENOTINIT
    implicit none
    type(INIDAT), intent(inout):: ini_dat
    logical, intent(out), optional:: err
                              ! 例外処理用フラグ.
                              ! デフォルトでは, この手続き内でエラーが
                              ! 生じた場合, プログラムは強制終了します.
                              ! 引数 *err* が与えられる場合,
                              ! プログラムは強制終了せず, 代わりに
                              ! *err* に .true. が代入されます.
                              !
                              ! Exception handling flag. 
                              ! By default, when error occur in 
                              ! this procedure, the program aborts. 
                              ! If this *err* argument is given, 
                              ! .true. is substituted to *err* and 
                              ! the program does not abort. 
    integer:: stat
    character(STRING):: cause_c
    character(*), parameter:: subname = 'InitialDataClose'
  continue
    call BeginSub(subname)
    stat = DC_NOERR
    cause_c = ''

    !-----------------------------------------------------------------
    !  初期設定のチェック
    !  Check initialization
    !-----------------------------------------------------------------
    if (.not. ini_dat % initialized) then
      stat = DCPAM_ENOTINIT
      cause_c = 'INIDAT'
      goto 999
    end if

    !-----------------------------------------------------------------
    !  終了処理, 例外処理
    !  Termination and Exception handling
    !-----------------------------------------------------------------
    ini_dat % initialized = .false.
999 continue
    call StoreError(stat, subname, err, cause_c)
    call EndSub(subname)
  end subroutine InitialDataClose

  subroutine InitialDataPutLine( ini_dat, unit, indent, err )
    !
    ! 引数 *ini_dat* に設定されている情報を印字します.
    ! デフォルトではメッセージは標準出力に出力されます. 
    ! *unit* に装置番号を指定することで, 出力先を変更することが可能です.
    !
    ! Print information of *ini_dat*.
    ! By default messages are output to standard output.
    ! Unit number for output can be changed by *unit* argument.
    !
    use dc_trace, only: BeginSub, EndSub
    use dc_types, only: STRING, STDOUT
    use dcpam_error, only: StoreError, DC_NOERR, DCPAM_ENOTINIT
    use dc_string, only: Printf
    implicit none
    type(INIDAT), intent(inout):: ini_dat
    integer, intent(in), optional:: unit
                              ! 出力先の装置番号.
                              ! デフォルトの出力先はは標準出力.
                              !
                              ! Unit number for output.
                              ! Default value is standard output.
    character(*), intent(in), optional:: indent
                              ! 表示されるメッセージの字下げ.
                              !
                              ! Indent of displayed messages.
    logical, intent(out), optional:: err
                              ! 例外処理用フラグ.
                              ! デフォルトでは, この手続き内でエラーが
                              ! 生じた場合, プログラムは強制終了します.
                              ! 引数 *err* が与えられる場合,
                              ! プログラムは強制終了せず, 代わりに
                              ! *err* に .true. が代入されます.
                              !
                              ! Exception handling flag. 
                              ! By default, when error occur in 
                              ! this procedure, the program aborts. 
                              ! If this *err* argument is given, 
                              ! .true. is substituted to *err* and 
                              ! the program does not abort. 
    integer:: stat
    character(STRING):: cause_c
    integer:: out_unit
    integer:: indent_len
    character(STRING):: indent_str
    character(*), parameter:: subname = 'InitialDataPutLine'
  continue
    call BeginSub(subname)
    stat = DC_NOERR
    cause_c = ''

    !-----------------------------------------------------------------
    !  初期設定のチェック
    !  Check initialization
    !-----------------------------------------------------------------
    if (present(unit)) then
      out_unit = unit
    else
      out_unit = STDOUT
    end if

    indent_len = 0
    indent_str = ''
    if (present(indent)) then
      if (len(indent) /= 0) then
        indent_len = len(indent)
        indent_str(1:indent_len) = indent
      end if
    end if


    !-----------------------------------------------------------------
    !  "INIDAT" の設定の印字
    !  Print the settings for "INIDAT"
    !-----------------------------------------------------------------
    if (ini_dat % initialized) then
      call Printf(out_unit, &
        & indent_str(1:indent_len) // &
        & '#<INIDAT:: @initialized=%y @imax=%d @jmax=%d @kmax=%d', &
        & i=(/ini_dat % imax, ini_dat % jmax, ini_dat % kmax/), &
        & l=(/ini_dat % initialized/))
    else
      call Printf(out_unit, &
        & indent_str(1:indent_len) // &
        & '#<INIDAT:: @initialized=%y>', &
        & l=(/ini_dat % initialized/))
    end if


    !-----------------------------------------------------------------
    !  終了処理, 例外処理
    !  Termination and Exception handling
    !-----------------------------------------------------------------
999 continue
    call StoreError(stat, subname, err, cause_c)
    call EndSub(subname)
  end subroutine InitialDataPutLine

  subroutine InitialDataGet( ini_dat, &
    & xyz_VorB, xyz_DivB, xyz_TempB, xyz_QVapB, xy_PsB, &
    & xyz_VorN, xyz_DivN, xyz_TempN, xyz_QVapN, xy_PsN, &
    & err )
    !
    ! GCM 用の初期値データを返します.
    ! 渦度, 発散, 温度, 比湿, 地表面気圧を返します.
    ! 時間積分法としてリープフロッグスキームを想定し, 
    ! $ t-\Delta t $ および $ t $ のデータを返します.
    !
    ! なお, 与えられた *ini_dat* が Create によって初期設定
    ! されていない場合, プログラムはエラーを発生させます.
    !
    ! Return initial data for GCM.
    ! Vorticity, divergence, temperature, specific humidity, surface pressure
    ! are returned.
    ! Assuming leap-frog scheme as time integration method, 
    ! data at $ t-\Delta t $ and $ t $ is returned.
    !
    ! If *ini_dat* is not initialized by Create yet,
    ! error is occurred.
    !
    use dc_trace, only: BeginSub, EndSub
    use dc_types, only: STRING, STDOUT, DP
    use dcpam_error, only: StoreError, DC_NOERR, DCPAM_ENOTINIT
    implicit none
    type(INIDAT), intent(inout):: ini_dat
    real(DP), intent(out):: xyz_VorB (0:ini_dat%imax-1, 0:ini_dat%jmax-1, 0:ini_dat%kmax-1)
                              ! $ \zeta (t-\Delta t) $ . 渦度. Vorticity
    real(DP), intent(out):: xyz_DivB (0:ini_dat%imax-1, 0:ini_dat%jmax-1, 0:ini_dat%kmax-1)
                              ! $ D (t-\Delta t) $ .     発散. Divergence
    real(DP), intent(out):: xyz_TempB (0:ini_dat%imax-1, 0:ini_dat%jmax-1, 0:ini_dat%kmax-1)
                              ! $ T (t-\Delta t) $ .     温度. Temperature
    real(DP), intent(out):: xyz_QVapB (0:ini_dat%imax-1, 0:ini_dat%jmax-1, 0:ini_dat%kmax-1)
                              ! $ q (t-\Delta t) $ .     比湿. Specific humidity
    real(DP), intent(out):: xy_PsB (0:ini_dat%imax-1, 0:ini_dat%jmax-1)
                              ! $ P_s (t-\Delta t) $ .   地表面気圧. Surface pressure

    real(DP), intent(out):: xyz_VorN (0:ini_dat%imax-1, 0:ini_dat%jmax-1, 0:ini_dat%kmax-1)
                              ! $ \zeta (t) $ . 渦度. Vorticity
    real(DP), intent(out):: xyz_DivN (0:ini_dat%imax-1, 0:ini_dat%jmax-1, 0:ini_dat%kmax-1)
                              ! $ D (t) $ .     発散. Divergence
    real(DP), intent(out):: xyz_TempN (0:ini_dat%imax-1, 0:ini_dat%jmax-1, 0:ini_dat%kmax-1)
                              ! $ T (t) $ .     温度. Temperature
    real(DP), intent(out):: xyz_QVapN (0:ini_dat%imax-1, 0:ini_dat%jmax-1, 0:ini_dat%kmax-1)
                              ! $ q (t) $ .     比湿. Specific humidity
    real(DP), intent(out):: xy_PsN (0:ini_dat%imax-1, 0:ini_dat%jmax-1)
                              ! $ P_s (t) $ .   地表面気圧. Surface pressure

    logical, intent(out), optional:: err
                              ! 例外処理用フラグ.
                              ! デフォルトでは, この手続き内でエラーが
                              ! 生じた場合, プログラムは強制終了します.
                              ! 引数 *err* が与えられる場合,
                              ! プログラムは強制終了せず, 代わりに
                              ! *err* に .true. が代入されます.
                              !
                              ! Exception handling flag. 
                              ! By default, when error occur in 
                              ! this procedure, the program aborts. 
                              ! If this *err* argument is given, 
                              ! .true. is substituted to *err* and 
                              ! the program does not abort. 

    !-----------------------------------
    !  作業変数
    !  Work variables
    integer:: imax            ! 経度格子点数. 
                              ! Number of grid points in longitude
    integer:: jmax            ! 緯度格子点数. 
                              ! Number of grid points in latitude
    integer:: kmax            ! 鉛直層数. 
                              ! Number of vertical level

    integer:: i, j, k         ! DO ループ用作業変数
                              ! Work variables for DO loop
    integer:: stat
    character(STRING):: cause_c
    character(*), parameter:: subname = 'InitialDataGet'
  continue
    call BeginSub(subname)
    stat = DC_NOERR
    cause_c = ''

    !-----------------------------------------------------------------
    !  初期設定のチェック
    !  Check initialization
    !-----------------------------------------------------------------
    if (.not. ini_dat % initialized) then
      stat = DCPAM_ENOTINIT
      cause_c = 'INIDAT'
      goto 999
    end if

    !-----------------------------------------------------------------
    !  *ini_dat* に格納される格子点数の取り出し
    !  Fetch number of grid points from *ini_dat*
    !-----------------------------------------------------------------
    imax = ini_dat % imax
    jmax = ini_dat % jmax
    kmax = ini_dat % kmax

    !-----------------------------------------------------------------
    !  初期値データの作成
    !  Generate initial data
    !-----------------------------------------------------------------

    !-----------------------------------
    !  AGCM5.3 のデフォルト初期値
    !  AGCM5.3 default initial values
    xyz_VorB = 0.0_DP
    xyz_VorN = 0.0_DP
    xyz_DivB = 0.0_DP
    xyz_DivN = 0.0_DP
    xyz_QVapB = 1.0e-10_DP
    xyz_QVapN = 1.0e-10_DP
    xy_PsB = 1.0e5_DP
    xy_PsN = 1.0e5_DP

    xyz_TempB = 285.0_DP

    do k = 0, kmax - 1
      do i = 0, imax - 1
        do j = 0, jmax - 1
          xyz_TempB(i,j,k) = xyz_TempB(i,j,k) &
            &  + 0.1_DP * sin ( real( i * j * ( kmax - 1 - k ) ) &
            &                  / real( imax * jmax * kmax, DP ) * 10.0_DP &
            &                 )
        end do
      end do
    end do

    xyz_TempN = xyz_TempB


    !-----------------------------------------------------------------
    !  終了処理, 例外処理
    !  Termination and Exception handling
    !-----------------------------------------------------------------
999 continue
    call StoreError(stat, subname, err, cause_c)
    call EndSub(subname)
  end subroutine InitialDataGet

end module initial_data

