Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions config_src/drivers/nuopc_cap/mom_cap.F90
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module MOM_cap_mod

use MOM_domains, only: get_domain_extent
use MOM_io, only: stdout, io_infra_end
use MOM_io, only: append_ensemble_appendix
use mpp_domains_mod, only: mpp_get_compute_domains
use mpp_domains_mod, only: mpp_get_ntile_count, mpp_get_pelist, mpp_get_global_domain
use mpp_domains_mod, only: mpp_get_domain_npes
Expand All @@ -24,6 +25,7 @@ module MOM_cap_mod
use MOM_ocean_model_nuopc, only: ocean_model_init_sfc, ocean_model_flux_init
use MOM_ocean_model_nuopc, only: ocean_model_init, update_ocean_model, ocean_model_end
use MOM_ocean_model_nuopc, only: get_ocean_grid, get_eps_omesh, query_ocean_state
use MOM_ocean_model_nuopc, only: stoch_restart_needed
use MOM_cap_time, only: AlarmInit
use MOM_cap_methods, only: mom_import, mom_export, mom_set_geomtype, mod2med_areacor
use MOM_cap_methods, only: med2mod_areacor, state_diagnose
Expand Down Expand Up @@ -1728,7 +1730,7 @@ subroutine ModelAdvance(gcomp, rc)
character(240) :: msgString
character(ESMF_MAXSTR) :: casename
integer :: iostat
integer :: writeunit
integer :: rpointer_unit
integer :: localPet
type(ESMF_VM) :: vm
integer :: n, i
Expand Down Expand Up @@ -1940,30 +1942,27 @@ subroutine ModelAdvance(gcomp, rc)
rpointer_filename = trim(rpointer_filename//timestamp)
endif

write(restartname,'(A,".mom6.r",A)') &
trim(casename), timestamp
write(stoch_restartname,'(A,".mom6.r_stoch",A,".nc")') &
trim(casename), timestamp
write(restartname,'(A,".mom6.r",A)') trim(casename), timestamp
write(stoch_restartname,'(A,".mom6.r_stoch",A,".nc")') trim(casename), timestamp

call append_ensemble_appendix(stoch_restartname, ".mom6")

call ESMF_LogWrite("MOM_cap: Writing restart : "//trim(restartname), ESMF_LOGMSG_INFO)
! write restart file(s)
call ocean_model_restart(ocean_state, restartname=restartname, &
stoch_restartname=stoch_restartname, num_rest_files=num_rest_files)
if (localPet == 0) then
! Write name of restart file in the rpointer file - this is currently hard-coded for the ocean
open(newunit=writeunit, file=rpointer_filename, form='formatted', status='unknown', iostat=iostat)
open(newunit=rpointer_unit, file=rpointer_filename, form='formatted', status='unknown', iostat=iostat)
if (iostat /= 0) then
call ESMF_LogSetError(ESMF_RC_FILE_OPEN, &
msg=subname//' ERROR opening '//rpointer_filename, line=__LINE__, file=u_FILE_u, rcToReturn=rc)
return
endif

! update restart file name to include the instance suffix
if (len_trim(inst_suffix) > 0) then
write(restartname, '(A,".mom6",A,".r",A)') trim(casename), trim(inst_suffix), timestamp
endif

write(writeunit,'(a)') trim(restartname)//'.nc'
call append_ensemble_appendix(restartname, ".mom6")

write(rpointer_unit,'(a)') trim(restartname)//'.nc'
if (num_rest_files > 1) then
! append i.th restart file name to rpointer
do i=1, num_rest_files-1
Expand All @@ -1972,10 +1971,15 @@ subroutine ModelAdvance(gcomp, rc)
else
write(suffix,'("_",I2)') i
endif
write(writeunit,'(a)') trim(restartname) // trim(suffix) // '.nc'
write(rpointer_unit,'(a)') trim(restartname) // trim(suffix) // '.nc'
enddo
endif
close(writeunit)

if (stoch_restart_needed(ocean_state)) then
write(rpointer_unit,'(a)') trim(stoch_restartname)
endif

close(rpointer_unit)
endif
else ! not cesm_coupled
write(restartname,'(i4.4,2(i2.2),A,3(i2.2),A)') year, month, day,".", hour, minute, seconds, &
Expand Down
16 changes: 11 additions & 5 deletions config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ module MOM_ocean_model_nuopc
public ocean_public_type_chksum
public get_ocean_grid, query_ocean_state
public get_eps_omesh
public stoch_restart_needed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like having this as a stand-alone function!


!> This type is used for communication with other components via the FMS coupler.
!! The element names and types can be changed only with great deliberation, hence
Expand Down Expand Up @@ -790,7 +791,7 @@ subroutine ocean_model_restart(OS, timestamp, restartname, stoch_restartname, nu
endif
endif
if (present(stoch_restartname)) then
if (OS%do_sppt .OR. OS%pert_epbl .OR. OS%do_skeb) then
if (stoch_restart_needed(OS)) then
call write_stoch_restart_ocn(trim(stoch_restartname))
endif
endif
Expand Down Expand Up @@ -1148,7 +1149,6 @@ end subroutine Ocean_stock_pe

!> Write out checksums for fields from the ocean surface state
subroutine ocean_public_type_chksum(id, timestep, ocn)

character(len=*), intent(in) :: id !< An identifying string for this call
integer, intent(in) :: timestep !< The number of elapsed timesteps
type(ocean_public_type), intent(in) :: ocn !< A structure containing various publicly
Expand All @@ -1174,17 +1174,23 @@ end subroutine ocean_public_type_chksum

subroutine get_ocean_grid(OS, Gridp)
! Obtain the ocean grid.
type(ocean_state_type) :: OS
type(ocean_grid_type) , pointer :: Gridp
type(ocean_state_type), intent(in) :: OS
type(ocean_grid_type) , pointer, intent(out) :: Gridp

Gridp => OS%grid
return
end subroutine get_ocean_grid

!> Returns eps_omesh read from param file
real function get_eps_omesh(OS)
type(ocean_state_type) :: OS
type(ocean_state_type), intent(in) :: OS
get_eps_omesh = OS%eps_omesh; return
end function

!> Returns true if a stochastic restart file is needed
logical function stoch_restart_needed(OS)
type(ocean_state_type), intent(in) :: OS
stoch_restart_needed = OS%do_sppt .OR. OS%pert_epbl .OR. OS%do_skeb
end function stoch_restart_needed

end module MOM_ocean_model_nuopc
43 changes: 43 additions & 0 deletions src/framework/MOM_io.F90
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ module MOM_io
public :: file_exists, open_ASCII_file, close_file
public :: MOM_file, MOM_infra_file, MOM_netcdf_file
public :: field_exists, get_filename_appendix
public :: append_ensemble_appendix
public :: fieldtype, field_size, get_field_atts
public :: axistype, get_axis_data
public :: MOM_read_data, MOM_read_vector, read_field_chksum
Expand Down Expand Up @@ -2997,6 +2998,48 @@ subroutine MOM_write_field_0d(IO_handle, field_md, field, tstamp, fill_value, sc
call IO_handle%write_field(field_md, scaled_val, tstamp=tstamp)
end subroutine MOM_write_field_0d

!> Append the ensemble appendix to a filename. If provided, the appendix is appended after
!! the last occurrence of the append_after substring in the filename.
subroutine append_ensemble_appendix(filename, append_after)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we rename this function insert_ensemble_id() or something in that vein? I mostly take issue with the append_ portion, because we are not always appending this string; I see that MOM and FMS use appendix and suffix to refer to the ensemble member identifier.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up renaming it as insert_ensemble_appendix, assuming that id refers to i while appendix refers to _000i for the i'th component (where 0<=i<=9)

character(len=*), intent(inout) :: filename !< The filename to which the appendix is appended
character(len=*), optional, intent(in) :: append_after !< The string after which the appendix is appended.
!! If not provided or found, the appendix is appended
!! at the end of the filename.
! Local variables
character(len=32) :: filename_appendix_t ! trimmed ensemble id to be appended to the filename
character(len=:), allocatable :: filename_t ! trimmed filename
character(len=:), allocatable :: append_after_t ! trimmed append_after
integer :: pos ! The filename string index after which the appendix is to be appended

call get_filename_appendix(filename_appendix_t)
filename_appendix_t = trim(filename_appendix_t)
if (len(filename_appendix_t) == 0) return

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of trimming the string and then finding the length, you could just check (len_trim(filename_appendix_t) == 0)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, I actually switched from filename_appendix_t -> filename_appendix and used len_trim since filename_appendix_t wasn't a deferred-length string, unlike the other two.


filename_t = trim(filename)
pos = len(filename_t)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, you can just use pos = len_trim(filename_t); you are going to change filename_t below anyway, so the assignment line isn't necessary

@alperaltuntas alperaltuntas Mar 3, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added _t versions of these strings to prevent multiple calls and accidental omissions of trim() in the rest of the function. In fact, I think I should have:

filename_t = trim(adjustl(filename))

If you think _t versions of these strings cause unnecessary confusion, I am fine with removing them.

(Just noticed that trim call in 3039 is unnecessary, so it needs to be removed at the least.)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I managed to miss that 3018 was filename_t on the lefthand side and filename on the right; I think your comment about using adjustl() makes more sense than dropping filename_t -- I noticed the trim(adjustl()) construct elsewhere in MOM6 when looking for where GRID_FILE is read in.


! If append_after is provided, find the last occurrence of append_after in the filename and set pos accordingly.
if (present(append_after)) then
append_after_t = trim(append_after)
pos = index(filename_t, append_after_t, back=.true.)
if (pos == 0) then
call MOM_error(FATAL, "append_ensemble_appendix: The string "//trim(append_after)// &
" was not found in the filename "//trim(filename))
endif
pos = pos + len_trim(append_after_t) - 1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opposite comment time :) Since append_after_t is deferred-length and is trim(append_after), don't you want len(append_after_t) instead of len_trim()?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, this should be just len(append_after_t). I think I initially had:

len_trim(append_after)

then changed append_after to append_after_t, but didn't update len_trim to len.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

endif

! Append the ensemble appendix to the filename. If the appendix is to be added to
! the end of the filename, do so before the .nc extension if it exists.
if (pos>3 .and. pos == len(filename_t)) then
if (filename_t(pos-2:pos) == ".nc") then
pos = pos - 3 ! Position before the .nc extension
endif
endif
filename = filename_t(1:pos)//trim(filename_appendix_t)//filename_t(pos+1:)

end subroutine append_ensemble_appendix

!> Given filename and fieldname, this subroutine returns the size of the field in the file
subroutine field_size(filename, fieldname, sizes, field_found, no_domain, ndims, ncid_in)
character(len=*), intent(in) :: filename !< The name of the file to read
Expand Down
56 changes: 11 additions & 45 deletions src/framework/MOM_restart.F90
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ module MOM_restart
use MOM_io, only : create_MOM_file, file_exists
use MOM_io, only : MOM_infra_file, MOM_field
use MOM_io, only : MOM_read_data, read_data, MOM_write_field, field_exists
use MOM_io, only : vardesc, var_desc, query_vardesc, modify_vardesc, get_filename_appendix
use MOM_io, only : vardesc, var_desc, query_vardesc, modify_vardesc
use MOM_io, only : MULTIPLE, READONLY_FILE, SINGLE_FILE
use MOM_io, only : CENTER, CORNER, NORTH_FACE, EAST_FACE
use MOM_io, only : axis_info, get_axis_info
use MOM_io, only : append_ensemble_appendix
use MOM_string_functions, only : lowercase
use MOM_time_manager, only : time_type, time_type_to_real, real_to_time
use MOM_time_manager, only : days_in_month, get_date, set_date
Expand Down Expand Up @@ -132,7 +133,8 @@ module MOM_restart
type(p4d), pointer :: var_ptr4d(:) => NULL()
!>@}
integer :: max_fields !< The maximum number of restart fields
character(len=32) :: restartfile_appx_prefix !< The prefix for the restart file appendix (i.e., ensemble id)
character(len=32) :: ensemble_appendix_prefix !< The prefix after which the ensemble id appendix is added
!! in output file names.
end type MOM_restart_CS

!> Register fields for restarts
Expand Down Expand Up @@ -1614,8 +1616,6 @@ subroutine save_restart(directory, time, G, CS, time_stamped, filename, GV, num_
integer :: turns ! Number of quarter turns from input to model domain
integer, parameter :: nmax_extradims = 5
type(axis_info), dimension(:), allocatable :: extra_axes
integer :: prefix_index ! The index of the first occurrence of prefix in the restart filename.
integer :: prefix_length ! The length of the prefix string.

turns = CS%turns

Expand Down Expand Up @@ -1654,31 +1654,7 @@ subroutine save_restart(directory, time, G, CS, time_stamped, filename, GV, num_
endif ; endif

! Determine if there is a filename_appendix (used for ensemble runs).
call get_filename_appendix(filename_appendix)
if (len_trim(filename_appendix) > 0) then
length = len_trim(restartname)

! Determine if a valid prefix for appendix is provided.
prefix_index = 0
prefix_length = len_trim(CS%restartfile_appx_prefix)
if (prefix_length > 0) prefix_index = index(restartname, trim(CS%restartfile_appx_prefix))

if (prefix_index == 0) then ! No prefix is found
if (restartname(length-2:length) == '.nc') then
restartname = restartname(1:length-3)//'.'//trim(filename_appendix)//'.nc'
else
restartname = restartname(1:length) //'.'//trim(filename_appendix)
endif
else ! Prefix is found
if (restartname(length-2:length) == '.nc') then
restartname = restartname(1:prefix_index-1+prefix_length) // &
trim(filename_appendix) // restartname(prefix_index+prefix_length:length-3) // '.nc'
else
restartname = restartname(1:prefix_index-1+prefix_length) // &
trim(filename_appendix) // restartname(prefix_index+prefix_length:)
endif
endif
endif
call append_ensemble_appendix(restartname, CS%ensemble_appendix_prefix)

next_var = 1
do while (next_var <= CS%novars )
Expand Down Expand Up @@ -2150,17 +2126,7 @@ function open_restart_units(filename, directory, G, CS, IO_handles, file_paths,
still_looking = (num_restart <= 0) ! Avoid going through the file list twice.
do while (still_looking)
restartname = trim(CS%restartfile)

! Determine if there is a filename_appendix (used for ensemble runs).
call get_filename_appendix(filename_appendix)
if (len_trim(filename_appendix) > 0) then
length = len_trim(restartname)
if (restartname(length-2:length) == '.nc') then
restartname = restartname(1:length-3)//'.'//trim(filename_appendix)//'.nc'
else
restartname = restartname(1:length) //'.'//trim(filename_appendix)
endif
endif
call append_ensemble_appendix(restartname, CS%ensemble_appendix_prefix)
filepath = trim(directory) // trim(restartname)

write(suffix,'("_",I0)') num_restart
Expand Down Expand Up @@ -2314,11 +2280,11 @@ subroutine restart_init(param_file, CS, restart_root)
"made from a run with a different mask_table than the current run, "//&
"in which case the checksums will not match and cause crash.",&
default=.true.)
call get_param(param_file, mdl, "RESTARTFILE_APPENDIX_PREFIX", CS%restartfile_appx_prefix, &
"The prefix for the restart file appendix (i.e., ensemble id for ensemble runs). "// &
"If this prefix is found in the restart file name, the appendix is added right after the "// &
"first occurrence of the prefix. If not found, the appendix is added to the end of the "// &
"file name. This parameter is ignored for non-ensemble runs.", &
call get_param(param_file, mdl, "ENSEMBLE_APPENDIX_PREFIX", CS%ensemble_appendix_prefix, &
"If set to a non-empty string, this value specifies the substring after which "//&
"the ensemble appendix is inserted in restart, initial conditions, and ocean "//&
"geometry file names. If the specified substring is not found in any of those "//&
"output file names, the model terminates with an error.", &
default="")
call get_param(param_file, mdl, "RESTART_SYMMETRIC_CHECKSUMS", CS%symmetric_checksums, &
"If true, do the restart checksums on all the edge points for a non-reentrant "//&
Expand Down
19 changes: 9 additions & 10 deletions src/initialization/MOM_shared_initialization.F90
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module MOM_shared_initialization
use MOM_io, only : MOM_read_data, MOM_read_vector, read_variable, stdout
use MOM_io, only : open_file_to_read, close_file_to_read, SINGLE_FILE, MULTIPLE
use MOM_io, only : slasher, vardesc, MOM_write_field, var_desc
use MOM_io, only : append_ensemble_appendix
use MOM_string_functions, only : uppercase
use MOM_unit_scaling, only : unit_scale_type

Expand Down Expand Up @@ -1342,6 +1343,7 @@ subroutine write_ocean_geometry_file(G, param_file, directory, US, geom_file)
character(len=240) :: filepath ! The full path to the file to write
character(len=40) :: mdl = "write_ocean_geometry_file"
character(len=32) :: filename_appendix = '' ! Appendix to geom filename for ensemble runs
character(len=32) :: ensemble_appendix_prefix ! The prefix after which the ensemble id appendix is added
type(vardesc), dimension(:), allocatable :: &
vars ! Types with metadata about the variables and their staggering
type(MOM_field), dimension(:), allocatable :: &
Expand Down Expand Up @@ -1407,16 +1409,13 @@ subroutine write_ocean_geometry_file(G, param_file, directory, US, geom_file)
filepath = trim(directory) // "ocean_geometry"
endif

! Append ensemble run number to filename if it is an ensemble run
call get_filename_appendix(filename_appendix)
if (len_trim(filename_appendix) > 0) then
geom_file_len = len_trim(filepath)
if (filepath(geom_file_len-2:geom_file_len) == ".nc") then
filepath = filepath(1:geom_file_len-3) // '.' // trim(filename_appendix) // ".nc"
else
filepath = filepath // '.' // trim(filename_appendix)
endif
endif
call get_param(param_file, mdl, "ENSEMBLE_APPENDIX_PREFIX", ensemble_appendix_prefix, &
"If set to a non-empty string, this value specifies the substring after which "//&
"the ensemble appendix is inserted in restart, initial conditions, and ocean "//&
"geometry file names. If the specified substring is not found in any of those "//&
"output file names, the model terminates with an error.", &
default="", do_not_log=.true.)
call append_ensemble_appendix(filepath, ensemble_appendix_prefix)

call get_param(param_file, mdl, "PARALLEL_RESTARTFILES", multiple_files, &
"If true, the IO layout is used to group processors that write to the same "//&
Expand Down