From 721627223d5043677da4948587a9ead63fac5659 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 13 Sep 2023 12:51:44 -0600 Subject: [PATCH 1/4] Added function to check if DOY is in interval. --- src/utils/clm_time_manager.F90 | 39 +++++++++++++++++++ .../test_clm_time_manager.pf | 31 +++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/utils/clm_time_manager.F90 b/src/utils/clm_time_manager.F90 index b8d9930b24..e1a94effc0 100644 --- a/src/utils/clm_time_manager.F90 +++ b/src/utils/clm_time_manager.F90 @@ -59,6 +59,7 @@ 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_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 @@ -1759,6 +1760,44 @@ end function is_perpetual !========================================================================================= + logical function is_doy_in_interval(start, end, doy_in) + + ! 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, optional, intent(in) :: doy_in ! day of year to query + + ! Local variables + integer :: doy + logical :: window_crosses_newyear + + character(len=*), parameter :: sub = 'clm::is_doy_in_interval' + + ! Get doy of beginning of current timestep if doy_in is not provided + if (present(doy_in)) then + doy = doy_in + else + doy = get_prev_calday() + end if + + 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 + + !========================================================================================= + subroutine timemgr_datediff(ymd1, tod1, ymd2, tod2, days) ! Calculate the difference (ymd2,tod2) - (ymd1,tod1) and return the result in days. diff --git a/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf b/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf index 435d795e50..d5f5dc9361 100644 --- a/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf +++ b/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf @@ -577,4 +577,35 @@ contains end subroutine bad_hilontolocal_time + @Test + subroutine check_is_doy_in_interval(this) + class(TestTimeManager), intent(inout) :: this + + integer :: start, end + + start = 100 + 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)) + + start = 300 + 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)) + + start = 300 + 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 + end module test_clm_time_manager From 5bdd59d5deecbe22eb506f3fd30afbaa4710cb9a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 13 Sep 2023 13:00:46 -0600 Subject: [PATCH 2/4] CropPhenology() now uses is_doy_in_interval(). --- src/biogeochem/CNPhenologyMod.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index 070dc0eb0f..7044cdc402 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -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 @@ -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 From 7b57111f1722ebb47661cdf728cecf7a1b02b0d8 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 15 Sep 2023 14:41:31 -0600 Subject: [PATCH 3/4] Added separate is_today_in_doy_interval() function. * Includes unit test for new function. * Existing function is_doy_in_interval() now requires queried doy to be specified, no longer falling back on "today." --- src/utils/clm_time_manager.F90 | 35 +++++++++++++----- .../test_clm_time_manager.pf | 37 +++++++++++++++++++ 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/utils/clm_time_manager.F90 b/src/utils/clm_time_manager.F90 index e1a94effc0..5c65f5decd 100644 --- a/src/utils/clm_time_manager.F90 +++ b/src/utils/clm_time_manager.F90 @@ -60,6 +60,7 @@ module clm_time_manager 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 @@ -1760,28 +1761,20 @@ end function is_perpetual !========================================================================================= - logical function is_doy_in_interval(start, end, doy_in) + 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, optional, intent(in) :: doy_in ! day of year to query + integer, intent(in) :: doy ! day of year to query ! Local variables - integer :: doy logical :: window_crosses_newyear character(len=*), parameter :: sub = 'clm::is_doy_in_interval' - ! Get doy of beginning of current timestep if doy_in is not provided - if (present(doy_in)) then - doy = doy_in - else - doy = get_prev_calday() - end if - window_crosses_newyear = end < start if (window_crosses_newyear .and. & @@ -1798,6 +1791,28 @@ 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. diff --git a/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf b/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf index d5f5dc9361..fe68efdbdc 100644 --- a/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf +++ b/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf @@ -608,4 +608,41 @@ contains end subroutine check_is_doy_in_interval + @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 From eded771363ee2020e51ad633712b89ce4d8f7e8b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 15 Sep 2023 15:16:45 -0600 Subject: [PATCH 4/4] Split check_is_doy_in_interval() into three tests. --- .../test_clm_time_manager.pf | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf b/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf index fe68efdbdc..78565fd54d 100644 --- a/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf +++ b/src/utils/test/clm_time_manager_test/test_clm_time_manager.pf @@ -578,35 +578,48 @@ contains end subroutine bad_hilontolocal_time @Test - subroutine check_is_doy_in_interval(this) + subroutine check_is_doy_in_interval_startend(this) class(TestTimeManager), intent(inout) :: this - integer :: start, end + integer, parameter :: start = 100 + integer, parameter :: end = 300 - start = 100 - 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)) - start = 300 - end = 100 + 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)) - start = 300 - end = 300 + 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 + end subroutine check_is_doy_in_interval_sameday @Test subroutine check_is_today_in_doy_interval(this)