From 35bed8a9e64b31497e5fbf1bca0733b4eec7c2ab Mon Sep 17 00:00:00 2001 From: hollyhan Date: Wed, 10 Jan 2024 18:29:59 -0700 Subject: [PATCH 01/11] Add restart option when the SLM is coupled to MALI --- .../mpas-albany-landice/src/Registry.xml | 4 + .../src/mode_forward/mpas_li_bedtopo.F | 193 +++++++++++------- 2 files changed, 123 insertions(+), 74 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry.xml b/components/mpas-albany-landice/src/Registry.xml index 279d7fb3c0a0..c4cd6df05bb9 100644 --- a/components/mpas-albany-landice/src/Registry.xml +++ b/components/mpas-albany-landice/src/Registry.xml @@ -149,6 +149,10 @@ description="Time interval at which the sea-level model is called by MALI. The interval has to be an even multiple of the option 'config_adaptive_timestep_force_interval" possible_values="Any time interval of the format 'YYYY-MM-DD_HH:MM:SS'" /> + Date: Wed, 21 Feb 2024 10:22:35 -0700 Subject: [PATCH 02/11] Improve synchronization of timesteps between MALI and SLM This PR updates handling of timesteps between MALI and the SLM in a few ways: * switch config_slm_coupling_interval to be an integer in years because we only allow integer year values * On init, check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval * On init, check that restart interval is an even multiple of config_slm_coupling_interval * On a restart, calculate which SLM time level to use based on the elapsed time from the start of the original simulation and config_slm_coupling_interval and make sure these divide cleanly --- .../mpas-albany-landice/src/Registry.xml | 10 +- .../src/mode_forward/mpas_li_bedtopo.F | 232 ++++++++++++++---- 2 files changed, 188 insertions(+), 54 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry.xml b/components/mpas-albany-landice/src/Registry.xml index c4cd6df05bb9..1c6e0f632985 100644 --- a/components/mpas-albany-landice/src/Registry.xml +++ b/components/mpas-albany-landice/src/Registry.xml @@ -145,13 +145,9 @@ description="Selection of the method for bedrock uplift calculation." possible_values="'none', 'data', 'sealevelmodel'" /> - - \brief Perform various checks on the SLM coupling interval setting +!> \author Matt Hoffman +!> \date Feb 2024 +!> \details +!> This routine checks that the SLM coupling interval is an even multiple +!> of the adaptive timestep force inverval and divides evenly into the +!> restart interval. It also checks that the coupling interval in the MALI +!> matches the value in the SLM namelist. +! +!----------------------------------------------------------------------- + + subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) + + use mpas_timekeeping + use mpas_stream_manager + use mpas_derived_types, only : MPAS_STREAM_PROPERTY_RECORD_INTV + + integer, intent (in) :: slm_dt1 + type (MPAS_streamManager_type), intent(inout) :: streamManager + integer, intent(out) :: err + + ! local variables + integer, pointer :: config_slm_coupling_interval + character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval + type (MPAS_Time_Type) :: force_interval, restart_interval + character(len=StrKIND) :: restart_interval_str + integer :: YYYY, MM, DD, H, M, S ! time components + type (MPAS_stream_list_type), pointer :: stream_cursor + integer :: err_tmp + + err = 0 + + ! First, check consistency in coupling interval set up in MALI and SLM + call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) + if (config_slm_coupling_interval /= slm_dt1) then + call mpas_log_write("The coupling interval in MALI and SLM settings are inconsistent", MPAS_LOG_ERR) + err = ior(err,1) + endif + + ! Check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval + call mpas_pool_get_config(liConfigs, "config_adaptive_timestep_force_interval", config_adaptive_timestep_force_interval) + ! Note: Using mpas_set_time instead of mpas_set_time_interval, even though this is an interval + ! This is because mpas_get_time_interval requires a reference time, which is not relevant + ! to these checks, and mpas_get_time allows us to get the component pieces that we want to check. + call mpas_set_time(force_interval, dateTimeString=config_adaptive_timestep_force_interval, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_get_time(force_interval, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) + if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then + call mpas_log_write("config_adaptive_timestep_force_interval currently not supported " // & + "to have nonzero values for months, days, hours, minutes, or seconds when sea-level model " // & + "is coupled. config_adaptive_timestep_force_interval=" //trim(config_adaptive_timestep_force_interval), MPAS_LOG_ERR) + ! Note: the actual requirement is that adapt dt force interval divides evenly into coupling interval + ! but that is tricky to check, and wanting anything but even years for that option is a rare use case. + err = ior(err, 1) + endif + ! Next check the number of years divides evenly into SLM coupling interval + if (mod(config_slm_coupling_interval, YYYY) /= 0) then + call mpas_log_write("config_adaptive_timestep_force_interval does not divide evenly into config_slm_coupling_interval" // & + "config_adaptive_timestep_force_interval=" // trim(config_adaptive_timestep_force_interval) // & + "; config_slm_coupling_interval=$i", MPAS_LOG_ERR, intArgs=(/config_slm_coupling_interval/)) + err = ior(err, 1) + endif + + ! Now check that restart interval is an even multiple of coupling interval + stream_cursor => streamManager % streams % head + do while (associated(stream_cursor)) + if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % valid) ) then + call MPAS_stream_mgr_get_property(streamManager, 'restart', MPAS_STREAM_PROPERTY_RECORD_INTV, & + restart_interval_str, ierr=err_tmp) + err = ior(err, err_tmp) + + call mpas_log_write('restart interval is: ' //trim(restart_interval_str)) + + call mpas_set_time(restart_interval, dateTimeString=restart_interval_str, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_get_time(restart_interval, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) + if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then + call mpas_log_write("If Sea Level Model is active, restart output_interval cannot include " // & + "nonzero months, days, hours, minutes or seconds. restart output_interval=" // & + trim(restart_interval_str), MPAS_LOG_ERR) + endif + err = ior(err, 1) + + if (mod(YYYY, config_slm_coupling_interval) /= 0) then + call mpas_log_write("restart output_interval must be a multiple of config_slm_coupling_interval", MPAS_LOG_ERR) + err = ior(err, 1) + endif + + endif + enddo + + !-------------------------------------------------------------------- + end subroutine check_SLM_coupling_interval + + +!*********************************************************************** +! +! routine find_slm_restart_timestep +! +!> \brief Perform various checks on the SLM coupling interval setting +!> \author Matt Hoffman +!> \date Feb 2024 +!> \details +!> This routine checks that the SLM coupling interval is an even multiple +!> of the adaptive timestep force inverval and divides evenly into the +!> restart interval. It also checks that the coupling interval in the MALI +!> matches the value in the SLM namelist. +! +!----------------------------------------------------------------------- + + subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) + + use mpas_timekeeping + + type (mpas_pool_type), intent(in) :: meshPool !< mesh information + integer, intent(out) :: slmTimeStep + integer, intent(out) :: err + + ! local vars + integer, pointer :: config_slm_coupling_interval + character (len=StrKIND), pointer :: xtime, simulationStartTime + character (len=StrKIND) :: elapsed_time_str + type (MPAS_Time_Type) :: start_time, curr_time + type (MPAS_Time_Type) :: elapsed_time ! should be a time interval but not possible to get years that way + integer :: YYYY, MM, DD, H, M, S ! time components + integer :: err_tmp + + err = 0 + + slmTimeStep = -999 ! initialize to bad number + + call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) + + call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) + call mpas_pool_get_array(meshPool, 'xtime', xtime) + call mpas_set_time(start_time, dateTimeString=simulationStartTime, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_set_time(curr_time, dateTimeString=xtime, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_get_timeInterval(curr_time - start_time, start_time, timeString=elapsed_time_str, ierr=err_tmp) + err = ior(err, err_tmp) + + ! convert elapsed time string to its units. Using the intermediate string format because mpas_get_timeInterval doesn't return + ! years, and figuring out years from days depends on the calendar + call mpas_set_time(elapsed_time, dateTimeString=elapsed_time_str, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_get_time(elapsed_time, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) + + ! make sure the elapsed time is an even year + if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then + call mpas_log_write("Elapsed time since simulationStartTime include nonzero months, days, hours, minutes, " // & + "or seconds.", MPAS_LOG_ERR) + err = ior(err, 1) + endif + + if (mod(YYYY, config_slm_coupling_interval) == 0) then + ! We can restart cleanly + slmTimeStep = YYYY / config_slm_coupling_interval + else + call mpas_log_write("Elapsed years since simulationStartTime is not evenly divisible by config_slm_coupling_interval." // & + " Unable to restart Sea Level Model cleanly.", MPAS_LOG_ERR) + err = ior(err, 1) + endif + + !-------------------------------------------------------------------- + end subroutine find_slm_restart_timestep + !*********************************************************************** end module li_bedtopo From 55e579bfe8ade495499de24aa3922bc3f4c59989 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 12:19:20 -0700 Subject: [PATCH 03/11] Improve error handling, correct other usage of config_uplift_method Also add missing =>next pointer assignment to keep code from hanging --- .../src/mode_forward/mpas_li_bedtopo.F | 42 +++++++++++++------ .../src/mode_forward/mpas_li_core.F | 11 ++--- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index 9a5cc0ad32aa..b9a09ed5f9ce 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -115,6 +115,7 @@ subroutine li_bedtopo_init(domain, err) !----------------------------------------------------------------- character (len=StrKIND), pointer :: config_uplift_method + integer :: err_tmp ! No init is needed. err = 0 @@ -122,7 +123,12 @@ subroutine li_bedtopo_init(domain, err) call mpas_pool_get_config(liConfigs, 'config_uplift_method', config_uplift_method) if (trim(config_uplift_method)=='sealevelmodel') then ! initialize the 1D sea-level model if fresh start - call slmodel_init(domain, err) + call slmodel_init(domain, err_tmp) + err = ior(err, err_tmp) + + if (err /= 0) then + call mpas_log_write('Error in li_bedtopo_init', MPAS_LOG_ERR) + endif endif !-------------------------------------------------------------------- @@ -445,7 +451,7 @@ subroutine slmodel_init(domain, err) call check_SLM_coupling_interval(dtime, domain % streamManager, err_tmp) err = ior(err, err_tmp) if (err /= 0) then - return + call mpas_log_write("Error occurred in check_SLM_coupling_interval.", MPAS_LOG_ERR) endif ! Set Displacement variable for GATHERV command @@ -473,8 +479,10 @@ subroutine slmodel_init(domain, err) call find_slm_restart_timestep(meshPool, slmTimeStep, err_tmp) err = ior(err, err_tmp) - call mpas_log_write("Calling the SLM. SLM timestep $i", intArgs=(/slmTimeStep/)) - call slmodel_solve(slmTimeStep, domain) + if (err == 0) then + call mpas_log_write("Calling the SLM. SLM timestep $i", intArgs=(/slmTimeStep/)) + call slmodel_solve(slmTimeStep, domain) + endif else @@ -532,11 +540,13 @@ subroutine slmodel_init(domain, err) slmTimeStep = 0 ! series of calling SLM routines - call sl_call_readnl - call sl_solver_checkpoint(itersl, dtime) - call sl_timewindow(slmTimeStep) - call sl_solver_init(itersl, starttime, ismIceload, ismBedtopo, ismMask) - call sl_deallocate_array + if (err == 0) then + call sl_call_readnl + call sl_solver_checkpoint(itersl, dtime) + call sl_timewindow(slmTimeStep) + call sl_solver_init(itersl, starttime, ismIceload, ismBedtopo, ismMask) + call sl_deallocate_array + endif endif deallocate(globalArrayThickness) @@ -995,12 +1005,14 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) integer :: err_tmp err = 0 + err_tmp = 0 ! First, check consistency in coupling interval set up in MALI and SLM call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) if (config_slm_coupling_interval /= slm_dt1) then - call mpas_log_write("The coupling interval in MALI and SLM settings are inconsistent", MPAS_LOG_ERR) - err = ior(err,1) + call mpas_log_write("The coupling interval in MALI ($i) and SLM ($i) are inconsistent", MPAS_LOG_ERR, & + intArgs=(/config_slm_coupling_interval, slm_dt1/)) + err = ior(err, 1) endif ! Check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval @@ -1015,6 +1027,7 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) call mpas_log_write("config_adaptive_timestep_force_interval currently not supported " // & "to have nonzero values for months, days, hours, minutes, or seconds when sea-level model " // & "is coupled. config_adaptive_timestep_force_interval=" //trim(config_adaptive_timestep_force_interval), MPAS_LOG_ERR) + call mpas_log_write(" MM=$i, DD=$i, H=$i, M=$i, S=$i", intArgs=(/MM, DD, H, M, S/)) ! Note: the actual requirement is that adapt dt force interval divides evenly into coupling interval ! but that is tricky to check, and wanting anything but even years for that option is a rare use case. err = ior(err, 1) @@ -1030,7 +1043,8 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) ! Now check that restart interval is an even multiple of coupling interval stream_cursor => streamManager % streams % head do while (associated(stream_cursor)) - if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % valid) ) then + if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % active_stream) ) then + call mpas_log_write("Checking restart interval against SLM coulping interval") call MPAS_stream_mgr_get_property(streamManager, 'restart', MPAS_STREAM_PROPERTY_RECORD_INTV, & restart_interval_str, ierr=err_tmp) err = ior(err, err_tmp) @@ -1044,8 +1058,8 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) call mpas_log_write("If Sea Level Model is active, restart output_interval cannot include " // & "nonzero months, days, hours, minutes or seconds. restart output_interval=" // & trim(restart_interval_str), MPAS_LOG_ERR) + err = ior(err, 1) endif - err = ior(err, 1) if (mod(YYYY, config_slm_coupling_interval) /= 0) then call mpas_log_write("restart output_interval must be a multiple of config_slm_coupling_interval", MPAS_LOG_ERR) @@ -1053,6 +1067,8 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) endif endif + + stream_cursor => stream_cursor % next enddo !-------------------------------------------------------------------- diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F index 10ee1e94b305..146b4e36d805 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F @@ -338,8 +338,8 @@ function li_core_init(domain, startTimeStamp) result(err) ! === call li_velocity_external_write_albany_mesh(domain) - call mpas_dmpar_max_int(domain % dminfo, err, globalErr) ! Find out if any blocks got an error - if (globalErr > 0) then + call mpas_dmpar_max_int(domain % dminfo, abs(err), globalErr) ! Find out if any blocks got an error + if (globalErr /= 0) then call mpas_log_write("An error has occurred in li_core_init. Aborting...", MPAS_LOG_CRIT) endif @@ -1111,7 +1111,8 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) character (len=StrKIND), pointer :: config_dt ! MPAS LI-specific config option character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval ! MPAS LI-specific config option character (len=StrKIND), pointer :: config_restart_timestamp_name - character (len=StrKIND), pointer :: config_uplift_method, config_slm_coupling_interval + character (len=StrKIND), pointer :: config_uplift_method + integer, pointer :: config_slm_coupling_interval character (len=StrKIND) :: restartTimeStamp !< string to be read from file integer, pointer :: config_year_digits integer :: err_tmp @@ -1197,7 +1198,7 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) ! Set up the coupling time interval if MALI is coupled to sea-level model if (trim(config_uplift_method) == "sealevelmodel") then - call mpas_set_timeInterval(slm_coupling_interval, timeString=config_slm_coupling_interval, ierr=err_tmp) + call mpas_set_timeInterval(slm_coupling_interval, YY=config_slm_coupling_interval, ierr=err_tmp) ierr = ior(ierr,err_tmp) call mpas_add_clock_alarm(core_clock, 'slmCouplingInterval', alarmTime=startTime, & alarmTimeInterval=slm_coupling_interval, ierr=err_tmp) @@ -1210,7 +1211,7 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) endif ! === error check - if (ierr > 0) then + if (ierr /= 0) then call mpas_log_write("An error has occurred in li_simulation_clock_init.", MPAS_LOG_ERR) endif From 32ff9f8e24f32a2b4a768d526397751e41f25357 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 13:17:55 -0700 Subject: [PATCH 04/11] Update checks using interval division Trying to cast intervals into dateTimeStrings did not work. --- .../src/mode_forward/mpas_li_bedtopo.F | 75 ++++++++----------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index b9a09ed5f9ce..dbdcb43d3aa5 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -448,7 +448,7 @@ subroutine slmodel_init(domain, err) call sl_drive_readnl(itersl, dtime, starttime) !SLM subroutine ! First, check consistency in coupling interval set up in MALI and SLM - call check_SLM_coupling_interval(dtime, domain % streamManager, err_tmp) + call check_SLM_coupling_interval(dtime, meshPool, domain % streamManager, err_tmp) err = ior(err, err_tmp) if (err /= 0) then call mpas_log_write("Error occurred in check_SLM_coupling_interval.", MPAS_LOG_ERR) @@ -985,23 +985,27 @@ end subroutine check ! !----------------------------------------------------------------------- - subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) + subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) use mpas_timekeeping use mpas_stream_manager use mpas_derived_types, only : MPAS_STREAM_PROPERTY_RECORD_INTV integer, intent (in) :: slm_dt1 + type (mpas_pool_type), intent(in) :: meshPool !< mesh information type (MPAS_streamManager_type), intent(inout) :: streamManager integer, intent(out) :: err ! local variables integer, pointer :: config_slm_coupling_interval character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval - type (MPAS_Time_Type) :: force_interval, restart_interval - character(len=StrKIND) :: restart_interval_str + type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, restart_interval, zero_interval + type (MPAS_Time_Type) :: start_time + character (len=StrKIND), pointer :: simulationStartTime integer :: YYYY, MM, DD, H, M, S ! time components type (MPAS_stream_list_type), pointer :: stream_cursor + integer (kind=I8KIND) :: n_intervals + type (MPAS_TimeInterval_type) :: remainder integer :: err_tmp err = 0 @@ -1015,28 +1019,26 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) err = ior(err, 1) endif + ! define zero interval for comparing against below + call mpas_set_timeInterval(zero_interval, dt = 0.0_RKIND) + ! get start time as a reference time + call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) + call mpas_set_time(start_time, dateTimeString=simulationStartTime) + ! define SLM coupling interval as a timeInterval type + call mpas_set_timeInterval(coupling_interval, YY=config_slm_coupling_interval, MM=0, DD=0, H=0, M=0, S=0, ierr=err_tmp) + err = ior(err, err_tmp) + ! Check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval call mpas_pool_get_config(liConfigs, "config_adaptive_timestep_force_interval", config_adaptive_timestep_force_interval) - ! Note: Using mpas_set_time instead of mpas_set_time_interval, even though this is an interval - ! This is because mpas_get_time_interval requires a reference time, which is not relevant - ! to these checks, and mpas_get_time allows us to get the component pieces that we want to check. - call mpas_set_time(force_interval, dateTimeString=config_adaptive_timestep_force_interval, ierr=err_tmp) + call mpas_set_timeInterval(force_interval, timeString=config_adaptive_timestep_force_interval, ierr=err_tmp) err = ior(err, err_tmp) - call mpas_get_time(force_interval, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) - if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then - call mpas_log_write("config_adaptive_timestep_force_interval currently not supported " // & - "to have nonzero values for months, days, hours, minutes, or seconds when sea-level model " // & - "is coupled. config_adaptive_timestep_force_interval=" //trim(config_adaptive_timestep_force_interval), MPAS_LOG_ERR) - call mpas_log_write(" MM=$i, DD=$i, H=$i, M=$i, S=$i", intArgs=(/MM, DD, H, M, S/)) - ! Note: the actual requirement is that adapt dt force interval divides evenly into coupling interval - ! but that is tricky to check, and wanting anything but even years for that option is a rare use case. - err = ior(err, 1) - endif - ! Next check the number of years divides evenly into SLM coupling interval - if (mod(config_slm_coupling_interval, YYYY) /= 0) then - call mpas_log_write("config_adaptive_timestep_force_interval does not divide evenly into config_slm_coupling_interval" // & - "config_adaptive_timestep_force_interval=" // trim(config_adaptive_timestep_force_interval) // & - "; config_slm_coupling_interval=$i", MPAS_LOG_ERR, intArgs=(/config_slm_coupling_interval/)) + call mpas_interval_division(start_time, coupling_interval, force_interval, n_intervals, remainder) + if (remainder .EQ. zero_interval) then + call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + else + call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) err = ior(err, 1) endif @@ -1045,27 +1047,16 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) do while (associated(stream_cursor)) if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % active_stream) ) then call mpas_log_write("Checking restart interval against SLM coulping interval") - call MPAS_stream_mgr_get_property(streamManager, 'restart', MPAS_STREAM_PROPERTY_RECORD_INTV, & - restart_interval_str, ierr=err_tmp) - err = ior(err, err_tmp) - - call mpas_log_write('restart interval is: ' //trim(restart_interval_str)) - - call mpas_set_time(restart_interval, dateTimeString=restart_interval_str, ierr=err_tmp) + restart_interval = MPAS_stream_mgr_get_stream_interval(streamManager, 'restart', MPAS_STREAM_OUTPUT, ierr=err_tmp) err = ior(err, err_tmp) - call mpas_get_time(restart_interval, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) - if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then - call mpas_log_write("If Sea Level Model is active, restart output_interval cannot include " // & - "nonzero months, days, hours, minutes or seconds. restart output_interval=" // & - trim(restart_interval_str), MPAS_LOG_ERR) - err = ior(err, 1) + call mpas_interval_division(start_time, restart_interval, coupling_interval, n_intervals, remainder) + if (remainder .EQ. zero_interval) then + call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & + "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + else + call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & + "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) endif - - if (mod(YYYY, config_slm_coupling_interval) /= 0) then - call mpas_log_write("restart output_interval must be a multiple of config_slm_coupling_interval", MPAS_LOG_ERR) - err = ior(err, 1) - endif - endif stream_cursor => stream_cursor % next From 869f944989932fb7b33822a2735fd70d5cf61cae Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 13:35:41 -0700 Subject: [PATCH 05/11] Adjust check if adaptive dt is on or not --- .../src/mode_forward/mpas_li_bedtopo.F | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index dbdcb43d3aa5..facbf8e9d6d7 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -998,8 +998,9 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) ! local variables integer, pointer :: config_slm_coupling_interval - character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval - type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, restart_interval, zero_interval + logical, pointer :: config_adaptive_timestep + character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval, config_dt + type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, dt_interval, restart_interval, zero_interval type (MPAS_Time_Type) :: start_time character (len=StrKIND), pointer :: simulationStartTime integer :: YYYY, MM, DD, H, M, S ! time components @@ -1011,10 +1012,15 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) err = 0 err_tmp = 0 + call mpas_log_write("") + call mpas_log_write("-- Checking consistency of config_slm_coupling_interval and other settings --") + ! First, check consistency in coupling interval set up in MALI and SLM call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) - if (config_slm_coupling_interval /= slm_dt1) then - call mpas_log_write("The coupling interval in MALI ($i) and SLM ($i) are inconsistent", MPAS_LOG_ERR, & + if (config_slm_coupling_interval == slm_dt1) then + call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are consistent - check passes") + else + call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are inconsistent", MPAS_LOG_ERR, & intArgs=(/config_slm_coupling_interval, slm_dt1/)) err = ior(err, 1) endif @@ -1028,18 +1034,35 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) call mpas_set_timeInterval(coupling_interval, YY=config_slm_coupling_interval, MM=0, DD=0, H=0, M=0, S=0, ierr=err_tmp) err = ior(err, err_tmp) - ! Check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval - call mpas_pool_get_config(liConfigs, "config_adaptive_timestep_force_interval", config_adaptive_timestep_force_interval) - call mpas_set_timeInterval(force_interval, timeString=config_adaptive_timestep_force_interval, ierr=err_tmp) - err = ior(err, err_tmp) - call mpas_interval_division(start_time, coupling_interval, force_interval, n_intervals, remainder) - if (remainder .EQ. zero_interval) then - call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + call mpas_pool_get_config(liConfigs, "config_adaptive_timestep", config_adaptive_timestep) + if (config_adaptive_timestep) then + ! for adaptive dt, check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval + call mpas_pool_get_config(liConfigs, "config_adaptive_timestep_force_interval", config_adaptive_timestep_force_interval) + call mpas_set_timeInterval(force_interval, timeString=config_adaptive_timestep_force_interval, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_interval_division(start_time, coupling_interval, force_interval, n_intervals, remainder) + if (remainder .EQ. zero_interval) then + call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + else + call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) + err = ior(err, 1) + endif else - call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + ! For fixed dt, check that dt divides evenly into config_slm_coupling_interval + call mpas_pool_get_config(liConfigs, "config_dt", config_dt) + call mpas_set_timeInterval(dt_interval, timeString=config_dt, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_interval_division(start_time, coupling_interval, dt_interval, n_intervals, remainder) + if (remainder .EQ. zero_interval) then + call mpas_log_write("config_dt divides into config_slm_coupling_interval $i times " // & + "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + else + call mpas_log_write("config_dt divides into config_slm_coupling_interval $i times " // & "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) - err = ior(err, 1) + err = ior(err, 1) + endif endif ! Now check that restart interval is an even multiple of coupling interval @@ -1061,6 +1084,7 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) stream_cursor => stream_cursor % next enddo + call mpas_log_write("") !-------------------------------------------------------------------- end subroutine check_SLM_coupling_interval From a4d0d68995bcc4ca94d12c4b780640e874a3ad66 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 13:48:16 -0700 Subject: [PATCH 06/11] Update restart check to also use time interval division --- .../src/mode_forward/mpas_li_bedtopo.F | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index facbf8e9d6d7..24fee4d71a22 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -1116,17 +1116,20 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) ! local vars integer, pointer :: config_slm_coupling_interval character (len=StrKIND), pointer :: xtime, simulationStartTime - character (len=StrKIND) :: elapsed_time_str + type (MPAS_TimeInterval_Type) :: coupling_interval, zero_interval type (MPAS_Time_Type) :: start_time, curr_time - type (MPAS_Time_Type) :: elapsed_time ! should be a time interval but not possible to get years that way - integer :: YYYY, MM, DD, H, M, S ! time components + integer (kind=I8KIND) :: n_intervals + type (MPAS_TimeInterval_type) :: remainder integer :: err_tmp err = 0 - - slmTimeStep = -999 ! initialize to bad number + err_tmp = 0 call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) + ! define SLM coupling interval as a timeInterval type + call mpas_set_timeInterval(coupling_interval, YY=config_slm_coupling_interval, MM=0, DD=0, H=0, M=0, S=0, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) call mpas_pool_get_array(meshPool, 'xtime', xtime) @@ -1134,30 +1137,20 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) err = ior(err, err_tmp) call mpas_set_time(curr_time, dateTimeString=xtime, ierr=err_tmp) err = ior(err, err_tmp) - call mpas_get_timeInterval(curr_time - start_time, start_time, timeString=elapsed_time_str, ierr=err_tmp) - err = ior(err, err_tmp) - - ! convert elapsed time string to its units. Using the intermediate string format because mpas_get_timeInterval doesn't return - ! years, and figuring out years from days depends on the calendar - call mpas_set_time(elapsed_time, dateTimeString=elapsed_time_str, ierr=err_tmp) - err = ior(err, err_tmp) - call mpas_get_time(elapsed_time, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) - - ! make sure the elapsed time is an even year - if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then - call mpas_log_write("Elapsed time since simulationStartTime include nonzero months, days, hours, minutes, " // & - "or seconds.", MPAS_LOG_ERR) - err = ior(err, 1) - endif - if (mod(YYYY, config_slm_coupling_interval) == 0) then - ! We can restart cleanly - slmTimeStep = YYYY / config_slm_coupling_interval + call mpas_interval_division(start_time, curr_time - start_time, coupling_interval, n_intervals, remainder) + call mpas_set_timeInterval(zero_interval, dt = 0.0_RKIND) + if (remainder .EQ. zero_interval) then + call mpas_log_write("SLM Restart check: config_slm_coupling_interval divides into elapsed time $i times " // & + "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + slmTimeStep = int(n_intervals) else - call mpas_log_write("Elapsed years since simulationStartTime is not evenly divisible by config_slm_coupling_interval." // & - " Unable to restart Sea Level Model cleanly.", MPAS_LOG_ERR) + call mpas_log_write("SLM Restart check: config_slm_coupling_interval divides into elapsed time $i times " // & + "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) err = ior(err, 1) + slmTimeStep = -999 endif + call mpas_log_write("") !-------------------------------------------------------------------- end subroutine find_slm_restart_timestep From a3c43371b118fc9b14ad66e36a4aad1b7b06427a Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 13:57:09 -0700 Subject: [PATCH 07/11] Add missing arguments to log write statement --- .../mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index 24fee4d71a22..aacfbed95ad3 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -1018,7 +1018,8 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) ! First, check consistency in coupling interval set up in MALI and SLM call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) if (config_slm_coupling_interval == slm_dt1) then - call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are consistent - check passes") + call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are consistent - check passes", & + intArgs=(/config_slm_coupling_interval, slm_dt1/)) else call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are inconsistent", MPAS_LOG_ERR, & intArgs=(/config_slm_coupling_interval, slm_dt1/)) From abaa6cae48047fb4d4759fbd8d25d66f096c0a18 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 23 Feb 2024 19:34:45 -0700 Subject: [PATCH 08/11] Add missing error flag so model actually dies when error occurs --- .../mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F | 1 + 1 file changed, 1 insertion(+) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index aacfbed95ad3..f1cc7aceed22 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -1080,6 +1080,7 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) else call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) + err = ior(err, 1) endif endif From 6bb3000ce6caa7769555b4f20bc6130f60d2fe1e Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 23 Feb 2024 19:59:03 -0700 Subject: [PATCH 09/11] Allow restarts at any interval when using SLM This commit changes how restarts are handled when the SLM is active to allow MALI to be restarted at any arbitrary restart interval and have the SLM restart correctly. This is done by changing the SLM coupling alarm to be based off of the original simulationStartTime (instead of the start time of the current execution). This required moving the creation of the coupling alarm to later in initialization so that the variable simulationStartTime is available. With this change, it was also necessary to change the way the SLM time level is calculated on a restart to take the floor of the elapsed time divided by the coupling interval, rather than requiring that there be no remainder. This adds a little fragility because there is no way to double check that is the correct SLM time level, but if this is set up correctly, it should be handled properly. Finally, as part of these changes, I also removed the check on init that the coupling interval divides evenly into the restart interval, because that's no longer a requirement. That's sort of too bad, because it was a lot of work to figure out how to make that check! But it's nicer to not have that restriction. --- .../src/mode_forward/mpas_li_bedtopo.F | 69 +++++++++---------- .../src/mode_forward/mpas_li_core.F | 17 ----- 2 files changed, 32 insertions(+), 54 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index f1cc7aceed22..4ead2074546f 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -407,6 +407,10 @@ subroutine slmodel_init(domain, err) integer :: itersl, dtime ! SLM variable real :: starttime ! SLM variable integer, dimension(:), pointer :: cellMask ! integer bitmask for cells + integer, pointer :: config_slm_coupling_interval + type (MPAS_TimeInterval_type) :: slm_coupling_interval + character (len=StrKIND), pointer :: simulationStartTime + type (MPAS_Time_type) :: simulationStartTime_timeType ! MPI variables integer, dimension(:), pointer :: indexToCellID @@ -415,12 +419,30 @@ subroutine slmodel_init(domain, err) err = 0 err_tmp = 0 + + call mpas_pool_get_subpool(domain % blocklist % structs, 'mesh', meshPool) + + ! Set up the alarm for the coupling time interval + call mpas_pool_get_config(liConfigs, 'config_slm_coupling_interval', config_slm_coupling_interval) + call mpas_set_timeInterval(slm_coupling_interval, YY=config_slm_coupling_interval, ierr=err_tmp) + err = ior(err,err_tmp) + call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) + call mpas_set_time(simulationStartTime_timeType, dateTimeString=simulationStartTime, ierr=err_tmp) + err = ior(err,err_tmp) + call mpas_add_clock_alarm(domain%clock, 'slmCouplingInterval', alarmTime=simulationStartTime_timeType, & + alarmTimeInterval=slm_coupling_interval, ierr=err_tmp) + err = ior(err,err_tmp) + if (mpas_is_alarm_ringing(domain%clock, 'slmCouplingInterval', ierr=err_tmp)) then + err = ior(err, err_tmp) + call mpas_reset_clock_alarm(domain%clock, 'slmCouplingInterval', ierr=err_tmp) + err = ior(err, err_tmp) + endif + ! initialize interpolation call interpolate_init(domain, err_tmp) err = ior(err, err_tmp) ! Set needed variables for using MPI - call mpas_pool_get_subpool(domain % blocklist % structs, 'mesh', meshPool) call mpas_pool_get_dimension(meshPool, 'nCells', nCellsAll) call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsOwned) call mpas_pool_get_array(meshPool, 'indexToCellID', indexToCellID) @@ -448,7 +470,7 @@ subroutine slmodel_init(domain, err) call sl_drive_readnl(itersl, dtime, starttime) !SLM subroutine ! First, check consistency in coupling interval set up in MALI and SLM - call check_SLM_coupling_interval(dtime, meshPool, domain % streamManager, err_tmp) + call check_SLM_coupling_interval(dtime, meshPool, err_tmp) err = ior(err, err_tmp) if (err /= 0) then call mpas_log_write("Error occurred in check_SLM_coupling_interval.", MPAS_LOG_ERR) @@ -985,7 +1007,7 @@ end subroutine check ! !----------------------------------------------------------------------- - subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) + subroutine check_SLM_coupling_interval(slm_dt1, meshPool, err) use mpas_timekeeping use mpas_stream_manager @@ -993,18 +1015,16 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) integer, intent (in) :: slm_dt1 type (mpas_pool_type), intent(in) :: meshPool !< mesh information - type (MPAS_streamManager_type), intent(inout) :: streamManager integer, intent(out) :: err ! local variables integer, pointer :: config_slm_coupling_interval logical, pointer :: config_adaptive_timestep character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval, config_dt - type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, dt_interval, restart_interval, zero_interval + type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, dt_interval, zero_interval type (MPAS_Time_Type) :: start_time character (len=StrKIND), pointer :: simulationStartTime integer :: YYYY, MM, DD, H, M, S ! time components - type (MPAS_stream_list_type), pointer :: stream_cursor integer (kind=I8KIND) :: n_intervals type (MPAS_TimeInterval_type) :: remainder integer :: err_tmp @@ -1066,26 +1086,9 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) endif endif - ! Now check that restart interval is an even multiple of coupling interval - stream_cursor => streamManager % streams % head - do while (associated(stream_cursor)) - if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % active_stream) ) then - call mpas_log_write("Checking restart interval against SLM coulping interval") - restart_interval = MPAS_stream_mgr_get_stream_interval(streamManager, 'restart', MPAS_STREAM_OUTPUT, ierr=err_tmp) - err = ior(err, err_tmp) - call mpas_interval_division(start_time, restart_interval, coupling_interval, n_intervals, remainder) - if (remainder .EQ. zero_interval) then - call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & - "with no remainder - check passes", intArgs=(/int(n_intervals)/)) - else - call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & - "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) - err = ior(err, 1) - endif - endif + ! No need to compare restart interval and coupling interval because restarts with SLM are supported for + ! any restart interval now - stream_cursor => stream_cursor % next - enddo call mpas_log_write("") !-------------------------------------------------------------------- @@ -1118,7 +1121,7 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) ! local vars integer, pointer :: config_slm_coupling_interval character (len=StrKIND), pointer :: xtime, simulationStartTime - type (MPAS_TimeInterval_Type) :: coupling_interval, zero_interval + type (MPAS_TimeInterval_Type) :: coupling_interval type (MPAS_Time_Type) :: start_time, curr_time integer (kind=I8KIND) :: n_intervals type (MPAS_TimeInterval_type) :: remainder @@ -1141,17 +1144,9 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) err = ior(err, err_tmp) call mpas_interval_division(start_time, curr_time - start_time, coupling_interval, n_intervals, remainder) - call mpas_set_timeInterval(zero_interval, dt = 0.0_RKIND) - if (remainder .EQ. zero_interval) then - call mpas_log_write("SLM Restart check: config_slm_coupling_interval divides into elapsed time $i times " // & - "with no remainder - check passes", intArgs=(/int(n_intervals)/)) - slmTimeStep = int(n_intervals) - else - call mpas_log_write("SLM Restart check: config_slm_coupling_interval divides into elapsed time $i times " // & - "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) - err = ior(err, 1) - slmTimeStep = -999 - endif + slmTimeStep = int(n_intervals) + call mpas_log_write("SLM Restart check: Using SLM time level $i because config_slm_coupling_interval divides into " // & + "elapsed time that many times ", intArgs=(/int(slmTimeStep)/)) call mpas_log_write("") !-------------------------------------------------------------------- diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F index 146b4e36d805..16c7c7807200 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F @@ -1105,13 +1105,11 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) type (MPAS_Time_Type) :: startTime, stopTime, alarmStartTime type (MPAS_TimeInterval_type) :: runDuration, timeStep, alarmTimeStep type (MPAS_TimeInterval_type) :: adaptDtForceInterval - type (MPAS_TimeInterval_type) :: slm_coupling_interval character (len=StrKIND), pointer :: config_start_time, config_run_duration, config_stop_time, & config_output_interval, config_restart_interval ! MPAS standard configs character (len=StrKIND), pointer :: config_dt ! MPAS LI-specific config option character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval ! MPAS LI-specific config option character (len=StrKIND), pointer :: config_restart_timestamp_name - character (len=StrKIND), pointer :: config_uplift_method integer, pointer :: config_slm_coupling_interval character (len=StrKIND) :: restartTimeStamp !< string to be read from file integer, pointer :: config_year_digits @@ -1131,7 +1129,6 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) call mpas_pool_get_config(configs, 'config_stop_time', config_stop_time) call mpas_pool_get_config(configs, 'config_restart_timestamp_name', config_restart_timestamp_name) call mpas_pool_get_config(configs, 'config_adaptive_timestep_force_interval', config_adaptive_timestep_force_interval) - call mpas_pool_get_config(configs, 'config_uplift_method', config_uplift_method) call mpas_pool_get_config(configs, 'config_slm_coupling_interval', config_slm_coupling_interval) @@ -1196,20 +1193,6 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) endif ierr = ior(ierr, err_tmp) - ! Set up the coupling time interval if MALI is coupled to sea-level model - if (trim(config_uplift_method) == "sealevelmodel") then - call mpas_set_timeInterval(slm_coupling_interval, YY=config_slm_coupling_interval, ierr=err_tmp) - ierr = ior(ierr,err_tmp) - call mpas_add_clock_alarm(core_clock, 'slmCouplingInterval', alarmTime=startTime, & - alarmTimeInterval=slm_coupling_interval, ierr=err_tmp) - ierr = ior(ierr,err_tmp) - if (mpas_is_alarm_ringing(core_clock, 'slmCouplingInterval', ierr=err_tmp)) then - ierr = ior(ierr, err_tmp) - call mpas_reset_clock_alarm(core_clock, 'slmCouplingInterval', ierr=err_tmp) - ierr = ior(ierr, err_tmp) - endif - endif - ! === error check if (ierr /= 0) then call mpas_log_write("An error has occurred in li_simulation_clock_init.", MPAS_LOG_ERR) From be5f341ce4d50beb4393df4f1dc386b4e6fb59df Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 23 Feb 2024 20:17:19 -0700 Subject: [PATCH 10/11] Add addl info on restart about the calculated time since last SLM call This doesn't serve any internal purpose, but it could help a user detect an error in their configuration. --- .../src/mode_forward/mpas_li_bedtopo.F | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index 4ead2074546f..b3461a52ae41 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -1125,6 +1125,7 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) type (MPAS_Time_Type) :: start_time, curr_time integer (kind=I8KIND) :: n_intervals type (MPAS_TimeInterval_type) :: remainder + character (len=StrKIND) :: remainder_string integer :: err_tmp err = 0 @@ -1135,7 +1136,6 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) call mpas_set_timeInterval(coupling_interval, YY=config_slm_coupling_interval, MM=0, DD=0, H=0, M=0, S=0, ierr=err_tmp) err = ior(err, err_tmp) - call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) call mpas_pool_get_array(meshPool, 'xtime', xtime) call mpas_set_time(start_time, dateTimeString=simulationStartTime, ierr=err_tmp) @@ -1145,8 +1145,12 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) call mpas_interval_division(start_time, curr_time - start_time, coupling_interval, n_intervals, remainder) slmTimeStep = int(n_intervals) - call mpas_log_write("SLM Restart check: Using SLM time level $i because config_slm_coupling_interval divides into " // & + call mpas_get_timeInterval(remainder, start_time, timeString=remainder_string, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_log_write("SLM Restart: Using SLM time level $i because config_slm_coupling_interval divides into " // & "elapsed time that many times ", intArgs=(/int(slmTimeStep)/)) + call mpas_log_write(" That calculation implies it has been " // trim(remainder_string) // " since last SLM coupling. " // & + "If that interval seems wrong, there may be an error in your configuration.") call mpas_log_write("") !-------------------------------------------------------------------- From 052b15de927db57d213bdc8e4eeba57237e9a8e6 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 23 Feb 2024 20:46:11 -0700 Subject: [PATCH 11/11] Don't call SLM on init of a restart It's not needed, and if the restart time is not a coupling interval, it will make the SLM get out of sync. --- .../src/mode_forward/mpas_li_bedtopo.F | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index b3461a52ae41..d5aaf12672bd 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -501,10 +501,13 @@ subroutine slmodel_init(domain, err) call find_slm_restart_timestep(meshPool, slmTimeStep, err_tmp) err = ior(err, err_tmp) - if (err == 0) then - call mpas_log_write("Calling the SLM. SLM timestep $i", intArgs=(/slmTimeStep/)) - call slmodel_solve(slmTimeStep, domain) - endif + + ! Note: no need to call slmodel_solve on init of a restart. + ! If this time level happens to be a coupling interval, SLM would have been solved already + ! in the previous run that generated the restart file. + ! While it would not hurt (other than unneeded execution time) to call SLM again if the + ! restart time level happens to be a coupling interval, if the restart time is in between + ! coupling intervals calling SLM here will make things out of sync. else