1626 lines
65 KiB
Fortran
1626 lines
65 KiB
Fortran
module clm_time_manager
|
|
|
|
use shr_kind_mod, only: r8 => shr_kind_r8
|
|
use shr_sys_mod , only: shr_sys_abort
|
|
use spmdMod , only: masterproc
|
|
use clm_varctl , only: iulog
|
|
use clm_varcon , only: isecspday
|
|
use ESMF
|
|
|
|
implicit none
|
|
private
|
|
|
|
! Public methods
|
|
|
|
public ::&
|
|
get_timemgr_defaults, &! get startup default values
|
|
set_timemgr_init, &! setup startup values
|
|
timemgr_init, &! time manager initialization
|
|
timemgr_restart_io, &! read/write time manager restart info and restart time manager
|
|
timemgr_restart, &! restart the time manager using info from timemgr_restart
|
|
timemgr_datediff, &! calculate difference between two time instants
|
|
advance_timestep, &! increment timestep number
|
|
get_clock, &! get the clock from the time-manager
|
|
get_curr_ESMF_Time, &! get current time in terms of the ESMF_Time
|
|
get_step_size, &! return step size in seconds
|
|
get_rad_step_size, &! return radiation 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 components of the start date
|
|
get_driver_start_ymd, &! return year/month/day (as integer in YYYYMMDD format) of driver start date
|
|
get_ref_date, &! return components of the reference date
|
|
get_perp_date, &! return components of the perpetual date, and current time of day
|
|
get_curr_time, &! return components of elapsed time since reference date at end of current timestep
|
|
get_prev_time, &! return components of elapsed time since reference date at beg of current timestep
|
|
get_curr_calday, &! return calendar day at end of current timestep
|
|
get_calday, &! return calendar day from input date
|
|
get_calendar, &! return calendar
|
|
get_days_per_year, &! return the days per year for current year
|
|
get_curr_yearfrac, &! return the fractional position in the current year
|
|
get_rest_date, &! return the date from the restart file
|
|
set_nextsw_cday, &! set the next radiation calendar day
|
|
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_beg_curr_day, &! return true on first timestep in current day
|
|
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
|
|
is_perpetual, &! return true if perpetual calendar is in use
|
|
is_restart, &! return true if this is a restart run
|
|
update_rad_dtime ! track radiation interval via nstep
|
|
|
|
! Public parameter data
|
|
character(len=*), public, parameter :: NO_LEAP_C = 'NO_LEAP'
|
|
character(len=*), public, parameter :: GREGORIAN_C = 'GREGORIAN'
|
|
|
|
! Private module data
|
|
|
|
! Private data for input
|
|
|
|
character(len=ESMF_MAXSTR), save ::&
|
|
calendar = NO_LEAP_C ! Calendar to use in date calculations.
|
|
integer, parameter :: uninit_int = -999999999
|
|
real(r8), parameter :: uninit_r8 = -999999999.0
|
|
|
|
! Input
|
|
integer, save ::&
|
|
dtime = uninit_int, &! timestep in seconds
|
|
dtime_rad = uninit_int, &! radiation interval in seconds
|
|
nstep_rad_prev = uninit_int ! radiation interval in seconds
|
|
|
|
! Input from CESM driver
|
|
integer, save ::&
|
|
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
|
|
type(ESMF_Calendar), target, save :: tm_cal ! calendar
|
|
type(ESMF_Clock), save :: tm_clock ! model clock
|
|
type(ESMF_Time), save :: tm_perp_date ! perpetual date
|
|
|
|
! Data required to restart time manager:
|
|
integer, save :: rst_step_sec = uninit_int ! timestep size seconds
|
|
integer, save :: rst_start_ymd = uninit_int ! start date
|
|
integer, save :: rst_start_tod = uninit_int ! start time of day
|
|
integer, save :: rst_ref_ymd = uninit_int ! reference date
|
|
integer, save :: rst_ref_tod = uninit_int ! reference time of day
|
|
integer, save :: rst_curr_ymd = uninit_int ! current date
|
|
integer, save :: rst_curr_tod = uninit_int ! current time of day
|
|
|
|
integer, save :: rst_nstep_rad_prev ! nstep of previous radiation call
|
|
integer, save :: perpetual_ymd = uninit_int ! Perpetual calendar date (YYYYMMDD)
|
|
logical, save :: tm_first_restart_step = .false. ! true for first step of a restart or branch run
|
|
logical, save :: tm_perp_calendar = .false. ! true when using perpetual calendar
|
|
logical, save :: timemgr_set = .false. ! true when timemgr initialized
|
|
integer, save :: nestep = uninit_int ! ending time-step
|
|
!
|
|
! Next short-wave radiation calendar day
|
|
!
|
|
real(r8) :: nextsw_cday = uninit_r8 ! calday from clock of next radiation computation
|
|
|
|
! Private module methods
|
|
|
|
private :: timemgr_spmdbcast
|
|
private :: init_calendar
|
|
private :: init_clock
|
|
private :: calc_nestep
|
|
private :: timemgr_print
|
|
private :: TimeGetymd
|
|
|
|
!=========================================================================================
|
|
contains
|
|
!=========================================================================================
|
|
|
|
subroutine get_timemgr_defaults( calendar_out, start_ymd_out, start_tod_out, ref_ymd_out, &
|
|
ref_tod_out, stop_ymd_out, stop_tod_out, nelapse_out, &
|
|
dtime_out )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! get time manager startup default values
|
|
!
|
|
! Arguments
|
|
character(len=*), optional, intent(OUT) :: calendar_out ! Calendar type
|
|
integer , optional, intent(OUT) :: nelapse_out ! Number of step (or days) to advance
|
|
integer , optional, intent(OUT) :: start_ymd_out ! Start date (YYYYMMDD)
|
|
integer , optional, intent(OUT) :: start_tod_out ! Start time of day (sec)
|
|
integer , optional, intent(OUT) :: ref_ymd_out ! Reference date (YYYYMMDD)
|
|
integer , optional, intent(OUT) :: ref_tod_out ! Reference time of day (sec)
|
|
integer , optional, intent(OUT) :: stop_ymd_out ! Stop date (YYYYMMDD)
|
|
integer , optional, intent(OUT) :: stop_tod_out ! Stop time of day (sec)
|
|
integer , optional, intent(OUT) :: dtime_out ! Time-step (sec)
|
|
!
|
|
character(len=*), parameter :: sub = 'clm::get_timemgr_defaults'
|
|
|
|
if ( timemgr_set ) call shr_sys_abort( sub//":: timemgr_init or timemgr_restart already called" )
|
|
if (present(calendar_out) ) calendar_out = trim(calendar)
|
|
if (present(start_ymd_out) ) start_ymd_out = start_ymd
|
|
if (present(start_tod_out) ) start_tod_out = start_tod
|
|
if (present(ref_ymd_out) ) ref_ymd_out = ref_ymd
|
|
if (present(ref_tod_out) ) ref_tod_out = ref_tod
|
|
if (present(stop_ymd_out) ) stop_ymd_out = stop_ymd
|
|
if (present(stop_tod_out) ) stop_tod_out = stop_tod
|
|
if (present(nelapse_out) ) nelapse_out = nelapse
|
|
if (present(dtime_out) ) dtime_out = dtime
|
|
|
|
end subroutine get_timemgr_defaults
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine set_timemgr_init( calendar_in, start_ymd_in, start_tod_in, ref_ymd_in, &
|
|
ref_tod_in, stop_ymd_in, stop_tod_in, perpetual_run_in, &
|
|
perpetual_ymd_in, nelapse_in, dtime_in )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! set time manager startup values
|
|
!
|
|
! Arguments
|
|
character(len=*), optional, intent(IN) :: calendar_in ! Calendar type
|
|
integer , optional, intent(IN) :: nelapse_in ! Number of step (or days) to advance
|
|
integer , optional, intent(IN) :: start_ymd_in ! Start date (YYYYMMDD)
|
|
integer , optional, intent(IN) :: start_tod_in ! Start time of day (sec)
|
|
integer , optional, intent(IN) :: ref_ymd_in ! Reference date (YYYYMMDD)
|
|
integer , optional, intent(IN) :: ref_tod_in ! Reference time of day (sec)
|
|
integer , optional, intent(IN) :: stop_ymd_in ! Stop date (YYYYMMDD)
|
|
integer , optional, intent(IN) :: stop_tod_in ! Stop time of day (sec)
|
|
logical , optional, intent(IN) :: perpetual_run_in ! If in perpetual mode or not
|
|
integer , optional, intent(IN) :: perpetual_ymd_in ! Perpetual date (YYYYMMDD)
|
|
integer , optional, intent(IN) :: dtime_in ! Time-step (sec)
|
|
!
|
|
character(len=*), parameter :: sub = 'clm::set_timemgr_init'
|
|
|
|
if ( timemgr_set ) call shr_sys_abort( sub//":: timemgr_init or timemgr_restart already called" )
|
|
if (present(calendar_in) ) calendar = trim(calendar_in)
|
|
if (present(start_ymd_in) ) start_ymd = start_ymd_in
|
|
if (present(start_tod_in) ) start_tod = start_tod_in
|
|
if (present(ref_ymd_in) ) ref_ymd = ref_ymd_in
|
|
if (present(ref_tod_in) ) ref_tod = ref_tod_in
|
|
if (present(stop_ymd_in) ) stop_ymd = stop_ymd_in
|
|
if (present(stop_tod_in) ) stop_tod = stop_tod_in
|
|
if (present(perpetual_run_in) )then
|
|
tm_perp_calendar = perpetual_run_in
|
|
if ( tm_perp_calendar ) then
|
|
if ( .not. present(perpetual_ymd_in) .or. perpetual_ymd == uninit_int) &
|
|
call shr_sys_abort( sub//":: perpetual_run set but NOT perpetual_ymd" )
|
|
perpetual_ymd = perpetual_ymd_in
|
|
end if
|
|
end if
|
|
if (present(nelapse_in) ) nelapse = nelapse_in
|
|
if (present(dtime_in) ) dtime = dtime_in
|
|
|
|
end subroutine set_timemgr_init
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine timemgr_init( )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Initialize the ESMF time manager from the sync clock
|
|
!
|
|
! Arguments
|
|
!
|
|
character(len=*), parameter :: sub = 'clm::timemgr_init'
|
|
integer :: rc ! return code
|
|
integer :: yr, mon, day, tod ! Year, month, day, and second as integers
|
|
type(ESMF_Time) :: start_date ! start date for run
|
|
type(ESMF_Time) :: stop_date ! stop date for run
|
|
type(ESMF_Time) :: curr_date ! temporary date used in logic
|
|
type(ESMF_Time) :: ref_date ! reference date for time coordinate
|
|
logical :: run_length_specified = .false.
|
|
type(ESMF_Time) :: current ! current date (from clock)
|
|
type(ESMF_TimeInterval) :: day_step_size ! day step size
|
|
type(ESMF_TimeInterval) :: step_size ! timestep size
|
|
!---------------------------------------------------------------------------------
|
|
call timemgr_spmdbcast( )
|
|
|
|
! Initalize calendar
|
|
|
|
call init_calendar()
|
|
|
|
! Initalize start date.
|
|
|
|
if ( start_ymd == uninit_int ) then
|
|
write(iulog,*)sub,': start_ymd must be specified '
|
|
call shr_sys_abort
|
|
end if
|
|
if ( start_tod == uninit_int ) then
|
|
write(iulog,*)sub,': start_tod must be specified '
|
|
call shr_sys_abort
|
|
end if
|
|
start_date = TimeSetymd( start_ymd, start_tod, "start_date" )
|
|
|
|
! Initialize current date
|
|
|
|
curr_date = start_date
|
|
|
|
! Initalize stop date.
|
|
|
|
stop_date = TimeSetymd( 99991231, stop_tod, "stop_date" )
|
|
|
|
call ESMF_TimeIntervalSet( step_size, s=dtime, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting step_size')
|
|
|
|
call ESMF_TimeIntervalSet( day_step_size, d=1, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting day_step_size')
|
|
|
|
if ( stop_ymd /= uninit_int ) then
|
|
current = TimeSetymd( stop_ymd, stop_tod, "stop_date" )
|
|
if ( current < stop_date ) stop_date = current
|
|
run_length_specified = .true.
|
|
end if
|
|
if ( nelapse /= uninit_int ) then
|
|
if ( nelapse >= 0 ) then
|
|
current = curr_date + step_size*nelapse
|
|
else
|
|
current = curr_date - day_step_size*nelapse
|
|
end if
|
|
if ( current < stop_date ) stop_date = current
|
|
run_length_specified = .true.
|
|
end if
|
|
if ( .not. run_length_specified ) then
|
|
call shr_sys_abort (sub//': Must specify stop_ymd or nelapse')
|
|
end if
|
|
|
|
! Error check
|
|
|
|
if ( stop_date <= start_date ) then
|
|
write(iulog,*)sub, ': stop date must be specified later than start date: '
|
|
call ESMF_TimeGet( start_date, yy=yr, mm=mon, dd=day, s=tod )
|
|
write(iulog,*) ' Start date (yr, mon, day, tod): ', yr, mon, day, tod
|
|
call ESMF_TimeGet( stop_date, yy=yr, mm=mon, dd=day, s=tod )
|
|
write(iulog,*) ' Stop date (yr, mon, day, tod): ', yr, mon, day, tod
|
|
call shr_sys_abort
|
|
end if
|
|
if ( curr_date >= stop_date ) then
|
|
write(iulog,*)sub, ': stop date must be specified later than current date: '
|
|
call ESMF_TimeGet( curr_date, yy=yr, mm=mon, dd=day, s=tod )
|
|
write(iulog,*) ' Current date (yr, mon, day, tod): ', yr, mon, day, tod
|
|
call ESMF_TimeGet( stop_date, yy=yr, mm=mon, dd=day, s=tod )
|
|
write(iulog,*) ' Stop date (yr, mon, day, tod): ', yr, mon, day, tod
|
|
call shr_sys_abort
|
|
end if
|
|
|
|
! Initalize reference date for time coordinate.
|
|
|
|
if ( ref_ymd /= uninit_int ) then
|
|
ref_date = TimeSetymd( ref_ymd, ref_tod, "ref_date" )
|
|
else
|
|
ref_date = start_date
|
|
end if
|
|
|
|
! Initialize clock
|
|
|
|
call init_clock( start_date, ref_date, curr_date, stop_date )
|
|
|
|
! Initialize date used for perpetual calendar day calculation.
|
|
|
|
if (tm_perp_calendar) then
|
|
tm_perp_date = TimeSetymd( perpetual_ymd, 0, "tm_perp_date" )
|
|
end if
|
|
|
|
! Print configuration summary to log file (stdout).
|
|
|
|
if (masterproc) call timemgr_print()
|
|
|
|
timemgr_set = .true.
|
|
|
|
end subroutine timemgr_init
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine init_clock( start_date, ref_date, curr_date, stop_date )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Purpose: Initialize the clock based on the start_date, ref_date, and curr_date
|
|
! as well as the settings from the namelist specifying the time to stop
|
|
!
|
|
type(ESMF_Time), intent(in) :: start_date ! start date for run
|
|
type(ESMF_Time), intent(in) :: ref_date ! reference date for time coordinate
|
|
type(ESMF_Time), intent(in) :: curr_date ! current date (equal to start_date)
|
|
type(ESMF_Time), intent(in) :: stop_date ! stop date for run
|
|
!
|
|
character(len=*), parameter :: sub = 'clm::init_clock'
|
|
type(ESMF_TimeInterval) :: step_size ! timestep size
|
|
type(ESMF_Time) :: current ! current date (from clock)
|
|
integer :: rc ! return code
|
|
!---------------------------------------------------------------------------------
|
|
|
|
call ESMF_TimeIntervalSet( step_size, s=dtime, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting step_size')
|
|
|
|
! Initialize the clock
|
|
|
|
tm_clock = ESMF_ClockCreate(name="CLM Time-manager clock", timeStep=step_size, startTime=start_date, &
|
|
stopTime=stop_date, refTime=ref_date, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_ClockSetup')
|
|
|
|
! Advance clock to the current time (in case of a restart)
|
|
|
|
call ESMF_ClockGet(tm_clock, currTime=current, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
do while( curr_date > current )
|
|
call ESMF_ClockAdvance( tm_clock, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockAdvance')
|
|
call ESMF_ClockGet(tm_clock, currTime=current )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
end do
|
|
end subroutine init_clock
|
|
|
|
!=========================================================================================
|
|
|
|
function TimeSetymd( ymd, tod, desc )
|
|
!---------------------------------------------------------------------------------
|
|
!
|
|
! Set the time by an integer as YYYYMMDD and integer seconds in the day
|
|
!
|
|
integer, intent(in) :: ymd ! Year, month, day YYYYMMDD
|
|
integer, intent(in) :: tod ! Time of day in seconds
|
|
character(len=*), intent(in) :: desc ! Description of time to set
|
|
|
|
type(ESMF_Time) :: TimeSetymd ! Return value
|
|
|
|
character(len=*), parameter :: sub = 'clm::TimeSetymd'
|
|
integer :: yr, mon, day ! Year, month, day as integers
|
|
integer :: rc ! return code
|
|
!---------------------------------------------------------------------------------
|
|
|
|
if ( (ymd < 0) .or. (tod < 0) .or. (tod > isecspday) )then
|
|
write(iulog,*) sub//': error yymmdd is a negative number or time-of-day out of bounds', &
|
|
ymd, tod
|
|
call shr_sys_abort
|
|
end if
|
|
yr = ymd / 10000
|
|
mon = (ymd - yr*10000) / 100
|
|
day = ymd - yr*10000 - mon*100
|
|
call ESMF_TimeSet( TimeSetymd, yy=yr, mm=mon, dd=day, s=tod, &
|
|
calendar=tm_cal, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeSet: setting '//trim(desc))
|
|
end function TimeSetymd
|
|
|
|
!=========================================================================================
|
|
|
|
integer function TimeGetymd( date, tod )
|
|
!
|
|
! Get the date and time of day in ymd from ESMF Time.
|
|
!
|
|
type(ESMF_Time), intent(inout) :: date ! Input date to convert to ymd
|
|
integer, intent(out), optional :: tod ! Time of day in seconds
|
|
|
|
character(len=*), parameter :: sub = 'clm::TimeGetymd'
|
|
integer :: yr, mon, day
|
|
integer :: rc ! return code
|
|
|
|
call ESMF_TimeGet( date, yy=yr, mm=mon, dd=day, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
TimeGetymd = yr*10000 + mon*100 + day
|
|
if ( present( tod ) )then
|
|
call ESMF_TimeGet( date, yy=yr, mm=mon, dd=day, s=tod, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
end if
|
|
if ( yr < 0 )then
|
|
write(iulog,*) sub//': error year is less than zero', yr
|
|
call shr_sys_abort
|
|
end if
|
|
end function TimeGetymd
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine timemgr_restart_io( ncid, flag )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Read/Write information needed on restart to a netcdf file.
|
|
use ncdio_pio, only: ncd_int
|
|
use pio, only: var_desc_t, file_desc_t
|
|
use restUtilMod
|
|
!
|
|
! Arguments
|
|
type(file_desc_t), intent(inout) :: ncid ! netcdf id
|
|
character(len=*), intent(in) :: flag ! 'read' or 'write'
|
|
!
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::timemgr_restart'
|
|
integer :: rc ! return code
|
|
logical :: readvar ! determine if variable is on initial file
|
|
type(ESMF_Time) :: start_date ! start date for run
|
|
type(ESMF_Time) :: ref_date ! reference date for run
|
|
type(ESMF_Time) :: curr_date ! date of data in restart file
|
|
integer :: rst_caltype ! calendar type
|
|
integer, parameter :: noleap = 1
|
|
integer, parameter :: gregorian = 2
|
|
character(len=len(calendar)) :: cal
|
|
!---------------------------------------------------------------------------------
|
|
|
|
if (flag == 'write') then
|
|
rst_nstep_rad_prev = nstep_rad_prev
|
|
end if
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_nstep_rad_prev', xtype=ncd_int, &
|
|
long_name='previous_radiation_nstep', units='unitless positive integer', &
|
|
ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_nstep_rad_prev)
|
|
if (flag == 'read') then
|
|
nstep_rad_prev = rst_nstep_rad_prev
|
|
end if
|
|
|
|
if (flag == 'write') then
|
|
cal = to_upper(calendar)
|
|
if ( trim(cal) == NO_LEAP_C ) then
|
|
rst_caltype = noleap
|
|
else if ( trim(cal) == GREGORIAN_C ) then
|
|
rst_caltype = gregorian
|
|
else
|
|
call shr_sys_abort(sub//'ERROR: unrecognized calendar specified= '//trim(calendar))
|
|
end if
|
|
end if
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_type', xtype=ncd_int, &
|
|
long_name='calendar type', units='unitless', flag_meanings=(/ "NO_LEAP_C", "GREGORIAN" /), &
|
|
flag_values=(/ noleap, gregorian /), ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_caltype)
|
|
if (flag == 'read') then
|
|
if ( rst_caltype == noleap ) then
|
|
calendar = NO_LEAP_C
|
|
else if ( rst_caltype == gregorian ) then
|
|
calendar = GREGORIAN_C
|
|
else
|
|
write(iulog,*)sub,': unrecognized calendar type in restart file: ',rst_caltype
|
|
call shr_sys_abort( sub//'ERROR: bad calendar type in restart file')
|
|
end if
|
|
end if
|
|
|
|
if (flag == 'write') then
|
|
call ESMF_ClockGet( tm_clock, startTime=start_date, currTime=curr_date, refTime=ref_date, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
rst_step_sec = dtime
|
|
rst_start_ymd = TimeGetymd( start_date, tod=rst_start_tod )
|
|
rst_ref_ymd = TimeGetymd( ref_date, tod=rst_ref_tod )
|
|
rst_curr_ymd = TimeGetymd( curr_date, tod=rst_curr_tod )
|
|
end if
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_step_sec', xtype=ncd_int, &
|
|
long_name='seconds component of timestep size', units='sec', &
|
|
nvalid_range=(/0,isecspday/), ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_step_sec)
|
|
if ((flag == 'read') .and. ( rst_step_sec < 0 .or. rst_step_sec > isecspday )) then
|
|
call shr_sys_abort( sub//'ERROR: timemgr_rst_step_sec out of range')
|
|
end if
|
|
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_start_ymd', xtype=ncd_int, &
|
|
long_name='start date', units='YYYYMMDD', ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_start_ymd)
|
|
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_start_tod', xtype=ncd_int, &
|
|
long_name='start time of day', units='sec', &
|
|
nvalid_range=(/0,isecspday/), ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_start_tod)
|
|
if ((flag == 'read') .and. ( rst_start_tod < 0 .or. rst_start_tod > isecspday )) then
|
|
call shr_sys_abort( sub//'ERROR: timemgr_rst_strart_tod out of range')
|
|
end if
|
|
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_ref_ymd', xtype=ncd_int, &
|
|
long_name='reference date', units='YYYYMMDD', ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_ref_ymd)
|
|
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_ref_tod', xtype=ncd_int, &
|
|
long_name='reference time of day', units='sec', &
|
|
nvalid_range=(/0,isecspday/), ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_ref_tod)
|
|
if ((flag == 'read') .and. ( rst_start_tod < 0 .or. rst_start_tod > isecspday )) then
|
|
call shr_sys_abort( sub//'ERROR: timemgr_rst_ref_tod out of range')
|
|
end if
|
|
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_curr_ymd', xtype=ncd_int, &
|
|
long_name='current date', units='YYYYMMDD', ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_curr_ymd)
|
|
|
|
call restartvar(ncid=ncid, flag=flag, varname='timemgr_rst_curr_tod', xtype=ncd_int, &
|
|
long_name='current time of day', units='sec', &
|
|
nvalid_range=(/0,isecspday/), ifill_value=uninit_int, &
|
|
interpinic_flag='skip', readvar=readvar, data=rst_curr_tod)
|
|
if ((flag == 'read') .and. ( rst_curr_tod < 0 .or. rst_curr_tod > isecspday )) then
|
|
call shr_sys_abort( sub//'ERROR: timemgr_rst_ref_ymd out of range')
|
|
end if
|
|
|
|
end subroutine timemgr_restart_io
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine timemgr_restart( )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Restart the ESMF time manager using the synclock for ending date.
|
|
!
|
|
character(len=*), parameter :: sub = 'clm::timemgr_restart'
|
|
integer :: rc ! return code
|
|
integer :: yr, mon, day, tod ! Year, month, day, and second as integers
|
|
type(ESMF_Time) :: start_date ! start date for run
|
|
type(ESMF_Time) :: ref_date ! reference date for run
|
|
type(ESMF_Time) :: curr_date ! date of data in restart file
|
|
type(ESMF_Time) :: stop_date ! stop date for run
|
|
type(ESMF_Time) :: current ! current date (from clock)
|
|
type(ESMF_TimeInterval) :: day_step_size ! day step size
|
|
type(ESMF_TimeInterval) :: step_size ! timestep size
|
|
logical :: run_length_specified = .false.
|
|
!---------------------------------------------------------------------------------
|
|
call timemgr_spmdbcast( )
|
|
|
|
! Initialize calendar from restart info
|
|
|
|
call init_calendar()
|
|
|
|
! Initialize the timestep from restart info
|
|
|
|
dtime = rst_step_sec
|
|
|
|
! Initialize start date from restart info
|
|
|
|
start_date = TimeSetymd( rst_start_ymd, rst_start_tod, "start_date" )
|
|
|
|
! Initialize current date from restart info
|
|
|
|
curr_date = TimeSetymd( rst_curr_ymd, rst_curr_tod, "curr_date" )
|
|
|
|
! Initialize stop date from sync clock or namelist input
|
|
|
|
stop_date = TimeSetymd( 99991231, stop_tod, "stop_date" )
|
|
|
|
call ESMF_TimeIntervalSet( step_size, s=dtime, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting step_size')
|
|
|
|
call ESMF_TimeIntervalSet( day_step_size, d=1, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting day_step_size')
|
|
|
|
if ( stop_ymd /= uninit_int ) then
|
|
current = TimeSetymd( stop_ymd, stop_tod, "stop_date" )
|
|
if ( current < stop_date ) stop_date = current
|
|
run_length_specified = .true.
|
|
else if ( nelapse /= uninit_int ) then
|
|
if ( nelapse >= 0 ) then
|
|
current = curr_date + step_size*nelapse
|
|
else
|
|
current = curr_date - day_step_size*nelapse
|
|
end if
|
|
if ( current < stop_date ) stop_date = current
|
|
run_length_specified = .true.
|
|
end if
|
|
if ( .not. run_length_specified ) then
|
|
call shr_sys_abort (sub//': Must specify stop_ymd or nelapse')
|
|
end if
|
|
|
|
! Error check
|
|
|
|
if ( stop_date <= start_date ) then
|
|
write(iulog,*)sub, ': stop date must be specified later than start date: '
|
|
call ESMF_TimeGet( start_date, yy=yr, mm=mon, dd=day, s=tod )
|
|
write(iulog,*) ' Start date (yr, mon, day, tod): ', yr, mon, day, tod
|
|
call ESMF_TimeGet( stop_date, yy=yr, mm=mon, dd=day, s=tod )
|
|
write(iulog,*) ' Stop date (yr, mon, day, tod): ', yr, mon, day, tod
|
|
call shr_sys_abort
|
|
end if
|
|
if ( curr_date >= stop_date ) then
|
|
write(iulog,*)sub, ': stop date must be specified later than current date: '
|
|
call ESMF_TimeGet( curr_date, yy=yr, mm=mon, dd=day, s=tod )
|
|
write(iulog,*) ' Current date (yr, mon, day, tod): ', yr, mon, day, tod
|
|
call ESMF_TimeGet( stop_date, yy=yr, mm=mon, dd=day, s=tod )
|
|
write(iulog,*) ' Stop date (yr, mon, day, tod): ', yr, mon, day, tod
|
|
call shr_sys_abort
|
|
end if
|
|
|
|
! Initialize nstep_rad_prev from restart info
|
|
|
|
nstep_rad_prev = rst_nstep_rad_prev
|
|
|
|
! Initialize ref date from restart info
|
|
|
|
ref_date = TimeSetymd( rst_ref_ymd, rst_ref_tod, "ref_date" )
|
|
|
|
! Initialize clock
|
|
|
|
call init_clock( start_date, ref_date, curr_date, stop_date )
|
|
|
|
! 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.
|
|
|
|
tm_first_restart_step = .true.
|
|
|
|
! Calculate ending time step
|
|
|
|
call calc_nestep( )
|
|
|
|
! Print configuration summary to log file (stdout).
|
|
|
|
if (masterproc) call timemgr_print()
|
|
|
|
timemgr_set = .true.
|
|
|
|
end subroutine timemgr_restart
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine calc_nestep()
|
|
!---------------------------------------------------------------------------------
|
|
!
|
|
! Calculate ending timestep number
|
|
! Calculation of ending timestep number (nestep) assumes a constant stepsize.
|
|
!
|
|
character(len=*), parameter :: sub = 'clm::calc_nestep'
|
|
integer :: ntspday ! Number of time-steps per day
|
|
type(ESMF_TimeInterval) :: diff !
|
|
type(ESMF_Time) :: start_date ! start date for run
|
|
type(ESMF_Time) :: stop_date ! stop date for run
|
|
integer :: ndays, nsecs ! Number of days, seconds to ending time
|
|
integer :: rc ! return code
|
|
!---------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet( tm_clock, stopTime=stop_date, startTime=start_date, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
ntspday = isecspday/dtime
|
|
diff = stop_date - start_date
|
|
call ESMF_TimeIntervalGet( diff, d=ndays, s=nsecs, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalGet calculating nestep')
|
|
nestep = ntspday*ndays + nsecs/dtime
|
|
if ( mod(nsecs,dtime) /= 0 ) nestep = nestep + 1
|
|
end subroutine calc_nestep
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine init_calendar( )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Initialize calendar
|
|
!
|
|
! Local variables
|
|
!
|
|
character(len=*), parameter :: sub = 'clm::init_calendar'
|
|
type(ESMF_CalKind_Flag) :: cal_type ! calendar type
|
|
character(len=len(calendar)) :: caltmp
|
|
integer :: rc ! return code
|
|
!---------------------------------------------------------------------------------
|
|
|
|
caltmp = to_upper(calendar)
|
|
if ( trim(caltmp) == NO_LEAP_C ) then
|
|
cal_type = ESMF_CALKIND_NOLEAP
|
|
else if ( trim(caltmp) == GREGORIAN_C ) then
|
|
cal_type = ESMF_CALKIND_GREGORIAN
|
|
else
|
|
write(iulog,*)sub,': unrecognized calendar specified: ',calendar
|
|
call shr_sys_abort
|
|
end if
|
|
tm_cal = ESMF_CalendarCreate( name=caltmp, calkindflag=cal_type, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_CalendarSet')
|
|
end subroutine init_calendar
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine timemgr_print()
|
|
|
|
!---------------------------------------------------------------------------------
|
|
character(len=*), parameter :: sub = 'clm::timemgr_print'
|
|
integer :: rc
|
|
integer :: yr, mon, day
|
|
integer :: & ! Data required to restart time manager:
|
|
nstep = uninit_int, &! current step number
|
|
step_sec = uninit_int, &! timestep size seconds
|
|
start_yr = uninit_int, &! start year
|
|
start_mon = uninit_int, &! start month
|
|
start_day = uninit_int, &! start day of month
|
|
start_tod = uninit_int, &! start time of day
|
|
stop_yr = uninit_int, &! stop year
|
|
stop_mon = uninit_int, &! stop month
|
|
stop_day = uninit_int, &! stop day of month
|
|
stop_tod = uninit_int, &! stop time of day
|
|
ref_yr = uninit_int, &! reference year
|
|
ref_mon = uninit_int, &! reference month
|
|
ref_day = uninit_int, &! reference day of month
|
|
ref_tod = uninit_int, &! reference time of day
|
|
curr_yr = uninit_int, &! current year
|
|
curr_mon = uninit_int, &! current month
|
|
curr_day = uninit_int, &! current day of month
|
|
curr_tod = uninit_int ! current time of day
|
|
integer(ESMF_KIND_I8) :: step_no
|
|
type(ESMF_Time) :: start_date! start date for run
|
|
type(ESMF_Time) :: stop_date ! stop date for run
|
|
type(ESMF_Time) :: curr_date ! date of data in restart file
|
|
type(ESMF_Time) :: ref_date ! reference date
|
|
type(ESMF_TimeInterval) :: step ! Time-step
|
|
!---------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet( tm_clock, startTime=start_date, currTime=curr_date, &
|
|
refTime=ref_date, stopTime=stop_date, timeStep=step, &
|
|
advanceCount=step_no, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
nstep = step_no
|
|
|
|
write(iulog,*)' ******** CLM Time Manager Configuration ********'
|
|
|
|
call ESMF_TimeIntervalGet( step, s=step_sec, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalGet')
|
|
|
|
call ESMF_TimeGet( start_date, yy=start_yr, mm=start_mon, dd=start_day, &
|
|
s=start_tod, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
call ESMF_TimeGet( stop_date, yy=stop_yr, mm=stop_mon, dd=stop_day, &
|
|
s=stop_tod, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
call ESMF_TimeGet( ref_date, yy=ref_yr, mm=ref_mon, dd=ref_day, s=ref_tod, &
|
|
rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
call ESMF_TimeGet( curr_date, yy=curr_yr, mm=curr_mon, dd=curr_day, &
|
|
s=curr_tod, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
|
|
write(iulog,*)' Calendar type: ',trim(calendar)
|
|
write(iulog,*)' Timestep size (seconds): ', step_sec
|
|
write(iulog,*)' Start date (yr mon day tod): ', start_yr, start_mon, &
|
|
start_day, start_tod
|
|
write(iulog,*)' Stop date (yr mon day tod): ', stop_yr, stop_mon, &
|
|
stop_day, stop_tod
|
|
write(iulog,*)' Reference date (yr mon day tod): ', ref_yr, ref_mon, &
|
|
ref_day, ref_tod
|
|
write(iulog,*)' Current step number: ', nstep
|
|
write(iulog,*)' Ending step number: ', nestep
|
|
write(iulog,*)' Current date (yr mon day tod): ', curr_yr, curr_mon, &
|
|
curr_day, curr_tod
|
|
|
|
if ( tm_perp_calendar ) then
|
|
call ESMF_TimeGet( tm_perp_date, yy=yr, mm=mon, dd=day, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
write(iulog,*)' Use perpetual diurnal cycle date (yr mon day): ', &
|
|
yr, mon, day
|
|
end if
|
|
|
|
write(iulog,*)' ************************************************'
|
|
|
|
end subroutine timemgr_print
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine advance_timestep()
|
|
|
|
! Increment the timestep number.
|
|
|
|
character(len=*), parameter :: sub = 'clm::advance_timestep'
|
|
integer :: rc
|
|
|
|
call ESMF_ClockAdvance( tm_clock, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockAdvance')
|
|
|
|
tm_first_restart_step = .false.
|
|
|
|
end subroutine advance_timestep
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_clock( clock )
|
|
|
|
! Return the ESMF clock
|
|
|
|
type(ESMF_Clock), intent(inout) :: clock
|
|
|
|
character(len=*), parameter :: sub = 'clm::get_clock'
|
|
type(ESMF_TimeInterval) :: step_size
|
|
type(ESMF_Time) :: start_date, stop_date, ref_date
|
|
integer :: rc
|
|
|
|
call ESMF_ClockGet( tm_clock, timeStep=step_size, startTime=start_date, &
|
|
stoptime=stop_date, reftime=ref_date, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
call ESMF_ClockSet(clock, timeStep=step_size, startTime=start_date, &
|
|
stoptime=stop_date, reftime=ref_date, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_ClockSet')
|
|
|
|
end subroutine get_clock
|
|
|
|
!=========================================================================================
|
|
|
|
function get_curr_ESMF_Time( )
|
|
|
|
! Return the current time as ESMF_Time
|
|
|
|
type(ESMF_Time) :: get_curr_ESMF_Time
|
|
character(len=*), parameter :: sub = 'clm::get_curr_ESMF_Time'
|
|
integer :: rc
|
|
|
|
call ESMF_ClockGet( tm_clock, currTime=get_curr_ESMF_Time, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
end function get_curr_ESMF_Time
|
|
|
|
!=========================================================================================
|
|
|
|
integer function get_step_size()
|
|
|
|
! Return the step size in seconds.
|
|
|
|
character(len=*), parameter :: sub = 'clm::get_step_size'
|
|
type(ESMF_TimeInterval) :: step_size ! timestep size
|
|
integer :: rc
|
|
|
|
call ESMF_ClockGet(tm_clock, timeStep=step_size, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
call ESMF_TimeIntervalGet(step_size, s=get_step_size, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_ClockTimeIntervalGet')
|
|
|
|
end function get_step_size
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine update_rad_dtime(doalb)
|
|
!---------------------------------------------------------------------------------
|
|
! called only on doalb timesteps to save off radiation nsteps
|
|
!
|
|
! Local Arguments
|
|
logical,intent(in) :: doalb
|
|
integer :: dtime,nstep
|
|
|
|
if (doalb) then
|
|
|
|
dtime=get_step_size()
|
|
nstep = get_nstep()
|
|
|
|
if (nstep_rad_prev == uninit_int ) then
|
|
dtime_rad = dtime
|
|
nstep_rad_prev = nstep
|
|
else
|
|
dtime_rad = (nstep - nstep_rad_prev) * dtime
|
|
nstep_rad_prev = nstep
|
|
endif
|
|
end if
|
|
end subroutine update_rad_dtime
|
|
|
|
!=========================================================================================
|
|
|
|
integer function get_rad_step_size()
|
|
|
|
if (nstep_rad_prev == uninit_int ) then
|
|
get_rad_step_size=get_step_size()
|
|
else
|
|
get_rad_step_size=dtime_rad
|
|
end if
|
|
|
|
end function get_rad_step_size
|
|
|
|
!=========================================================================================
|
|
|
|
integer function get_nstep()
|
|
|
|
! Return the timestep number.
|
|
|
|
character(len=*), parameter :: sub = 'clm::get_nstep'
|
|
integer :: rc
|
|
integer(ESMF_KIND_I8) :: step_no
|
|
|
|
call ESMF_ClockGet(tm_clock, advanceCount=step_no, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
get_nstep = step_no
|
|
|
|
end function get_nstep
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_curr_date(yr, mon, day, tod, offset)
|
|
|
|
!-----------------------------------------------------------------------------------------
|
|
! Return date components valid at end of current timestep with an optional
|
|
! offset (positive or negative) in seconds.
|
|
|
|
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.
|
|
|
|
character(len=*), parameter :: sub = 'clm::get_curr_date'
|
|
integer :: rc
|
|
type(ESMF_Time) :: date
|
|
type(ESMF_TimeInterval) :: off
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet( tm_clock, currTime=date, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
if (present(offset)) then
|
|
if (offset > 0) then
|
|
call ESMF_TimeIntervalSet( off, s=offset, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet')
|
|
date = date + off
|
|
else if (offset < 0) then
|
|
call ESMF_TimeIntervalSet( off, s=-offset, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet')
|
|
date = date - off
|
|
end if
|
|
end if
|
|
|
|
call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
|
|
end subroutine get_curr_date
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_perp_date(yr, mon, day, tod, offset)
|
|
|
|
!-----------------------------------------------------------------------------------------
|
|
! Return time of day valid at end of current timestep and the components
|
|
! of the perpetual date (with an optional offset (positive or negative) in seconds.
|
|
|
|
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.
|
|
|
|
character(len=*), parameter :: sub = 'clm::get_perp_date'
|
|
integer :: rc
|
|
type(ESMF_Time) :: date
|
|
type(ESMF_TimeInterval) :: DelTime
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet( tm_clock, currTime=date, rc=rc )
|
|
! Get time of day add it to perpetual date
|
|
! Get year, month, day so that seconds are time-of-day rather than since start time
|
|
call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
call ESMF_TimeIntervalSet(DelTime, s=tod, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet')
|
|
date = tm_perp_date + DelTime
|
|
if ( present(offset) )then
|
|
call ESMF_TimeIntervalSet(DelTime, s=offset, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet')
|
|
date = date + DelTime
|
|
end if
|
|
! Get time of day from the result
|
|
! Get year, month, day so that seconds are time-of-day rather than since start time
|
|
call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc)
|
|
|
|
! Get the date from the fixed perpetual date (in case it overflows to next day)
|
|
call ESMF_TimeGet(tm_perp_date, yy=yr, mm=mon, dd=day, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
|
|
end subroutine get_perp_date
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_prev_date(yr, mon, day, tod)
|
|
|
|
! Return date components valid at beginning of current timestep.
|
|
|
|
! Arguments
|
|
integer, intent(out) ::&
|
|
yr, &! year
|
|
mon, &! month
|
|
day, &! day of month
|
|
tod ! time of day (seconds past 0Z)
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::get_prev_date'
|
|
integer :: rc
|
|
type(ESMF_Time) :: date
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet(tm_clock, prevTime=date, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
|
|
end subroutine get_prev_date
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_start_date(yr, mon, day, tod)
|
|
|
|
! Return date components valid at beginning of initial run.
|
|
|
|
! Arguments
|
|
integer, intent(out) ::&
|
|
yr, &! year
|
|
mon, &! month
|
|
day, &! day of month
|
|
tod ! time of day (seconds past 0Z)
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::get_start_date'
|
|
integer :: rc
|
|
type(ESMF_Time) :: date
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet(tm_clock, startTime=date, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
|
|
end subroutine get_start_date
|
|
|
|
!=========================================================================================
|
|
|
|
integer function get_driver_start_ymd( tod )
|
|
|
|
! Return date of start of simulation from driver (i.e. NOT from restart file)
|
|
! Note: get_start_date gets you the date from the beginning of the simulation
|
|
! on the restart file.
|
|
|
|
! Arguments
|
|
integer, optional, intent(out) ::&
|
|
tod ! time of day (seconds past 0Z)
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::get_driver_start_ymd'
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
if ( start_ymd == uninit_int )then
|
|
call shr_sys_abort( sub//': error driver start date is NOT set yet' )
|
|
end if
|
|
if ( start_ymd < 101 .or. start_ymd > 99991231 )then
|
|
call shr_sys_abort( sub//': error driver start date is invalid' )
|
|
end if
|
|
if ( present(tod) )then
|
|
tod = start_tod
|
|
if ( (tod < 0) .or. (tod > isecspday) )then
|
|
call shr_sys_abort( sub//': error driver start tod is invalid' )
|
|
end if
|
|
end if
|
|
get_driver_start_ymd = start_ymd
|
|
|
|
end function get_driver_start_ymd
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_ref_date(yr, mon, day, tod)
|
|
|
|
! Return date components of the reference date.
|
|
|
|
! Arguments
|
|
integer, intent(out) ::&
|
|
yr, &! year
|
|
mon, &! month
|
|
day, &! day of month
|
|
tod ! time of day (seconds past 0Z)
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::get_ref_date'
|
|
integer :: rc
|
|
type(ESMF_Time) :: date
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet(tm_clock, refTime=date, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
|
|
end subroutine get_ref_date
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_curr_time(days, seconds)
|
|
|
|
! Return time components valid at end of current timestep.
|
|
! Current time is the time interval between the current date and the reference date.
|
|
|
|
! Arguments
|
|
integer, intent(out) ::&
|
|
days, &! number of whole days in time interval
|
|
seconds ! remaining seconds in time interval
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::get_curr_time'
|
|
integer :: rc
|
|
type(ESMF_Time) :: cdate, rdate
|
|
type(ESMF_TimeInterval) :: diff
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet( tm_clock, currTime=cdate, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
call ESMF_ClockGet( tm_clock, refTime=rdate, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
diff = cdate - rdate
|
|
|
|
call ESMF_TimeIntervalGet(diff, d=days, s=seconds, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalGet')
|
|
|
|
end subroutine get_curr_time
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_prev_time(days, seconds)
|
|
|
|
! Return time components valid at beg of current timestep.
|
|
! prev time is the time interval between the prev date and the reference date.
|
|
|
|
! Arguments
|
|
integer, intent(out) ::&
|
|
days, &! number of whole days in time interval
|
|
seconds ! remaining seconds in time interval
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::get_prev_time'
|
|
integer :: rc
|
|
type(ESMF_Time) :: date, ref_date
|
|
type(ESMF_TimeInterval) :: diff
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet(tm_clock, prevTime=date, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet for prevTime')
|
|
call ESMF_ClockGet(tm_clock, refTime=ref_date, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet for refTime')
|
|
diff = date - ref_date
|
|
call ESMF_TimeIntervalGet( diff, d=days, s=seconds, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeintervalGet')
|
|
|
|
end subroutine get_prev_time
|
|
|
|
!=========================================================================================
|
|
|
|
function get_curr_calday(offset)
|
|
|
|
! Return calendar day at end of current timestep with optional offset.
|
|
! Calendar day 1.0 = 0Z on Jan 1.
|
|
|
|
! Arguments
|
|
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 = 'clm::get_curr_calday'
|
|
integer :: rc
|
|
type(ESMF_Time) :: date
|
|
type(ESMF_TimeInterval) :: off, diurnal
|
|
integer :: year, month, day, tod
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet( tm_clock, currTime=date, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
|
|
if (present(offset)) then
|
|
if (offset > 0) then
|
|
call ESMF_TimeIntervalSet( off, s=offset, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet')
|
|
date = date + off
|
|
else if (offset < 0) then
|
|
call ESMF_TimeIntervalSet( off, s=-offset, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet')
|
|
date = date - off
|
|
end if
|
|
end if
|
|
|
|
if ( tm_perp_calendar ) then
|
|
call ESMF_TimeGet(date, yy=year, mm=month, dd=day, s=tod, rc=rc)
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
call ESMF_TimeIntervalSet( diurnal, s=tod, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet')
|
|
date = tm_perp_date + diurnal
|
|
end if
|
|
|
|
call ESMF_TimeGet( date, dayOfYear_r8=get_curr_calday, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
!----------------------------------------------------------------------------------------!
|
|
!!!!!!!!!!!!!! WARNING HACK TO ENABLE Gregorian CALENDAR WITH SHR_ORB !!!!!!!!!!!!!!!!!!!!
|
|
!!!! The following hack fakes day 366 by reusing day 365. This is just because the !!!!!!
|
|
!!!! current shr_orb_decl calculation can't handle days > 366. !!!!!!
|
|
!!!! Dani Bundy-Coleman and Erik Kluzek Aug/2008 !!!!!!
|
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
if ( (get_curr_calday > 366.0) .and. (get_curr_calday <= 367.0) .and. &
|
|
(trim(calendar) == GREGORIAN_C) )then
|
|
get_curr_calday = get_curr_calday - 1.0_r8
|
|
end if
|
|
!!!!!!!!!!!!!! END HACK TO ENABLE Gregorian CALENDAR WITH SHR_ORB !!!!!!!!!!!!!!!!!!!!!!!!
|
|
!----------------------------------------------------------------------------------------!
|
|
if ( (get_curr_calday < 1.0) .or. (get_curr_calday > 366.0) )then
|
|
write(iulog,*) sub, ' = ', get_curr_calday
|
|
if ( present(offset) ) write(iulog,*) 'offset = ', offset
|
|
call shr_sys_abort( sub//': error get_curr_calday out of bounds' )
|
|
end if
|
|
|
|
end function get_curr_calday
|
|
|
|
!=========================================================================================
|
|
|
|
function get_calday(ymd, tod)
|
|
|
|
! Return calendar day corresponding to specified time instant.
|
|
! Calendar day 1.0 = 0Z on Jan 1.
|
|
|
|
! Arguments
|
|
integer, intent(in) :: &
|
|
ymd, &! date in yearmmdd format
|
|
tod ! time of day (seconds past 0Z)
|
|
|
|
! Return value
|
|
real(r8) :: get_calday
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::get_calday'
|
|
integer :: rc ! return code
|
|
type(ESMF_Time) :: date
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
date = TimeSetymd( ymd, tod, "get_calday" )
|
|
call ESMF_TimeGet( date, dayOfYear_r8=get_calday, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
!----------------------------------------------------------------------------------------!
|
|
!!!!!!!!!!!!!! WARNING HACK TO ENABLE Gregorian CALENDAR WITH SHR_ORB !!!!!!!!!!!!!!!!!!!!
|
|
!!!! The following hack fakes day 366 by reusing day 365. This is just because the !!!!!!
|
|
!!!! current shr_orb_decl calculation can't handle days > 366. !!!!!!
|
|
!!!! Dani Bundy-Coleman and Erik Kluzek Aug/2008 !!!!!!
|
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
if ( (get_calday > 366.0) .and. (get_calday <= 367.0) .and. &
|
|
(trim(calendar) == GREGORIAN_C) )then
|
|
get_calday = get_calday - 1.0_r8
|
|
end if
|
|
!!!!!!!!!!!!!! END HACK TO ENABLE Gregorian CALENDAR WITH SHR_ORB !!!!!!!!!!!!!!!!!!!!!!!!
|
|
!----------------------------------------------------------------------------------------!
|
|
if ( (get_calday < 1.0) .or. (get_calday > 366.0) )then
|
|
write(iulog,*) sub, ' = ', get_calday
|
|
call shr_sys_abort( sub//': error calday out of range' )
|
|
end if
|
|
|
|
end function get_calday
|
|
|
|
!=========================================================================================
|
|
|
|
function get_calendar()
|
|
|
|
! Return calendar
|
|
|
|
! Return value
|
|
character(len=ESMF_MAXSTR) :: get_calendar
|
|
|
|
get_calendar = calendar
|
|
|
|
end function get_calendar
|
|
|
|
!=========================================================================================
|
|
|
|
integer function get_days_per_year( offset )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Get the number of days per year for currrent year
|
|
|
|
!
|
|
! Arguments
|
|
integer, optional, intent(in) :: offset ! Offset from current time in seconds.
|
|
! Positive for future times, negative
|
|
! for previous times.
|
|
|
|
character(len=*), parameter :: sub = 'clm::get_days_per_year'
|
|
integer :: yr, mon, day, tod ! current date year, month, day and time-of-day
|
|
type(ESMF_Time) :: eDate ! ESMF date
|
|
integer :: rc ! ESMF return code
|
|
!---------------------------------------------------------------------------------
|
|
|
|
if ( present(offset) )then
|
|
call get_curr_date(yr, mon, day, tod, offset )
|
|
else
|
|
call get_curr_date(yr, mon, day, tod )
|
|
end if
|
|
eDate = TimeSetymd( ymd=yr*10000+1231, tod=0, desc="end of year" )
|
|
call ESMF_TimeGet( eDate, dayOfYear=get_days_per_year, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeGet')
|
|
|
|
end function get_days_per_year
|
|
|
|
!=========================================================================================
|
|
|
|
function get_curr_yearfrac( offset )
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Get the fractional position in the current year. This is 0 at midnight on Jan 1,
|
|
! and 1 at the end of Dec 31.
|
|
|
|
!
|
|
! Arguments
|
|
real(r8) :: get_curr_yearfrac ! function result
|
|
|
|
integer, optional, intent(in) :: offset ! Offset from current time in seconds.
|
|
! Positive for future times, negative
|
|
! for previous times.
|
|
|
|
character(len=*), parameter :: sub = 'clm::get_curr_yearfrac'
|
|
real(r8) :: cday ! current calendar day (1.0 = 0Z on Jan 1)
|
|
real(r8) :: days_per_year ! days per year
|
|
|
|
cday = get_curr_calday(offset=offset)
|
|
days_per_year = get_days_per_year()
|
|
|
|
get_curr_yearfrac = (cday - 1._r8)/days_per_year
|
|
|
|
end function get_curr_yearfrac
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine get_rest_date(ncid, yr)
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Get the date from the restart file.
|
|
!
|
|
! Currently just returns the year (because the month & day are harder to extract, and
|
|
! currently aren't needed).
|
|
use pio, only: file_desc_t
|
|
use ncdio_pio, only: ncd_io
|
|
!
|
|
! Arguments
|
|
type(file_desc_t) , intent(inout) :: ncid ! netcdf id for the restart file
|
|
integer , intent(out) :: yr ! year from restart file
|
|
|
|
integer :: ymd ! yyyymmdd from the restart file
|
|
logical :: readvar ! whether the variable was read from the file
|
|
|
|
integer, parameter :: year_mask = 10000 ! divide by this to get year from ymd
|
|
|
|
character(len=*), parameter :: subname = 'get_rest_date'
|
|
!-----------------------------------------------------------------------
|
|
|
|
! Get the date (yyyymmdd) from restart file.
|
|
! Note that we cannot simply use the rst_curr_ymd module variable, because that isn't
|
|
! set under some circumstances
|
|
call ncd_io(varname='timemgr_rst_curr_ymd', data=ymd, &
|
|
ncid=ncid, flag='read', readvar=readvar)
|
|
if (.not. readvar) then
|
|
call shr_sys_abort(subname//' ERROR: timemgr_rst_curr_ymd not found on restart file')
|
|
end if
|
|
|
|
! Extract the year
|
|
yr = ymd / year_mask
|
|
end subroutine get_rest_date
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine set_nextsw_cday( nextsw_cday_in )
|
|
|
|
! Set the next radiation calendar day, so that radiation step can be calculated
|
|
!
|
|
! Arguments
|
|
real(r8), intent(IN) :: nextsw_cday_in ! input calday of next radiation computation
|
|
|
|
character(len=*), parameter :: sub = 'clm::set_nextsw_cday'
|
|
|
|
nextsw_cday = nextsw_cday_in
|
|
|
|
end subroutine set_nextsw_cday
|
|
|
|
!=========================================================================================
|
|
|
|
function is_beg_curr_day()
|
|
|
|
! Return true if current timestep is first timestep in current day.
|
|
|
|
! Return value
|
|
logical :: is_beg_curr_day
|
|
|
|
! Local variables
|
|
integer ::&
|
|
yr, &! year
|
|
mon, &! month
|
|
day, &! day of month
|
|
tod ! time of day (seconds past 0Z)
|
|
|
|
call get_curr_date(yr, mon, day, tod)
|
|
is_beg_curr_day = ( tod == dtime )
|
|
|
|
end function is_beg_curr_day
|
|
|
|
!=========================================================================================
|
|
|
|
function is_end_curr_day()
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Return true if current timestep is last timestep in current day.
|
|
|
|
! 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)
|
|
!---------------------------------------------------------------------------------
|
|
|
|
call get_curr_date(yr, mon, day, tod)
|
|
is_end_curr_day = (tod == 0)
|
|
|
|
end function is_end_curr_day
|
|
|
|
!=========================================================================================
|
|
|
|
logical function is_end_curr_month()
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Return true if current timestep is last timestep in current month.
|
|
|
|
! Local variables
|
|
integer ::&
|
|
yr, &! year
|
|
mon, &! month
|
|
day, &! day of month
|
|
tod ! time of day (seconds past 0Z)
|
|
!---------------------------------------------------------------------------------
|
|
|
|
call get_curr_date(yr, mon, day, tod)
|
|
is_end_curr_month = (day == 1 .and. tod == 0)
|
|
|
|
end function is_end_curr_month
|
|
|
|
!=========================================================================================
|
|
|
|
logical function is_first_step()
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Return true on first step of initial run only.
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::is_first_step'
|
|
integer :: rc
|
|
integer :: nstep
|
|
integer(ESMF_KIND_I8) :: step_no
|
|
!---------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet( tm_clock, advanceCount=step_no, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
nstep = step_no
|
|
is_first_step = (nstep == 0)
|
|
|
|
end function is_first_step
|
|
!=========================================================================================
|
|
|
|
logical function is_first_restart_step()
|
|
|
|
! Return true on first step of restart run only.
|
|
|
|
is_first_restart_step = tm_first_restart_step
|
|
|
|
end function is_first_restart_step
|
|
|
|
!=========================================================================================
|
|
|
|
logical function is_last_step()
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Return true on last timestep.
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::is_last_step'
|
|
type(ESMF_Time) :: stop_date
|
|
type(ESMF_Time) :: curr_date
|
|
type(ESMF_TimeInterval) :: time_step
|
|
integer :: rc
|
|
!---------------------------------------------------------------------------------
|
|
|
|
call ESMF_ClockGet( tm_clock, stopTime=stop_date, &
|
|
currTime=curr_date, TimeStep=time_step, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_ClockGet')
|
|
if ( curr_date+time_step > stop_date ) then
|
|
is_last_step = .true.
|
|
else
|
|
is_last_step = .false.
|
|
end if
|
|
|
|
end function is_last_step
|
|
|
|
!=========================================================================================
|
|
|
|
logical function is_perpetual()
|
|
|
|
! Return true on last timestep.
|
|
|
|
is_perpetual = tm_perp_calendar
|
|
|
|
end function is_perpetual
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine timemgr_datediff(ymd1, tod1, ymd2, tod2, days)
|
|
|
|
! Calculate the difference (ymd2,tod2) - (ymd1,tod1) and return the result in days.
|
|
! Arguments
|
|
integer, intent(in) ::&
|
|
ymd1, &! date1 in yyyymmdd format
|
|
tod1, &! time of day relative to date1 (seconds past 0Z)
|
|
ymd2, &! date2 in yyyymmdd format
|
|
tod2 ! time of day relative to date2 (seconds past 0Z)
|
|
|
|
real(r8) :: days ! (ymd2,tod2)-(ymd1,tod1) in days
|
|
|
|
! Local variables
|
|
character(len=*), parameter :: sub = 'clm::timemgr_datediff'
|
|
integer :: rc ! return code
|
|
|
|
type(ESMF_Time) :: date1
|
|
type(ESMF_Time) :: date2
|
|
type(ESMF_TimeInterval) :: diff
|
|
!-----------------------------------------------------------------------------------------
|
|
|
|
date1 = TimeSetymd( ymd1, tod1, "date1" )
|
|
date2 = TimeSetymd( ymd2, tod2, "date2" )
|
|
diff = date2 - date1
|
|
call ESMF_TimeIntervalGet( diff, d_r8=days, rc=rc )
|
|
call chkrc(rc, sub//': error return from ESMF_TimeIntervalGet')
|
|
days = days + 1.0_r8
|
|
|
|
end subroutine timemgr_datediff
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine chkrc(rc, mes)
|
|
integer, intent(in) :: rc ! return code from time management library
|
|
character(len=*), intent(in) :: mes ! error message
|
|
if ( rc == ESMF_SUCCESS ) return
|
|
write(iulog,*) mes
|
|
call shr_sys_abort ('CHKRC')
|
|
end subroutine chkrc
|
|
|
|
!=========================================================================================
|
|
|
|
function to_upper(str)
|
|
|
|
!---------------------------------------------------------------------------------
|
|
! Convert character string to upper case. Use achar and iachar intrinsics
|
|
! to ensure use of ascii collating sequence.
|
|
!
|
|
! !INPUT PARAMETERS:
|
|
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
|
|
!---------------------------------------------------------------------------------
|
|
|
|
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
|
|
|
|
!=========================================================================================
|
|
|
|
logical function is_restart( )
|
|
! Determine if restart run
|
|
use clm_varctl, only : nsrest, nsrContinue
|
|
if (nsrest == nsrContinue) then
|
|
is_restart = .true.
|
|
else
|
|
is_restart = .false.
|
|
end if
|
|
end function is_restart
|
|
|
|
!=========================================================================================
|
|
|
|
subroutine timemgr_spmdbcast( )
|
|
|
|
use spmdMod, only : mpicom, MPI_INTEGER
|
|
|
|
integer :: ier
|
|
|
|
call mpi_bcast (dtime , 1, MPI_INTEGER , 0, mpicom, ier)
|
|
|
|
end subroutine timemgr_spmdbcast
|
|
|
|
end module clm_time_manager
|