← back to index

config_src/infra/FMS2/MOM_time_manager.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Wraps the FMS time manager functions
6module MOM_time_manager
7
8use time_manager_mod, only : time_type, get_time, set_time
9use time_manager_mod, only : time_type_to_real, real_to_time_type
10use time_manager_mod, only : operator(+), operator(-), operator(*), operator(/)
11use time_manager_mod, only : operator(>), operator(<), operator(>=), operator(<=)
12use time_manager_mod, only : operator(==), operator(/=), operator(//)
13use time_manager_mod, only : set_ticks_per_second , get_ticks_per_second
14use time_manager_mod, only : get_date, set_date, increment_date
15use time_manager_mod, only : days_in_month, month_name
16use time_manager_mod, only : set_calendar_type, get_calendar_type
17use time_manager_mod, only : JULIAN, NOLEAP, THIRTY_DAY_MONTHS, GREGORIAN
18use time_manager_mod, only : NO_CALENDAR
19
20implicit none ; private
21
22! FMS re-exports
23public :: time_type, get_time, set_time
24public :: time_type_to_real, real_to_time_type
25public :: set_ticks_per_second, get_ticks_per_second
26public :: operator(+), operator(-), operator(*), operator(/)
27public :: operator(>), operator(<), operator(>=), operator(<=)
28public :: operator(==), operator(/=), operator(//)
29public :: get_date, set_date, increment_date, month_name, days_in_month
30public :: JULIAN, NOLEAP, THIRTY_DAY_MONTHS, GREGORIAN, NO_CALENDAR
31public :: set_calendar_type, get_calendar_type
32! Module functions
33public :: real_to_time, time_minus_signed, time_to_real
34
35contains
36
37!> Returns a time_type version of a real time in seconds, using an alternate implementation to the
38!! FMS function real_to_time_type that is accurate over a larger range of input values. With 32 bit
39!! signed integers, this version should work over the entire valid range (2^31 days or ~5.8835
40!! million years) of time_types, whereas the standard version in the FMS time_manager stops working
41!! for conversions of times greater than 2^31 seconds, or ~68.1 years.
42139type(time_type) function real_to_time(time_in, err_msg, unscale)
43! type(time_type) :: real_to_time !< The output time as a time_type
44 real, intent(in) :: time_in !< The input time in [s] or [T ~> s]
45 character(len=*), optional, intent(out) :: err_msg !< An optional returned error message.
46 real, optional, intent(in) :: unscale !< A scaling factor that the input time is
47 !! multiplied by, often in [s T-1 ~> nondim]
48
49 ! Local variables
50 real :: x ! The time in real seconds [s]
51 real :: real_subsecond_remainder ! The fractional seconds from time_in [s]
52 integer :: seconds, days, ticks
53
54134 x = time_in ; if (present(unscale)) x = unscale*time_in
55
56139 days = floor(x/86400.)
57139 seconds = floor(x - 86400.*days)
58139 real_subsecond_remainder = x - (days*86400. + seconds)
59139 ticks = nint(real_subsecond_remainder * get_ticks_per_second())
60
61139 real_to_time = set_time(seconds=seconds, days=days, ticks=ticks, err_msg=err_msg)
62
63278end function real_to_time
64
65!> Returns the real number of seconds encoded in the time type [s] or the rescaled
66!! amount of time in other units, often [T ~> s]
6725real function time_to_real(time, scale)
68 type(time_type), intent(in) :: time !< The time to be converted.
69 real, optional, intent(in) :: scale !< A scaling factor that returned the time is
70 !! multiplied by, often in [T s-1 ~> nondim]
71
7225 time_to_real = time_type_to_real(time)
7325 if (present(scale)) time_to_real = scale * time_to_real
74
7525end function time_to_real
76
77!> Returns a real number representing time_a - time_b in [s] or [T ~> s] if scale is present.
78!! The FMS - operator for time types returns a new time type representing
79!! a difference that is always >= 0.
80!! In contrast, this function returns a negative real number if time_b > time_a,
81!! and a positive real otherwise, as would be expected for subtraction.
820real function time_minus_signed(time_a, time_b, scale)
83 type(time_type), intent(in) :: time_a, time_b !< Two times for calculating time_a - time_b
84 real, optional, intent(in) :: scale !< A scaling factor that returned the time is
85 !! multiplied by, often in [T s-1 ~> nondim]
86
87 ! Local variables
88 real :: abs_diff ! The absolute value of the difference in times [s] or [T ~> s]
89
90 ! Do FMS time subtraction, which will always be >= 0,
91 ! and convert to a real number.
920 abs_diff = time_to_real(time_a - time_b, scale)
93
94 ! Add the sign back by comparing time_a and time_b
950 time_minus_signed = merge(abs_diff, -abs_diff, time_a >= time_b)
96
970end function time_minus_signed
98
99end module MOM_time_manager