!---------------------------------------------------------------------
!     Copyright (C) GFD Dennou Club, 2005. All rights reserved.
!---------------------------------------------------------------------

module physics_radiation_main_mod
  ! == DESCRIPTION
  ! * 長波放射計算モジュールには 2 種類のスキームが用意されている.
  !   use 文を書き換えることによりスキームの切り換えをおこなう.
  ! * 入射短波フラックス計算モジュールには 2 種類のスキームが用意されている.
  !   use 文を書き換えることによりスキームの切り換えをおこなう.
  !
  ! == TODO
  ! * 物理過程のメインではなく, 一段下がったこのレベルで use 文を
  !   書き換えることにしておいて良いのか?
  ! * usu 文の変更を手動でやるには無理があるのでなんらかの仕組み
  !   が必要.
  !
  ! == History
  !   2005-09-21 Yamada Yukiko     create
  !   2007-05-04 Masaki Ishiwatari physics_radiation_incoming_sr is made
  !   2007-05-11 Masaki Ishiwatari interface is changed.
  !   2007-5-12 M.Ishiwatari 放射モジュールのiterface を変更. xyr_Temp 追加.
  !
  implicit none

  private
  public :: physics_radiation_main
  public :: physics_radiation_deltemp

contains

  subroutine physics_radiation_main( &
    & xyr_RadLFlux              , & ! (out) 長波フラックス
    & xyo_SurfRadLMatrix        , & ! (out) Ｔ陰解行列：地表
    & xyro_DelRadLFlux          , & ! (out) 長波地表温度変化
    & xyr_RadSFlux              , & ! (out) 日射フラックス
    & xyz_Temp                  , & ! (in) 温度(整数)
    & xyr_Temp                  , & ! (in) 温度(半整数)
    & xy_SurfTemp               , & ! (in) 地表面温度 
    & xyz_Qvap                  , & ! (in) 比湿
    & xyr_Press                 , & ! (in) 圧力
    & x_Lon                     , & 
    & y_Lat                     , &
    & xy_SurfAlbedo )               ! (in) 地表アルベド

    use type_mod,    only: REKIND, DBKIND, INTKIND, TOKEN, STRING
    use grid_3d_mod, only: im, jm, km
    use constants_mod, only: Grav

    ! Switch for incoming solar radiation
    !use physics_radiation_incoming_mod, only: physics_radiation_incoming
    use physics_radiation_incoming_sr_mod, only: physics_radiation_incoming

    use physics_radiation_short_mod,  only: physics_radiation_short

    ! Switch for incoming solar radiation
    use physics_radiation_long_mod,  only: physics_radiation_long
    !use physics_radiation_long_runaway_mod,  only: physics_radiation_long

    use dc_trace,    only: SetDebug, BeginSub, EndSub, DbgMessage, DataDump
    use dycore_time_mod, only: CurrentTime, CurrentLoop

    implicit none

    real(DBKIND), intent(out) :: xyr_RadLFlux(im,jm,km+1) ! 長波フラックス
    real(DBKIND), intent(out) :: xyo_SurfRadLMatrix(im,jm,-1:1) 
                                                          !Ｔ陰解行列：地表
    real(DBKIND), intent(out) :: xyro_DelRadLFlux(im,jm,km+1,0:1)
                                                          ! 長波地表温度変化
    real(DBKIND), intent(out) :: xyr_RadSFlux(im,jm,km+1) ! 日射フラックス
    real(DBKIND), intent(in) :: xyz_Temp(im,jm,km)
    real(DBKIND), intent(in) :: xyr_Temp(im,jm,km+1)
    real(DBKIND), intent(in) :: xy_SurfTemp(im,jm)
    real(DBKIND), intent(in) :: xyz_Qvap(im,jm,km)
    real(DBKIND), intent(in) :: xyr_Press(im,jm,km+1)
    real(DBKIND), intent(in) :: xy_SurfAlbedo(im,jm)
    real(DBKIND), intent(in) :: x_Lon(im) 
    real(DBKIND), intent(in) :: y_Lat(jm)


    !----- 作業用内部変数 -----
    character(STRING),  parameter:: subname = "physics_radiation_main"

    ! do ループ用作業変数 (東西 i*、南北 j*、鉛直 k*、波数 l*用)
    integer(INTKIND)    :: k

    real(DBKIND) :: &
         & xyr_TauQvap(im,jm,km+1)   , &  !" 光学的厚さ：水
         & xyr_TauDryAir(im,jm,km+1) , &  !" 光学的厚さ：空気
         & xy_InAngle(im,jm)              !" sec(入射角)


    ! (2007-5-20 石渡) この設定は時間の単位も指定して
    ! できるようにしないといけない.
    !real(DBKIND), parameter :: RadLDelTime = 3.0
    !real(DBKIND), parameter :: RadSDelTime = 1.0
    real(DBKIND), parameter :: RadLDelTime = 0.0
    real(DBKIND), parameter :: RadSDelTime = 0.0
    
    real(DBKIND),allocatable,save :: xy_TempOld(:,:)
    real(DBKIND),allocatable,save :: xyr_RadLFluxOld(:,:,:)
    real(DBKIND),allocatable,save :: xyr_RadSFluxOld(:,:,:)
    real(DBKIND),allocatable,save :: xyro_DelRadLFluxOld(:,:,:,:)
    real(DBKIND),save :: RadLTime, RadSTime
    
    continue

    !----------------------------------------------------------------
    !   開始処理
    !----------------------------------------------------------------
    call BeginSub(subname)

    !----------------------------------------------------------------
    !   放射計算
    !----------------------------------------------------------------

    ! 本当は, 放射計算の間隔を外から与えられるようにしないといけない. 
    ! AGCM5 では, 短波は 1 時間, 長波は 3 時間間隔. 

    if ( CurrentLoop .EQ. 1 ) then
       RadLTime = -999.0d0 * 60*60
       RadSTime = -999.0d0 * 60*60
       
       allocate( &
            & xy_TempOld(im,jm), &
            & xyr_RadLFluxOld(im,jm,km+1), &
            & xyr_RadSFluxOld(im,jm,km+1), &
            & xyro_DelRadLFluxOld(im,jm,km+1,0:1) &
            & )
    end if
    
    ! ---- 1. τ の計算 ----
    xyr_TauQvap   = 0.0d0
    xyr_TauDryAir = 0.0d0

    do k = km , 1, -1
       xyr_TauQvap(:,:,k) = xyr_TauQvap(:,:,k+1) &
            &           + xyz_Qvap(:,:,k)     & 
            &           * ( xyr_Press(:,:,k) - xyr_Press(:,:,k+1) ) / Grav 
       
       xyr_TauDryAir(:,:,k) = xyr_TauDryAir(:,:,k+1) &
            &           + ( xyr_Press(:,:,k) - xyr_Press(:,:,k+1) ) / Grav 
    end do


    ! ---- 2. 長波フラックスの算出 ----
    ! (2007-5-4 石渡) 
    ! * ここは論理変数を用意して見てパッとわかるようにできないかな?
    if ( (CurrentTime - RadLTime) .GE. (RadLDelTime*60*60) ) then
       
       RadLTime = CurrentTime
       
       call physics_radiation_long( &
            & xyr_RadLFlux          , & ! (out) 長波フラックス
            & xyro_DelRadLFlux      , & ! (out) 長波地表温度変化
            & xyz_Temp              , & ! (in) 温度 (整数)
            & xyr_Temp              , & ! (in) 温度 (半整数)
            & xy_SurfTemp           , & ! (in) 地表面温度
            & xyr_TauQvap           , & ! (in) 光学的厚さ：水
            & xyr_TauDryAir           ) ! (in) 光学的厚さ：空気
       
    ! ---- 2*. 長波フラックスを計算しない場合 ----
    else
       
       xyr_RadLFlux = xyr_RadLFluxOld
       xyro_DelRadLFlux = xyro_DelRadLFluxOld
       
       do k = 1, km+1
          xyr_RadLFlux(:,:,k) = xyr_RadLFlux(:,:,k) &
               & +  xyro_DelRadLFlux(:,:,k,1) &
               &  * (xyz_Temp(:,:,1) - xy_TempOld(:,:) )
          xyro_DelRadLFlux(:,:,k,1) = xyro_DelRadLFlux(:,:,k,1) &
               & / (xy_TempOld(:,:)**3) * (xyz_Temp(:,:,1)**3)
       end do
    end if


    ! ---- 3. 長波陰解用行列 ----    
    xyo_SurfRadLMatrix(:,:,0)  = xyro_DelRadLFlux(:,:,1,0)
    xyo_SurfRadLMatrix(:,:,1)  = xyro_DelRadLFlux(:,:,1,1)
    xyo_SurfRadLMatrix(:,:,-1) = 0.0d0


    if ( (CurrentTime - RadSTime) .GE. (RadSDelTime*60*60) ) then

       ! ----  4. 短波入射 ----
       call physics_radiation_incoming( &
         & xyr_RadSFlux(:,:,km+1)   , & ! (out) 短波フラックス
         & xy_InAngle              , & ! (out) sec(入射角)
         & x_Lon                   , & !(in) 経度
         & y_Lat                    ) !(in) 緯度
       
       ! ----  5. 短波フラックス ----
       call physics_radiation_short( &
            & xyr_RadSFlux         , & ! (inout) 短波フラックス
            & xyr_TauQvap          , & ! (in) 光学的厚さ：水
            & xyr_TauDryAir        , & ! (in) 光学的厚さ：空気
            & xy_InAngle           , & ! (in) sec(入射角)
            & xy_SurfAlbedo          ) ! (in) 地表アルベド

    else
       xyr_RadSFlux = xyr_RadSFluxOld
    end if


    ! ---- 古い値の保存 ----
    xy_TempOld = xyz_Temp(:,:,1)
    xyr_RadLFluxOld = xyr_RadLFlux
    xyr_RadSFluxOld = xyr_RadSFlux
    xyro_DelRadLFluxOld = xyro_DelRadLFlux


    !----------------------------------------------------------------
    !   終了処理
    !----------------------------------------------------------------
    call EndSub(subname)

   end subroutine physics_radiation_main



  subroutine physics_radiation_deltemp( &
    & xyz_DRadLTempDt, xyz_DRadSTempDt, & !(out)
    & xyr_RadLFlux, xyr_RadSFlux, xyr_Press & !(in)
    & )
    !
    !== 放射加熱率の計算
    !
    ! 短波放射, 長波放射それぞれの加熱率を計算する.
    !
    use type_mod,    only: REKIND, DBKIND, INTKIND, TOKEN, STRING
    use grid_3d_mod, only: im, jm, km
    use constants_mod, only: Cp    ,& ! 大気定圧比熱 
         &                   Grav     ! 重力加速度
    use dc_trace,    only: SetDebug, BeginSub, EndSub, DbgMessage, DataDump
    implicit none
    real(DBKIND), intent(out) :: xyz_DRadLTempDt(im,jm,km) ! 長波加熱率
    real(DBKIND), intent(out) :: xyz_DRadSTempDt(im,jm,km) ! 短波加熱率
    real(DBKIND), intent(in) :: xyr_RadLFlux(im,jm,km+1) ! 長波フラックス
    real(DBKIND), intent(in) :: xyr_RadSFlux(im,jm,km+1) ! 短波フラックス
    real(DBKIND), intent(in) :: xyr_Press(im,jm,km+1) ! 圧力 (半整数)
    character(STRING), parameter:: subname = "physics_radiation_deltemp"
      ! 作業用内部変数
    integer(INTKIND) :: k
      ! do ループ用作業変数 (東西 i*、南北 j*、鉛直 k*、波数 l*用)
    continue

    !----------------------------------------------------------------
    !   開始処理
    !----------------------------------------------------------------
    call BeginSub(subname)

    !----------------------------------------------------------------
    !   放射冷却率の演算 (加熱率では?)
    !----------------------------------------------------------------

    do k = 1, km
       xyz_DRadLTempDt(:,:,k) =( xyr_RadLFlux(:,:,k) - xyr_RadLFlux(:,:,k+1) ) &
            & / (xyr_Press(:,:,k) - xyr_Press(:,:,k+1) ) / Cp * Grav
       xyz_DRadSTempDt(:,:,k) =( xyr_RadSFlux(:,:,k) - xyr_RadSFlux(:,:,k+1) ) &
            & / (xyr_Press(:,:,k) - xyr_Press(:,:,k+1) ) / Cp * Grav
    end do

    !----------------------------------------------------------------
    !   終了処理
    !----------------------------------------------------------------
    call EndSub(subname)

  end subroutine physics_radiation_deltemp


end module physics_radiation_main_mod
















