#include <misc.h>
#include <preproc.h>
module time_manager 160,10
#if (defined OFFLINE) || (defined COUP_CSM)
!---------------------------------------------------------------------------
!BOP
!
! !MODULE: time_manager
!
! !DESCRIPTION:
! Provides generic interface to time/calendar management routines.
!
! !USES:
use shr_kind_mod
, only: r8 => shr_kind_r8
use ESMF_TimeMgmtMod, only: &
esmf_errhandlersettype, esmf_err_return, esmf_errprint, esmf_success, &
esmf_time, esmf_timeinit, esmf_timeget, esmf_timegetdays, &
esmf_timeincrement, esmf_timedecrement, &
esmf_date, esmf_dateinit, esmf_gregorian, esmf_no_leap, esmf_dateget, &
esmf_dateincrementsec, esmf_dateincrementday, esmf_datedecrement, &
esmf_datediff, esmf_dategetfltdayofyear, &
esmf_timemgr, esmf_timemgrinit, esmf_timemgradvance, &
esmf_timemgrgetnstep, esmf_timemgrgetstepsize, &
esmf_timemgrgetstartdate, esmf_timemgrgetbasedate, &
esmf_timemgrlaststep, esmf_timemgrgetcurrdate, &
esmf_timemgrgetprevdate, esmf_dateislater, &
esmf_timemgrrestartwrite, esmf_timemgrrestartread
#if (defined SPMD)
use spmdMod
, only: masterproc, mpicom, MPI_INTEGER
#else
use spmdMod
, only: masterproc
#endif
use abortutils
, only: endrun
!
! !PUBLIC TYPES:
implicit none
private
save
!
! !PUBLIC MEMBER FUNCTIONS:
public :: &
timemgr_init, &! time manager initialization
advance_timestep, &! increment timestep number
get_step_size, &! return step size in seconds
get_nstep, &! return timestep number
get_curr_date, &! return date components at end of current timestep
get_prev_date, &! return date components at beginning of current timestep
get_start_date, &! return date components of the start date
get_ref_date, &! return date components of the reference date
get_curr_time, &! return components of elapsed time since reference date
get_curr_calday, &! return calendar day at end of current timestep
is_first_step, &! return true on first step of initial run
is_first_restart_step, &! return true on first step of restart or branch run
is_end_curr_day, &! return true on last timestep in current day
is_end_curr_month, &! return true on last timestep in current month
is_last_step, &! return true on last timestep
timemgr_write_restart, &! write info to file needed to restart the time manager
timemgr_read_restart, &! read info from file needed to restart the time manager
timemgr_restart ! restart the time manager
!
! !PUBLIC DATA MEMBERS:
character(len=32), public :: &
calendar = 'NO_LEAP' ! Calendar in date calculations ('NO_LEAP' or 'GREGORIAN')
integer, parameter :: uninit_int = -999999999 !This is private to this module
integer, public :: &
dtime = uninit_int, &! timestep in seconds
nestep = uninit_int, &! final timestep (or day if negative) number
nelapse = uninit_int, &! number of timesteps (or days if negative) to extend a run
start_ymd = uninit_int, &! starting date for run in yearmmdd format
start_tod = 0, &! starting time of day for run in seconds
stop_ymd = uninit_int, &! stopping date for run in yearmmdd format
stop_tod = 0, &! stopping time of day for run in seconds
ref_ymd = uninit_int, &! reference date for time coordinate in yearmmdd format
ref_tod = 0 ! reference time of day for time coordinate in seconds
!
! !REVISION HISTORY:
!
!EOP
!
! Private module data
type(esmf_timemgr) :: tm_id ! time manager ID
integer ::& ! Data required to restart time manager:
rst_type = uninit_int, &! calendar type
rst_nstep = uninit_int, &! current step number
rst_step_days = uninit_int, &! days component of timestep size
rst_step_sec = uninit_int, &! seconds component of timestep size
rst_start_ymd = uninit_int, &! start date
rst_start_tod = uninit_int, &! start time of day
rst_stop_ymd = uninit_int, &! stop date
rst_stop_tod = uninit_int, &! stop time of day
rst_ref_ymd = uninit_int, &! reference date
rst_ref_tod = uninit_int, &! reference time of day
rst_curr_ymd = uninit_int, &! current date
rst_curr_tod = uninit_int ! current time of day
logical :: first_restart_step = .false. ! true for first step of a restart or branch run
!============================================================================
contains
!============================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: timemgr_init
!
! !INTERFACE:
subroutine timemgr_init() 2,35
!
! !DESCRIPTION:
! Initialize the ESMF time manager.
!
! NOTE - This assumes that the namelist variables
! have been set before this routine is called.
!
! !ARGUMENTS:
implicit none
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'timemgr_init'
character(len=len(calendar)) :: cal
integer :: rc ! return code
integer :: cal_type ! calendar type
type(esmf_time) :: step_size ! timestep size
type(esmf_date) :: start_date ! start date for run
type(esmf_date) :: stop_date ! stop date for run
type(esmf_date) :: ref_date ! reference date for time coordinate
! Some backwards compatibility stuff:
type(esmf_time) :: diff
integer :: ntspday, ndays, nsecs
logical :: islater
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
! Initialize error handling.
call esmf_errhandlersettype(esmf_err_return)
! Initialize calendar type.
cal = to_upper
(calendar)
if ( trim(cal) == 'NO_LEAP' ) then
cal_type = esmf_no_leap
else if ( trim(cal) == 'GREGORIAN' ) then
cal_type = esmf_gregorian
else
write(6,*)sub,': unrecognized calendar specified: ',calendar
call endrun
end if
! Initialize timestep size.
if ( dtime == uninit_int ) then
write(6,*)sub,': dtime must be specified in namelist'
call endrun
end if
if ( mod(86400,dtime) /=0 ) then
write(6,*)sub,': timestep must divide evenly into 1 day'
call endrun
end if
step_size = esmf_timeinit(0, dtime, rc)
call chkrc
(rc, sub//': error return from esmf_timeinit: setting step_size')
! Initialize start date.
if ( start_ymd == uninit_int ) then
write(6,*)sub,': start_ymd must be specified in namelist'
call endrun
end if
if ( start_tod == uninit_int ) then
write(6,*)sub,': start_tod must be specified in namelist'
call endrun
end if
start_date = esmf_dateinit(cal_type, start_ymd, start_tod, rc)
call chkrc
(rc, sub//': error return from esmf_dateinit: setting start_date')
! Initialize reference date for time coordinate.
if ( ref_ymd /= uninit_int ) then
ref_date = esmf_dateinit(cal_type, ref_ymd, ref_tod, rc)
else
ref_date = esmf_dateinit(start_date, rc)
end if
call chkrc
(rc, sub//': error return from esmf_dateinit: setting ref_date')
! Initialize stop date.
if ( stop_ymd /= uninit_int ) then
stop_date = esmf_dateinit(cal_type, stop_ymd, stop_tod, rc)
else if ( nestep /= uninit_int ) then
if ( nestep >= 0 ) then
stop_date = esmf_dateincrementsec(start_date, dtime*nestep, rc)
else
stop_date = esmf_dateincrementday(start_date, -nestep, rc)
end if
else if ( nelapse /= uninit_int ) then
if ( nelapse >= 0 ) then
stop_date = esmf_dateincrementsec(start_date, dtime*nelapse, rc)
else
stop_date = esmf_dateincrementday(start_date, -nelapse, rc)
end if
else
write(6,*)sub,': Must specify one of stop_ymd, nestep, or nelapse'
call endrun
end if
call chkrc
(rc, sub//': error return setting stop_date')
! Initialize a time manager.
tm_id = esmf_timemgrinit(step_size, start_date, stop_date, ref_date, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrinit')
! Calculation of ending timestep number (nestep) assumes a constant stepsize.
ntspday = 86400/dtime
diff = esmf_timeinit()
call esmf_datediff(start_date, stop_date, diff, islater, rc)
call chkrc
(rc, sub//': error return from esmf_datediff calculating nestep')
call esmf_timeget(diff, ndays, nsecs, rc)
call chkrc
(rc, sub//': error return from esmf_timeget calculating nestep')
nestep = ntspday*ndays + nsecs/dtime
if ( mod(nsecs,dtime) /= 0 ) nestep = nestep + 1
! Print configuration summary to log file (stdout).
if (masterproc) then
call timemgr_print
()
end if
end subroutine timemgr_init
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: timemgr_restart
!
! !INTERFACE:
subroutine timemgr_restart() 3,42
!
! !DESCRIPTION:
! Restart the ESMF time manager.
!
! NOTE - Assumptions:
! 1) The namelist variables have been set before this routine is called. The
! stop date is the only thing that can be changed by the user on restart.
! 2) Restart data have been read on the master process before this routine
! is called.
! (timemgr_read_restart called from control/restart.F90::read_restart)
!
! !ARGUMENTS:
implicit none
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'timemgr_restart'
integer :: rc ! return code
type(esmf_date) :: start_date ! start date for run
type(esmf_date) :: stop_date ! stop date for run
type(esmf_date) :: curr_date ! date of data in restart file
logical :: islater
integer :: ymd, tod
integer :: ier !error code
! Some backwards compatibility stuff:
type(esmf_time) :: diff
integer :: ntspday, ndays, nsecs
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
#if ( defined SPMD )
call mpi_bcast(rst_type, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_nstep, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_step_days, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_step_sec, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_start_ymd, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_start_tod, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_stop_ymd, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_stop_tod, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_ref_ymd, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_ref_tod, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_curr_ymd, 1, MPI_INTEGER, 0, mpicom, ier)
call mpi_bcast(rst_curr_tod, 1, MPI_INTEGER, 0, mpicom, ier)
#endif
! Initialize error handling.
call esmf_errhandlersettype(esmf_err_return)
! Initialize calendar type.
if ( rst_type == esmf_no_leap ) then
calendar = 'NO_LEAP'
else if ( rst_type == esmf_gregorian ) then
calendar = 'GREGORIAN'
else
write(6,*)sub,': unrecognized calendar type in restart file: ',rst_type
call endrun
end if
! Initialize the timestep.
dtime = rst_step_days*86400 + rst_step_sec
! Initialize start date.
start_date = esmf_dateinit(rst_type, rst_start_ymd, rst_start_tod, rc)
call chkrc
(rc, sub//': error return from esmf_dateinit: setting start_date')
! Initialize current date.
curr_date = esmf_dateinit(rst_type, rst_curr_ymd, rst_curr_tod, rc)
call chkrc
(rc, sub//': error return from esmf_dateinit: setting curr_date')
! Initialize stop date.
if ( stop_ymd /= uninit_int ) then
stop_date = esmf_dateinit(rst_type, stop_ymd, stop_tod, rc)
else if ( nestep /= uninit_int ) then
if ( nestep >= 0 ) then
stop_date = esmf_dateincrementsec(start_date, dtime*nestep, rc)
else
stop_date = esmf_dateincrementday(start_date, -nestep, rc)
end if
else if ( nelapse /= uninit_int ) then
if ( nelapse >= 0 ) then
stop_date = esmf_dateincrementsec(curr_date, dtime*nelapse, rc)
else
stop_date = esmf_dateincrementday(curr_date, -nelapse, rc)
end if
else
stop_date = esmf_dateinit(rst_type, rst_stop_ymd, rst_stop_tod, rc)
end if
call chkrc
(rc, sub//': error return setting stop_date')
! Check that stop date is later than current date.
call esmf_dateislater(curr_date, stop_date, islater, rc)
call chkrc
(rc, sub//': error return from esmf_dateislater: comparing start and stop dates')
if ( .not. islater ) then
write(6,*)sub,': stop date must be specified later than current date: '
call esmf_dateget(curr_date, ymd, tod)
write(6,*)' Current date (ymd tod): ', ymd, tod
call esmf_dateget(stop_date, ymd, tod)
write(6,*)' Stop date (ymd tod): ', ymd, tod
call endrun
end if
call esmf_dateget(stop_date, rst_stop_ymd, rst_stop_tod)
! Restart a time manager.
tm_id = esmf_timemgrrestartread(rst_type, rst_nstep, rst_step_days, rst_step_sec, rst_start_ymd, &
rst_start_tod, rst_stop_ymd, rst_stop_tod, rst_ref_ymd, rst_ref_tod, &
rst_curr_ymd, rst_curr_tod, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrrestartread')
! Advance the timestep. Data from the restart file corresponds to the
! last timestep of the previous run.
call advance_timestep
()
! Set flag that this is the first timestep of the restart run.
first_restart_step = .true.
! Set variables from "comtim.h interface" for backwards compatibility.
! Calculation of ending timestep number (nestep) assumes a constant stepsize.
ntspday = 86400/dtime
diff = esmf_timeinit()
call esmf_datediff(start_date, stop_date, diff, islater, rc)
call chkrc
(rc, sub//': error return from esmf_datediff calculating nestep')
call esmf_timeget(diff, ndays, nsecs, rc)
call chkrc
(rc, sub//': error return from esmf_timeget calculating nestep')
nestep = ntspday*ndays + nsecs/dtime
if ( mod(nsecs,dtime) /= 0 ) nestep = nestep + 1
! Print configuration summary to log file (stdout).
if (masterproc) then
call timemgr_print
()
end if
end subroutine timemgr_restart
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: timemgr_print
!
! !INTERFACE:
subroutine timemgr_print() 4,2
!
! !DESCRIPTION:
! Print out ESMF time manager information.
!
! !ARGUMENTS:
implicit none
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'timemgr_print'
integer :: rc
integer :: day, sec, ymd, tod
character(len=32) :: cal ! Calendar to use in date calculations.
integer ::& ! Data required to restart time manager:
type = uninit_int, &! calendar type
nstep = uninit_int, &! current step number
step_days = uninit_int, &! days component of timestep size
step_sec = uninit_int, &! seconds component of timestep size
start_ymd = uninit_int, &! start date
start_tod = uninit_int, &! start time of day
stop_ymd = uninit_int, &! stop date
stop_tod = uninit_int, &! stop time of day
ref_ymd = uninit_int, &! reference date
ref_tod = uninit_int, &! reference time of day
curr_ymd = uninit_int, &! current date
curr_tod = uninit_int ! current time of day
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
call esmf_timemgrrestartwrite(tm_id, type, nstep, step_days, step_sec, &
start_ymd, start_tod, stop_ymd, stop_tod, ref_ymd, &
ref_tod, curr_ymd, curr_tod, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrrestartwrite')
write(6,*)' ********** Time Manager Configuration **********'
if ( type == esmf_no_leap ) then
cal = 'NO_LEAP'
else if ( type == esmf_gregorian ) then
cal = 'GREGORIAN'
end if
write(6,*)' Calendar type: ',trim(cal)
write(6,*)' Timestep size (seconds): ', (step_days*86400 + step_sec)
write(6,*)' Start date (ymd tod): ', start_ymd, start_tod
write(6,*)' Stop date (ymd tod): ', stop_ymd, stop_tod
write(6,*)' Reference date (ymd tod): ', ref_ymd, ref_tod
write(6,*)' Current step number: ', nstep
write(6,*)' Ending step number: ', nestep
write(6,*)' Current date (ymd tod): ', curr_ymd, curr_tod
write(6,*)' ************************************************'
end subroutine timemgr_print
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: advance_timestep
!
! !INTERFACE:
subroutine advance_timestep() 7,2
!
! !DESCRIPTION:
! Increment the timestep number.
!
! !ARGUMENTS:
implicit none
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'advance_timestep'
integer :: rc
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
call esmf_timemgradvance(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgradvance')
! Set first step flag off.
first_restart_step = .false.
end subroutine advance_timestep
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: get_step_size
!
! !INTERFACE:
function get_step_size() 65,2
!
! !DESCRIPTION:
! Return the step size in seconds.
!
! !ARGUMENTS:
implicit none
!
! !RETURN VALUE:
integer :: get_step_size
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'get_step_size'
integer :: days, seconds
integer :: rc
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
call esmf_timemgrgetstepsize(tm_id, days, seconds, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetstepsize')
get_step_size = 86400*days + seconds
end function get_step_size
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: get_nstep
!
! !INTERFACE:
function get_nstep() 59,2
!
! !DESCRIPTION:
! Return the timestep number.
!
! !ARGUMENTS:
implicit none
!
! !RETURN VALUE:
integer :: get_nstep
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'get_nstep'
integer :: rc
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
get_nstep = esmf_timemgrgetnstep(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetnstep')
end function get_nstep
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: get_curr_date
!
! !INTERFACE:
subroutine get_curr_date(yr, mon, day, tod, offset) 70,10
!
! !DESCRIPTION:
! Return date components valid at end of current timestep with an optional
! offset (positive or negative) in seconds.
!
! !ARGUMENTS:
implicit none
integer, intent(out) ::&
yr, &! year
mon, &! month
day, &! day of month
tod ! time of day (seconds past 0Z)
integer, optional, intent(in) :: offset ! Offset from current time in
! seconds. Positive for future
! times, negative for previous
! times.
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'get_curr_date'
integer :: rc
type(esmf_date) :: date
type(esmf_time) :: off
integer :: ymd
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
date = esmf_timemgrgetcurrdate(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetcurrdate')
if (present(offset)) then
if (offset > 0) then
date = esmf_dateincrementsec(date, offset, rc)
call chkrc
(rc, sub//': error incrementing current date')
else if (offset < 0) then
off = esmf_timeinit(0, -offset, rc)
call chkrc
(rc, sub//': error setting offset time type')
date = esmf_datedecrement(date, off, rc)
call chkrc
(rc, sub//': error decrementing current date')
end if
end if
call esmf_dateget(date, ymd, tod, rc)
call chkrc
(rc, sub//': error return from esmf_dateget')
yr = ymd/10000
mon = mod(ymd, 10000) / 100
day = mod(ymd, 100)
end subroutine get_curr_date
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: get_prev_date
!
! !INTERFACE:
subroutine get_prev_date(yr, mon, day, tod) 8,4
!
! !DESCRIPTION:
! Return date components valid at beginning of current timestep.
!
! !ARGUMENTS:
implicit none
integer, intent(out) ::&
yr, &! year
mon, &! month
day, &! day of month
tod ! time of day (seconds past 0Z)
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'get_prev_date'
integer :: rc
type(esmf_date) :: date
integer :: ymd
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
date = esmf_timemgrgetprevdate(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetprevdate')
call esmf_dateget(date, ymd, tod, rc)
call chkrc
(rc, sub//': error return from esmf_dateget')
yr = ymd/10000
mon = mod(ymd, 10000) / 100
day = mod(ymd, 100)
end subroutine get_prev_date
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: get_start_date
!
! !INTERFACE:
subroutine get_start_date(yr, mon, day, tod) 1,4
!
! !DESCRIPTION:
! Return date components valid at beginning of initial run.
!
! !ARGUMENTS:
implicit none
integer, intent(out) ::&
yr, &! year
mon, &! month
day, &! day of month
tod ! time of day (seconds past 0Z)
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'get_start_date'
integer :: rc
type(esmf_date) :: date
integer :: ymd
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
date = esmf_timemgrgetstartdate(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetstartdate')
call esmf_dateget(date, ymd, tod, rc)
call chkrc
(rc, sub//': error return from esmf_dateget')
yr = ymd/10000
mon = mod(ymd, 10000) / 100
day = mod(ymd, 100)
end subroutine get_start_date
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: get_ref_date
!
! !INTERFACE:
subroutine get_ref_date(yr, mon, day, tod) 5,4
!
! !DESCRIPTION:
! Return date components of the reference date.
!
! !ARGUMENTS:
implicit none
integer, intent(out) ::&
yr, &! year
mon, &! month
day, &! day of month
tod ! time of day (seconds past 0Z)
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'get_ref_date'
integer :: rc
type(esmf_date) :: date
integer :: ymd
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
date = esmf_timemgrgetbasedate(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetbasedate')
call esmf_dateget(date, ymd, tod, rc)
call chkrc
(rc, sub//': error return from esmf_dateget')
yr = ymd/10000
mon = mod(ymd, 10000) / 100
day = mod(ymd, 100)
end subroutine get_ref_date
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: get_curr_time
!
! !INTERFACE:
subroutine get_curr_time(days, seconds) 7,8
!
! !DESCRIPTION:
! Return time components valid at end of current timestep. Current time
! is the time interval between the current date and the reference date.
!
! !ARGUMENTS:
implicit none
integer, intent(out) ::&
days, &! number of whole days in time interval
seconds ! remaining seconds in time interval
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'get_curr_time'
integer :: rc
type(esmf_date) :: cdate, rdate
type(esmf_time) :: diff
logical :: islater
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
cdate = esmf_timemgrgetcurrdate(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetcurrdate')
rdate = esmf_timemgrgetbasedate(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetbasedate')
call esmf_datediff(rdate, cdate, diff, islater, rc)
call chkrc
(rc, sub//': error return from esmf_datediff')
call esmf_timeget(diff, days, seconds, rc)
call chkrc
(rc, sub//': error return from esmf_timeget')
end subroutine get_curr_time
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: get_curr_calday
!
! !INTERFACE:
function get_curr_calday(offset) 36,12
!
! !DESCRIPTION:
! Return calendar day at end of current timestep with optional offset.
! Calendar day 1.0 = 0Z on Jan 1.
!
! !ARGUMENTS:
implicit none
integer, optional, intent(in) :: offset ! Offset from current time in
! seconds. Positive for future
! times, negative for previous
! times.
!
! !RETURN VALUE:
real(r8) :: get_curr_calday
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'get_curr_calday'
integer :: rc
type(esmf_date) :: date
type(esmf_time) :: off
integer :: ymd, tod
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
date = esmf_timemgrgetcurrdate(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetcurrdate')
if (present(offset)) then
if (offset > 0) then
date = esmf_dateincrementsec(date, offset, rc)
call chkrc
(rc, sub//': error incrementing current date')
else if (offset < 0) then
off = esmf_timeinit(0, -offset, rc)
call chkrc
(rc, sub//': error setting offset time type')
date = esmf_datedecrement(date, off, rc)
call chkrc
(rc, sub//': error decrementing current date')
end if
end if
get_curr_calday = esmf_dategetfltdayofyear(date, rc)
call chkrc
(rc, sub//': error return from esmf_dategetfltdayofyear')
end function get_curr_calday
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: is_end_curr_day
!
! !INTERFACE:
function is_end_curr_day() 5,2
!
! !DESCRIPTION:
! Return true if current timestep is last timestep in current day.
!
! !ARGUMENTS:
implicit none
!
! !RETURN VALUE:
logical :: is_end_curr_day
!
! !LOCAL VARIABLES:
integer ::&
yr, &! year
mon, &! month
day, &! day of month
tod ! time of day (seconds past 0Z)
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
call get_curr_date
(yr, mon, day, tod)
is_end_curr_day = (tod == 0)
end function is_end_curr_day
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: is_end_curr_month
!
! !INTERFACE:
function is_end_curr_month(),2
!
! !DESCRIPTION:
! Return true if current timestep is last timestep in current month.
!
! !ARGUMENTS:
implicit none
!
! !RETURN VALUE:
logical :: is_end_curr_month
!
! !LOCAL VARIABLES:
integer ::&
yr, &! year
mon, &! month
day, &! day of month
tod ! time of day (seconds past 0Z)
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
call get_curr_date
(yr, mon, day, tod)
is_end_curr_month = (day == 1 .and. tod == 0)
end function is_end_curr_month
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: is_first_step
!
! !INTERFACE:
function is_first_step() 22,2
!
! !DESCRIPTION:
! Return true on first step of initial run only.
!
! !ARGUMENTS:
implicit none
!
! !RETURN VALUE:
logical :: is_first_step
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'is_first_step'
integer :: rc
integer :: nstep
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
nstep = esmf_timemgrgetnstep(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrgetnstep')
is_first_step = (nstep == 0)
end function is_first_step
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: is_first_restart_step
!
! !INTERFACE:
function is_first_restart_step() 1
!
! !DESCRIPTION:
! Return true on first step of restart run only.
!
! !ARGUMENTS:
implicit none
!
! !RETURN VALUE:
logical :: is_first_restart_step
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
is_first_restart_step = first_restart_step
end function is_first_restart_step
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: is_last_step
!
! !INTERFACE:
function is_last_step() 6,2
!
! !DESCRIPTION:
! Return true on last timestep.
!
! !ARGUMENTS:
implicit none
!
! !RETURN VALUE:
logical :: is_last_step
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'is_last_step'
integer :: rc
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
is_last_step = esmf_timemgrlaststep(tm_id, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrlaststep')
end function is_last_step
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: timemgr_write_restart
!
! !INTERFACE:
subroutine timemgr_write_restart(ftn_unit) 3,5
!
! !DESCRIPTION:
! Write information needed on restart to a binary Fortran file. It is
! assumed that this routine is called only from the master proc if in
! SPMD mode.
!
! !ARGUMENTS:
implicit none
integer, intent(in) :: ftn_unit ! Fortran unit number
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'timemgr_write_restart'
integer :: rc ! return code
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
call esmf_timemgrrestartwrite(tm_id, rst_type, rst_nstep, rst_step_days, rst_step_sec, &
rst_start_ymd, rst_start_tod, rst_stop_ymd, rst_stop_tod, rst_ref_ymd, &
rst_ref_tod, rst_curr_ymd, rst_curr_tod, rc)
call chkrc
(rc, sub//': error return from esmf_timemgrrestartwrite')
write(ftn_unit, iostat=rc) rst_type, rst_nstep, rst_step_days, rst_step_sec, &
rst_start_ymd, rst_start_tod, rst_stop_ymd, rst_stop_tod, rst_ref_ymd, &
rst_ref_tod, rst_curr_ymd, rst_curr_tod
if (rc /= 0 ) then
write (6,*) 'WRITE iostat= ',rc,' on i/o unit = ',ftn_unit
call endrun
end if
end subroutine timemgr_write_restart
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: timemgr_read_restart
!
! !INTERFACE:
subroutine timemgr_read_restart(ftn_unit) 3,2
!
! !DESCRIPTION:
! Read information needed on restart from a binary Fortran file. It is
! assumed that this routine is called only from the master proc if in
! SPMD mode.
!
! !ARGUMENTS:
implicit none
integer, intent(in) :: ftn_unit ! Fortran unit number
!
! !LOCAL VARIABLES:
character(len=*), parameter :: sub = 'timemgr_read_restart'
integer :: rc ! return code
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
read(ftn_unit, iostat=rc) rst_type, rst_nstep, rst_step_days, rst_step_sec, &
rst_start_ymd, rst_start_tod, rst_stop_ymd, rst_stop_tod, rst_ref_ymd, &
rst_ref_tod, rst_curr_ymd, rst_curr_tod
if (rc /= 0 ) then
write (6,*) 'READ iostat= ',rc,' on i/o unit = ',ftn_unit
call endrun
end if
end subroutine timemgr_read_restart
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: chkrc
!
! !INTERFACE:
subroutine chkrc(rc, mes) 111,2
!
! !DESCRIPTION:
! Check time manager return code. If an error occurs, print the appropriate
! error message and abort the run.
!
! !ARGUMENTS:
implicit none
integer, intent(in) :: rc ! return code from time management
! library
character(len=*), intent(in) :: mes ! error message
!
! !REVISION HISTORY:
!
!EOP
!----------------------------------------------------------------------------
if ( rc == esmf_success ) return
write(6,*) mes
call esmf_errprint(rc)
call endrun
end subroutine chkrc
!=========================================================================================
!---------------------------------------------------------------------------
!BOP
!
! !IROUTINE: to_upper
!
! !INTERFACE:
function to_upper(str) 13,2
!
! !DESCRIPTION:
! Convert character string to upper case. Use achar and iachar intrinsics
! to ensure use of ascii collating sequence.
!
! !ARGUMENTS:
implicit none
character(len=*), intent(in) :: str ! String to convert to upper case
!
! !RETURN VALUE:
character(len=len(str)) :: to_upper
!
! !LOCAL VARIABLES:
integer :: i ! Index
integer :: aseq ! ascii collating sequence
character(len=1) :: ctmp ! Character temporary
!
! !REVISION HISTORY:
! Author: B. Eaton, July 2001
!
!EOP
!----------------------------------------------------------------------------
do i = 1, len(str)
ctmp = str(i:i)
aseq = iachar(ctmp)
if ( aseq >= 97 .and. aseq <= 122 ) ctmp = achar(aseq - 32)
to_upper
(i:i) = ctmp
end do
end function to_upper
!=========================================================================================
#endif
end module time_manager