Skip to content

Commit ff387d6

Browse files
alperaltuntasclaude
andcommitted
Switch CESM to netCDF restarts with binary fallback; in-core calm IC
Make netCDF (PIO) restarts the default for CESM while keeping binary restarts as a coexisting, backward-compatible fallback, and start initial runs from in-core calm conditions rather than a binary calm_strt.ww3 file. - wav_comp_nuopc.F90: set use_restartnc=.true. for CESM; defer model init (waveinit_cesm/wav_history_init) to InitializeRealize after wav_pio_init, since CESM PIO is only set up at PostChildrenAdvertise. - w3initmd.F90: CESM restart read selects netCDF vs binary by the initfile extension (.nc -> read_restart, else -> binary w3iors fallback); an initial run with no initfile starts from in-core calm (read_restart('none')). - w3iorsmd.F90: accept a legacy-version binary restart ('2021-05-28') with a warning instead of aborting -- the FULL-restart record layout is unchanged, so hybrid/branch runs stay backward compatible with pre-merge binary restarts. - w3wavemd.F90: keep the CESM gridded-output/coupling-export handling (which keeps the HS/Stokes/period arrays current for the mediator export) and write netCDF restarts via wav_restart_mod when use_restartnc. - wav_history_mod.F90: skip the per-history indicator log file for CESM (#ifndef W3_CESMCOUPLED); retained for UFS. Validated against the 30a09a baseline: aux_ww3 (ERS/ERI/SMS_D/SMS-CW/ SMS-legacy_cpl) -- cpl.hi/cpl.hx.ww3/mom6 identical, exact-restart and branch/hybrid comparisons pass, only the known ww3.hi THM convention delta remains; plus multi-instance netCDF exact-restart (ERS _C3) and branch/hybrid from pre-merge binary restarts all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 3ea16a5 commit ff387d6

5 files changed

Lines changed: 133 additions & 21 deletions

File tree

model/src/w3initmd.F90

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ SUBROUTINE W3INIT ( IMOD, IsMulti, FEXT, MDS, MTRACE, ODAT, FLGRD, FLGR2, FLGD,
454454
#ifdef W3_PIO
455455
use wav_restart_mod, only : read_restart
456456
use w3odatmd, only : runtype, restart_from_binary, use_restartnc, user_restfname
457+
use w3odatmd, only : use_user_restname, initfile
457458
#endif
458459
!/
459460
#ifdef W3_MPI
@@ -983,6 +984,40 @@ SUBROUTINE W3INIT ( IMOD, IsMulti, FEXT, MDS, MTRACE, ODAT, FLGRD, FLGR2, FLGD,
983984
#ifdef W3_PIO
984985
if (use_restartnc) then
985986
call set_user_timestring(time,user_timestring)
987+
#ifdef W3_CESMCOUPLED
988+
! CESM: netCDF restarts are the default; binary restart/IC files are a
989+
! coexisting, backward-compatible fallback selected by the initfile
990+
! extension. An initial run with no initfile starts from in-core calm
991+
! conditions (read_restart('none')) -- no binary initial-condition file.
992+
if (trim(runtype) == 'continue') then
993+
fname = trim(user_restfname)//trim(user_timestring)//'.nc'
994+
inquire(file=trim(fname), exist=exists)
995+
if (.not. exists) then
996+
call extcde (60, msg="required restart file " // trim(fname) // " does not exist")
997+
end if
998+
call read_restart(trim(fname), va=va, mapsta=mapsta, mapst2=mapst2)
999+
else if (len_trim(initfile) == 0) then
1000+
if (trim(runtype) == 'branch') then
1001+
call extcde (60, msg="branch run requires a non-empty initfile")
1002+
end if
1003+
! initial run with no IC file: start from in-core calm conditions
1004+
call read_restart('none')
1005+
flcold = .true.
1006+
else
1007+
inquire(file=trim(initfile), exist=exists)
1008+
if (.not. exists) then
1009+
call extcde (60, msg="required IC/restart file " // trim(initfile) // " does not exist")
1010+
end if
1011+
if (index(initfile, '.nc', back=.true.) == len_trim(initfile) - 2) then
1012+
! netCDF IC/restart file
1013+
call read_restart(trim(initfile), va=va, mapsta=mapsta, mapst2=mapst2)
1014+
else
1015+
! binary IC/restart file (backward-compatible fallback)
1016+
call w3iors('READ', nds(6), sig(nk), imod, filename=trim(initfile))
1017+
flcold = rstype <= 1 .or. rstype == 4
1018+
end if
1019+
end if
1020+
#else
9861021
if (restart_from_binary) then
9871022
fname = trim(user_restfname)//trim(user_timestring)
9881023
else
@@ -998,14 +1033,14 @@ SUBROUTINE W3INIT ( IMOD, IsMulti, FEXT, MDS, MTRACE, ODAT, FLGRD, FLGR2, FLGD,
9981033
else
9991034
if (runtype == 'continue') then
10001035
call extcde (60, msg="required restart file " // trim(fname) // " does not exist")
1001-
elseif (restart_from_binary) then
1036+
elseif (restart_from_binary) then
10021037
call extcde (60, msg="required restart file " // trim(fname) // " does not exist")
1003-
else
1038+
else
10041039
call read_restart('none')
1005-
! mapst2 is module variable defined in read of mod_def; maptst is from 2.b above
1006-
flcold = .true.
1007-
endif
1040+
flcold = .true.
1041+
endif
10081042
end if
1043+
#endif
10091044
else
10101045
#endif
10111046

model/src/w3iorsmd.F90

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -617,9 +617,20 @@ SUBROUTINE W3IORS ( INXOUT, NDSR, DUMFPI, IMOD, FLRSTRT , filename)
617617
CALL EXTCDE ( 10 )
618618
END IF
619619
IF ( VERTST .NE. VERINI ) THEN
620-
IF ( IAPROC .EQ. NAPERR ) &
621-
WRITE (NDSE,902) VERTST, VERINI
622-
CALL EXTCDE ( 11 )
620+
! Backward compatibility: the FULL-type restart record layout is
621+
! unchanged between version '2021-05-28' (CESM3 release / dev_unified)
622+
! and the current VERINI -- the only differences in W3IORS are the
623+
! version-string bump and a GOTO cleanup. A legacy-version restart can
624+
! therefore be read safely; accept it with a warning instead of
625+
! aborting, so hybrid/branch runs remain backward compatible.
626+
IF ( VERTST .EQ. '2021-05-28' ) THEN
627+
IF ( IAPROC .EQ. NAPERR ) &
628+
WRITE (NDSE,9021) VERTST, VERINI
629+
ELSE
630+
IF ( IAPROC .EQ. NAPERR ) &
631+
WRITE (NDSE,902) VERTST, VERINI
632+
CALL EXTCDE ( 11 )
633+
END IF
623634
END IF
624635
IF ( TNAME .NE. GNAME ) THEN
625636
IF ( IAPROC .EQ. NAPERR ) &
@@ -1640,6 +1651,10 @@ SUBROUTINE W3IORS ( INXOUT, NDSR, DUMFPI, IMOD, FLRSTRT , filename)
16401651
902 FORMAT (/' *** WAVEWATCH III ERROR IN W3IORS :'/ &
16411652
' ILLEGAL VERINI, READ : ',A/ &
16421653
' CHECK : ',A/)
1654+
9021 FORMAT (/' *** WAVEWATCH III WARNING IN W3IORS :'/ &
1655+
' READING LEGACY-VERSION RESTART, READ : ',A/ &
1656+
' CURRENT : ',A/ &
1657+
' RECORD LAYOUT IS COMPATIBLE; CONTINUING.'/)
16431658
903 FORMAT (/' *** WAVEWATCH III WARNING IN W3IORS :'/ &
16441659
' ILLEGAL GNAME, READ : ',A/ &
16451660
' CHECK : ',A/)

model/src/w3wavemd.F90

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,9 @@ SUBROUTINE W3WAVE ( IMOD, ODAT, TEND, STAMP, NO_OUT &
560560
use w3odatmd , only : histwr, rstwr
561561
#ifdef W3_PIO
562562
use wav_history_mod , only : write_history
563-
USE W3ODATMD, ONLY : FNMRST
563+
use wav_restart_mod , only : write_restart
564+
use w3timemd , only : set_user_timestring
565+
USE W3ODATMD, ONLY : FNMRST, user_restfname
564566
USE W3GDATMD, ONLY : MAPST2
565567
#endif
566568
use w3odatmd , only : use_historync, use_restartnc
@@ -693,6 +695,10 @@ SUBROUTINE W3WAVE ( IMOD, ODAT, TEND, STAMP, NO_OUT &
693695
logical, parameter :: w3_cesmcoupled_flag = .false.
694696
#endif
695697
integer :: memunit
698+
#ifdef W3_PIO
699+
character(len=512) :: rstfname ! netCDF restart filename
700+
character(len=16) :: rst_timestring ! YYYY-MM-DD-SSSSS
701+
#endif
696702
logical :: do_gridded_output
697703
logical :: do_point_output
698704
logical :: do_track_output
@@ -2744,8 +2750,17 @@ SUBROUTINE W3WAVE ( IMOD, ODAT, TEND, STAMP, NO_OUT &
27442750
CALL W3IOTR ( NDS(11), NDS(12), VA, IMOD )
27452751

27462752
ELSE IF ( do_restart_output ) THEN
2747-
CALL W3IORS ('HOT', NDS(6), XXX, IMOD, FLOUT(8) )
2748-
ITEST = RSTYPE
2753+
if (use_restartnc) then
2754+
#ifdef W3_PIO
2755+
! netCDF (PIO) restart: casename.ww3.r.YYYY-MM-DD-SSSSS.nc
2756+
call set_user_timestring(time, rst_timestring)
2757+
rstfname = trim(FNMRST)//trim(user_restfname)//trim(rst_timestring)//'.nc'
2758+
call write_restart(trim(rstfname), va, mapsta+8*mapst2)
2759+
#endif
2760+
else
2761+
CALL W3IORS ('HOT', NDS(6), XXX, IMOD, FLOUT(8) )
2762+
ITEST = RSTYPE
2763+
end if
27492764

27502765
ELSE IF ( do_wavefield_separation_output ) THEN
27512766
IF ( IAPROC .EQ. NAPBPT ) THEN

model/src/wav_comp_nuopc.F90

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,12 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
620620
user_histfname = trim(casename)//'.ww3.hi.'
621621
endif
622622

623-
! netcdf (PIO) is used for CESM gridded history output; restarts
624-
! remain binary, with the initial file read via initfile (see waveinit_cesm)
623+
! netcdf (PIO) is used for CESM gridded history output and restarts.
624+
! Initial and branch runs still read the binary initial-condition file
625+
! provided via initfile (see waveinit_cesm); continue runs read the
626+
! netcdf restart written by wav_restart_mod.
625627
use_historync = .true.
628+
use_restartnc = .true.
626629
else
627630
call NUOPC_CompAttributeGet(gcomp, name='use_restartnc', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc)
628631
if (ChkErr(rc,__LINE__,u_FILE_u)) return
@@ -680,16 +683,15 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
680683
! Wave model initialization
681684
!--------------------------------------------------------------------
682685

683-
time = time0
686+
! In CESM, wave model initialization (w3init) is deferred to
687+
! InitializeRealize: w3init reads the netCDF restart, which requires PIO,
688+
! and CESM PIO is only set up by the driver after the advertise phase
689+
! (PostChildrenAdvertise). For UFS, model init stays here in the advertise
690+
! phase, matching emc.
684691
#ifndef W3_CESMCOUPLED
692+
time = time0
685693
call waveinit_ufs(gcomp, stdout, ntrace, mpicomm, mds, rc)
686694
if (ChkErr(rc,__LINE__,u_FILE_u)) return
687-
#else
688-
call ESMF_ClockGet( clock, timeStep=timeStep, rc=rc)
689-
if (ChkErr(rc,__LINE__,u_FILE_u)) return
690-
call waveinit_cesm(gcomp, ntrace, mpicomm, mds, rc)
691-
if (ChkErr(rc,__LINE__,u_FILE_u)) return
692-
#endif
693695
!call mpi_barrier ( mpicomm, ierr )
694696
if ( root_task ) then
695697
inquire(unit=stdout, name=logfile)
@@ -712,6 +714,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
712714
if (use_historync) then
713715
call wav_history_init(stdout)
714716
end if
717+
#endif
715718

716719
call advertise_fields(importState, exportState, flds_scalar_name, rc)
717720
if (ChkErr(rc,__LINE__,u_FILE_u)) return
@@ -751,11 +754,15 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
751754

752755
use w3odatmd , only : naproc
753756
use w3gdatmd , only : mapsf
754-
use w3gdatmd , only : nx, ny, ungtype, gtype, nseal, nsea
757+
use w3gdatmd , only : nx, ny, ungtype, gtype, nseal, nsea, nk
755758
use w3wdatmd , only : time
756759
use w3parall , only : init_get_isea
757760
use wav_shr_mod , only : diagnose_mesh, write_meshdecomp, wav_loginit
758761
use wav_pio_mod , only : wav_pio_init
762+
#ifdef W3_CESMCOUPLED
763+
use wav_shel_inp , only : set_shel_io
764+
use wav_history_mod , only : wav_history_init
765+
#endif
759766
#ifdef W3_PDLIB
760767
use yowNodepool , only : ng
761768
#endif
@@ -789,6 +796,12 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
789796
integer(i4), pointer :: meshmask(:)
790797
integer :: iam
791798
integer :: localcomm
799+
#ifdef W3_CESMCOUPLED
800+
type(MPI_COMM) :: mpicomm
801+
integer :: mds(15)
802+
integer :: ntrace(2)
803+
character(CL) :: logfile
804+
#endif
792805
character(len=*), parameter :: subname = '(wav_comp_nuopc:InitializeRealize)'
793806
! -------------------------------------------------------------------
794807

@@ -814,6 +827,38 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc)
814827
call wav_pio_init(gcomp, localcomm, stdout, naproc, rc)
815828
if (ChkErr(rc,__LINE__,u_FILE_u)) return
816829
end if
830+
831+
!--------------------------------------------------------------------
832+
! Wave model initialization (deferred from InitializeAdvertise so that
833+
! PIO, set up by the driver after the advertise phase, is available to
834+
! read the netCDF restart in w3init)
835+
!--------------------------------------------------------------------
836+
837+
time = time0
838+
call set_shel_io(stdout, mds, ntrace)
839+
call ESMF_VMGet(vm, mpiCommunicator=mpicomm%mpi_val, rc=rc)
840+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
841+
call waveinit_cesm(gcomp, ntrace, mpicomm, mds, rc)
842+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
843+
844+
if ( root_task ) then
845+
inquire(unit=stdout, name=logfile)
846+
write(*,'(a)')'WW3 log written to '//trim(logfile)
847+
end if
848+
849+
if (wav_coupling_to_cice) then
850+
if (nwav_elev_spectrum .gt. nk) then
851+
call ESMF_LogWrite('nwav_elev_spectrum is greater than nk ', ESMF_LOGMSG_INFO)
852+
call ESMF_Finalize(endflag=ESMF_END_ABORT)
853+
end if
854+
end if
855+
856+
! Intialize the list of requested output variables for netCDF output.
857+
! This needs to occur after mod_def has been read in w3init since
858+
! some variables are available only if they are defined in the mod_def
859+
if (use_historync) then
860+
call wav_history_init(stdout)
861+
end if
817862
#endif
818863

819864
call ESMF_ClockGet( clock, startTime=startTime, rc=rc)

model/src/wav_history_mod.F90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ subroutine write_history ( timen )
522522

523523
call pio_closefile(pioid)
524524

525+
#ifndef W3_CESMCOUPLED
525526
! create indicator log file after NetCDF file is written
526527
if (iaproc == 1) then ! only root processor writes the log file
527528
! open the log file and write the complete message
@@ -530,6 +531,7 @@ subroutine write_history ( timen )
530531
call flush(log_unit)
531532
close(log_unit)
532533
end if
534+
#endif
533535

534536
end subroutine write_history
535537

0 commit comments

Comments
 (0)