!***********************************************************************
!* GNU Lesser General Public License
!*
!* This file is part of the GFDL Flexible Modeling System (FMS).
!*
!* FMS is free software: you can redistribute it and/or modify it under
!* the terms of the GNU Lesser General Public License as published by
!* the Free Software Foundation, either version 3 of the License, or (at
!* your option) any later version.
!*
!* FMS is distributed in the hope that it will be useful, but WITHOUT
!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
!* for more details.
!*
!* You should have received a copy of the GNU Lesser General Public
!* License along with FMS. If not, see .
!***********************************************************************
module time_interp_mod
!
! Bruce Wyman
!
!
!
! Computes a weight and dates/indices for linearly interpolating between two dates.
!
!
! A time type is converted into two consecutive dates plus
! a fraction representing the distance between the dates.
! This information can be used to interpolate between the dates.
! The dates may be expressed as years, months, or days or
! as indices in an array.
!
!
! Description summarizing public interface.
!
!-----------------------------------------------------------------------
use time_manager_mod, only: time_type, get_date, set_date, set_time, &
days_in_year, days_in_month, leap_year, &
time_type_to_real, real_to_time_type, &
get_calendar_type, JULIAN, GREGORIAN, NO_CALENDAR, &
operator(+), operator(-), operator(>), &
operator(<), operator( // ), operator( / ), &
operator(>=), operator(<=), operator( * ), &
operator(==), print_date, print_time,&
time_list_error, date_to_string
use fms_mod, only: write_version_number, &
error_mesg, FATAL, stdout, stdlog, &
open_namelist_file, close_file, check_nml_error, &
fms_error_handler
use mpp_mod, only: input_nml_file
implicit none
private
!-----------------------------------------------------------------------
public :: time_interp_init, time_interp, fraction_of_year
!
!
! Returns a weight and dates or indices for interpolating between two dates. The
! interface fraction_of_year is provided for backward compatibility with the
! previous version.
!
!
! Returns weight by interpolating Time between Time1 and Time2.
! i.e. weight = (Time-Time1)/(Time2-Time1)
! Time1 and Time2 may be specified by any of several different ways,
! which is the reason for multiple interfaces.
! If Time1 and Time2 are the begining and end of the year in which
! Time falls, use first interface.
! If Time1 and Time2 fall on year boundaries, use second interface.
! If Time1 and Time2 fall on month boundaries, use third.
! If Time1 and Time2 fall on day boundaries, use fourth.
! If Time1 and Time2 are consecutive elements of an assending list, use fifth.
! The fifth also returns the indices of Timelist between which Time falls.
! The sixth interface is for cyclical data. Time_beg and Time_end specify the
! begining and end of a repeating period. In this case:
! weight = (Time_adjusted - Time1) / (Time2 - Time1)
! Where:
! Time1 = Timelist(index1)
! Time2 = Timelist(index2)
! Time_adjusted = Time - N*Period
! Period = Time_end-Time_beg
! N is between (Time-Time_end)/Period and (Time-Time_beg)/Period
! That is, N is the integer that results in Time_adjusted that is between Time_beg and Time_end.
!
!
!
! 1. call time_interp( Time, weight )
!
!
! 2. call time_interp( Time, weight, year1, year2 )
!
!
! 3. call time_interp( Time, weight, year1, year2, month1, month2 )
!
!
! 4. call time_interp( Time, weight, year1, year2, month1, month2, day1, day2 )
!
!
! 5. call time_interp( Time, Timelist, weight, index1, index2 [, modtime] )
!
!
! 6. call time_interp( Time, Time_beg, Time_end, Timelist, weight, index1, index2 [,correct_leap_year_inconsistency])
!
!
! The time at which the the weight is computed.
!
!
! For cyclical interpolation: Time_beg specifies the begining time of a cycle.
!
!
! For cyclical interpolation: Time_end specifies the ending time of a cycle.
!
!
! For cyclical interpolation: Timelist is an array of times between Time_beg and Time_end.
! Must be monotonically increasing.
!
!
!
!
! Timelist(index1) = The largest value of Timelist which is less than mod(Time,Time_end-Time_beg)
!
!
! Timelist(index2) = The smallest value of Timelist which is greater than mod(Time,Time_end-Time_beg)
!
!
! Turns on a kluge for an inconsistency which may occur in a special case.
! When the modulo time period (i.e. Time_end - Time_beg) is a whole number of years
! and is not a multiple of 4, and the calendar in use has leap years, then it is
! likely that the interpolation will involve mapping a common year onto a leap year.
! In this case it is often desirable, but not absolutely necessary, to use data for
! Feb 28 of the leap year when it is mapped onto a common year.
! To turn this on, set correct_leap_year_inconsistency=.true.
!
!
! weight = (mod(Time,Time_end-Time_beg) - Timelist(index1)) / (Timelist(index2) - Timelist(index1))
!
!
!
!
!
!
!
!
!
!
! The list of input time types must have ascending dates.
!
!
! The length of the current month for input Time and Time_list
! must be the same when using the modulo month option. The
! modulo month option is available but not supported.
!
!
! The optional argument modtime must have a value set by one
! of the public parameters: NONE, YEAR, MONTH, DAY. The
! MONTH and DAY options are available but not supported.
!
!
! The difference between the last and first values in the input
! Time list/array exceeds the length of the modulo period.
!
!
! The difference between the last and first values in the input
! These errors occur when you are not using a modulo axis and
! the input Time occurs before the first value in the Time
! list/array or after the last value in the Time list/array.
!
!
! Examples:
!
!
interface time_interp
module procedure time_interp_frac, time_interp_year, &
time_interp_month, time_interp_day, &
time_interp_list, time_interp_modulo
end interface
!
integer, public, parameter :: NONE=0, YEAR=1, MONTH=2, DAY=3
!-----------------------------------------------------------------------
integer, parameter :: secmin = 60, minhour = 60, hourday = 24, &
sechour = secmin*minhour, &
secday = secmin*minhour*hourday
integer, parameter :: monyear = 12
integer, parameter :: halfday = secday/2
integer :: yrmod, momod, dymod
logical :: mod_leapyear
! Include variable "version" to be written to log file.
#include
logical :: module_is_initialized=.FALSE.
logical :: perthlike_behavior=.FALSE.
namelist / time_interp_nml / perthlike_behavior
contains
subroutine time_interp_init()
integer :: ierr, io, namelist_unit, logunit
if ( module_is_initialized ) return
#ifdef INTERNAL_FILE_NML
read (input_nml_file, time_interp_nml, iostat=io)
ierr = check_nml_error (io, 'time_interp_nml')
#else
namelist_unit = open_namelist_file()
ierr=1
do while (ierr /= 0)
read(namelist_unit, nml=time_interp_nml, iostat=io, end=20)
ierr = check_nml_error (io, 'time_interp_nml')
enddo
20 call close_file (namelist_unit)
#endif
call write_version_number("TIME_INTERP_MOD", version)
logunit = stdlog()
write(logunit,time_interp_nml)
module_is_initialized = .TRUE.
end subroutine time_interp_init
!#######################################################################
!
!
!
!
! returns the fractional time into the current year
subroutine time_interp_frac ( Time, weight )
type(time_type), intent(in) :: Time
real , intent(out) :: weight
integer :: year, month, day, hour, minute, second
type(time_type) :: Year_beg, Year_end
if ( .not. module_is_initialized ) call time_interp_init
! ---- compute fractional time of year -----
call get_date (Time, year, month, day, hour, minute, second)
Year_beg = set_date(year , 1, 1)
Year_end = set_date(year+1, 1, 1)
weight = (Time - Year_beg) // (Year_end - Year_beg)
end subroutine time_interp_frac
!#######################################################################
!
!
! Wrapper for backward compatibility
!
!
function fraction_of_year (Time)
type(time_type), intent(in) :: Time
real :: fraction_of_year
call time_interp_frac ( Time, fraction_of_year )
end function fraction_of_year
!#######################################################################
!
!
!
!
!
!
! returns fractional time between mid points of consecutive years
subroutine time_interp_year ( Time, weight, year1, year2 )
type(time_type), intent(in) :: Time
real , intent(out) :: weight
integer , intent(out) :: year1, year2
integer :: year, month, day, hour, minute, second
type (time_type) :: Mid_year, Mid_year1, Mid_year2
if ( .not. module_is_initialized ) call time_interp_init()
call get_date (Time, year, month, day, hour, minute, second)
! mid point of current year
Mid_year = year_midpt(year)
if ( Time >= Mid_year ) then
! current time is after mid point of current year
year1 = year
year2 = year+1
Mid_year2 = year_midpt(year2)
weight = (Time - Mid_year) // (Mid_year2 - Mid_year)
else
! current time is before mid point of current year
year2 = year
year1 = year-1
Mid_year1 = year_midpt(year1)
weight = (Time - Mid_year1) // (Mid_year - Mid_year1)
endif
end subroutine time_interp_year
!#######################################################################
!
!
!
!
!
!
!
!
! returns fractional time between mid points of consecutive months
subroutine time_interp_month ( Time, weight, year1, year2, month1, month2 )
type(time_type), intent(in) :: Time
real , intent(out) :: weight
integer , intent(out) :: year1, year2, month1, month2
integer :: year, month, day, hour, minute, second, &
mid_month, cur_month, mid1, mid2
if ( .not. module_is_initialized ) call time_interp_init()
call get_date (Time, year, month, day, hour, minute, second)
! mid point of current month in seconds
mid_month = days_in_month(Time) * halfday
! time into current month in seconds
cur_month = second + secmin*minute + sechour*hour + secday*(day-1)
if ( cur_month >= mid_month ) then
! current time is after mid point of current month
year1 = year; month1 = month
year2 = year; month2 = month+1
if (month2 > monyear) then
year2 = year2+1; month2 = 1
endif
mid1 = mid_month
mid2 = days_in_month(set_date(year2,month2,2)) * halfday
weight = real(cur_month - mid1) / real(mid1+mid2)
else
! current time is before mid point of current month
year2 = year; month2 = month
year1 = year; month1 = month-1
if (month1 < 1) then
year1 = year1-1; month1 = monyear
endif
if (year1>0) then
mid1 = days_in_month(set_date(year1,month1,2)) * halfday
else
! this can happen if we are at the beginning of year 1. In this case
! use December 0001 to calculate the duration of December 0000.
! This should work for all calendars
mid1 = days_in_month(set_date(1,month1,2)) * halfday
endif
mid2 = mid_month
weight = real(cur_month + mid1) / real(mid1+mid2)
endif
end subroutine time_interp_month
!#######################################################################
!
!
!
!
!
!
!
!
!
!
! returns fractional time between mid points of consecutive days
subroutine time_interp_day ( Time, weight, year1, year2, month1, month2, day1, day2 )
type(time_type), intent(in) :: Time
real , intent(out) :: weight
integer , intent(out) :: year1, year2, month1, month2, day1, day2
integer :: year, month, day, hour, minute, second, sday
if ( .not. module_is_initialized ) call time_interp_init()
call get_date (Time, year, month, day, hour, minute, second)
! time into current day in seconds
sday = second + secmin*minute + sechour*hour
if ( sday >= halfday ) then
! current time is after mid point of day
year1 = year; month1 = month; day1 = day
year2 = year; month2 = month; day2 = day + 1
weight = real(sday - halfday) / real(secday)
if (day2 > days_in_month(Time)) then
month2 = month2 + 1
day2 = 1
if (month2 > monyear) then
month2 = 1; year2 = year2+1
endif
endif
else
! current time is before mid point of day
year2 = year; month2 = month; day2 = day
year1 = year; month1 = month; day1 = day - 1
weight = real(sday + halfday) / real(secday)
if (day1 < 1) then
month1 = month1 - 1
if (month1 < 1) then
month1 = monyear; year1 = year1-1
endif
day1 = days_in_month(set_date(year1,month1,2))
endif
endif
end subroutine time_interp_day
!#######################################################################
!
!
!
!
!
!
! Turns on a kluge for an inconsistency which may occur in a special case.
! When the modulo time period (i.e. Time_end - Time_beg) is a whole number of years
! and is not a multiple of 4, and the calendar in use has leap years, then it is
! likely that the interpolation will involve mapping a common year onto a leap year.
! In this case it is often desirable, but not absolutely necessary, to use data for
! Feb 28 of the leap year when it is mapped onto a common year.
! To turn this on, set correct_leap_year_inconsistency=.true.
!
!
!
!
subroutine time_interp_modulo(Time, Time_beg, Time_end, Timelist, weight, index1, index2, &
correct_leap_year_inconsistency, err_msg)
type(time_type), intent(in) :: Time, Time_beg, Time_end, Timelist(:)
real , intent(out) :: weight
integer , intent(out) :: index1, index2
logical, intent(in), optional :: correct_leap_year_inconsistency
character(len=*), intent(out), optional :: err_msg
type(time_type) :: Period, T
integer :: is, ie,i1,i2
integer :: ys,ms,ds,hs,mins,ss ! components of the starting date
integer :: ye,me,de,he,mine,se ! components of the ending date
integer :: yt,mt,dt,ht,mint,st ! components of the current date
integer :: dt1 ! temporary value for day
integer :: n ! size of Timelist
integer :: stdoutunit
logical :: correct_lyr, calendar_has_leap_years, do_the_lyr_correction
if ( .not. module_is_initialized ) call time_interp_init
if( present(err_msg) ) err_msg = ''
stdoutunit = stdout()
n = size(Timelist)
if (Time_beg>=Time_end) then
if(fms_error_handler('time_interp_modulo', &
'end of the specified time loop interval must be later than its beginning',err_msg)) return
endif
calendar_has_leap_years = (get_calendar_type() == JULIAN .or. get_calendar_type() == GREGORIAN)
Period = Time_end-Time_beg ! period of the time axis
if(present(correct_leap_year_inconsistency)) then
correct_lyr = correct_leap_year_inconsistency
else
correct_lyr = .false.
endif
! bring the requested time inside the specified time period
T = Time
do_the_lyr_correction = .false.
! Determine if the leap year correction needs to be done.
! It never needs to be done unless 3 conditions are met:
! 1) We are using a calendar with leap years
! 2) optional argument correct_leap_year_inconsistency is present and equals .true.
! 3) The modulo time period is an integer number of years
! If all of these are true then set do_the_lyr_correction to .true.
if(calendar_has_leap_years .and. correct_lyr) then
call get_date(Time_beg,ys,ms,ds,hs,mins,ss)
call get_date(Time_end,ye,me,de,he,mine,se)
if(ms==me.and.ds==de.and.hs==he.and.mins==mine.and.ss==se) then
! whole number of years
do_the_lyr_correction = .true.
endif
endif
if(do_the_lyr_correction) then
call get_date(T,yt,mt,dt,ht,mint,st)
yt = ys+modulo(yt-ys,ye-ys)
dt1 = dt
! If it is Feb 29, but we map into a common year, use Feb 28
if(mt==2.and.dt==29.and..not.leap_year(set_date(yt,1,1))) dt1=28
T = set_date(yt,mt,dt1,ht,mint,st)
if (T < Time_beg) then
! the requested time is within the first year,
! but before the starting date. So we shift it to the last year.
if(mt==2.and.dt==29.and..not.leap_year(set_date(ye,1,1))) dt=28
T = set_date(ye,mt,dt,ht,mint,st)
endif
else
do while ( T >= Time_end )
T = T-Period
enddo
do while ( T < Time_beg )
T = T+Period
enddo
endif
! find indices of the first and last records in the Timelist that are within
! the requested time period.
if (Time_end<=Timelist(1).or.Time_beg>=Timelist(n)) then
if(get_calendar_type() == NO_CALENDAR) then
call print_time(Time_beg, 'Time_beg' )
call print_time(Time_end, 'Time_end' )
call print_time(Timelist(1), 'Timelist(1)' )
call print_time(Timelist(n), 'Timelist(n)' )
else
call print_date(Time_beg, 'Time_beg' )
call print_date(Time_end, 'Time_end' )
call print_date(Timelist(1), 'Timelist(1)' )
call print_date(Timelist(n), 'Timelist(n)' )
endif
write(stdoutunit,*)'where n = size(Timelist) =',n
if(fms_error_handler('time_interp_modulo', &
'the entire time list is outside the specified time loop interval',err_msg)) return
endif
call bisect(Timelist,Time_beg,index1=i1,index2=i2)
if (i1 < 1) then
is = 1 ! Time_beg before lower boundary
else if (Time_beg == Timelist(i1)) then
is = i1 ! Time_beg right on the lower boundary
else
is = i2 ! Time_beg inside the interval or on upper boundary
endif
call bisect(Timelist,Time_end,index1=i1,index2=i2)
if (Time_end > Timelist(i1)) then
ie = i1
else if (Time_end == Timelist(i1)) then
if(Time_beg == Timelist(is)) then
! Timelist includes time levels at both the lower and upper ends of the period.
! The endpoints of Timelist specify the same point in the cycle.
! This ambiguity is resolved by ignoring the last time level.
ie = i1-1
else
ie = i1
endif
else
! This should never happen because bisect does not return i1 such that Time_end < Timelist(i1)
endif
if (is>=ie) then
if(get_calendar_type() == NO_CALENDAR) then
call print_time(Time_beg, 'Time_beg =')
call print_time(Time_end, 'Time_end =')
call print_time(Timelist(1), 'Timelist(1)=')
call print_time(Timelist(n), 'Timelist(n)=')
else
call print_date(Time_beg, 'Time_beg =')
call print_date(Time_end, 'Time_end =')
call print_date(Timelist(1), 'Timelist(1)=')
call print_date(Timelist(n), 'Timelist(n)=')
endif
write(stdoutunit,*)'where n = size(Timelist) =',n
write(stdoutunit,*)'is =',is,'ie =',ie
if(fms_error_handler('time_interp_modulo', &
'error in calculation of time list bounds within the specified time loop interval',err_msg)) return
endif
! handle special cases:
if( T>=Timelist(ie) ) then
! time is after the end of the portion of the time list within the requested period
index1 = ie; index2 = is
weight = (T-Timelist(ie))//(Period-(Timelist(ie)-Timelist(is)))
else if (T 1)
i = (iu+il)/2
if(Timelist(i) > Time) then
iu = i
else
il = i
endif
enddo
i1 = il ; i2 = il+1
endif
if(PRESENT(index1)) index1 = i1
if(PRESENT(index2)) index2 = i2
end subroutine bisect
!#######################################################################
!
!
!
!
!
!
!
!
subroutine time_interp_list ( Time, Timelist, weight, index1, index2, modtime, err_msg )
type(time_type) , intent(in) :: Time, Timelist(:)
real , intent(out) :: weight
integer , intent(out) :: index1, index2
integer, optional, intent(in) :: modtime
character(len=*), intent(out), optional :: err_msg
integer :: n, hr, mn, se, mtime
type(time_type) :: T, Ts, Te, Td, Period, Time_mod
character(len=:),allocatable :: terr, tserr, teerr
if ( .not. module_is_initialized ) call time_interp_init
if( present(err_msg) ) err_msg = ''
weight = 0.; index1 = 0; index2 = 0
n = size(Timelist(:))
! setup modular time axis?
mtime = NONE
if (present(modtime)) then
mtime = modtime
Time_mod = (Timelist(1)+Timelist(n))/2
call get_date (Time_mod, yrmod, momod, dymod, hr, mn, se)
mod_leapyear = leap_year(Time_mod)
endif
! set period for modulo axis
select case (mtime)
case (NONE)
! do nothing
case (YEAR)
Period = set_time(0,days_in_year(Time_mod))
case (MONTH)
! month length must be equal
if (days_in_month(Time_mod) /= days_in_month(Time)) then
if(fms_error_handler ('time_interp_list','modulo months must have same length',err_msg)) return
endif
Period = set_time(0,days_in_month(Time_mod))
case (DAY)
Period = set_time(0,1)
case default
if(fms_error_handler ('time_interp_list','invalid value for argument modtime',err_msg)) return
end select
! If modulo time is in effect and Timelist spans a time interval exactly equal to
! the modulo period, then the endpoints of Timelist specify the same point in the cycle.
! This ambiguity is resolved by ignoring the last time level.
if (mtime /= NONE .and. Timelist(size(Timelist))-Timelist(1) == Period) then
n = size(Timelist) - 1
else
n = size(Timelist)
endif
! starting and ending times from list
Ts = Timelist(1)
Te = Timelist(n)
Td = Te-Ts
T = set_modtime(Time,mtime)
! Check that Timelist does not span a time interval greater than the modulo period
if (mtime /= NONE) then
if (Td > Period) then
if(fms_error_handler ('time_interp_list','period of list exceeds modulo period',err_msg)) return
endif
endif
! time falls on start or between start and end list values
if ( T >= Ts .and. T < Te ) then
call bisect(Timelist(1:n),T,index1,index2)
weight = (T-Timelist(index1)) // (Timelist(index2)-Timelist(index1))
! time falls before starting list value
else if ( T < Ts ) then
if (mtime == NONE) then
call time_list_error(T,terr)
call time_list_error(Ts,tserr)
call time_list_error(Te,teerr)
if(fms_error_handler ('time_interp_list',&
'time '//trim(terr)//' ('//date_to_string(T)//' is before range of list '//trim(tserr)//'-'//trim(teerr)//&
'('//date_to_string(Ts)//' - '//date_to_string(Te)//')',&
err_msg)) return
deallocate(terr,tserr,teerr)
endif
Td = Te-Ts
weight = 1. - ((Ts-T) // (Period-Td))
index1 = n
index2 = 1
! time falls on ending list value
else if ( T == Te ) then
if(perthlike_behavior) then
weight = 1.0
index1 = n-1
index2 = n
else
weight = 0.
index1 = n
if (mtime == NONE) then
index2 = n
else
index2 = 1
endif
endif
! time falls after ending list value
else if ( T > Te ) then
if (mtime == NONE) then
call time_list_error(T,terr)
call time_list_error(Ts,tserr)
call time_list_error(Te,teerr)
if(fms_error_handler ('time_interp_list',&
'time '//trim(terr)//' ('//date_to_string(T)//' is after range of list '//trim(tserr)//'-'//trim(teerr)//&
'('//date_to_string(Ts)//' - '//date_to_string(Te)//')',&
err_msg)) return
deallocate(terr,tserr,teerr)
endif
Td = Te-Ts
weight = (T-Te) // (Period-Td)
index1 = n
index2 = 1
endif
end subroutine time_interp_list
!#######################################################################
! private routines
!#######################################################################
function year_midpt (year)
integer, intent(in) :: year
type (time_type) :: year_midpt, year_beg, year_end
year_beg = set_date(year , 1, 1)
year_end = set_date(year+1, 1, 1)
year_midpt = (year_beg + year_end) / 2
end function year_midpt
!#######################################################################
function month_midpt (year, month)
integer, intent(in) :: year, month
type (time_type) :: month_midpt, month_beg, month_end
! --- beginning of this month ---
month_beg = set_date(year, month, 1)
! --- start of next month ---
if (month < 12) then
month_end = set_date(year, month+1, 1)
else
month_end = set_date(year+1, 1, 1)
endif
month_midpt = (month_beg + month_end) / 2
end function month_midpt
!#######################################################################
function set_modtime (Tin, modtime) result (Tout)
type(time_type), intent(in) :: Tin
integer, intent(in), optional :: modtime
type(time_type) :: Tout
integer :: yr, mo, dy, hr, mn, se, mtime
if(present(modtime)) then
mtime = modtime
else
mtime = NONE
endif
select case (mtime)
case (NONE)
Tout = Tin
case (YEAR)
call get_date (Tin, yr, mo, dy, hr, mn, se)
yr = yrmod
! correct leap year dates
if (.not.mod_leapyear .and. mo == 2 .and. dy > 28) then
mo = 3; dy = dy-28
endif
Tout = set_date (yr, mo, dy, hr, mn, se)
case (MONTH)
call get_date (Tin, yr, mo, dy, hr, mn, se)
yr = yrmod; mo = momod
Tout = set_date (yr, mo, dy, hr, mn, se)
case (DAY)
call get_date (Tin, yr, mo, dy, hr, mn, se)
yr = yrmod; mo = momod; dy = dymod
Tout = set_date (yr, mo, dy, hr, mn, se)
end select
end function set_modtime
!#######################################################################
subroutine error_handler (string)
character(len=*), intent(in) :: string
call error_mesg ('time_interp_mod', trim(string), FATAL)
! write (*,'(a)') 'ERROR in time_interp: ' // trim(string)
! stop 111
end subroutine error_handler
!#######################################################################
end module time_interp_mod
!
!
! The list of input time types must have ascending dates.
! *
!
! The length of the current month for input Time and Time_list
! must be the same when using the modulo month option.
! The modulo month option is available but not supported.
! *
!
! The optional argument modtime must have a value set by one
! of the public parameters: NONE, YEAR, MONTH, DAY.
! The MONTH and DAY options are available but not supported.
! *
!
! The difference between the last and first values in the
! input Time list/array exceeds the length of the modulo period.
! *
!
! These errors occur when you are not using a modulo axis and the
! input Time occurs before the first value in the Time list/array
! or after the last value in the Time list/array.
! *
!
! For all routines in this module the calendar type in module
! time_manager must be set.
!
!
! The following private parameters are set by this module:
!
! seconds per minute = 60
! minutes per hour = 60
! hours per day = 24
! months per year = 12
!