module restart_dynamics 2,11
!-----------------------------------------------------------------------
!
! Purpose: Read and write restart file
!
! !HISTORY:
! 2000.01.01 ?????? Creation
! 2006.04.13 Sawyer Removed dependency on prognostics
! 2006.07.01 Sawyer Transitioned q3 tracers to T_TRACERS
! 2008.10.02 Edwards Added pio support
!
!-----------------------------------------------------------------------
use shr_kind_mod
, only: r8 => shr_kind_r8, r4=> shr_kind_r4
use spmd_utils
, only: masterproc
use pmgrid
, only: plon, plat, plev
use constituents
, only: pcnst
use io_dist
, only: fv_write_r4, fv_write_r8, fv_read_r8
use dyn_comp
, only: dyn_import_t, dyn_export_t
use abortutils
, only: endrun
use fv_control_mod
, only: tmass0
use dynamics_vars
, only: T_FVDYCORE_STATE
use cam_logfile
, only: iulog
#if ( defined OFFLINE_DYN )
use metdata
, only: write_met_restart, read_met_restart
#endif
use pio, only: file_desc_t, io_desc_t, var_desc_t, &
pio_double, pio_unlimited, pio_offset, &
pio_setdebuglevel, pio_setframe, &
pio_def_var, pio_def_dim, &
pio_inq_varid, &
pio_put_var, pio_get_var, &
pio_write_darray, pio_read_darray, &
pio_initdecomp, pio_freedecomp
implicit none
public read_restart_dynamics, write_restart_dynamics
private
real(r8), parameter :: D0_0 = 0.0_r8
real(r8), parameter :: D1E5 = 1.0e5_r8
public init_restart_dynamics
integer, parameter :: namlen=16
type restart_var_t
real(r8), pointer :: v2d(:,:)
real(r8), pointer :: v3d(:, :, :)
real(r8), pointer :: v4d(:, :, :, :)
real(r8), pointer :: v5d(:, :, :, :, :)
real(r4), pointer :: v2dr4(:,:)
real(r4), pointer :: v3dr4(:, :, :)
real(r4), pointer :: v4dr4(:, :, :, :)
real(r4), pointer :: v5dr4(:, :, :, :, :)
type(var_desc_t), pointer :: vdesc
integer :: ndims
integer :: timelevels
character(len=namlen) :: name
end type restart_var_t
integer, parameter :: restartvarcnt = 6+pcnst
type(var_desc_t) :: timedesc, tmass0desc
type(restart_var_t) :: restartvars(restartvarcnt)
logical :: restart_varlistw_initialized=.false.
logical :: restart_varlistr_initialized=.false.
CONTAINS
subroutine set_r_var(name, timelevels, index, v2, v3, v4, v5, v2r4, v3r4, v4r4, v5r4) 14,2
use abortutils
, only: endrun
character(len=*), intent(in) :: name
integer, intent(in) :: timelevels, index
real(r8), target, optional :: v2(:,:), v3(:,:,:), v4(:,:,:,:), v5(:,:,:,:,:)
real(r4), target, optional :: v2r4(:,:), v3r4(:,:,:), v4r4(:,:,:,:), v5r4(:,:,:,:,:)
restartvars(index)%name=name
restartvars(index)%timelevels = timelevels
if(present(v2)) then
restartvars(index)%ndims = 2
restartvars(index)%v2d => v2
else if(present(v3)) then
restartvars(index)%ndims = 3
restartvars(index)%v3d => v3
else if(present(v4)) then
restartvars(index)%ndims = 4
restartvars(index)%v4d => v4
else if(present(v5)) then
restartvars(index)%ndims = 5
restartvars(index)%v5d => v5
else if(present(v2r4)) then
restartvars(index)%ndims = 2
restartvars(index)%v2dr4 => v2r4
else if(present(v3r4)) then
restartvars(index)%ndims = 3
restartvars(index)%v3dr4 => v3r4
else if(present(v4r4)) then
restartvars(index)%ndims = 4
restartvars(index)%v4dr4 => v4r4
else if(present(v5r4)) then
restartvars(index)%ndims = 5
restartvars(index)%v5dr4 => v5r4
else
call endrun
('bad ndims in call to set_r_var')
end if
allocate(restartvars(index)%vdesc)
end subroutine set_r_var
subroutine init_restart_varlistw(dyn_out) 1,11
use abortutils
, only: endrun
use dyn_comp
, only : dyn_export_t
use constituents
, only : cnst_name
type(dyn_export_t) :: dyn_out
integer :: vcnt=1
integer :: i, m
! Should only be called once
if(restart_varlistw_initialized) return
restart_varlistw_initialized=.true.
call set_r_var
('PHIS', 1, vcnt, v2=dyn_out%phis)
vcnt=vcnt+1
call set_r_var
('U', 1, vcnt, v3=dyn_out%u3s)
vcnt=vcnt+1
call set_r_var
('V', 1, vcnt, v3=dyn_out%v3s)
vcnt=vcnt+1
call set_r_var
('DELP', 1, vcnt, v3=dyn_out%delp)
vcnt=vcnt+1
call set_r_var
('PT', 1, vcnt, v3=dyn_out%pt)
do m=1,pcnst
vcnt=vcnt+1
call set_r_var
(cnst_name(m), 1, vcnt, v3=dyn_out%tracer(:,:,:,m) )
end do
vcnt=vcnt+1
call set_r_var
('PS', 1, vcnt, v2=dyn_out%ps )
if(vcnt.ne.restartvarcnt) then
write(iulog,*) 'vcnt= ',vcnt, ' restartvarcnt=',restartvarcnt
call endrun
('bad restartvarcnt')
end if
end subroutine init_restart_varlistw
subroutine init_restart_varlistr(dyn_in) 1,11
use abortutils
, only: endrun
use dyn_comp
, only : dyn_import_t
use constituents
, only : cnst_name
type(dyn_import_t) :: dyn_in
integer :: vcnt=1
integer :: i, m
! Should only be called once
if(restart_varlistr_initialized) return
restart_varlistr_initialized=.true.
call set_r_var
('PHIS', 1, vcnt, v2=dyn_in%phis)
vcnt=vcnt+1
call set_r_var
('U', 1, vcnt, v3=dyn_in%u3s)
vcnt=vcnt+1
call set_r_var
('V', 1, vcnt, v3=dyn_in%v3s)
vcnt=vcnt+1
call set_r_var
('DELP', 1, vcnt, v3=dyn_in%delp)
vcnt=vcnt+1
call set_r_var
('PT', 1, vcnt, v3=dyn_in%pt)
do m=1,pcnst
vcnt=vcnt+1
call set_r_var
(cnst_name(m), 1, vcnt, v3=dyn_in%tracer(:,:,:,m) )
end do
vcnt=vcnt+1
call set_r_var
('PS', 1, vcnt, v2=dyn_in%ps )
if(vcnt.ne.restartvarcnt) then
write(iulog,*) 'vcnt= ',vcnt, ' restartvarcnt=',restartvarcnt
call endrun
('bad restartvarcnt')
end if
end subroutine init_restart_varlistr
subroutine init_restart_dynamics(File, hdimids, vdimids, dyn_out) 1,8
use dyn_comp
, only : dyn_export_t
use dyn_grid
, only : get_horiz_grid_dim_d
use constituents
, only: pcnst
!
! Input arguments
!
type(File_desc_t), intent(inout) :: File ! Unit number
type(Dyn_export_t), intent(in) :: dyn_out ! Not used in eul dycore
integer, intent(in) :: vdimids(2)
integer :: hdim1, hdim2
integer, pointer :: hdimids(:)
character(len=namlen) :: name
integer :: alldims(3), alldims2d(2)
integer :: i, ierr, timelevels
type(var_desc_t), pointer :: vdesc
integer :: ndims
call get_horiz_grid_dim_d
(hdim1, hdim2)
allocate(hdimids(2))
ierr = PIO_Def_Dim(File, 'lon',hdim1, hdimids(1))
ierr = PIO_Def_Dim(File, 'lat',hdim2, hdimids(2))
ierr = PIO_Def_Var(File, 'time', pio_double, timedesc)
ierr = PIO_Def_var(File, 'tmass0', pio_double, tmass0desc)
alldims(1:2) = hdimids(1:2)
alldims(3) = vdimids(1)
alldims2d(1:2) = hdimids(1:2)
call init_restart_varlistw
(dyn_out)
do i=1,restartvarcnt
call get_restart_var
(i, name, timelevels, ndims, vdesc)
if(timelevels>1) then
call endrun
('not expecting timelevels>1 in fv dycore')
else
if(ndims==1) then
! broken i think
ierr = PIO_Def_Var(File, name, pio_double, hdimids(2:2), vdesc)
else if(ndims==2) then
ierr = PIO_Def_Var(File, name, pio_double, alldims2d(1:2), vdesc)
else if(ndims==3) then
ierr = PIO_Def_Var(File, name, pio_double, alldims(1:3), vdesc)
end if
end if
end do
#if ( defined OFFLINE_DYN )
call write_met_restart
( File )
#endif
end subroutine init_restart_dynamics
subroutine write_restart_dynamics (File, dyn_out) 1,13
use cam_pio_utils
, only : pio_subsystem
use dyn_comp
, only : dyn_export_t
use time_manager
, only: get_curr_time, get_step_size
use pmgrid
, only: plon, plat
use dyn_grid
, only : get_horiz_grid_dim_d
use dyn_internal_state
, only : get_dyn_state
!
! Input arguments
!
type(File_desc_t), intent(inout) :: File ! Unit number
type(Dyn_export_t), intent(in) :: dyn_out ! Not used in eul dycore
!
! Local workspace
!
type(io_desc_t) :: iodesc2d, iodesc3d
integer :: ierr ! error status
integer :: ndcur, nscur
real(r8) :: time, dtime, mold(1), null(0)
integer :: i, s3d(1), s2d(1), ct
integer(kind=pio_offset) :: t
integer :: ndims, isize(1), timelevels
type(var_desc_t), pointer :: vdesc
integer :: hdim1, hdim2
integer, pointer :: ldof(:)
character(len=namlen) :: name
logical :: use_transfer
type (T_FVDYCORE_STATE), pointer :: dyn_state
!
! transfer is the fastest method to flatten the multidimensional arrays into the 1d needed by pio
! but it doesn't work correctly if the array is zero length...
use_transfer = .true.
#if ( defined SPMD )
dyn_state => get_dyn_state
()
if (dyn_state%grid%iam >= dyn_state%grid%npes_xy) then
use_transfer = .false.
end if
#endif
call get_curr_time
(ndcur, nscur)
dtime = get_step_size
()
call get_horiz_grid_dim_d
(hdim1, hdim2)
ldof => get_restart_decomp
(hdim1, hdim2, plev)
call pio_initdecomp(pio_subsystem, pio_double, (/hdim1, hdim2, plev/), ldof, iodesc3d)
deallocate(ldof)
ldof => get_restart_decomp
(hdim1, hdim2, 1)
call pio_initdecomp(pio_subsystem, pio_double, (/hdim1, hdim2/), ldof, iodesc2d)
deallocate(ldof)
ierr = pio_put_var(File, tmass0desc, (/tmass0/))
time = ndcur+(real(nscur,kind=r8))/86400_r8
ierr = pio_put_var(File,timedesc%varid, time)
do i=1,restartvarcnt
call get_restart_var
(i, name, timelevels, ndims, vdesc)
if(ndims==2) then
if(use_transfer) then
call pio_write_darray(File, vdesc, iodesc2d, transfer(restartvars(i)%v2d(:,:), mold), ierr)
else
call pio_write_darray(File, vdesc, iodesc2d, null, ierr)
end if
else if(ndims==3) then
if(use_transfer) then
call pio_write_darray(File, vdesc, iodesc3d, transfer(restartvars(i)%v3d(:,:,:), mold), ierr)
else
call pio_write_darray(File, vdesc, iodesc3d, null, ierr)
end if
end if
end do
call pio_freedecomp(File, iodesc2d)
call pio_freedecomp(File, iodesc3d)
end subroutine write_restart_dynamics
!
! Get the integer mapping of a variable in the dynamics decomp in memory.
! The canonical ordering is as on the file. A 0 value indicates that the
! variable is not on the file (eg halo or boundary values)
!
function get_restart_decomp(hdim1, hdim2, nlev) result(ldof) 4,5
use dyn_grid
, only : get_dyn_grid_parm
integer, intent(in) :: hdim1, hdim2, nlev
integer, pointer :: ldof(:)
integer :: i, k, j
integer :: lcnt
integer :: bfirst, blast, ncols
integer :: beglatxy, beglonxy, endlatxy, endlonxy
beglonxy = get_dyn_grid_parm
('beglonxy')
endlonxy = get_dyn_grid_parm
('endlonxy')
beglatxy = get_dyn_grid_parm
('beglatxy')
endlatxy = get_dyn_grid_parm
('endlatxy')
lcnt=(endlatxy-beglatxy+1)*nlev*(endlonxy-beglonxy+1)
allocate(ldof(lcnt))
lcnt=0
ldof(:)=0
do k=1,nlev
do j=beglatxy,endlatxy
do i=beglonxy, endlonxy
lcnt=lcnt+1
ldof(lcnt)=i+(j-(plat-hdim2+1))*hdim1+(k-1)*hdim1*hdim2
end do
end do
end do
end function get_restart_decomp
subroutine get_restart_var(i,name, timelevels, ndims, vdesc) 3
integer, intent(in) :: i
character(len=namlen), intent(out) :: name
integer, intent(out) :: ndims, timelevels
type(var_desc_t), pointer :: vdesc
name = restartvars(i)%name
timelevels = restartvars(i)%timelevels
ndims = restartvars(i)%ndims
if(.not.associated(restartvars(i)%vdesc)) then
allocate(restartvars(i)%vdesc)
end if
vdesc => restartvars(i)%vdesc
call pio_setframe(vdesc,int(-1,kind=pio_offset))
end subroutine get_restart_var
subroutine read_restart_dynamics(File, dyn_in, dyn_out, NLFileName) 1,16
use cam_pio_utils
, only : pio_subsystem
use physconst
, only: omega, rearth, &
rair, cpair, &
zvir, pi
use pmgrid
use dyn_comp
, only : dyn_init
use time_manager
, only: get_step_size
use hycoef
, only: hyai, hybi
use fv_control_mod
, only : kord, dyn_conservative, jord, iord, nsplit, nspltrac, nspltvrm, filtcw
use dyn_internal_state
, only : get_dyn_state
type(file_desc_t) :: File
type(dyn_export_t) :: dyn_out
type(dyn_import_t) :: dyn_in
character(len=*), intent(in) :: NLFileName
real(r8), allocatable :: ak(:), bk(:), tmp(:)
real(r8) :: dtime
integer :: dims3d(3)
integer :: ndims
integer :: ierr
character(len=namlen) :: name
integer, pointer :: ldof(:)
type (T_FVDYCORE_STATE), pointer :: dyn_state
integer :: timelevels ! not used in fv
type(var_desc_t), pointer :: vdesc
type(io_desc_t) :: iodesc2d, iodesc3d
integer :: s2d, s3d, i, k, ks
#if ( defined OFFLINE_DYN )
call read_met_restart
( File )
#endif
dtime = get_step_size
()
allocate( ak(plev+1) )
allocate( bk(plev+1) )
do k = 1, plev+1
ak(k) = hyai(k) * D1E5
bk(k) = hybi(k)
if( bk(k) == D0_0 ) ks = k-1
end do
!
! Initialize the dynamics
!
dyn_state => get_dyn_state
()
call dyn_init
( "NOT USED", "NOT_USED", plon, plat, plev, dtime, NSPLIT,&
NSPLTRAC, NSPLTVRM, IORD, JORD, KORD, 0, AK, BK, pcnst, pcnst, KS,& ! "0" temporary
filtcw, beglonxy, endlonxy, beglatxy, endlatxy, &
beglat, endlat, beglev, endlev, pi, &
omega, cpair, rair, &
rearth, rair/cpair, &
zvir, (/ npr_y, npr_z, nprxy_x, nprxy_y /), &
twod_decomp, mod_geopk, mod_transpose, mod_gatscat, &
dyn_conservative, dyn_state, dyn_in, dyn_out, NLFileName )
deallocate( ak, bk )
dims3d(1)=(endlonxy-beglonxy+1)
dims3d(2)=(endlatxy-beglatxy+1)
dims3d(3)=plev
s2d = dims3d(1)*dims3d(2)
s3d = s2d*dims3d(3)
allocate(tmp(s3d))
call init_restart_varlistr
(dyn_in)
ierr = PIO_Inq_varid(File, 'tmass0', tmass0desc)
ierr = pio_get_var(File, tmass0desc, tmass0)
ldof => get_restart_decomp
(plon, plat, plev)
call pio_initdecomp(pio_subsystem, pio_double, (/plon, plat, plev/), ldof, iodesc3d)
deallocate(ldof)
ldof => get_restart_decomp
(plon, plat, 1)
call pio_initdecomp(pio_subsystem, pio_double, (/plon, plat/), ldof, iodesc2d)
deallocate(ldof)
do i=1,restartvarcnt
call get_restart_var
(i, name, timelevels, ndims, vdesc)
ierr = PIO_Inq_varid(File, name, vdesc)
if(ndims==2) then
call pio_read_darray(File, vdesc, iodesc2d, tmp(1:s2d), ierr)
restartvars(i)%v2d(:,:) = reshape(tmp(1:s2d), dims3d(1:2))
else if(ndims==3) then
call pio_read_darray(File, restartvars(i)%vdesc, iodesc3d, tmp(1:s3d), ierr)
restartvars(i)%v3d(:,:,:) = reshape(tmp(1:s3d), dims3d)
end if
end do
deallocate(tmp)
call pio_freedecomp(File, iodesc2d)
call pio_freedecomp(File, iodesc3d)
end subroutine read_restart_dynamics
end module restart_dynamics