Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase precision of time handling #833

Merged
merged 4 commits into from
Aug 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions src/core/MOM.F90
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module MOM
use MOM_restart, only : register_restart_field, query_initialized, save_restart
use MOM_restart, only : restart_init, is_new_run, MOM_restart_CS
use MOM_spatial_means, only : global_mass_integral
use MOM_time_manager, only : time_type, set_time, time_type_to_real, operator(+)
use MOM_time_manager, only : time_type, real_to_time, time_type_to_real, operator(+)
use MOM_time_manager, only : operator(-), operator(>), operator(*), operator(/)
use MOM_time_manager, only : operator(>=), increment_date
use MOM_unit_tests, only : unit_tests
Expand Down Expand Up @@ -556,7 +556,7 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &
do j=js,je ; do i=is,ie ; CS%ssh_rint(i,j) = 0.0 ; enddo ; enddo

if (associated(CS%VarMix)) then
call enable_averaging(cycle_time, Time_start+set_time(int(cycle_time)), &
call enable_averaging(cycle_time, Time_start + real_to_time(cycle_time), &
CS%diag)
call calc_resoln_function(h, CS%tv, G, GV, CS%VarMix)
call disable_averaging(CS%diag)
Expand All @@ -582,7 +582,7 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &

if (CS%UseWaves) then
! Update wave information, which is presently kept static over each call to step_mom
call enable_averaging(time_interval, Time_start + set_time(int(floor(time_interval+0.5))), CS%diag)
call enable_averaging(time_interval, Time_start + real_to_time(time_interval), CS%diag)
call Update_Stokes_Drift(G, GV, Waves, h, forces%ustar)
call disable_averaging(CS%diag)
endif
Expand All @@ -604,9 +604,9 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &
do n=1,n_max
rel_time = rel_time + dt ! The relative time at the end of the step.
! Set the universally visible time to the middle of the time step.
CS%Time = Time_start + set_time(int(floor(0.5 + rel_time - 0.5*dt)))
CS%Time = Time_start + real_to_time(rel_time - 0.5*dt)
! Set the local time to the end of the time step.
Time_local = Time_start + set_time(int(floor(rel_time+0.5)))
Time_local = Time_start + real_to_time(rel_time)

if (showCallTree) call callTree_enter("DT cycles (step_MOM) n=",n)

Expand All @@ -633,10 +633,10 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &
if (dtdia > dt) then
! If necessary, temporarily reset CS%Time to the center of the period covered
! by the call to step_MOM_thermo, noting that they begin at the same time.
CS%Time = CS%Time + set_time(int(floor(0.5*(dtdia-dt) + 0.5)))
CS%Time = CS%Time + real_to_time(0.5*(dtdia-dt))
! The end-time of the diagnostic interval needs to be set ahead if there
! are multiple dynamic time steps worth of thermodynamics applied here.
end_time_thermo = Time_local + set_time(int(floor(dtdia-dt+0.5)))
end_time_thermo = Time_local + real_to_time(dtdia-dt)
endif

! Apply diabatic forcing, do mixing, and regrid.
Expand All @@ -649,7 +649,7 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &
if (showCallTree) call callTree_waypoint("finished diabatic_first (step_MOM)")

if (dtdia > dt) & ! Reset CS%Time to its previous value.
CS%Time = Time_start + set_time(int(floor(0.5 + rel_time - 0.5*dt)))
CS%Time = Time_start + real_to_time(rel_time - 0.5*dt)
endif ! end of block "(CS%diabatic_first .and. (CS%t_dyn_rel_adv==0.0))"

if (do_dyn) then
Expand Down Expand Up @@ -731,7 +731,7 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &

! If necessary, temporarily reset CS%Time to the center of the period covered
! by the call to step_MOM_thermo, noting that they end at the same time.
if (dtdia > dt) CS%Time = CS%Time - set_time(int(floor(0.5*(dtdia-dt) + 0.5)))
if (dtdia > dt) CS%Time = CS%Time - real_to_time(0.5*(dtdia-dt))

! Apply diabatic forcing, do mixing, and regrid.
call step_MOM_thermo(CS, G, GV, u, v, h, CS%tv, fluxes, dtdia, &
Expand All @@ -740,7 +740,7 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &
CS%t_dyn_rel_thermo = 0.0

if (dtdia > dt) & ! Reset CS%Time to its previous value.
CS%Time = Time_start + set_time(int(floor(0.5 + rel_time - 0.5*dt)))
CS%Time = Time_start + real_to_time(rel_time - 0.5*dt)
endif

if (do_dyn) then
Expand Down Expand Up @@ -774,7 +774,7 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &
CS%t_dyn_rel_diag = 0.0

call cpu_clock_begin(id_clock_Z_diag)
if (Time_local + set_time(int(0.5*dt_therm)) > CS%Z_diag_time) then
if (Time_local + real_to_time(0.5*dt_therm) > CS%Z_diag_time) then
call enable_averaging(real(time_type_to_real(CS%Z_diag_interval)), &
CS%Z_diag_time, CS%diag)
!### This is the one place where fluxes might used if do_thermo=.false. Is this correct?
Expand Down Expand Up @@ -852,7 +852,7 @@ subroutine step_MOM(forces, fluxes, sfc_state, Time_start, time_interval, CS, &
if (MOM_state_is_synchronized(CS)) &
call write_energy(CS%u, CS%v, CS%h, CS%tv, Time_local, CS%nstep_tot, &
G, GV, CS%sum_output_CSp, CS%tracer_flow_CSp, &
dt_forcing=set_time(int(floor(time_interval+0.5))) )
dt_forcing=real_to_time(time_interval) )

call cpu_clock_end(id_clock_other)

Expand Down Expand Up @@ -912,7 +912,7 @@ subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_thermo, &

if ((CS%t_dyn_rel_adv == 0.0) .and. CS%thickness_diffuse .and. CS%thickness_diffuse_first) then

call enable_averaging(dt_thermo, Time_local+set_time(int(floor(dt_thermo-dt+0.5))), CS%diag)
call enable_averaging(dt_thermo, Time_local+real_to_time(dt_thermo-dt), CS%diag)
call cpu_clock_begin(id_clock_thick_diff)
if (associated(CS%VarMix)) &
call calc_slope_functions(h, CS%tv, dt, G, GV, CS%VarMix)
Expand All @@ -931,7 +931,7 @@ subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_thermo, &
! The bottom boundary layer properties need to be recalculated.
if (bbl_time_int > 0.0) then
call enable_averaging(bbl_time_int, &
Time_local + set_time(int(bbl_time_int-dt+0.5)), CS%diag)
Time_local + real_to_time(bbl_time_int-dt), CS%diag)
! Calculate the BBL properties and store them inside visc (u,h).
call cpu_clock_begin(id_clock_BBL_visc)
call set_viscous_BBL(CS%u, CS%v, CS%h, CS%tv, CS%visc, G, GV, &
Expand Down Expand Up @@ -2286,7 +2286,7 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, &
CS%OBC, CS%update_OBC_CSp, CS%ALE_CSp, CS%set_visc_CSp, &
CS%visc, dirs, CS%ntrunc, calc_dtbt=calc_dtbt)
if (CS%dtbt_reset_period > 0.0) then
CS%dtbt_reset_interval = set_time(int(floor(CS%dtbt_reset_period)))
CS%dtbt_reset_interval = real_to_time(CS%dtbt_reset_period)
! Set dtbt_reset_time to be the next even multiple of dtbt_reset_interval.
CS%dtbt_reset_time = Time_init + CS%dtbt_reset_interval * &
((Time - Time_init) / CS%dtbt_reset_interval)
Expand Down Expand Up @@ -2325,11 +2325,10 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, &
param_file, diag, CS%diagnostics_CSp, CS%tv)
call diag_copy_diag_to_storage(CS%diag_pre_sync, CS%h, CS%diag)

CS%Z_diag_interval = set_time(int((CS%dt_therm) * &
max(1,floor(0.01 + Z_diag_int/(CS%dt_therm)))))
CS%Z_diag_interval = real_to_time(CS%dt_therm * max(1,floor(0.01 + Z_diag_int/CS%dt_therm)))
call MOM_diag_to_Z_init(Time, G, GV, param_file, diag, CS%diag_to_Z_CSp)
CS%Z_diag_time = Start_time + CS%Z_diag_interval * (1 + &
((Time + set_time(int(CS%dt_therm))) - Start_time) / CS%Z_diag_interval)
((Time + real_to_time(CS%dt_therm)) - Start_time) / CS%Z_diag_interval)

if (associated(CS%sponge_CSp)) &
call init_sponge_diags(Time, G, diag, CS%sponge_CSp)
Expand Down
6 changes: 3 additions & 3 deletions src/core/MOM_barotropic.F90
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module MOM_barotropic
use MOM_open_boundary, only : OBC_DIRECTION_N, OBC_DIRECTION_S, OBC_segment_type
use MOM_restart, only : register_restart_field, query_initialized, MOM_restart_CS
use MOM_tidal_forcing, only : tidal_forcing_sensitivity, tidal_forcing_CS
use MOM_time_manager, only : time_type, set_time, operator(+), operator(-)
use MOM_time_manager, only : time_type, real_to_time, operator(+), operator(-)
use MOM_variables, only : BT_cont_type, alloc_bt_cont_type
use MOM_verticalGrid, only : verticalGrid_type

Expand Down Expand Up @@ -723,7 +723,7 @@ subroutine btstep(U_in, V_in, eta_in, dt, bc_accel_u, bc_accel_v, &
(CS%id_uhbt_hifreq > 0) .or. (CS%id_vhbt_hifreq > 0)) then
do_hifreq_output = query_averaging_enabled(CS%diag, time_int_in, time_end_in)
if (do_hifreq_output) &
time_bt_start = time_end_in - set_time(int(floor(dt+0.5)))
time_bt_start = time_end_in - real_to_time(dt)
endif

!--- begin setup for group halo update
Expand Down Expand Up @@ -2008,7 +2008,7 @@ subroutine btstep(U_in, V_in, eta_in, dt, bc_accel_u, bc_accel_v, &
enddo ; enddo

if (do_hifreq_output) then
time_step_end = time_bt_start + set_time(int(floor(n*dtbt+0.5)))
time_step_end = time_bt_start + real_to_time(n*dtbt)
call enable_averaging(dtbt, time_step_end, CS%diag)
if (CS%id_ubt_hifreq > 0) call post_data(CS%id_ubt_hifreq, ubt(IsdB:IedB,jsd:jed), CS%diag)
if (CS%id_vbt_hifreq > 0) call post_data(CS%id_vbt_hifreq, vbt(isd:ied,JsdB:JedB), CS%diag)
Expand Down
2 changes: 1 addition & 1 deletion src/core/MOM_dynamics_split_RK2.F90
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module MOM_dynamics_split_RK2
use MOM_io, only : MOM_io_init, vardesc, var_desc
use MOM_restart, only : register_restart_field, query_initialized, save_restart
use MOM_restart, only : restart_init, is_new_run, MOM_restart_CS
use MOM_time_manager, only : time_type, set_time, time_type_to_real, operator(+)
use MOM_time_manager, only : time_type, time_type_to_real, operator(+)
use MOM_time_manager, only : operator(-), operator(>), operator(*), operator(/)

use MOM_ALE, only : ALE_CS
Expand Down
4 changes: 2 additions & 2 deletions src/core/MOM_dynamics_unsplit.F90
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ module MOM_dynamics_unsplit
use MOM_io, only : MOM_io_init
use MOM_restart, only : register_restart_field, query_initialized, save_restart
use MOM_restart, only : restart_init, MOM_restart_CS
use MOM_time_manager, only : time_type, set_time, time_type_to_real, operator(+)
use MOM_time_manager, only : time_type, real_to_time, operator(+)
use MOM_time_manager, only : operator(-), operator(>), operator(*), operator(/)

use MOM_ALE, only : ALE_CS
Expand Down Expand Up @@ -267,7 +267,7 @@ subroutine step_MOM_dyn_unsplit(u, v, h, tv, visc, Time_local, dt, forces, &
call pass_var(hp, G%Domain, clock=id_clock_pass)
call pass_vector(uh, vh, G%Domain, clock=id_clock_pass)

call enable_averaging(0.5*dt,Time_local-set_time(int(0.5*dt)), CS%diag)
call enable_averaging(0.5*dt,Time_local-real_to_time(0.5*dt), CS%diag)
! Here the first half of the thickness fluxes are offered for averaging.
if (CS%id_uh > 0) call post_data(CS%id_uh, uh, CS%diag)
if (CS%id_vh > 0) call post_data(CS%id_vh, vh, CS%diag)
Expand Down
2 changes: 1 addition & 1 deletion src/core/MOM_dynamics_unsplit_RK2.F90
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ module MOM_dynamics_unsplit_RK2
use MOM_io, only : MOM_io_init
use MOM_restart, only : register_restart_field, query_initialized, save_restart
use MOM_restart, only : restart_init, MOM_restart_CS
use MOM_time_manager, only : time_type, set_time, time_type_to_real, operator(+)
use MOM_time_manager, only : time_type, time_type_to_real, operator(+)
use MOM_time_manager, only : operator(-), operator(>), operator(*), operator(/)

use MOM_ALE, only : ALE_CS
Expand Down
12 changes: 5 additions & 7 deletions src/framework/MOM_file_parser.F90
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ module MOM_file_parser
use MOM_coms, only : root_PE, broadcast
use MOM_error_handler, only : MOM_error, FATAL, WARNING, MOM_mesg
use MOM_error_handler, only : is_root_pe, stdlog, stdout
use MOM_time_manager, only : set_time, get_time, time_type, get_ticks_per_second
use MOM_time_manager, only : set_date, get_date
use MOM_time_manager, only : get_time, time_type, get_ticks_per_second
use MOM_time_manager, only : set_date, get_date, real_to_time, operator(-), set_time
use MOM_document, only : doc_param, doc_module, doc_init, doc_end, doc_type
use MOM_document, only : doc_openBlock, doc_closeBlock
use MOM_string_functions, only : left_int, left_ints, slasher
Expand Down Expand Up @@ -821,7 +821,7 @@ subroutine read_param_time(CS, varname, value, timeunit, fail_if_missing, date_f
character(len=240) :: err_msg
logical :: found, defined
real :: real_time, time_unit
integer :: days, secs, vals(7)
integer :: vals(7)

if (present(date_format)) date_format = .false.

Expand Down Expand Up @@ -854,10 +854,8 @@ subroutine read_param_time(CS, varname, value, timeunit, fail_if_missing, date_f
else
time_unit = 1.0 ; if (present(timeunit)) time_unit = timeunit
read( value_string(1), *) real_time
days = int(real_time*(time_unit/86400.0))
secs = int(floor((real_time*(time_unit/86400.0)-days)*86400.0 + 0.5))
value = set_time(secs, days)
endif
value = real_to_time(real_time*time_unit)
endif
else
if (present(fail_if_missing)) then ; if (fail_if_missing) then
if (.not.found) then
Expand Down
2 changes: 1 addition & 1 deletion src/framework/MOM_horizontal_regridding.F90
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module MOM_horizontal_regridding
use MOM_io, only : open_file, read_data, read_axis_data, SINGLE_FILE, MULTIPLE
use MOM_io, only : slasher, vardesc, write_field
use MOM_string_functions, only : uppercase
use MOM_time_manager, only : time_type, set_time, get_external_field_size
use MOM_time_manager, only : time_type, get_external_field_size
use MOM_time_manager, only : init_external_field, time_interp_external
use MOM_time_manager, only : get_external_field_axes, get_external_field_missing
use MOM_variables, only : thermo_var_ptrs
Expand Down
17 changes: 7 additions & 10 deletions src/framework/MOM_restart.F90
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ module MOM_restart
use MOM_io, only : vardesc, var_desc, query_vardesc, modify_vardesc
use MOM_io, only : MULTIPLE, NETCDF_FILE, READONLY_FILE, SINGLE_FILE
use MOM_io, only : CENTER, CORNER, NORTH_FACE, EAST_FACE
use MOM_time_manager, only : time_type, get_time, get_date, set_date, set_time
use MOM_time_manager, only : days_in_month
use MOM_time_manager, only : time_type, time_type_to_real, real_to_time
use MOM_time_manager, only : days_in_month, get_date, set_date
use MOM_verticalGrid, only : verticalGrid_type
use mpp_mod, only: mpp_chksum
use mpp_io_mod, only: mpp_attribute_exist, mpp_get_atts
Expand Down Expand Up @@ -801,15 +801,14 @@ subroutine save_restart(directory, time, G, CS, time_stamped, filename, GV)

! With parallel read & write, it is possible to disable the following...

! jgj: this was set to 4294967292, changed to 4294967295 (see mpp_parameter.F90)
if (CS%large_file_support) max_file_size = 4294967295_8
! The maximum file size is 4294967292, according to the NetCDF documentation.
if (CS%large_file_support) max_file_size = 4294967292_8

num_files = 0
next_var = 0
nz = 1 ; if (present(GV)) nz = GV%ke

call get_time(time,seconds,days)
restart_time = real(days) + real(seconds)/86400.0
restart_time = time_type_to_real(time) / 86400.0

restartname = trim(CS%restartfile)
if (present(filename)) restartname = trim(filename)
Expand Down Expand Up @@ -982,7 +981,7 @@ subroutine restore_state(filename, directory, day, G, CS)
character(len=80) :: varname ! A variable's name.
integer :: num_file ! The number of files (restart files and others
! explicitly in filename) that are open.
integer :: i, n, m, start_of_day, num_days, missing_fields
integer :: i, n, m, missing_fields
integer :: isL, ieL, jsL, jeL, is0, js0
integer :: sizes(7)
integer :: ndim, nvar, natt, ntime, pos
Expand Down Expand Up @@ -1028,9 +1027,7 @@ subroutine restore_state(filename, directory, day, G, CS)
t1 = time_vals(1)
deallocate(time_vals)

start_of_day = INT((t1 - INT(t1)) *86400) ! Number of seconds.
num_days = INT(t1)
day = set_time(start_of_day, num_days)
day = real_to_time(t1*86400.0)
exit
enddo

Expand Down
30 changes: 28 additions & 2 deletions src/framework/MOM_time_manager.F90
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ module MOM_time_manager

implicit none ; private

public :: time_type, get_time, set_time, time_type_to_real, real_to_time_type
public :: set_ticks_per_second , get_ticks_per_second
public :: time_type, get_time, set_time
public :: time_type_to_real, real_to_time_type, real_to_time
public :: set_ticks_per_second, get_ticks_per_second
public :: operator(+), operator(-), operator(*), operator(/)
public :: operator(>), operator(<), operator(>=), operator(<=)
public :: operator(==), operator(/=), operator(//)
Expand All @@ -35,4 +36,29 @@ module MOM_time_manager
public :: get_external_field_axes
public :: get_external_field_missing

contains

!> This is an alternate implementation of the FMS function real_to_time_type that is accurate over
!! a larger range of input values. With 32 bit signed integers, this version should work over the
!! entire valid range (2^31 days or ~5.8835 million years) of time_types, whereas the standard
!! version in the FMS time_manager stops working for conversions of times greater than 2^31 seconds,
!! or ~68.1 years.
function real_to_time(x, err_msg)
type(time_type) :: real_to_time !< The output time as a time_type
real, intent(in) :: x !< The input time in real seconds.
character(len=*), intent(out), optional :: err_msg !< An optional returned error message.

! Local variables
integer :: seconds, days, ticks
real :: real_subsecond_remainder

days = floor(x/86400.)
seconds = floor(x - 86400.*days)
real_subsecond_remainder = x - (days*86400. + seconds)
ticks = nint(real_subsecond_remainder * get_ticks_per_second())

real_to_time = set_time(seconds=seconds, days=days, ticks=ticks, err_msg=err_msg)
end function real_to_time


end module MOM_time_manager
6 changes: 3 additions & 3 deletions src/ice_shelf/MOM_ice_shelf.F90
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module MOM_ice_shelf
use MOM_io, only : write_field, close_file, SINGLE_FILE, MULTIPLE
use MOM_restart, only : register_restart_field, query_initialized, save_restart
use MOM_restart, only : restart_init, restore_state, MOM_restart_CS
use MOM_time_manager, only : time_type, set_time, time_type_to_real
use MOM_time_manager, only : time_type, time_type_to_real, time_type_to_real, real_to_time
use MOM_transcribe_grid, only : copy_dyngrid_to_MOM_grid, copy_MOM_grid_to_dyngrid
use MOM_variables, only : surface
use MOM_forcing_type, only : forcing, allocate_forcing_type, MOM_forcing_chksum
Expand All @@ -47,7 +47,7 @@ module MOM_ice_shelf
use MOM_checksums, only : hchksum, qchksum, chksum, uchksum, vchksum, uvchksum
use time_interp_external_mod, only : init_external_field, time_interp_external
use time_interp_external_mod, only : time_interp_external_init
use time_manager_mod, only : print_time, time_type_to_real, real_to_time_type
use time_manager_mod, only : print_time
implicit none ; private

#include <MOM_memory.h>
Expand Down Expand Up @@ -979,7 +979,7 @@ subroutine add_shelf_flux(G, CS, state, fluxes)

! just compute changes in mass after first time step
if (t0>0.0) then
Time0 = real_to_time_type(t0)
Time0 = real_to_time(t0)
last_hmask(:,:) = ISS%hmask(:,:) ; last_area_shelf_h(:,:) = ISS%area_shelf_h(:,:)
call time_interp_external(CS%id_read_mass, Time0, last_mass_shelf)
last_h_shelf = last_mass_shelf/CS%density_ice
Expand Down
Loading