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

Add is_doy_in_interval() function #2158

Merged
merged 4 commits into from
Sep 19, 2023
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
3 changes: 2 additions & 1 deletion src/biogeochem/CNPhenologyMod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , &
use clm_time_manager , only : get_prev_calday, get_curr_days_per_year, is_beg_curr_year
use clm_time_manager , only : get_average_days_per_year
use clm_time_manager , only : get_prev_date
use clm_time_manager , only : is_doy_in_interval
use pftconMod , only : ntmp_corn, nswheat, nwwheat, ntmp_soybean
use pftconMod , only : nirrig_tmp_corn, nirrig_swheat, nirrig_wwheat, nirrig_tmp_soybean
use pftconMod , only : ntrp_corn, nsugarcane, ntrp_soybean, ncotton, nrice
Expand Down Expand Up @@ -1930,7 +1931,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , &
end if

! This is outside the croplive check so that the "harvest if planting conditions were met today" conditional works.
is_in_sowing_window = jday >= minplantjday(ivt(p),h) .and. jday <= maxplantjday(ivt(p),h)
is_in_sowing_window = is_doy_in_interval(minplantjday(ivt(p),h), maxplantjday(ivt(p),h), jday)
is_end_sowing_window = jday == maxplantjday(ivt(p),h)
!
! Only allow sowing according to normal "window" rules if not using prescribed
Expand Down
54 changes: 54 additions & 0 deletions src/utils/clm_time_manager.F90
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ module clm_time_manager
is_beg_curr_year, &! return true on first timestep in current year
is_end_curr_year, &! return true on last timestep in current year
is_perpetual, &! return true if perpetual calendar is in use
is_doy_in_interval, &! return true if day of year is in the provided interval
is_today_in_doy_interval, &! return true if today's day of year is in the provided interval
is_near_local_noon, &! return true if near local noon
is_restart, &! return true if this is a restart run
update_rad_dtime, &! track radiation interval via nstep
Expand Down Expand Up @@ -1759,6 +1761,58 @@ end function is_perpetual

!=========================================================================================

logical function is_doy_in_interval(start, end, doy)

! Return true if day of year is in the provided interval.
! Does not treat leap years differently from normal years.
! Arguments
integer, intent(in) :: start ! start of interval (day of year)
integer, intent(in) :: end ! end of interval (day of year)
integer, intent(in) :: doy ! day of year to query

! Local variables
logical :: window_crosses_newyear

character(len=*), parameter :: sub = 'clm::is_doy_in_interval'

window_crosses_newyear = end < start

if (window_crosses_newyear .and. &
(doy >= start .or. doy <= end)) then
is_doy_in_interval = .true.
else if (.not. window_crosses_newyear .and. &
(doy >= start .and. doy <= end)) then
is_doy_in_interval = .true.
else
is_doy_in_interval = .false.
end if

end function is_doy_in_interval

!=========================================================================================

logical function is_today_in_doy_interval(start, end)

! Return true if today's day of year is in the provided interval.
! Does not treat leap years differently from normal years.
! Arguments
integer, intent(in) :: start ! start of interval (day of year)
integer, intent(in) :: end ! end of interval (day of year)

! Local variable(s)
integer :: doy_today

character(len=*), parameter :: sub = 'clm::is_today_in_doy_interval'

! Get doy of beginning of current timestep
doy_today = get_prev_calday()

is_today_in_doy_interval = is_doy_in_interval(start, end, doy_today)

end function is_today_in_doy_interval

!=========================================================================================

subroutine timemgr_datediff(ymd1, tod1, ymd2, tod2, days)

! Calculate the difference (ymd2,tod2) - (ymd1,tod1) and return the result in days.
Expand Down
81 changes: 81 additions & 0 deletions src/utils/test/clm_time_manager_test/test_clm_time_manager.pf
Original file line number Diff line number Diff line change
Expand Up @@ -577,4 +577,85 @@ contains

end subroutine bad_hilontolocal_time

@Test
subroutine check_is_doy_in_interval_startend(this)
class(TestTimeManager), intent(inout) :: this

integer, parameter :: start = 100
integer, parameter :: end = 300

@assertTrue(is_doy_in_interval(start, end, start))
@assertTrue(is_doy_in_interval(start, end, end))
@assertTrue(is_doy_in_interval(start, end, 200))
@assertFalse(is_doy_in_interval(start, end, 35))
@assertFalse(is_doy_in_interval(start, end, 350))

end subroutine check_is_doy_in_interval_startend

@Test
subroutine check_is_doy_in_interval_endstart(this)
class(TestTimeManager), intent(inout) :: this

integer, parameter :: start = 300
integer, parameter :: end = 100

@assertTrue(is_doy_in_interval(start, end, start))
@assertTrue(is_doy_in_interval(start, end, end))
@assertFalse(is_doy_in_interval(start, end, 200))
@assertTrue(is_doy_in_interval(start, end, 35))
@assertTrue(is_doy_in_interval(start, end, 350))

end subroutine check_is_doy_in_interval_endstart

@Test
subroutine check_is_doy_in_interval_sameday(this)
class(TestTimeManager), intent(inout) :: this

integer, parameter :: start = 300
integer, parameter :: end = 300

@assertTrue(is_doy_in_interval(start, end, start))
@assertTrue(is_doy_in_interval(start, end, end))
@assertFalse(is_doy_in_interval(start, end, 200))
@assertFalse(is_doy_in_interval(start, end, 350))

end subroutine check_is_doy_in_interval_sameday

@Test
subroutine check_is_today_in_doy_interval(this)
class(TestTimeManager), intent(inout) :: this

integer :: start, end

call unittest_timemgr_setup(dtime=dtime, use_gregorian_calendar=.true.)

start = 100 ! April 10
end = 300 ! October 27

! Test well before interval
call set_date(yr=2009, mon=3, day=25, tod=0)
@assertFalse(is_today_in_doy_interval(start, end))

! Test last timestep before interval
call set_date(yr=2009, mon=4, day=10, tod=0)
@assertFalse(is_today_in_doy_interval(start, end))

! Test first timestep of interval
call set_date(yr=2009, mon=4, day=10, tod=dtime)
@assertTrue(is_today_in_doy_interval(start, end))

! Test well within interval
call set_date(yr=2009, mon=7, day=24, tod=0)
@assertTrue(is_today_in_doy_interval(start, end))

! Test last timestep of interval
call set_date(yr=2009, mon=10, day=28, tod=0)
@assertTrue(is_today_in_doy_interval(start, end))

! Test first timestep after interval
call set_date(yr=2009, mon=10, day=28, tod=dtime)
@assertFalse(is_today_in_doy_interval(start, end))

end subroutine check_is_today_in_doy_interval

end module test_clm_time_manager