Skip to content

Commit

Permalink
Merge PR E3SM-Project#1418 'matthewhoffman/framework/output_record_re…
Browse files Browse the repository at this point in the history
…ference_time' into develop

Previously, a stream's reference_time only applied to determining the
filename breaks. Right now, output is always relative to the time of
the start of the current simulation (even if it is a restart). There is
no way to force, say, monthly output (i.e. on the 1st of every month) if
your restart does not start on the first of a month.

This commit extends reference_time to also apply to
determining when individual records should be written. Thus, output
stream behavior will not change after a restart.

This is done by adding a new routine to mpas_timekeeping that adjusts
the prevRingTime of an alarm to be an integer multiple of the stream's
output_interval away from the stream's reference_time. This routine is
called for each output stream created by the stream manager.

Fixes Issue E3SM-Project#1307.
  • Loading branch information
mark-petersen committed Oct 10, 2017
2 parents 263e14f + 5bf84f9 commit f444d0f
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 9 deletions.
36 changes: 27 additions & 9 deletions src/framework/mpas_stream_manager.F
Original file line number Diff line number Diff line change
Expand Up @@ -6016,9 +6016,11 @@ subroutine stream_mgr_add_alarm_c(manager_c, streamID_c, direction_c, alarmTime_
use mpas_derived_types, only : MPAS_streamManager_type, MPAS_Clock_type, MPAS_Time_type, MPAS_TimeInterval_type, &
MPAS_STREAM_MGR_NOERR, MPAS_STREAM_INPUT, MPAS_STREAM_OUTPUT, MPAS_START_TIME, &
MPAS_STOP_TIME, MPAS_STREAM_PROPERTY_REF_TIME
use mpas_stream_manager, only : MPAS_stream_mgr_get_clock, MPAS_stream_mgr_add_alarm, MPAS_stream_mgr_set_property
use mpas_stream_manager, only : MPAS_stream_mgr_get_clock, MPAS_stream_mgr_add_alarm, MPAS_stream_mgr_set_property, &
MPAS_stream_mgr_get_property
use mpas_kind_types, only : StrKIND
use mpas_timekeeping, only : mpas_add_clock_alarm, mpas_set_time, mpas_get_time, mpas_set_timeInterval, mpas_get_clock_time
use mpas_timekeeping, only : mpas_add_clock_alarm, mpas_set_time, mpas_get_time, mpas_set_timeInterval, mpas_get_clock_time, &
mpas_adjust_alarm_to_reference_time
implicit none
Expand All @@ -6034,11 +6036,14 @@ subroutine stream_mgr_add_alarm_c(manager_c, streamID_c, direction_c, alarmTime_
character(len=StrKIND) :: streamID, direction, alarmID, alarmTime, alarmInterval, alarmString
type (MPAS_Time_type) :: alarmTime_local
type (MPAS_TimeInterval_type) :: alarmInterval_local
character(len=StrKIND) :: streamReferenceTimeString
type (MPAS_Time_type) :: streamReferenceTime
integer :: idirection
integer :: ierr
integer :: ierr, ierr_tmp
ierr = 0
ierr_tmp = 0
call c_f_pointer(manager_c, manager)
call mpas_c_to_f_string(streamID_c, streamID)
Expand All @@ -6061,23 +6066,36 @@ subroutine stream_mgr_add_alarm_c(manager_c, streamID_c, direction_c, alarmTime_
call MPAS_stream_mgr_get_clock(manager, clock)
if (trim(alarmTime) == 'start' .and. trim(alarmInterval) == 'final_only') then
alarmTime_local = mpas_get_clock_time(clock, MPAS_STOP_TIME, ierr=ierr)
alarmTime_local = mpas_get_clock_time(clock, MPAS_STOP_TIME, ierr=ierr_tmp)
ierr = ior(ierr, ierr_tmp)
call mpas_get_time(alarmTime_local, dateTimeString=alarmString)
call MPAS_stream_mgr_set_property(manager, streamID, MPAS_STREAM_PROPERTY_REF_TIME, alarmString, ierr=ierr)
call MPAS_stream_mgr_set_property(manager, streamID, MPAS_STREAM_PROPERTY_REF_TIME, alarmString, ierr=ierr_tmp)
ierr = ior(ierr, ierr_tmp)
else if (trim(alarmTime) == 'start') then
alarmTime_local = mpas_get_clock_time(clock, MPAS_START_TIME, ierr=ierr)
alarmTime_local = mpas_get_clock_time(clock, MPAS_START_TIME, ierr=ierr_tmp)
ierr = ior(ierr, ierr_tmp)
else
call mpas_set_time(alarmTime_local, dateTimeString=alarmTime)
end if
if (trim(alarmInterval) == 'initial_only' .or. trim(alarmInterval) == 'final_only') then
call mpas_add_clock_alarm(clock, alarmID, alarmTime_local, ierr=ierr)
call mpas_add_clock_alarm(clock, alarmID, alarmTime_local, ierr=ierr_tmp)
ierr = ior(ierr, ierr_tmp)
else
call mpas_set_timeInterval(alarmInterval_local, timeString=alarmInterval)
call mpas_add_clock_alarm(clock, alarmID, alarmTime_local, alarmTimeInterval=alarmInterval_local, ierr=ierr)
call mpas_add_clock_alarm(clock, alarmID, alarmTime_local, alarmTimeInterval=alarmInterval_local, ierr=ierr_tmp)
ierr = ior(ierr, ierr_tmp)
! Now calibrate alarm to use the stream's reference time as the time coordinate origin for the stream's output alarm.
call MPAS_stream_mgr_get_property(manager, streamID, MPAS_STREAM_PROPERTY_REF_TIME, streamReferenceTimeString, ierr=ierr_tmp)
ierr = ior(ierr, ierr_tmp)
call mpas_set_time(streamReferenceTime, dateTimeString=streamReferenceTimeString, ierr=ierr_tmp)
ierr = ior(ierr, ierr_tmp)
call mpas_adjust_alarm_to_reference_time(clock, alarmID, streamReferenceTime, ierr)
ierr = ior(ierr, ierr_tmp)
end if
call MPAS_stream_mgr_add_alarm(manager, streamID, alarmID, idirection, ierr=ierr)
call MPAS_stream_mgr_add_alarm(manager, streamID, alarmID, idirection, ierr=ierr_tmp)
ierr = ior(ierr, ierr_tmp)
if (ierr == MPAS_STREAM_MGR_NOERR) then
ierr_c = 0
Expand Down
69 changes: 69 additions & 0 deletions src/framework/mpas_timekeeping.F
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,75 @@ subroutine mpas_reset_clock_alarm(clock, alarmID, interval, ierr)
end subroutine mpas_reset_clock_alarm


! Adjust the previous ring time of a recurring alarm to be away from a provided reference time
! by an integer multiple of the alarm's interval.
! This is useful if the alarm's default prevRingTime, which is the current time when the alarm
! is created, is not desired.
subroutine mpas_adjust_alarm_to_reference_time(clock, alarmID, referenceTime, ierr)

implicit none

type (MPAS_Clock_type), intent(inout) :: clock
character (len=*), intent(in) :: alarmID
type (MPAS_Time_type) :: referenceTime
type (MPAS_Time_type) :: now
integer, intent(out) :: ierr

! Local variables
type (MPAS_Alarm_type), pointer :: alarmPtr
type (MPAS_TimeInterval_type) :: searchInterval, searchRemainder
integer (kind=I8KIND) :: nDivs
integer :: threadNum
integer :: ierr_tmp

ierr = 0
ierr_tmp = 0

threadNum = mpas_threading_get_thread_num()

if ( threadNum == 0 ) then
alarmPtr => clock % alarmListHead
do while (associated(alarmPtr))

if (trim(alarmPtr % alarmID) == trim(alarmID)) then

if (alarmPtr % isRecurring) then
!call mpas_print_alarm(clock, alarmID, ierr_tmp)
now = mpas_get_clock_time(clock, MPAS_NOW, ierr_tmp)
ierr = ior(ierr, ierr_tmp)
if(clock % direction == MPAS_FORWARD) then
if (now > referenceTime) then
searchInterval = now - referenceTime
call mpas_interval_division(referenceTime, searchInterval, alarmPtr % ringTimeInterval, nDivs, searchRemainder)
alarmPtr % prevRingTime = now - searchRemainder
else
searchInterval = referenceTime - now
call mpas_interval_division(referenceTime, searchInterval, alarmPtr % ringTimeInterval, nDivs, searchRemainder)
alarmPtr % prevRingTime = now - (alarmPtr % ringTimeInterval - searchRemainder)
endif
else ! MPAS_REVERSE
if (now < referenceTime) then
searchInterval = now - referenceTime
call mpas_interval_division(referenceTime, searchInterval, alarmPtr % ringTimeInterval, nDivs, searchRemainder)
alarmPtr % prevRingTime = now - searchRemainder
else
searchInterval = referenceTime - now
call mpas_interval_division(referenceTime, searchInterval, alarmPtr % ringTimeInterval, nDivs, searchRemainder)
alarmPtr % prevRingTime = now - (alarmPtr % ringTimeInterval - searchRemainder)
endif
end if ! forward direction
!call mpas_print_alarm(clock, alarmID, ierr_tmp)
end if ! isRecurring
exit ! exit after we found the alarm we were looking for
end if ! if this alarm we were looking for
alarmPtr => alarmPtr % next
end do
end if ! thread check

!$omp barrier
end subroutine mpas_adjust_alarm_to_reference_time



! specify a valid previousRingTime for each alarm
subroutine mpas_calibrate_alarms(clock, ierr)
Expand Down

0 comments on commit f444d0f

Please sign in to comment.