From 7610d50e22278abd0c2da929438bdd2b242d8f4b Mon Sep 17 00:00:00 2001 From: Darian Boggs Date: Fri, 17 Jan 2025 10:15:13 -0500 Subject: [PATCH 1/3] Add reference date (start date) for timestep. --- generic3g/ComponentSpecParser.F90 | 4 ++- .../parse_component_spec.F90 | 2 +- .../ComponentSpecParser/parse_timestep.F90 | 24 +++++++++++--- generic3g/specs/ComponentSpec.F90 | 1 + generic3g/tests/Test_ComponentSpecParser.pf | 33 +++++++++++++------ 5 files changed, 47 insertions(+), 17 deletions(-) diff --git a/generic3g/ComponentSpecParser.F90 b/generic3g/ComponentSpecParser.F90 index ebee7d966ed..43cf6106f77 100644 --- a/generic3g/ComponentSpecParser.F90 +++ b/generic3g/ComponentSpecParser.F90 @@ -64,6 +64,7 @@ module mapl3g_ComponentSpecParser character(*), parameter :: KEY_VERTICAL_DIM_SPEC = 'vertical_dim_spec' character(*), parameter :: KEY_ACCUMULATION_TYPE = 'accumulation_type' character(*), parameter :: KEY_TIMESTEP = 'timestep' + character(*), parameter :: KEY_TIMESTEP_START = 'timestep_start' !> ! Submodule declarations @@ -112,9 +113,10 @@ module function parse_child(hconfig, rc) result(child) integer, optional, intent(out) :: rc end function parse_child - module subroutine parse_timestep(hconfig, timestep, rc) + module subroutine parse_timestep(hconfig, timestep, start, rc) type(ESMF_HConfig), intent(in) :: hconfig type(ESMF_TimeInterval), allocatable, intent(inout) :: timestep + type(ESMF_Time), allocatable, intent(inout) :: start integer, optional, intent(out) :: rc end subroutine parse_timestep diff --git a/generic3g/ComponentSpecParser/parse_component_spec.F90 b/generic3g/ComponentSpecParser/parse_component_spec.F90 index 696aedf2ace..5136c5aa9fa 100644 --- a/generic3g/ComponentSpecParser/parse_component_spec.F90 +++ b/generic3g/ComponentSpecParser/parse_component_spec.F90 @@ -22,7 +22,7 @@ module function parse_component_spec(hconfig, registry, rc) result(spec) spec%var_specs = parse_var_specs(mapl_cfg, _RC) spec%connections = parse_connections(mapl_cfg, _RC) spec%children = parse_children(mapl_cfg, _RC) - call parse_timestep(mapl_cfg, spec%timestep, _RC) + call parse_timestep(mapl_cfg, spec%timestep, spec%timestep_start, _RC) call ESMF_HConfigDestroy(mapl_cfg, _RC) diff --git a/generic3g/ComponentSpecParser/parse_timestep.F90 b/generic3g/ComponentSpecParser/parse_timestep.F90 index 023a1e4288a..df6b522c343 100644 --- a/generic3g/ComponentSpecParser/parse_timestep.F90 +++ b/generic3g/ComponentSpecParser/parse_timestep.F90 @@ -1,22 +1,36 @@ #include "MAPL_ErrLog.h" submodule (mapl3g_ComponentSpecParser) parse_timestep_smod - use MAPL_TimeStringConversion, only: parse_isostring => string_to_esmf_timeinterval + use MAPL_TimeStringConversion, only: parse_isoduration => string_to_esmf_timeinterval +! use MAPL_TimeStringConversion, only: parse_isotime => string_to_esmf_time !wdb fixme deleteme contains - module subroutine parse_timestep(hconfig, timestep, rc) + module subroutine parse_timestep(hconfig, timestep, start, rc) type(ESMF_HConfig), intent(in) :: hconfig type(ESMF_TimeInterval), allocatable, intent(inout) :: timestep + type(ESMF_Time), allocatable, intent(inout) :: start integer, optional, intent(out) :: rc integer :: status - logical :: has_timestep - character(len=:), allocatable :: iso_duration + logical :: has_timestep, has_start + character(len=32) :: iso_datetime + character(len=128) :: iso_duration + type(ESMF_Time) :: datetime has_timestep = ESMF_HConfigIsDefined(hconfig, keyString=KEY_TIMESTEP, _RC) _RETURN_UNLESS(has_timestep) iso_duration = ESMF_HConfigAsString(hconfig, keyString=KEY_TIMESTEP, _RC) - timestep = parse_isostring(iso_duration, _RC) + timestep = parse_isoduration(trim(iso_duration), _RC) + + has_start = ESMF_HConfigIsDefined(hconfig, keyString=KEY_TIMESTEP_START, _RC) + _RETURN_UNLESS(has_start) + iso_datetime = ESMF_HConfigAsString(hconfig, keyString=KEY_TIMESTEP_START, _RC) + iso_datetime = adjustl(iso_datetime) +! start = parse_isotime(iso_datetime, _RC) !wdb fixme deleteme + _HERE, 'iso_datetime: ', trim(iso_datetime) !wdb fixme deleteme + call ESMF_TimeSet(datetime, timeString=trim(iso_datetime), _RC) !wdb fixme + allocate(start, source=datetime) !wdb fixme + _RETURN(_SUCCESS) end subroutine parse_timestep diff --git a/generic3g/specs/ComponentSpec.F90 b/generic3g/specs/ComponentSpec.F90 index afef31a36d3..dfe89c5a453 100644 --- a/generic3g/specs/ComponentSpec.F90 +++ b/generic3g/specs/ComponentSpec.F90 @@ -22,6 +22,7 @@ module mapl3g_ComponentSpec type(ChildSpecMap) :: children type(ESMF_HConfig), allocatable :: geom_hconfig ! optional type(ESMF_TimeInterval), allocatable :: timestep + type(ESMF_Time), allocatable :: timestep_start contains procedure :: has_geom_hconfig procedure :: add_var_spec diff --git a/generic3g/tests/Test_ComponentSpecParser.pf b/generic3g/tests/Test_ComponentSpecParser.pf index 50dd4ec4b48..12e65d36e44 100644 --- a/generic3g/tests/Test_ComponentSpecParser.pf +++ b/generic3g/tests/Test_ComponentSpecParser.pf @@ -182,34 +182,47 @@ contains @test subroutine test_parse_timestep() - integer(kind=ESMF_KIND_I4) :: d(6) + integer(kind=ESMF_KIND_I4), parameter :: IMM=3 + integer(kind=ESMF_KIND_I4), parameter :: MM=1 + integer(kind=ESMF_KIND_I4), parameter :: YY=0 + integer(kind=ESMF_KIND_I4), parameter :: DD=15 type(ESMF_TimeInterval) :: expected + type(ESMF_Time) :: expected_start character(len=:), allocatable :: iso_duration + character(len=:), allocatable :: iso_time character(len=:), allocatable :: content type(ESMF_HConfig) :: hconfig type(ESMF_TimeInterval), allocatable :: actual + type(ESMF_Time), allocatable :: actual_start integer :: rc, status character(len=:), allocatable :: msg character(len=ESMF_MAXSTR) :: expected_timestring, actual_timestring + character(len=ESMF_MAXSTR) :: expected_start_string, actual_start_string ! Test with correct key for timestep - d = [10, 3, 7, 13, 57, 32] - call ESMF_TimeIntervalSet(expected, yy=d(1), mm=d(2), d=d(3), h=d(4), m=d(5), s=d(6), _RC) - iso_duration = 'P10Y3M7DT13H57M32S' + call ESMF_TimeIntervalSet(expected, mm=IMM, _RC) + iso_duration = 'P3M' + !call ESMF_TimeSet(expected_start, yy=YY, mm=MM, dd=DD, _RC) + iso_time = '1999-12-31' + call ESMF_TimeSet(expected_start, timeString=trim(iso_time), _RC) !wdb fixme deleteme content = 'timestep: ' // iso_duration + content = content // new_line('NEW_LINE') // 'timestep_start: ' // iso_time hconfig = ESMF_HConfigCreate(content=content, _RC) - call parse_timestep(hconfig, actual, _RC) - call ESMF_TimeIntervalGet(expected, timeString=expected_timestring, _RC) - call ESMF_TimeIntervalGet(actual, timeString=actual_timestring, _RC) - msg = trim(actual_timestring) // ' /= ' // trim(expected_timestring) - @assertTrue(actual == expected, msg) + call parse_timestep(hconfig, actual, actual_start, _RC) +! call ESMF_TimeIntervalGet(expected, timeString=expected_timestring, _RC) +! call ESMF_TimeIntervalGet(actual, timeString=actual_timestring, _RC) +! msg = trim(actual_timestring) // ' /= ' // trim(expected_timestring) +! @assertTrue(actual == expected, msg) + @assertTrue(actual == expected, 'Actual timestep does not match expected timestep.') + @assertTrue(actual_start == expected_start, 'Actual timestep start does not match expected timestep start.') call ESMF_HConfigDestroy(hconfig, _RC) ! Test with incorrect key for timestep; should return without setting actual (invalid) content = 'run_dmc: ' // iso_duration hconfig = ESMF_HConfigCreate(content=content, _RC) deallocate(actual) - call parse_timestep(hconfig, actual, _RC) + deallocate(actual_start) + call parse_timestep(hconfig, actual, actual_start, _RC) @assert_that(allocated(actual), is(false())) call ESMF_HConfigDestroy(hconfig, _RC) From fe02e4a6789813a863d830a02c1e8a3dcb95cc4e Mon Sep 17 00:00:00 2001 From: Darian Boggs Date: Fri, 17 Jan 2025 15:44:03 -0500 Subject: [PATCH 2/3] Timestep start time; pass:ifort, nagfor, gfortran --- .../ComponentSpecParser/parse_timestep.F90 | 12 +++------ generic3g/tests/Test_ComponentSpecParser.pf | 25 ++++++------------- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/generic3g/ComponentSpecParser/parse_timestep.F90 b/generic3g/ComponentSpecParser/parse_timestep.F90 index df6b522c343..5a9e3172097 100644 --- a/generic3g/ComponentSpecParser/parse_timestep.F90 +++ b/generic3g/ComponentSpecParser/parse_timestep.F90 @@ -1,8 +1,7 @@ #include "MAPL_ErrLog.h" submodule (mapl3g_ComponentSpecParser) parse_timestep_smod - use MAPL_TimeStringConversion, only: parse_isoduration => string_to_esmf_timeinterval -! use MAPL_TimeStringConversion, only: parse_isotime => string_to_esmf_time !wdb fixme deleteme + use MAPL_TimeStringConversion, only: string_to_esmf_timeinterval, string_to_esmf_time contains module subroutine parse_timestep(hconfig, timestep, start, rc) @@ -15,21 +14,16 @@ module subroutine parse_timestep(hconfig, timestep, start, rc) logical :: has_timestep, has_start character(len=32) :: iso_datetime character(len=128) :: iso_duration - type(ESMF_Time) :: datetime has_timestep = ESMF_HConfigIsDefined(hconfig, keyString=KEY_TIMESTEP, _RC) _RETURN_UNLESS(has_timestep) iso_duration = ESMF_HConfigAsString(hconfig, keyString=KEY_TIMESTEP, _RC) - timestep = parse_isoduration(trim(iso_duration), _RC) + timestep = string_to_esmf_timeinterval(trim(iso_duration), _RC) has_start = ESMF_HConfigIsDefined(hconfig, keyString=KEY_TIMESTEP_START, _RC) _RETURN_UNLESS(has_start) iso_datetime = ESMF_HConfigAsString(hconfig, keyString=KEY_TIMESTEP_START, _RC) - iso_datetime = adjustl(iso_datetime) -! start = parse_isotime(iso_datetime, _RC) !wdb fixme deleteme - _HERE, 'iso_datetime: ', trim(iso_datetime) !wdb fixme deleteme - call ESMF_TimeSet(datetime, timeString=trim(iso_datetime), _RC) !wdb fixme - allocate(start, source=datetime) !wdb fixme + start = string_to_esmf_time(iso_datetime, _RC) _RETURN(_SUCCESS) diff --git a/generic3g/tests/Test_ComponentSpecParser.pf b/generic3g/tests/Test_ComponentSpecParser.pf index 12e65d36e44..873322d3439 100644 --- a/generic3g/tests/Test_ComponentSpecParser.pf +++ b/generic3g/tests/Test_ComponentSpecParser.pf @@ -6,6 +6,7 @@ module Test_ComponentSpecParser use mapl3g_ChildSpec use mapl3g_ChildSpecMap use mapl_ErrorHandling + use MAPL_TimeStringConversion use esmf implicit none @@ -183,36 +184,26 @@ contains @test subroutine test_parse_timestep() integer(kind=ESMF_KIND_I4), parameter :: IMM=3 - integer(kind=ESMF_KIND_I4), parameter :: MM=1 - integer(kind=ESMF_KIND_I4), parameter :: YY=0 + integer(kind=ESMF_KIND_I4), parameter :: MM=10 + integer(kind=ESMF_KIND_I4), parameter :: YY=1582 integer(kind=ESMF_KIND_I4), parameter :: DD=15 type(ESMF_TimeInterval) :: expected type(ESMF_Time) :: expected_start - character(len=:), allocatable :: iso_duration - character(len=:), allocatable :: iso_time + character(len=*), parameter :: iso_duration = 'P3M' + character(len=*), parameter :: iso_time = '1582-10-15' + character(len=*), parameter :: NL = new_line('NL') character(len=:), allocatable :: content type(ESMF_HConfig) :: hconfig type(ESMF_TimeInterval), allocatable :: actual type(ESMF_Time), allocatable :: actual_start integer :: rc, status - character(len=:), allocatable :: msg - character(len=ESMF_MAXSTR) :: expected_timestring, actual_timestring - character(len=ESMF_MAXSTR) :: expected_start_string, actual_start_string ! Test with correct key for timestep call ESMF_TimeIntervalSet(expected, mm=IMM, _RC) - iso_duration = 'P3M' - !call ESMF_TimeSet(expected_start, yy=YY, mm=MM, dd=DD, _RC) - iso_time = '1999-12-31' - call ESMF_TimeSet(expected_start, timeString=trim(iso_time), _RC) !wdb fixme deleteme - content = 'timestep: ' // iso_duration - content = content // new_line('NEW_LINE') // 'timestep_start: ' // iso_time + call ESMF_TimeSet(expected_start, yy=YY, mm=MM, dd=DD, _RC) + content = 'timestep: ' // iso_duration // NL // 'timestep_start: ' // iso_time hconfig = ESMF_HConfigCreate(content=content, _RC) call parse_timestep(hconfig, actual, actual_start, _RC) -! call ESMF_TimeIntervalGet(expected, timeString=expected_timestring, _RC) -! call ESMF_TimeIntervalGet(actual, timeString=actual_timestring, _RC) -! msg = trim(actual_timestring) // ' /= ' // trim(expected_timestring) -! @assertTrue(actual == expected, msg) @assertTrue(actual == expected, 'Actual timestep does not match expected timestep.') @assertTrue(actual_start == expected_start, 'Actual timestep start does not match expected timestep start.') call ESMF_HConfigDestroy(hconfig, _RC) From 42fa9bea170fbcce289696e1e326d658ad457c1a Mon Sep 17 00:00:00 2001 From: Darian Boggs Date: Fri, 17 Jan 2025 15:56:22 -0500 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4d9b3785b9..3dd1590505c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add run_dt to ComponentSpec and ComponentSpecParser - Add run_dt to FieldSpec - Add FrequencyAspect +- Add timestep_start ### Changed