From 30b74f74fd9218bb6f057064925124ed77dd2d19 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Tue, 2 Jun 2026 10:50:34 -0600 Subject: [PATCH 01/15] first draft --- src/driver/mpas_subdriver.F | 3 +- src/framework/mpas_stream_manager.F | 85 +++++++++++++++++++++++++++++ src/framework/xml_stream_parser.c | 14 ++--- 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/src/driver/mpas_subdriver.F b/src/driver/mpas_subdriver.F index 68adea9dc3..42132c8a8b 100644 --- a/src/driver/mpas_subdriver.F +++ b/src/driver/mpas_subdriver.F @@ -44,7 +44,7 @@ subroutine mpas_init(corelist, domain_ptr, external_comm, namelistFileParam, str #ifdef MPAS_USE_MPI_F08 use mpi_f08, only : MPI_Comm #endif - use mpas_stream_manager, only : MPAS_stream_mgr_init, MPAS_build_stream_filename, MPAS_stream_mgr_validate_streams + use mpas_stream_manager, only : MPAS_stream_mgr_init, MPAS_build_stream_filename, MPAS_stream_mgr_validate_streams, MPAS_stream_mgr_validate_streams2 use iso_c_binding, only : c_char, c_loc, c_ptr, c_int use mpas_c_interfacing, only : mpas_f_to_c_string, mpas_c_to_f_string use mpas_timekeeping, only : mpas_get_clock_time, mpas_get_time @@ -382,6 +382,7 @@ end subroutine xml_stream_get_attributes if ( ierr /= MPAS_STREAM_MGR_NOERR ) then call mpas_dmpar_global_abort('ERROR: Validation of streams failed for core ' // trim(domain_ptr % core % coreName)) end if + call MPAS_stream_mgr_validate_streams2(domain_ptr % streamManager, ierr = ierr) ! ! Finalize the setup of blocks and fields diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index 609663ed58..d0a48921a3 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -21,6 +21,7 @@ module mpas_stream_manager MPAS_stream_mgr_finalize, & MPAS_stream_mgr_create_stream, & MPAS_stream_mgr_validate_streams, & + MPAS_stream_mgr_validate_streams2, & MPAS_stream_mgr_destroy_stream, & MPAS_stream_mgr_get_clock, & MPAS_stream_mgr_set_property, & @@ -567,6 +568,90 @@ subroutine MPAS_stream_mgr_validate_streams(manager, streamID, ierr)!{{{ end subroutine MPAS_stream_mgr_validate_streams!}}} + + !----------------------------------------------------------------------- + ! routine MPAS_stream_mgr_validate_streams2 + ! + !> \brief Validate all streams or one stream, if optional argument streamID is present. + !> \author Dom Heinzeller + !> \date 12 September 2017 + !> \details + !> Validates all streams of a stream manager, or one stream if optional argument + !> streamID is specified. A low-level validation of streams happens within + !> xml_stream_parser in xml_stream_parser.c (e.g. immutable streams must not be + !> specified as mutable streams etc.). MPAS_stream_mgr_validate_streams performs + !> higher-level checks that should stay separate from the low-level checks and + !> that may require additional logic or settings not necessarily present when + !> calling xml_stream_parser. + ! + !----------------------------------------------------------------------- + subroutine MPAS_stream_mgr_validate_streams2(manager, ierr)!{{{ + + implicit none + + type (MPAS_streamManager_type), intent(inout) :: manager + integer, intent(out), optional :: ierr + + character(len=StrKIND) :: stream1_name, stream2_name, stream1_filename, stream2_filename + character(len=StrKIND) :: filename_interval + integer :: direction, io_type, threadNum, err_local + character (len=StrKIND) :: message, streamID + type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor + + logical :: stream1_active, stream2_active, stream1_pkg_active, stream2_pkg_active + + STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_validate_streams2() for all streams') + + threadNum = mpas_threading_get_thread_num() + + if ( threadNum == 0 ) then + + streamID = '.*' ! query all streams + + nullify(stream1_cursor) + do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor, ierr=err_local)) + + stream1_name = stream1_cursor % name + stream1_active = stream1_cursor % active_stream + stream1_filename = stream1_cursor % filename_template + stream1_pkg_active = stream_active_pkg_check(stream1_cursor) + + call mpas_log_write('Stream 1 '//trim(stream1_name)//' filename '//trim(stream1_filename)//' & + active = $l packages_active $l',logicArgs=(/stream1_active, stream1_pkg_active/)) + + if ( stream1_active .and. stream1_pkg_active) then + + nullify(stream2_cursor) + do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor, ierr=err_local)) + + stream2_name = stream2_cursor % name + stream2_active = stream2_cursor % active_stream + stream2_pkg_active = stream_active_pkg_check(stream2_cursor) + + ! uniqueness_check has already checked that two different streams do not have the same name + if ( trim(stream1_name) /= trim(stream2_name) .and. stream2_active .and. stream2_pkg_active) then + + stream2_filename = stream2_cursor % filename_template + call mpas_log_write('Stream 2 '//trim(stream2_name)//' filename '//trim(stream2_filename)//' & + active = $l pkg_active: $l',logicArgs=(/stream2_active, stream2_pkg_active/)) + + if ( trim(stream1_filename) == trim(stream2_filename) ) then + message = 'Filename template ''' // trim(stream1_filename) // ''' is used by multiple active streams (e.g. stream ''' // trim(stream1_name) // ''' and stream ''' // trim(stream2_name) // '''). This may lead to file conflicts. Please ensure that each active stream has a unique filename template.' + call mpas_log_write(message, MPAS_LOG_CRIT) + end if + + end if + end do + + end if + + end do + + end if + + + end subroutine MPAS_stream_mgr_validate_streams2!}}} + !----------------------------------------------------------------------- ! routine MPAS_stream_mgr_destroy_stream ! diff --git a/src/framework/xml_stream_parser.c b/src/framework/xml_stream_parser.c index 470cc0fe63..7d4e56cc43 100644 --- a/src/framework/xml_stream_parser.c +++ b/src/framework/xml_stream_parser.c @@ -486,13 +486,13 @@ int uniqueness_check(ezxml_t stream1, ezxml_t stream2) fmt_err(msgbuf); return 1; } - if (strstr(type, "output") != NULL || strstr(type2, "output") != NULL){ - if (strcmp(filename, filename2) == 0) { - snprintf(msgbuf, MSGSIZE, "Output streams \"%s\" and \"%s\" cannot share the filename_template \"%s\".", name, name2, filename); - fmt_err(msgbuf); - return 1; - } - } + // if (strstr(type, "output") != NULL || strstr(type2, "output") != NULL){ + // if (strcmp(filename, filename2) == 0) { + // snprintf(msgbuf, MSGSIZE, "Output streams \"%s\" and \"%s\" cannot share the filename_template \"%s\".", name, name2, filename); + // fmt_err(msgbuf); + // return 1; + // } + // } } return 0; From 42399bca04f113c15496bb4ffb273f3b8eb248a2 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Wed, 3 Jun 2026 13:10:44 -0600 Subject: [PATCH 02/15] Only crash out if it's an output stream --- src/framework/mpas_stream_manager.F | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index d0a48921a3..5713783988 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -594,11 +594,12 @@ subroutine MPAS_stream_mgr_validate_streams2(manager, ierr)!{{{ character(len=StrKIND) :: stream1_name, stream2_name, stream1_filename, stream2_filename character(len=StrKIND) :: filename_interval - integer :: direction, io_type, threadNum, err_local + integer :: threadNum, err_local character (len=StrKIND) :: message, streamID type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor logical :: stream1_active, stream2_active, stream1_pkg_active, stream2_pkg_active + logical :: stream1_output, stream2_output STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_validate_streams2() for all streams') @@ -615,11 +616,13 @@ subroutine MPAS_stream_mgr_validate_streams2(manager, ierr)!{{{ stream1_active = stream1_cursor % active_stream stream1_filename = stream1_cursor % filename_template stream1_pkg_active = stream_active_pkg_check(stream1_cursor) + stream1_output = (stream1_cursor % direction == MPAS_STREAM_OUTPUT) .or. & + (stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) call mpas_log_write('Stream 1 '//trim(stream1_name)//' filename '//trim(stream1_filename)//' & - active = $l packages_active $l',logicArgs=(/stream1_active, stream1_pkg_active/)) + active = $l output = $l packages_active $l',logicArgs=(/stream1_active, stream1_output, stream1_pkg_active/)) - if ( stream1_active .and. stream1_pkg_active) then + if ( stream1_active .and. stream1_output .and. stream1_pkg_active) then nullify(stream2_cursor) do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor, ierr=err_local)) @@ -627,16 +630,20 @@ subroutine MPAS_stream_mgr_validate_streams2(manager, ierr)!{{{ stream2_name = stream2_cursor % name stream2_active = stream2_cursor % active_stream stream2_pkg_active = stream_active_pkg_check(stream2_cursor) + stream2_output = (stream2_cursor % direction == MPAS_STREAM_OUTPUT) .or. & + (stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) ! uniqueness_check has already checked that two different streams do not have the same name - if ( trim(stream1_name) /= trim(stream2_name) .and. stream2_active .and. stream2_pkg_active) then + if ( trim(stream1_name) /= trim(stream2_name) .and. stream2_active .and. stream2_output .and. stream2_pkg_active) then stream2_filename = stream2_cursor % filename_template call mpas_log_write('Stream 2 '//trim(stream2_name)//' filename '//trim(stream2_filename)//' & - active = $l pkg_active: $l',logicArgs=(/stream2_active, stream2_pkg_active/)) + active = $l output = $l pkg_active: $l',logicArgs=(/stream2_active, stream2_output, stream2_pkg_active/)) if ( trim(stream1_filename) == trim(stream2_filename) ) then - message = 'Filename template ''' // trim(stream1_filename) // ''' is used by multiple active streams (e.g. stream ''' // trim(stream1_name) // ''' and stream ''' // trim(stream2_name) // '''). This may lead to file conflicts. Please ensure that each active stream has a unique filename template.' + message = 'Found identical values of the filename_template attribute for multiple active output streams & + (' // trim(stream1_name) // ' and ' // trim(stream2_name) // ') in streams.. This may & + result in file conflicts.' call mpas_log_write(message, MPAS_LOG_CRIT) end if From 74af38bb520906e91945ecac6c1cbb32c6df4478 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Wed, 3 Jun 2026 14:56:45 -0600 Subject: [PATCH 03/15] Rename subroutine and call from stream_mgr_validate_streams --- src/driver/mpas_subdriver.F | 3 +-- src/framework/mpas_stream_manager.F | 31 +++++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/driver/mpas_subdriver.F b/src/driver/mpas_subdriver.F index 42132c8a8b..68adea9dc3 100644 --- a/src/driver/mpas_subdriver.F +++ b/src/driver/mpas_subdriver.F @@ -44,7 +44,7 @@ subroutine mpas_init(corelist, domain_ptr, external_comm, namelistFileParam, str #ifdef MPAS_USE_MPI_F08 use mpi_f08, only : MPI_Comm #endif - use mpas_stream_manager, only : MPAS_stream_mgr_init, MPAS_build_stream_filename, MPAS_stream_mgr_validate_streams, MPAS_stream_mgr_validate_streams2 + use mpas_stream_manager, only : MPAS_stream_mgr_init, MPAS_build_stream_filename, MPAS_stream_mgr_validate_streams use iso_c_binding, only : c_char, c_loc, c_ptr, c_int use mpas_c_interfacing, only : mpas_f_to_c_string, mpas_c_to_f_string use mpas_timekeeping, only : mpas_get_clock_time, mpas_get_time @@ -382,7 +382,6 @@ end subroutine xml_stream_get_attributes if ( ierr /= MPAS_STREAM_MGR_NOERR ) then call mpas_dmpar_global_abort('ERROR: Validation of streams failed for core ' // trim(domain_ptr % core % coreName)) end if - call MPAS_stream_mgr_validate_streams2(domain_ptr % streamManager, ierr = ierr) ! ! Finalize the setup of blocks and fields diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index 5713783988..92f6be0d1c 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -21,7 +21,6 @@ module mpas_stream_manager MPAS_stream_mgr_finalize, & MPAS_stream_mgr_create_stream, & MPAS_stream_mgr_validate_streams, & - MPAS_stream_mgr_validate_streams2, & MPAS_stream_mgr_destroy_stream, & MPAS_stream_mgr_get_clock, & MPAS_stream_mgr_set_property, & @@ -564,28 +563,30 @@ subroutine MPAS_stream_mgr_validate_streams(manager, streamID, ierr)!{{{ #endif end do + + ! Only check filename_template uniqueness when validating all streams + if (.not. present(streamID)) then + call MPAS_stream_mgr_check_filename_template(manager, ierr=err_local) + end if end subroutine MPAS_stream_mgr_validate_streams!}}} !----------------------------------------------------------------------- - ! routine MPAS_stream_mgr_validate_streams2 + ! routine MPAS_stream_mgr_check_filename_template ! - !> \brief Validate all streams or one stream, if optional argument streamID is present. - !> \author Dom Heinzeller - !> \date 12 September 2017 + !> \brief Check for identical filename templates in active output streams. + !> \author Abishek Gopal + !> \date June 3 2026 !> \details - !> Validates all streams of a stream manager, or one stream if optional argument - !> streamID is specified. A low-level validation of streams happens within - !> xml_stream_parser in xml_stream_parser.c (e.g. immutable streams must not be - !> specified as mutable streams etc.). MPAS_stream_mgr_validate_streams performs - !> higher-level checks that should stay separate from the low-level checks and - !> that may require additional logic or settings not necessarily present when - !> calling xml_stream_parser. + !> Checks that there are no identical filename templates among active output + !> streams in the stream manager, which may lead to file conflicts. This + !> routine can be called from within MPAS_stream_mgr_validate_streams or + !> separately as needed. ! !----------------------------------------------------------------------- - subroutine MPAS_stream_mgr_validate_streams2(manager, ierr)!{{{ + subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ implicit none @@ -601,7 +602,7 @@ subroutine MPAS_stream_mgr_validate_streams2(manager, ierr)!{{{ logical :: stream1_active, stream2_active, stream1_pkg_active, stream2_pkg_active logical :: stream1_output, stream2_output - STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_validate_streams2() for all streams') + STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_check_filename_template() for all streams') threadNum = mpas_threading_get_thread_num() @@ -657,7 +658,7 @@ subroutine MPAS_stream_mgr_validate_streams2(manager, ierr)!{{{ end if - end subroutine MPAS_stream_mgr_validate_streams2!}}} + end subroutine MPAS_stream_mgr_check_filename_template!}}} !----------------------------------------------------------------------- ! routine MPAS_stream_mgr_destroy_stream From 8eb3e56e3e7c293f2ccede132b38d87e3e9496fc Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Wed, 3 Jun 2026 14:59:56 -0600 Subject: [PATCH 04/15] Remove commented lines --- src/framework/xml_stream_parser.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/framework/xml_stream_parser.c b/src/framework/xml_stream_parser.c index 7d4e56cc43..87c0cb8037 100644 --- a/src/framework/xml_stream_parser.c +++ b/src/framework/xml_stream_parser.c @@ -486,13 +486,6 @@ int uniqueness_check(ezxml_t stream1, ezxml_t stream2) fmt_err(msgbuf); return 1; } - // if (strstr(type, "output") != NULL || strstr(type2, "output") != NULL){ - // if (strcmp(filename, filename2) == 0) { - // snprintf(msgbuf, MSGSIZE, "Output streams \"%s\" and \"%s\" cannot share the filename_template \"%s\".", name, name2, filename); - // fmt_err(msgbuf); - // return 1; - // } - // } } return 0; From 64e585681b5396dd009364cd9db36d02f06e906d Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Thu, 4 Jun 2026 15:14:24 -0600 Subject: [PATCH 05/15] Some cleanups addressing review comments --- src/framework/mpas_stream_manager.F | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index 92f6be0d1c..e57e65807e 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -594,7 +594,6 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ integer, intent(out), optional :: ierr character(len=StrKIND) :: stream1_name, stream2_name, stream1_filename, stream2_filename - character(len=StrKIND) :: filename_interval integer :: threadNum, err_local character (len=StrKIND) :: message, streamID type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor @@ -621,7 +620,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ (stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) call mpas_log_write('Stream 1 '//trim(stream1_name)//' filename '//trim(stream1_filename)//' & - active = $l output = $l packages_active $l',logicArgs=(/stream1_active, stream1_output, stream1_pkg_active/)) + & active = $l output = $l packages_active $l',logicArgs=(/stream1_active, stream1_output, stream1_pkg_active/)) if ( stream1_active .and. stream1_output .and. stream1_pkg_active) then @@ -639,12 +638,12 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ stream2_filename = stream2_cursor % filename_template call mpas_log_write('Stream 2 '//trim(stream2_name)//' filename '//trim(stream2_filename)//' & - active = $l output = $l pkg_active: $l',logicArgs=(/stream2_active, stream2_output, stream2_pkg_active/)) + & active = $l output = $l pkg_active: $l',logicArgs=(/stream2_active, stream2_output, stream2_pkg_active/)) if ( trim(stream1_filename) == trim(stream2_filename) ) then message = 'Found identical values of the filename_template attribute for multiple active output streams & - (' // trim(stream1_name) // ' and ' // trim(stream2_name) // ') in streams.. This may & - result in file conflicts.' + & (' // trim(stream1_name) // ' and ' // trim(stream2_name) // ') in streams.. This may & + & result in file conflicts.' call mpas_log_write(message, MPAS_LOG_CRIT) end if From 3bf5404e8d1a8c400e95ca37fc2cc3eed3917c61 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Thu, 4 Jun 2026 15:51:06 -0600 Subject: [PATCH 06/15] remove trailing whitespace --- src/framework/mpas_stream_manager.F | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index e57e65807e..278b2cd0bf 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -581,9 +581,9 @@ end subroutine MPAS_stream_mgr_validate_streams!}}} !> \date June 3 2026 !> \details !> Checks that there are no identical filename templates among active output - !> streams in the stream manager, which may lead to file conflicts. This - !> routine can be called from within MPAS_stream_mgr_validate_streams or - !> separately as needed. + !> streams in the stream manager, which may lead to file conflicts. This + !> routine can be called from within MPAS_stream_mgr_validate_streams or + !> separately as needed. ! !----------------------------------------------------------------------- subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ @@ -611,7 +611,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ nullify(stream1_cursor) do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor, ierr=err_local)) - + stream1_name = stream1_cursor % name stream1_active = stream1_cursor % active_stream stream1_filename = stream1_cursor % filename_template @@ -623,7 +623,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ & active = $l output = $l packages_active $l',logicArgs=(/stream1_active, stream1_output, stream1_pkg_active/)) if ( stream1_active .and. stream1_output .and. stream1_pkg_active) then - + nullify(stream2_cursor) do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor, ierr=err_local)) @@ -639,7 +639,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ stream2_filename = stream2_cursor % filename_template call mpas_log_write('Stream 2 '//trim(stream2_name)//' filename '//trim(stream2_filename)//' & & active = $l output = $l pkg_active: $l',logicArgs=(/stream2_active, stream2_output, stream2_pkg_active/)) - + if ( trim(stream1_filename) == trim(stream2_filename) ) then message = 'Found identical values of the filename_template attribute for multiple active output streams & & (' // trim(stream1_name) // ' and ' // trim(stream2_name) // ') in streams.. This may & @@ -649,14 +649,14 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ end if end do - + end if end do - + end if - + end subroutine MPAS_stream_mgr_check_filename_template!}}} !----------------------------------------------------------------------- From 5c7a075a7745f4ab45ad5f03ddc406e0df8c5131 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Thu, 4 Jun 2026 16:41:23 -0600 Subject: [PATCH 07/15] Negating if conditions, removing unused variables and whitespace fixes --- src/framework/mpas_stream_manager.F | 66 ++++++++++++++--------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index 278b2cd0bf..419d01aff1 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -572,7 +572,6 @@ subroutine MPAS_stream_mgr_validate_streams(manager, streamID, ierr)!{{{ end subroutine MPAS_stream_mgr_validate_streams!}}} - !----------------------------------------------------------------------- ! routine MPAS_stream_mgr_check_filename_template ! @@ -593,12 +592,10 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ type (MPAS_streamManager_type), intent(inout) :: manager integer, intent(out), optional :: ierr - character(len=StrKIND) :: stream1_name, stream2_name, stream1_filename, stream2_filename integer :: threadNum, err_local character (len=StrKIND) :: message, streamID type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor - - logical :: stream1_active, stream2_active, stream1_pkg_active, stream2_pkg_active + logical :: stream1_pkg_active, stream2_pkg_active logical :: stream1_output, stream2_output STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_check_filename_template() for all streams') @@ -607,58 +604,57 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ if ( threadNum == 0 ) then - streamID = '.*' ! query all streams + streamID = '.*' ! query all streams - nullify(stream1_cursor) - do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor, ierr=err_local)) + nullify(stream1_cursor) + do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor, ierr=err_local)) - stream1_name = stream1_cursor % name - stream1_active = stream1_cursor % active_stream - stream1_filename = stream1_cursor % filename_template - stream1_pkg_active = stream_active_pkg_check(stream1_cursor) - stream1_output = (stream1_cursor % direction == MPAS_STREAM_OUTPUT) .or. & - (stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) + stream1_pkg_active = stream_active_pkg_check(stream1_cursor) + stream1_output = (stream1_cursor % direction == MPAS_STREAM_OUTPUT) .or. & + (stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) - call mpas_log_write('Stream 1 '//trim(stream1_name)//' filename '//trim(stream1_filename)//' & - & active = $l output = $l packages_active $l',logicArgs=(/stream1_active, stream1_output, stream1_pkg_active/)) + call mpas_log_write('Stream 1 '//trim(stream1_cursor % name)//' filename '//trim(stream1_cursor % filename_template)//' & + & active = $l output = $l packages_active $l',logicArgs=(/stream1_cursor % active_stream, stream1_output, stream1_pkg_active/)) + + if (.not. stream1_cursor % active_stream .or. .not. stream1_output & + .or. .not. stream1_pkg_active) then + cycle + end if - if ( stream1_active .and. stream1_output .and. stream1_pkg_active) then - nullify(stream2_cursor) do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor, ierr=err_local)) - stream2_name = stream2_cursor % name - stream2_active = stream2_cursor % active_stream stream2_pkg_active = stream_active_pkg_check(stream2_cursor) stream2_output = (stream2_cursor % direction == MPAS_STREAM_OUTPUT) .or. & - (stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) + (stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) ! uniqueness_check has already checked that two different streams do not have the same name - if ( trim(stream1_name) /= trim(stream2_name) .and. stream2_active .and. stream2_output .and. stream2_pkg_active) then - - stream2_filename = stream2_cursor % filename_template - call mpas_log_write('Stream 2 '//trim(stream2_name)//' filename '//trim(stream2_filename)//' & - & active = $l output = $l pkg_active: $l',logicArgs=(/stream2_active, stream2_output, stream2_pkg_active/)) + if (trim(stream1_cursor % name) == trim(stream2_cursor % name) & + .or. .not. stream2_cursor % active_stream & + .or. .not. stream2_output & + .or. .not. stream2_pkg_active) then + cycle + end if - if ( trim(stream1_filename) == trim(stream2_filename) ) then - message = 'Found identical values of the filename_template attribute for multiple active output streams & - & (' // trim(stream1_name) // ' and ' // trim(stream2_name) // ') in streams.. This may & - & result in file conflicts.' - call mpas_log_write(message, MPAS_LOG_CRIT) - end if + call mpas_log_write('Stream 2 '//trim(stream2_cursor % name)//' filename '//trim(stream2_cursor % filename_template)//' & + & active = $l output = $l pkg_active: $l',logicArgs=(/stream2_cursor % active_stream, stream2_output, stream2_pkg_active/)) + if ( trim(stream1_cursor % filename_template) == trim(stream2_cursor % filename_template) ) then + message = 'Found identical values of the filename_template attribute for multiple active output streams & + & (' // trim(stream1_cursor % name) // ' and ' // trim(stream2_cursor % name) // ') in streams.. This may & + & result in file conflicts.' + call mpas_log_write(message, MPAS_LOG_CRIT) end if - end do - end if + end do - end do + end do end if - end subroutine MPAS_stream_mgr_check_filename_template!}}} + !----------------------------------------------------------------------- ! routine MPAS_stream_mgr_destroy_stream ! From 97c6d2538ca52fdd606d3534a8e5f524f865d7b5 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Thu, 4 Jun 2026 17:07:08 -0600 Subject: [PATCH 08/15] Edits to pass ierr to calling routine --- src/framework/mpas_stream_manager.F | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index 419d01aff1..a2c57c9706 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -567,6 +567,7 @@ subroutine MPAS_stream_mgr_validate_streams(manager, streamID, ierr)!{{{ ! Only check filename_template uniqueness when validating all streams if (.not. present(streamID)) then call MPAS_stream_mgr_check_filename_template(manager, ierr=err_local) + if (present(ierr)) ierr = err_local end if end subroutine MPAS_stream_mgr_validate_streams!}}} @@ -592,7 +593,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ type (MPAS_streamManager_type), intent(inout) :: manager integer, intent(out), optional :: ierr - integer :: threadNum, err_local + integer :: threadNum character (len=StrKIND) :: message, streamID type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor logical :: stream1_pkg_active, stream2_pkg_active @@ -600,6 +601,8 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_check_filename_template() for all streams') + if (present(ierr)) ierr = MPAS_STREAM_LIST_NOERR + threadNum = mpas_threading_get_thread_num() if ( threadNum == 0 ) then @@ -607,7 +610,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ streamID = '.*' ! query all streams nullify(stream1_cursor) - do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor, ierr=err_local)) + do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor)) stream1_pkg_active = stream_active_pkg_check(stream1_cursor) stream1_output = (stream1_cursor % direction == MPAS_STREAM_OUTPUT) .or. & @@ -622,7 +625,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ end if nullify(stream2_cursor) - do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor, ierr=err_local)) + do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor)) stream2_pkg_active = stream_active_pkg_check(stream2_cursor) stream2_output = (stream2_cursor % direction == MPAS_STREAM_OUTPUT) .or. & @@ -639,11 +642,14 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ call mpas_log_write('Stream 2 '//trim(stream2_cursor % name)//' filename '//trim(stream2_cursor % filename_template)//' & & active = $l output = $l pkg_active: $l',logicArgs=(/stream2_cursor % active_stream, stream2_output, stream2_pkg_active/)) - if ( trim(stream1_cursor % filename_template) == trim(stream2_cursor % filename_template) ) then - message = 'Found identical values of the filename_template attribute for multiple active output streams & - & (' // trim(stream1_cursor % name) // ' and ' // trim(stream2_cursor % name) // ') in streams.. This may & - & result in file conflicts.' - call mpas_log_write(message, MPAS_LOG_CRIT) + if (trim(stream1_cursor % filename_template) == trim(stream2_cursor % filename_template)) then + message = 'Found identical values of the filename_template attribute for multiple & + active output streams (' // trim(stream1_cursor % name) // ' and ' // & + trim(stream2_cursor % name) // ') in streams.. This may result in & + file conflicts.' + call mpas_log_write(message) + if (present(ierr)) ierr = MPAS_STREAM_MGR_ERROR + return end if end do From 741c4956338c991a49d8eb8c4668ce9e82b4d34b Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Fri, 5 Jun 2026 13:20:13 -0600 Subject: [PATCH 09/15] Fixes to address review comments, and cleanup of logging statements --- src/framework/mpas_stream_manager.F | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index a2c57c9706..6c4adfeeb4 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -601,7 +601,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_check_filename_template() for all streams') - if (present(ierr)) ierr = MPAS_STREAM_LIST_NOERR + if (present(ierr)) ierr = MPAS_STREAM_MGR_NOERR threadNum = mpas_threading_get_thread_num() @@ -616,11 +616,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ stream1_output = (stream1_cursor % direction == MPAS_STREAM_OUTPUT) .or. & (stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) - call mpas_log_write('Stream 1 '//trim(stream1_cursor % name)//' filename '//trim(stream1_cursor % filename_template)//' & - & active = $l output = $l packages_active $l',logicArgs=(/stream1_cursor % active_stream, stream1_output, stream1_pkg_active/)) - - if (.not. stream1_cursor % active_stream .or. .not. stream1_output & - .or. .not. stream1_pkg_active) then + if (.not. stream1_cursor % active_stream .or. .not. stream1_output .or. .not. stream1_pkg_active) then cycle end if @@ -639,15 +635,11 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ cycle end if - call mpas_log_write('Stream 2 '//trim(stream2_cursor % name)//' filename '//trim(stream2_cursor % filename_template)//' & - & active = $l output = $l pkg_active: $l',logicArgs=(/stream2_cursor % active_stream, stream2_output, stream2_pkg_active/)) - if (trim(stream1_cursor % filename_template) == trim(stream2_cursor % filename_template)) then - message = 'Found identical values of the filename_template attribute for multiple & - active output streams (' // trim(stream1_cursor % name) // ' and ' // & - trim(stream2_cursor % name) // ') in streams.. This may result in & - file conflicts.' - call mpas_log_write(message) + message = 'Found identical values of the filename_template attribute for multiple active output streams, ' & + // trim(stream1_cursor % name) // ' and ' // trim(stream2_cursor % name) // & + ', in streams.. This may result in file conflicts.' + call mpas_log_write(message, messageType=MPAS_LOG_ERR) if (present(ierr)) ierr = MPAS_STREAM_MGR_ERROR return end if @@ -657,7 +649,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ end do end if - + end subroutine MPAS_stream_mgr_check_filename_template!}}} From 035a4a7fcbd8a716fab7142a5b67c58e1e6106b5 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Wed, 10 Jun 2026 09:10:54 -0600 Subject: [PATCH 10/15] Redoing logic --- src/framework/mpas_stream_manager.F | 104 ++++++++++++++++++++++++---- src/framework/mpas_timekeeping.F | 19 +++++ 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index 6c4adfeeb4..c2aec2d03d 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -44,6 +44,7 @@ module mpas_stream_manager MPAS_stream_mgr_get_next_field, & MPAS_stream_mgr_stream_exists, & MPAS_stream_mgr_get_stream_interval, & + MPAS_stream_mgr_check_valid_record_interval, & MPAS_get_stream_filename, & MPAS_build_stream_filename @@ -593,11 +594,17 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ type (MPAS_streamManager_type), intent(inout) :: manager integer, intent(out), optional :: ierr - integer :: threadNum + integer :: threadNum, err_local,err_local1, err_local2 + real (RKIND) :: dt_i, dt_o character (len=StrKIND) :: message, streamID type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor + type (MPAS_TimeInterval_type) :: clock_interval logical :: stream1_pkg_active, stream2_pkg_active + !character (len=StrKIND) :: stream1_input_interval, stream2_input_interval, stream1_output_interval, stream2_output_interval + logical :: stream1_input, stream2_input logical :: stream1_output, stream2_output + logical :: stream1_input_interval, stream1_output_interval + logical :: stream2_input_interval, stream2_output_interval STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_check_filename_template() for all streams') @@ -613,25 +620,53 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor)) stream1_pkg_active = stream_active_pkg_check(stream1_cursor) - stream1_output = (stream1_cursor % direction == MPAS_STREAM_OUTPUT) .or. & - (stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) - - if (.not. stream1_cursor % active_stream .or. .not. stream1_output .or. .not. stream1_pkg_active) then + ! call mpas_stream_mgr_get_property(manager, stream1_cursor % name, MPAS_STREAM_PROPERTY_RECORD_INTV, & + ! stream1_input_interval, MPAS_STREAM_INPUT, err_local) + stream1_input_interval = MPAS_stream_mgr_check_valid_record_interval(manager, trim(stream1_cursor % name), & + MPAS_STREAM_INPUT, err_local1) + stream1_output_interval = MPAS_stream_mgr_check_valid_record_interval(manager, trim(stream1_cursor % name), & + MPAS_STREAM_OUTPUT, err_local2) + + stream1_input = ((stream1_cursor % direction == MPAS_STREAM_INPUT .or. & + stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & + stream1_input_interval) + stream1_output = ((stream1_cursor % direction == MPAS_STREAM_OUTPUT .or. & + stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & + stream1_output_interval) + + call mpas_log_write('Stream 1 '//trim(stream1_cursor % name)//' filename '//trim(stream1_cursor % filename_template)//' & + & active = $l input = $l output = $l packages_active $l',logicArgs=(/stream1_cursor % active_stream, stream1_input, stream1_output, stream1_pkg_active/)) + + if (.not. stream1_cursor % active_stream & + .or. .not. (stream1_input .or. stream1_output) & + .or. .not. stream1_pkg_active) then + !call mpas_log_write('cycle1') cycle end if nullify(stream2_cursor) do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor)) - stream2_pkg_active = stream_active_pkg_check(stream2_cursor) - stream2_output = (stream2_cursor % direction == MPAS_STREAM_OUTPUT) .or. & - (stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) + stream2_input_interval = MPAS_stream_mgr_check_valid_record_interval(manager, trim(stream2_cursor % name), MPAS_STREAM_INPUT, err_local1) + stream2_output_interval = MPAS_stream_mgr_check_valid_record_interval(manager, trim(stream2_cursor % name), MPAS_STREAM_OUTPUT, err_local2) + stream2_pkg_active = stream_active_pkg_check(stream2_cursor) + stream2_input = ((stream2_cursor % direction == MPAS_STREAM_INPUT .or. & + stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & + stream2_input_interval) + stream2_output = ((stream2_cursor % direction == MPAS_STREAM_OUTPUT .or. & + stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & + stream2_output_interval) + + call mpas_log_write('Stream 2 '//trim(stream2_cursor % name)//' filename '//trim(stream2_cursor % filename_template)//' & + & active = $l input = $l output = $l pkg_active: $l',logicArgs=(/stream2_cursor % active_stream, stream2_input, stream2_output, stream2_pkg_active/)) ! uniqueness_check has already checked that two different streams do not have the same name - if (trim(stream1_cursor % name) == trim(stream2_cursor % name) & - .or. .not. stream2_cursor % active_stream & - .or. .not. stream2_output & - .or. .not. stream2_pkg_active) then + if (trim(stream1_cursor % name) == trim(stream2_cursor % name) & ! Skip comparing the stream to itself + .or. .not. stream2_cursor % active_stream & ! Skip if Stream 2 is not active + .or. .not. (stream2_input .or. stream2_output) & + .or. (stream1_input .and. stream2_input) & ! Skip if Streams 1 and 2 are both input streams + .or. .not. stream2_pkg_active) then ! Skip if Stream 2 is inactive due to inactive package + !call mpas_log_write('cycle2') cycle end if @@ -641,7 +676,6 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ ', in streams.. This may result in file conflicts.' call mpas_log_write(message, messageType=MPAS_LOG_ERR) if (present(ierr)) ierr = MPAS_STREAM_MGR_ERROR - return end if end do @@ -1857,6 +1891,50 @@ function MPAS_stream_mgr_get_stream_interval(manager, streamID, direction, ierr) end function MPAS_stream_mgr_get_stream_interval + + function MPAS_stream_mgr_check_valid_record_interval(manager, streamID, direction, ierr) result(validInterval) + + implicit none + + logical :: validInterval + + type (MPAS_streamManager_type), intent(in) :: manager + character(len=*), intent(in) :: streamID + integer, intent(in) :: direction + integer, intent(out) :: ierr + + type (mpas_stream_list_type), pointer :: streamCursor, alarmCursor + + validInterval = .false. + ierr = MPAS_STREAM_MGR_NOERR + nullify(streamCursor) + !call mpas_set_timeInterval(interval, dt = 0.0_RKIND) + + if ( mpas_stream_list_query(manager % streams, streamID, streamCursor) ) then + + if (direction == MPAS_STREAM_INPUT) then + + call mpas_check_alarms(manager % streamClock, streamCursor % alarmList_in % head, validInterval) + + else if (direction == MPAS_STREAM_OUTPUT) then + + call mpas_check_alarms(manager % streamClock, streamCursor % alarmList_out % head, validInterval) + else + + ierr = MPAS_STREAM_MGR_ERROR + call MPAS_stream_mesg(manager % errorLevel, 'Invalid direction encountered in MPAS_stream_mgr_get_stream_interval') + + end if + + else + + ierr = MPAS_STREAM_MGR_ERROR + call MPAS_stream_mesg(manager % errorLevel, 'Stream ''' // trim(streamID) // ''' does not exist. Cannot retrieve stream input/output intervals') + + end if + + end function MPAS_stream_mgr_check_valid_record_interval + !----------------------------------------------------------------------- ! routine MPAS_stream_mgr_set_property_int ! diff --git a/src/framework/mpas_timekeeping.F b/src/framework/mpas_timekeeping.F index bfecc3e0f7..87b788ebaf 100644 --- a/src/framework/mpas_timekeeping.F +++ b/src/framework/mpas_timekeeping.F @@ -1590,6 +1590,25 @@ subroutine mpas_set_timeInterval(interval, YY, MM, DD, H, M, S, S_n, S_d, S_i8, end subroutine mpas_set_timeInterval + subroutine mpas_check_alarms(clock, alarmListPtr, alarmPresent) + + implicit none + + type (MPAS_Clock_type), intent(in) :: clock + type (MPAS_stream_list_type), pointer :: alarmListPtr + logical, intent(out) :: alarmPresent + + type (MPAS_Alarm_type), pointer :: alarmPtr + + alarmPresent = .false. + + if(associated(alarmListPtr)) then + alarmPtr => clock % alarmListHead + if (associated(alarmPtr)) alarmPresent = .true. + end if + + end subroutine mpas_check_alarms + subroutine mpas_get_timeInterval(interval, StartTimeIn, DD, H, M, S, S_n, S_d, S_i8, timeString, dt, ierr) ! TODO: add double-precision seconds From f5e7f5c3f749200cae71cd512fb9be1999165606 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Wed, 10 Jun 2026 23:51:52 -0600 Subject: [PATCH 11/15] Using stream_mgr_get_num_alarms in the logic. And some cleanup --- src/framework/mpas_stream_manager.F | 81 ++++++++++++++--------------- src/framework/mpas_timekeeping.F | 19 ------- 2 files changed, 39 insertions(+), 61 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index c2aec2d03d..a1761f0148 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -44,7 +44,6 @@ module mpas_stream_manager MPAS_stream_mgr_get_next_field, & MPAS_stream_mgr_stream_exists, & MPAS_stream_mgr_get_stream_interval, & - MPAS_stream_mgr_check_valid_record_interval, & MPAS_get_stream_filename, & MPAS_build_stream_filename @@ -577,11 +576,11 @@ end subroutine MPAS_stream_mgr_validate_streams!}}} !----------------------------------------------------------------------- ! routine MPAS_stream_mgr_check_filename_template ! - !> \brief Check for identical filename templates in active output streams. + !> \brief Check for identical filename templates in active I/O streams. !> \author Abishek Gopal !> \date June 3 2026 !> \details - !> Checks that there are no identical filename templates among active output + !> Checks that there are no identical filename templates among active I/O !> streams in the stream manager, which may lead to file conflicts. This !> routine can be called from within MPAS_stream_mgr_validate_streams or !> separately as needed. @@ -595,16 +594,14 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ integer, intent(out), optional :: ierr integer :: threadNum, err_local,err_local1, err_local2 - real (RKIND) :: dt_i, dt_o character (len=StrKIND) :: message, streamID type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor type (MPAS_TimeInterval_type) :: clock_interval logical :: stream1_pkg_active, stream2_pkg_active - !character (len=StrKIND) :: stream1_input_interval, stream2_input_interval, stream1_output_interval, stream2_output_interval logical :: stream1_input, stream2_input logical :: stream1_output, stream2_output - logical :: stream1_input_interval, stream1_output_interval - logical :: stream2_input_interval, stream2_output_interval + integer :: stream1_input_nalarms, stream1_output_nalarms + integer :: stream2_input_nalarms, stream2_output_nalarms STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_check_filename_template() for all streams') @@ -620,19 +617,18 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor)) stream1_pkg_active = stream_active_pkg_check(stream1_cursor) - ! call mpas_stream_mgr_get_property(manager, stream1_cursor % name, MPAS_STREAM_PROPERTY_RECORD_INTV, & - ! stream1_input_interval, MPAS_STREAM_INPUT, err_local) - stream1_input_interval = MPAS_stream_mgr_check_valid_record_interval(manager, trim(stream1_cursor % name), & - MPAS_STREAM_INPUT, err_local1) - stream1_output_interval = MPAS_stream_mgr_check_valid_record_interval(manager, trim(stream1_cursor % name), & - MPAS_STREAM_OUTPUT, err_local2) + + stream1_input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream1_cursor % name), & + MPAS_STREAM_INPUT, err_local1) + stream1_output_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream1_cursor % name), & + MPAS_STREAM_OUTPUT, err_local2) stream1_input = ((stream1_cursor % direction == MPAS_STREAM_INPUT .or. & stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & - stream1_input_interval) + stream1_input_nalarms > 0) stream1_output = ((stream1_cursor % direction == MPAS_STREAM_OUTPUT .or. & stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & - stream1_output_interval) + stream1_output_nalarms > 0) call mpas_log_write('Stream 1 '//trim(stream1_cursor % name)//' filename '//trim(stream1_cursor % filename_template)//' & & active = $l input = $l output = $l packages_active $l',logicArgs=(/stream1_cursor % active_stream, stream1_input, stream1_output, stream1_pkg_active/)) @@ -640,23 +636,24 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ if (.not. stream1_cursor % active_stream & .or. .not. (stream1_input .or. stream1_output) & .or. .not. stream1_pkg_active) then - !call mpas_log_write('cycle1') cycle end if nullify(stream2_cursor) do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor)) - stream2_input_interval = MPAS_stream_mgr_check_valid_record_interval(manager, trim(stream2_cursor % name), MPAS_STREAM_INPUT, err_local1) - stream2_output_interval = MPAS_stream_mgr_check_valid_record_interval(manager, trim(stream2_cursor % name), MPAS_STREAM_OUTPUT, err_local2) + stream2_input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & + MPAS_STREAM_INPUT, err_local1) + stream2_output_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & + MPAS_STREAM_OUTPUT, err_local2) stream2_pkg_active = stream_active_pkg_check(stream2_cursor) stream2_input = ((stream2_cursor % direction == MPAS_STREAM_INPUT .or. & stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & - stream2_input_interval) + stream2_input_nalarms > 0) stream2_output = ((stream2_cursor % direction == MPAS_STREAM_OUTPUT .or. & stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & - stream2_output_interval) + stream2_output_nalarms > 0) call mpas_log_write('Stream 2 '//trim(stream2_cursor % name)//' filename '//trim(stream2_cursor % filename_template)//' & & active = $l input = $l output = $l pkg_active: $l',logicArgs=(/stream2_cursor % active_stream, stream2_input, stream2_output, stream2_pkg_active/)) @@ -666,7 +663,6 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ .or. .not. (stream2_input .or. stream2_output) & .or. (stream1_input .and. stream2_input) & ! Skip if Streams 1 and 2 are both input streams .or. .not. stream2_pkg_active) then ! Skip if Stream 2 is inactive due to inactive package - !call mpas_log_write('cycle2') cycle end if @@ -1891,49 +1887,50 @@ function MPAS_stream_mgr_get_stream_interval(manager, streamID, direction, ierr) end function MPAS_stream_mgr_get_stream_interval - - function MPAS_stream_mgr_check_valid_record_interval(manager, streamID, direction, ierr) result(validInterval) + !----------------------------------------------------------------------- + ! routine MPAS_stream_mgr_get_num_alarms + ! + !> \brief Returns the number of I/O alarms associated with a stream in a given direction + !> \author Abishek Gopal + !> \date 10 June 2026 + !> \details + !> Returns the number of I/O alarms associated with a stream in a given direction. + ! + !----------------------------------------------------------------------- + function MPAS_stream_mgr_get_num_alarms(manager, streamID, direction, ierr) result(numAlarms) implicit none - logical :: validInterval + integer :: numAlarms type (MPAS_streamManager_type), intent(in) :: manager character(len=*), intent(in) :: streamID integer, intent(in) :: direction integer, intent(out) :: ierr - type (mpas_stream_list_type), pointer :: streamCursor, alarmCursor + type (mpas_stream_list_type), pointer :: streamCursor - validInterval = .false. + numAlarms = 0 ierr = MPAS_STREAM_MGR_NOERR nullify(streamCursor) - !call mpas_set_timeInterval(interval, dt = 0.0_RKIND) if ( mpas_stream_list_query(manager % streams, streamID, streamCursor) ) then - if (direction == MPAS_STREAM_INPUT) then - - call mpas_check_alarms(manager % streamClock, streamCursor % alarmList_in % head, validInterval) - + numAlarms = MPAS_stream_list_length(streamCursor % alarmList_in, ierr) else if (direction == MPAS_STREAM_OUTPUT) then - - call mpas_check_alarms(manager % streamClock, streamCursor % alarmList_out % head, validInterval) + numAlarms = MPAS_stream_list_length(streamCursor % alarmList_out, ierr) else - - ierr = MPAS_STREAM_MGR_ERROR - call MPAS_stream_mesg(manager % errorLevel, 'Invalid direction encountered in MPAS_stream_mgr_get_stream_interval') - + ierr = MPAS_STREAM_MGR_ERROR + call MPAS_stream_mesg(manager % errorLevel, 'Invalid direction encountered in MPAS_stream_mgr_get_num_alarms') end if - else - ierr = MPAS_STREAM_MGR_ERROR - call MPAS_stream_mesg(manager % errorLevel, 'Stream ''' // trim(streamID) // ''' does not exist. Cannot retrieve stream input/output intervals') - + call MPAS_stream_mesg(manager % errorLevel, 'Stream ''' // trim(streamID) // ''' & + does not exist. Cannot retrieve number of alarms in stream.') end if - end function MPAS_stream_mgr_check_valid_record_interval + end function MPAS_stream_mgr_get_num_alarms + !----------------------------------------------------------------------- ! routine MPAS_stream_mgr_set_property_int diff --git a/src/framework/mpas_timekeeping.F b/src/framework/mpas_timekeeping.F index 87b788ebaf..bfecc3e0f7 100644 --- a/src/framework/mpas_timekeeping.F +++ b/src/framework/mpas_timekeeping.F @@ -1590,25 +1590,6 @@ subroutine mpas_set_timeInterval(interval, YY, MM, DD, H, M, S, S_n, S_d, S_i8, end subroutine mpas_set_timeInterval - subroutine mpas_check_alarms(clock, alarmListPtr, alarmPresent) - - implicit none - - type (MPAS_Clock_type), intent(in) :: clock - type (MPAS_stream_list_type), pointer :: alarmListPtr - logical, intent(out) :: alarmPresent - - type (MPAS_Alarm_type), pointer :: alarmPtr - - alarmPresent = .false. - - if(associated(alarmListPtr)) then - alarmPtr => clock % alarmListHead - if (associated(alarmPtr)) alarmPresent = .true. - end if - - end subroutine mpas_check_alarms - subroutine mpas_get_timeInterval(interval, StartTimeIn, DD, H, M, S, S_n, S_d, S_i8, timeString, dt, ierr) ! TODO: add double-precision seconds From ff95f35f2d17550dce3947e55aa4587e00b8354f Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Thu, 11 Jun 2026 23:17:26 -0600 Subject: [PATCH 12/15] Modifying logic so inner loop starts with the outer loop iterator --- src/framework/mpas_stream_manager.F | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index a1761f0148..4204ee4ac2 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -640,6 +640,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ end if nullify(stream2_cursor) + stream2_cursor => stream1_cursor do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor)) stream2_input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & @@ -657,9 +658,8 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ call mpas_log_write('Stream 2 '//trim(stream2_cursor % name)//' filename '//trim(stream2_cursor % filename_template)//' & & active = $l input = $l output = $l pkg_active: $l',logicArgs=(/stream2_cursor % active_stream, stream2_input, stream2_output, stream2_pkg_active/)) - ! uniqueness_check has already checked that two different streams do not have the same name - if (trim(stream1_cursor % name) == trim(stream2_cursor % name) & ! Skip comparing the stream to itself - .or. .not. stream2_cursor % active_stream & ! Skip if Stream 2 is not active + + if (.not. stream2_cursor % active_stream & ! Skip if Stream 2 is not active .or. .not. (stream2_input .or. stream2_output) & .or. (stream1_input .and. stream2_input) & ! Skip if Streams 1 and 2 are both input streams .or. .not. stream2_pkg_active) then ! Skip if Stream 2 is inactive due to inactive package From 5d540333d2b9bb0d43be1cde1793f055ffb8cc1d Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Mon, 15 Jun 2026 16:03:22 -0600 Subject: [PATCH 13/15] Make ierr in get_num_alarms optional and cleanup unused variables --- src/framework/mpas_stream_manager.F | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index 4204ee4ac2..d40be72527 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -593,7 +593,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ type (MPAS_streamManager_type), intent(inout) :: manager integer, intent(out), optional :: ierr - integer :: threadNum, err_local,err_local1, err_local2 + integer :: threadNum, err_local character (len=StrKIND) :: message, streamID type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor type (MPAS_TimeInterval_type) :: clock_interval @@ -619,9 +619,9 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ stream1_pkg_active = stream_active_pkg_check(stream1_cursor) stream1_input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream1_cursor % name), & - MPAS_STREAM_INPUT, err_local1) + MPAS_STREAM_INPUT) stream1_output_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream1_cursor % name), & - MPAS_STREAM_OUTPUT, err_local2) + MPAS_STREAM_OUTPUT) stream1_input = ((stream1_cursor % direction == MPAS_STREAM_INPUT .or. & stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & @@ -644,9 +644,9 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor)) stream2_input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & - MPAS_STREAM_INPUT, err_local1) + MPAS_STREAM_INPUT) stream2_output_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & - MPAS_STREAM_OUTPUT, err_local2) + MPAS_STREAM_OUTPUT) stream2_pkg_active = stream_active_pkg_check(stream2_cursor) stream2_input = ((stream2_cursor % direction == MPAS_STREAM_INPUT .or. & @@ -1906,29 +1906,32 @@ function MPAS_stream_mgr_get_num_alarms(manager, streamID, direction, ierr) resu type (MPAS_streamManager_type), intent(in) :: manager character(len=*), intent(in) :: streamID integer, intent(in) :: direction - integer, intent(out) :: ierr + integer, intent(out), optional :: ierr type (mpas_stream_list_type), pointer :: streamCursor + integer :: err_local numAlarms = 0 - ierr = MPAS_STREAM_MGR_NOERR + err_local = MPAS_STREAM_MGR_NOERR nullify(streamCursor) if ( mpas_stream_list_query(manager % streams, streamID, streamCursor) ) then if (direction == MPAS_STREAM_INPUT) then - numAlarms = MPAS_stream_list_length(streamCursor % alarmList_in, ierr) + numAlarms = MPAS_stream_list_length(streamCursor % alarmList_in, err_local) else if (direction == MPAS_STREAM_OUTPUT) then - numAlarms = MPAS_stream_list_length(streamCursor % alarmList_out, ierr) + numAlarms = MPAS_stream_list_length(streamCursor % alarmList_out, err_local) else - ierr = MPAS_STREAM_MGR_ERROR + err_local = MPAS_STREAM_MGR_ERROR call MPAS_stream_mesg(manager % errorLevel, 'Invalid direction encountered in MPAS_stream_mgr_get_num_alarms') end if else - ierr = MPAS_STREAM_MGR_ERROR + err_local = MPAS_STREAM_MGR_ERROR call MPAS_stream_mesg(manager % errorLevel, 'Stream ''' // trim(streamID) // ''' & does not exist. Cannot retrieve number of alarms in stream.') end if + if (present(ierr)) ierr = err_local + end function MPAS_stream_mgr_get_num_alarms From a30e46c981da88506fcd0dffc841d3375ac58c9b Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Mon, 15 Jun 2026 18:34:20 -0600 Subject: [PATCH 14/15] Fixing whitespace, comment block and error messages --- src/framework/mpas_stream_manager.F | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index d40be72527..4f0be377ca 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -576,14 +576,22 @@ end subroutine MPAS_stream_mgr_validate_streams!}}} !----------------------------------------------------------------------- ! routine MPAS_stream_mgr_check_filename_template ! - !> \brief Check for identical filename templates in active I/O streams. + !> \brief Check for filename_template conflicts between active output and I/O streams. !> \author Abishek Gopal !> \date June 3 2026 !> \details - !> Checks that there are no identical filename templates among active I/O - !> streams in the stream manager, which may lead to file conflicts. This - !> routine can be called from within MPAS_stream_mgr_validate_streams or - !> separately as needed. + !> Checks that there are no active output streams that share an identical + !> filename_template attribute with any other active input or output streams + !> in the stream manager, which may lead to file conflicts. An active stream + !> in this context is a stream with active_stream = .true. and is not + !> deactivated by an inactive package and is either an input or output + !> stream with at least one active alarm. + !> + !> If this routine detects any filename_template conflicts, an error message + !> is logged for each pair of conflicting streams, and an MPAS_STREAM_MGR_ERROR + !> error code is returned. In the case of a successful check, an + !> MPAS_STREAM_MGR_NOERR error code is returned. This routine can be called + !> from within MPAS_stream_mgr_validate_streams or separately as needed. ! !----------------------------------------------------------------------- subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ @@ -609,7 +617,7 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ threadNum = mpas_threading_get_thread_num() - if ( threadNum == 0 ) then + if (threadNum == 0) then streamID = '.*' ! query all streams @@ -667,9 +675,10 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ end if if (trim(stream1_cursor % filename_template) == trim(stream2_cursor % filename_template)) then - message = 'Found identical values of the filename_template attribute for multiple active output streams, ' & - // trim(stream1_cursor % name) // ' and ' // trim(stream2_cursor % name) // & - ', in streams.. This may result in file conflicts.' + message = 'Detected identical values of filename_template between an active output stream and an I/O stream' + call mpas_log_write(message, messageType=MPAS_LOG_ERR) + message = 'Streams '// trim(stream1_cursor % name) // ' and ' // trim(stream2_cursor % name) // & + ' share the filename_template attribute in streams.. This may result in file conflicts.' call mpas_log_write(message, messageType=MPAS_LOG_ERR) if (present(ierr)) ierr = MPAS_STREAM_MGR_ERROR end if @@ -1915,7 +1924,7 @@ function MPAS_stream_mgr_get_num_alarms(manager, streamID, direction, ierr) resu err_local = MPAS_STREAM_MGR_NOERR nullify(streamCursor) - if ( mpas_stream_list_query(manager % streams, streamID, streamCursor) ) then + if (mpas_stream_list_query(manager % streams, streamID, streamCursor)) then if (direction == MPAS_STREAM_INPUT) then numAlarms = MPAS_stream_list_length(streamCursor % alarmList_in, err_local) else if (direction == MPAS_STREAM_OUTPUT) then From 0376fed46d266660b410291f351bac7cc75075a7 Mon Sep 17 00:00:00 2001 From: Abishek Gopal Date: Mon, 15 Jun 2026 18:46:45 -0600 Subject: [PATCH 15/15] Reducing number of variables + cleanup --- src/framework/mpas_stream_manager.F | 41 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/framework/mpas_stream_manager.F b/src/framework/mpas_stream_manager.F index 4f0be377ca..969101b040 100644 --- a/src/framework/mpas_stream_manager.F +++ b/src/framework/mpas_stream_manager.F @@ -605,11 +605,10 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ character (len=StrKIND) :: message, streamID type (MPAS_stream_list_type), pointer :: stream1_cursor, stream2_cursor type (MPAS_TimeInterval_type) :: clock_interval - logical :: stream1_pkg_active, stream2_pkg_active + logical :: pkg_active logical :: stream1_input, stream2_input logical :: stream1_output, stream2_output - integer :: stream1_input_nalarms, stream1_output_nalarms - integer :: stream2_input_nalarms, stream2_output_nalarms + integer :: input_nalarms, output_nalarms STREAM_DEBUG_WRITE('-- Called MPAS_stream_mgr_check_filename_template() for all streams') @@ -624,26 +623,26 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ nullify(stream1_cursor) do while (MPAS_stream_list_query(manager % streams, streamID, stream1_cursor)) - stream1_pkg_active = stream_active_pkg_check(stream1_cursor) + pkg_active = stream_active_pkg_check(stream1_cursor) - stream1_input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream1_cursor % name), & + input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream1_cursor % name), & MPAS_STREAM_INPUT) - stream1_output_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream1_cursor % name), & + output_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream1_cursor % name), & MPAS_STREAM_OUTPUT) stream1_input = ((stream1_cursor % direction == MPAS_STREAM_INPUT .or. & stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & - stream1_input_nalarms > 0) + input_nalarms > 0) stream1_output = ((stream1_cursor % direction == MPAS_STREAM_OUTPUT .or. & stream1_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & - stream1_output_nalarms > 0) + output_nalarms > 0) call mpas_log_write('Stream 1 '//trim(stream1_cursor % name)//' filename '//trim(stream1_cursor % filename_template)//' & - & active = $l input = $l output = $l packages_active $l',logicArgs=(/stream1_cursor % active_stream, stream1_input, stream1_output, stream1_pkg_active/)) + & active = $l input = $l output = $l packages_active $l',logicArgs=(/stream1_cursor % active_stream, stream1_input, stream1_output, pkg_active/)) if (.not. stream1_cursor % active_stream & .or. .not. (stream1_input .or. stream1_output) & - .or. .not. stream1_pkg_active) then + .or. .not. pkg_active) then cycle end if @@ -651,34 +650,34 @@ subroutine MPAS_stream_mgr_check_filename_template(manager, ierr)!{{{ stream2_cursor => stream1_cursor do while (MPAS_stream_list_query(manager % streams, streamID, stream2_cursor)) - stream2_input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & + input_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & MPAS_STREAM_INPUT) - stream2_output_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & + output_nalarms = MPAS_stream_mgr_get_num_alarms(manager, trim(stream2_cursor % name), & MPAS_STREAM_OUTPUT) - stream2_pkg_active = stream_active_pkg_check(stream2_cursor) + pkg_active = stream_active_pkg_check(stream2_cursor) stream2_input = ((stream2_cursor % direction == MPAS_STREAM_INPUT .or. & stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & - stream2_input_nalarms > 0) + input_nalarms > 0) stream2_output = ((stream2_cursor % direction == MPAS_STREAM_OUTPUT .or. & stream2_cursor % direction == MPAS_STREAM_INPUT_OUTPUT) .and. & - stream2_output_nalarms > 0) + output_nalarms > 0) call mpas_log_write('Stream 2 '//trim(stream2_cursor % name)//' filename '//trim(stream2_cursor % filename_template)//' & - & active = $l input = $l output = $l pkg_active: $l',logicArgs=(/stream2_cursor % active_stream, stream2_input, stream2_output, stream2_pkg_active/)) + & active = $l input = $l output = $l pkg_active: $l',logicArgs=(/stream2_cursor % active_stream, stream2_input, stream2_output, pkg_active/)) if (.not. stream2_cursor % active_stream & ! Skip if Stream 2 is not active .or. .not. (stream2_input .or. stream2_output) & .or. (stream1_input .and. stream2_input) & ! Skip if Streams 1 and 2 are both input streams - .or. .not. stream2_pkg_active) then ! Skip if Stream 2 is inactive due to inactive package + .or. .not. pkg_active) then ! Skip if Stream 2 is inactive due to inactive package cycle end if if (trim(stream1_cursor % filename_template) == trim(stream2_cursor % filename_template)) then message = 'Detected identical values of filename_template between an active output stream and an I/O stream' - call mpas_log_write(message, messageType=MPAS_LOG_ERR) + call mpas_log_write(message) message = 'Streams '// trim(stream1_cursor % name) // ' and ' // trim(stream2_cursor % name) // & - ' share the filename_template attribute in streams.. This may result in file conflicts.' + ' have identical filename_template attribute in streams.. This may result in file conflicts.' call mpas_log_write(message, messageType=MPAS_LOG_ERR) if (present(ierr)) ierr = MPAS_STREAM_MGR_ERROR end if @@ -1935,8 +1934,8 @@ function MPAS_stream_mgr_get_num_alarms(manager, streamID, direction, ierr) resu end if else err_local = MPAS_STREAM_MGR_ERROR - call MPAS_stream_mesg(manager % errorLevel, 'Stream ''' // trim(streamID) // ''' & - does not exist. Cannot retrieve number of alarms in stream.') + call MPAS_stream_mesg(manager % errorLevel, 'Stream ' // trim(streamID) // & + ' does not exist. Cannot retrieve number of alarms in stream.') end if if (present(ierr)) ierr = err_local