From d9689af631c74a671c0397445149f0aeb09136bf Mon Sep 17 00:00:00 2001 From: alperaltuntas Date: Wed, 21 Jan 2026 22:07:12 -0700 Subject: [PATCH 1/5] bump up core WW3 --- .gitmodules | 2 +- WW3 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 1ee425d..f885443 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "WW3"] path = WW3 url = https://github.com/ESCOMP/WW3.git -fxtag = dev/unified_0.0.14 +fxtag = dev/unified_0.0.15 fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/WW3.git diff --git a/WW3 b/WW3 index 32b667d..9ea1d89 160000 --- a/WW3 +++ b/WW3 @@ -1 +1 @@ -Subproject commit 32b667de558e7c928f1e6a7baf71e5b5436d178b +Subproject commit 9ea1d89550db30dd2eb22cb1018f16506941be74 From 7b20d7fde18334e4bc3ffb3581fe7c1ff916da01 Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Tue, 12 May 2026 14:38:24 -0600 Subject: [PATCH 2/5] Fix ww3 grid input staging and mod_def generation for wgx3v7 buildnml: Guard against a missing/empty WW3_GRID_INP_DIR, and warn (instead of crashing) when ww3_grid.inp or the ww3_grid executable aren't present yet before attempting mod_def generation. namelist_definition_ww3.xml: Add six individual grid input file entries (g37_mapsta.inp, g37_bottom.inp, g37_y.inp, g37_x.inp, ww3_grid.inp, ww3_strt.inp) for the wgx3v7 grid so check_input_data can download them automatically. --- cime_config/buildnml | 17 +++--- cime_config/namelist_definition_ww3.xml | 72 +++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/cime_config/buildnml b/cime_config/buildnml index 680ea17..efe6a2d 100755 --- a/cime_config/buildnml +++ b/cime_config/buildnml @@ -208,19 +208,22 @@ def _prestage_inputs(case): # Copy ww3_inp and other needed info to ww3_moddef_create directory input_dir = case.get_value("WW3_GRID_INP_DIR") - files = os.listdir(input_dir) - for filename in files: - if not os.path.isfile(os.path.join(output_dir, filename)): - safe_copy(os.path.join(input_dir, filename), os.path.join(output_dir, filename)) + if os.path.isdir(input_dir): + files = os.listdir(input_dir) + for filename in files: + if not os.path.isfile(os.path.join(output_dir, filename)): + safe_copy(os.path.join(input_dir, filename), os.path.join(output_dir, filename)) # Create mod_def file using ww3_grid and the grid_input files - if os.path.isfile(os.path.join(output_dir,"ww3_grid")): + if not os.path.isfile(os.path.join(output_dir,"ww3_grid")): + logger.warning("ww3_grid file not found. The mod_def.ww3 file will be created after the build phase.") + elif not os.path.isfile(os.path.join(output_dir,"ww3_grid.inp")): + logger.warning("ww3_grid.inp file not found. The file will automatically be downloaded at the ./case.submit phase.") + else: run_cmd("./ww3_grid > mod_def.ww3.log", from_dir=output_dir) if not os.path.isfile(os.path.join(output_dir,"mod_def.ww3")): raise RuntimeError("mod_def.ww3 was not created, check mod_def.ww3.log for errors.") shutil.move(os.path.join(output_dir,"mod_def.ww3"), os.path.join(rundir, "mod_def.ww3")) - else: - logger.warning("ww3_grid file not found. The mod_def.ww3 file will be created after the build phase.") else: # Use mod_def already created diff --git a/cime_config/namelist_definition_ww3.xml b/cime_config/namelist_definition_ww3.xml index a4abb5c..b404457 100644 --- a/cime_config/namelist_definition_ww3.xml +++ b/cime_config/namelist_definition_ww3.xml @@ -80,6 +80,78 @@ + + char + prestage_only + prestage_only + abs + + UNSET + $WW3_GRID_INP_DIR/g37_mapsta.inp + + Grid mask file; listed so check_input_data can download it. + + + + char + prestage_only + prestage_only + abs + + UNSET + $WW3_GRID_INP_DIR/g37_bottom.inp + + Grid bottom depth file; listed so check_input_data can download it. + + + + char + prestage_only + prestage_only + abs + + UNSET + $WW3_GRID_INP_DIR/g37_y.inp + + Grid y-coordinate file; listed so check_input_data can download it. + + + + char + prestage_only + prestage_only + abs + + UNSET + $WW3_GRID_INP_DIR/g37_x.inp + + Grid x-coordinate file; listed so check_input_data can download it. + + + + char + prestage_only + prestage_only + abs + + UNSET + $WW3_GRID_INP_DIR/ww3_grid.inp + + Grid input file; listed so check_input_data can download it. + + + + char + prestage_only + prestage_only + abs + + UNSET + $WW3_GRID_INP_DIR/ww3_strt.inp + + Grid strt file; listed so check_input_data can download it. + + real ww3_inparm From e1b86fc00103400c9eaf8008be030f9e29bb5d90 Mon Sep 17 00:00:00 2001 From: alperaltuntas Date: Tue, 2 Jun 2026 10:34:51 -0600 Subject: [PATCH 3/5] Auto-generate WW3 initial conditions and add IOSTYP control Generate the calm-start initial condition file at build time via the ww3_strt tool instead of pre-staging per-grid restart files. buildnml now copies the ww3_strt executable alongside ww3_grid, runs it to produce restart.ww3, and stages it to rundir as calm_strt.ww3. The initfile namelist default points to calm_strt.ww3 for auto-generated grids; supplying a custom WW3_MODDEF now requires an explicit initfile. Also: - Add domain_percent_iostyp (DOMAIN%IOSTYP) namelist entry, default 1 - Add grid input files (mapsta/bottom/x/y/grid/strt) for ww3a and wtx2_3v2 grids - Bump grid_inp data for wgx3v7 to .260527. This is to update IC4METHOD from 8 to 10. - Updates in tests. --- cime_config/buildnml | 37 ++++++++++++++++++---- cime_config/config_component.xml | 2 +- cime_config/namelist_definition_ww3.xml | 41 +++++++++++++++++++------ cime_config/testdefs/testlist_ww3.xml | 14 +++++++-- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/cime_config/buildnml b/cime_config/buildnml index efe6a2d..f24accd 100755 --- a/cime_config/buildnml +++ b/cime_config/buildnml @@ -36,6 +36,7 @@ def _create_namelists(case, confdir, namelist_infile, nmlgen, data_list_path): run_type = case.get_value("RUN_TYPE") config["runtype"] = run_type config["wav_grid"] = case.get_value("WAV_GRID") + config["ww3_moddef"] = case.get_value("WW3_MODDEF") rundir = case.get_value("RUNDIR") start_date = case.get_value("RUN_STARTDATE") @@ -63,6 +64,15 @@ def _create_namelists(case, confdir, namelist_infile, nmlgen, data_list_path): filename = "%s.ww3.r.%s-%s" %(run_refcase, run_refdate, run_tod) nmlgen.add_default("initfile", value=filename, ignore_abs_path=True) else: + user_initfile = nmlgen.get_value("initfile") + if (case.get_value("WW3_MODDEF") != 'unset' + and not (user_initfile and user_initfile.strip().strip("'\"").strip())): + expect(False, + "WW3_MODDEF is set to a user-supplied mod_def file, but no " + "initfile was provided. When you supply your own WW3_MODDEF, " + "you must also supply initfile via user_nl_ww3 (e.g., " + "initfile = '/path/to/restart.ww3'). Alternatively, unset " + "WW3_MODDEF to use the auto-generated calm_strt.ww3.") nmlgen.add_default("initfile") # error check @@ -190,15 +200,19 @@ def _prestage_inputs(case): rundir = case.get_value("RUNDIR") # Create rundir/ww3_moddef_create - filename = "ww3_grid" bldroot = os.path.join(case.get_value("EXEROOT"),"wav","obj") - item = os.path.join(bldroot, filename) - if os.path.isfile(item): + bld_ww3_grid = os.path.join(bldroot, "ww3_grid") # executable to create mod_def.ww3 file + if os.path.isfile(bld_ww3_grid): + bld_ww3_strt = os.path.join(bldroot, "ww3_strt") # executable to create ww3 i.c. file + if not os.path.isfile(bld_ww3_strt): + raise RuntimeError("ww3_strt executable not found in {} while ww3_grid is available".format(bldroot)) ww3_moddef_dir = os.path.join(rundir, "ww3_moddef_create") if not os.path.exists(ww3_moddef_dir): os.makedirs(ww3_moddef_dir) - if not os.path.exists(os.path.join(ww3_moddef_dir,filename)): - safe_copy(item, ww3_moddef_dir) + if not os.path.exists(os.path.join(ww3_moddef_dir, "ww3_grid")): + safe_copy(bld_ww3_grid, ww3_moddef_dir) + if not os.path.exists(os.path.join(ww3_moddef_dir, "ww3_strt")): + safe_copy(bld_ww3_strt, ww3_moddef_dir) if case.get_value("WW3_MODDEF") == 'unset': # Create output dir ww3_moddef_create if appropriate @@ -220,11 +234,22 @@ def _prestage_inputs(case): elif not os.path.isfile(os.path.join(output_dir,"ww3_grid.inp")): logger.warning("ww3_grid.inp file not found. The file will automatically be downloaded at the ./case.submit phase.") else: + # Generate mod_def.ww3 file using ww3_grid executable and the grid_input files run_cmd("./ww3_grid > mod_def.ww3.log", from_dir=output_dir) if not os.path.isfile(os.path.join(output_dir,"mod_def.ww3")): raise RuntimeError("mod_def.ww3 was not created, check mod_def.ww3.log for errors.") + # Generate ww3_strt.ww3 file using ww3_strt executable and the grid_input files + if not os.path.isfile(os.path.join(output_dir,"ww3_strt")): + raise RuntimeError("ww3_strt file not found.") + if not os.path.isfile(os.path.join(output_dir,"ww3_strt.inp")): + raise RuntimeError("ww3_strt.inp file not found.") + run_cmd("./ww3_strt > ww3_strt.ww3.log", from_dir=output_dir) + if not os.path.isfile(os.path.join(output_dir,"restart.ww3")): + raise RuntimeError("restart.ww3 was not created, check ww3_strt.ww3.log for errors.") + # Copy mod_def.ww3 and ww3_strt.ww3 files to rundir shutil.move(os.path.join(output_dir,"mod_def.ww3"), os.path.join(rundir, "mod_def.ww3")) - + shutil.move(os.path.join(output_dir,"restart.ww3"), os.path.join(rundir, "calm_strt.ww3")) + else: # Use mod_def already created mod_def_in = case.get_value("WW3_MODDEF") diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml index ba99e3c..2019866 100644 --- a/cime_config/config_component.xml +++ b/cime_config/config_component.xml @@ -55,7 +55,7 @@ $DIN_LOC_ROOT/wav/ww3/grid_inp.${WAV_GRID} $DIN_LOC_ROOT/wav/ww3/grid_inp.${WAV_GRID}.231018 - $DIN_LOC_ROOT/wav/ww3/grid_inp.${WAV_GRID}.250428 + $DIN_LOC_ROOT/wav/ww3/grid_inp.${WAV_GRID}.260527 $DIN_LOC_ROOT/wav/ww3/grid_inp.${WAV_GRID}.240722 case_comp diff --git a/cime_config/namelist_definition_ww3.xml b/cime_config/namelist_definition_ww3.xml index b404457..3a9cfac 100644 --- a/cime_config/namelist_definition_ww3.xml +++ b/cime_config/namelist_definition_ww3.xml @@ -35,16 +35,12 @@ "" "" - $DIN_LOC_ROOT/wav/ww3/ww3a.restart.ww3.calm.wwver7.14.220119 - $DIN_LOC_ROOT/wav/ww3/ww3a.restart.ww3.calm.wwver7.14.220119 - $DIN_LOC_ROOT/wav/ww3/wgx3v7.restart.ww3.calm.240722 - $DIN_LOC_ROOT/wav/ww3/wgx3v7.restart.ww3.calm.240722 - $DIN_LOC_ROOT/wav/ww3/wt232.restart.ww3.calm.240722 - $DIN_LOC_ROOT/wav/ww3/wt232.restart.ww3.calm.240722 - ' ' - ' ' - $DIN_LOC_ROOT/wav/ww3/wtnx1v4.restart.ww3.230308 - $DIN_LOC_ROOT/wav/ww3/wtnx1v4.restart.ww3.230308 + "calm_strt.ww3" + "calm_strt.ww3" + ' ' + ' ' + $DIN_LOC_ROOT/wav/ww3/wtnx1v4.restart.ww3.230308 + $DIN_LOC_ROOT/wav/ww3/wtnx1v4.restart.ww3.230308 Initial condition file. @@ -87,7 +83,9 @@ abs UNSET + $WW3_GRID_INP_DIR/ww3a_mapsta.inp $WW3_GRID_INP_DIR/g37_mapsta.inp + $WW3_GRID_INP_DIR/t232_mapsta.inp Grid mask file; listed so check_input_data can download it. @@ -99,7 +97,9 @@ abs UNSET + $WW3_GRID_INP_DIR/ww3a_bottom.inp $WW3_GRID_INP_DIR/g37_bottom.inp + $WW3_GRID_INP_DIR/t232_bottom.inp Grid bottom depth file; listed so check_input_data can download it. @@ -112,6 +112,7 @@ UNSET $WW3_GRID_INP_DIR/g37_y.inp + $WW3_GRID_INP_DIR/t232_y.inp Grid y-coordinate file; listed so check_input_data can download it. @@ -124,6 +125,7 @@ UNSET $WW3_GRID_INP_DIR/g37_x.inp + $WW3_GRID_INP_DIR/t232_x.inp Grid x-coordinate file; listed so check_input_data can download it. @@ -135,7 +137,9 @@ abs UNSET + $WW3_GRID_INP_DIR/ww3_grid.inp $WW3_GRID_INP_DIR/ww3_grid.inp + $WW3_GRID_INP_DIR/ww3_grid.inp Grid input file; listed so check_input_data can download it. @@ -147,7 +151,9 @@ abs UNSET + $WW3_GRID_INP_DIR/ww3_strt.inp $WW3_GRID_INP_DIR/ww3_strt.inp + $WW3_GRID_INP_DIR/ww3_strt.inp Grid strt file; listed so check_input_data can download it. @@ -229,6 +235,21 @@ + + integer + domain_nml + setup + + WW3 restart/output I/O type. 0 = no dedicated output process, each process + writes its own data (requires a parallel file system); 1 = no dedicated + output process, gather to a single writer (any file system); 2 = single + dedicated output process; 3 = multiple dedicated output processes. + + + 1 + + + char input_nml diff --git a/cime_config/testdefs/testlist_ww3.xml b/cime_config/testdefs/testlist_ww3.xml index aa9fdec..95bdbb1 100644 --- a/cime_config/testdefs/testlist_ww3.xml +++ b/cime_config/testdefs/testlist_ww3.xml @@ -1,6 +1,6 @@ - + @@ -21,10 +21,18 @@ - + + + + + + + + + - + From 5884734696d7397000200a95f0de1840c7b23b7b Mon Sep 17 00:00:00 2001 From: alperaltuntas Date: Thu, 18 Jun 2026 14:26:59 -0600 Subject: [PATCH 4/5] ww3: in-core calm initial conditions; netCDF restart naming in buildnml buildnml: initial (and hybrid) runs default to an empty initfile so WW3 starts from in-core calm conditions; the binary calm_strt.ww3 and its ww3_strt generation are dropped (mod_def.ww3 generation is kept). Branch runs resolve initfile to the netCDF reference restart (.nc), falling back to the binary restart when that is what the reference case wrote. Update WW3 submodule to ff387d68 (netCDF restarts with binary fallback; in-core calm initial conditions). Co-Authored-By: Claude Opus 4.8 (1M context) --- WW3 | 2 +- cime_config/buildnml | 44 +++++++++++++++++++------------------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/WW3 b/WW3 index 9ea1d89..ff387d6 160000 --- a/WW3 +++ b/WW3 @@ -1 +1 @@ -Subproject commit 9ea1d89550db30dd2eb22cb1018f16506941be74 +Subproject commit ff387d68e1d2159f050e525f0e85aa33348a9397 diff --git a/cime_config/buildnml b/cime_config/buildnml index f24accd..b9cf573 100755 --- a/cime_config/buildnml +++ b/cime_config/buildnml @@ -61,19 +61,25 @@ def _create_namelists(case, confdir, namelist_infile, nmlgen, data_list_path): run_refcase = case.get_value("RUN_REFCASE") run_refdate = case.get_value("RUN_REFDATE") run_tod = case.get_value("RUN_REFTOD") - filename = "%s.ww3.r.%s-%s" %(run_refcase, run_refdate, run_tod) + base = "%s.ww3.r.%s-%s" %(run_refcase, run_refdate, run_tod) + # WW3 writes netCDF restarts by default, so prefer the netCDF reference + # restart. Fall back to a binary restart (backward compatibility) when + # that is what the reference case wrote. + if (os.path.isfile(os.path.join(rundir, base)) + and not os.path.isfile(os.path.join(rundir, base + ".nc"))): + filename = base # binary reference restart (fallback) + else: + filename = base + ".nc" # netCDF reference restart (default) nmlgen.add_default("initfile", value=filename, ignore_abs_path=True) else: + # Initial (and hybrid) runs: an explicit initfile may be supplied via + # user_nl_ww3 (netCDF or binary). With no initfile, WW3 starts from + # in-core calm conditions -- no binary initial-condition file is needed. user_initfile = nmlgen.get_value("initfile") - if (case.get_value("WW3_MODDEF") != 'unset' - and not (user_initfile and user_initfile.strip().strip("'\"").strip())): - expect(False, - "WW3_MODDEF is set to a user-supplied mod_def file, but no " - "initfile was provided. When you supply your own WW3_MODDEF, " - "you must also supply initfile via user_nl_ww3 (e.g., " - "initfile = '/path/to/restart.ww3'). Alternatively, unset " - "WW3_MODDEF to use the auto-generated calm_strt.ww3.") - nmlgen.add_default("initfile") + if user_initfile and user_initfile.strip().strip("'\"").strip(): + nmlgen.add_default("initfile") + else: + nmlgen.set_value("initfile", "") # error check dtcpl = basedt / int(ncpl) @@ -203,16 +209,11 @@ def _prestage_inputs(case): bldroot = os.path.join(case.get_value("EXEROOT"),"wav","obj") bld_ww3_grid = os.path.join(bldroot, "ww3_grid") # executable to create mod_def.ww3 file if os.path.isfile(bld_ww3_grid): - bld_ww3_strt = os.path.join(bldroot, "ww3_strt") # executable to create ww3 i.c. file - if not os.path.isfile(bld_ww3_strt): - raise RuntimeError("ww3_strt executable not found in {} while ww3_grid is available".format(bldroot)) ww3_moddef_dir = os.path.join(rundir, "ww3_moddef_create") if not os.path.exists(ww3_moddef_dir): os.makedirs(ww3_moddef_dir) if not os.path.exists(os.path.join(ww3_moddef_dir, "ww3_grid")): safe_copy(bld_ww3_grid, ww3_moddef_dir) - if not os.path.exists(os.path.join(ww3_moddef_dir, "ww3_strt")): - safe_copy(bld_ww3_strt, ww3_moddef_dir) if case.get_value("WW3_MODDEF") == 'unset': # Create output dir ww3_moddef_create if appropriate @@ -238,17 +239,10 @@ def _prestage_inputs(case): run_cmd("./ww3_grid > mod_def.ww3.log", from_dir=output_dir) if not os.path.isfile(os.path.join(output_dir,"mod_def.ww3")): raise RuntimeError("mod_def.ww3 was not created, check mod_def.ww3.log for errors.") - # Generate ww3_strt.ww3 file using ww3_strt executable and the grid_input files - if not os.path.isfile(os.path.join(output_dir,"ww3_strt")): - raise RuntimeError("ww3_strt file not found.") - if not os.path.isfile(os.path.join(output_dir,"ww3_strt.inp")): - raise RuntimeError("ww3_strt.inp file not found.") - run_cmd("./ww3_strt > ww3_strt.ww3.log", from_dir=output_dir) - if not os.path.isfile(os.path.join(output_dir,"restart.ww3")): - raise RuntimeError("restart.ww3 was not created, check ww3_strt.ww3.log for errors.") - # Copy mod_def.ww3 and ww3_strt.ww3 files to rundir + # Copy mod_def.ww3 to rundir. No binary initial-condition file is + # generated: WW3 initial runs start from in-core calm conditions + # (or a user-supplied initfile), and restarts are netCDF. shutil.move(os.path.join(output_dir,"mod_def.ww3"), os.path.join(rundir, "mod_def.ww3")) - shutil.move(os.path.join(output_dir,"restart.ww3"), os.path.join(rundir, "calm_strt.ww3")) else: # Use mod_def already created From 7108141b086cbb69244c55ebbf37f323618882df Mon Sep 17 00:00:00 2001 From: alperaltuntas Date: Thu, 18 Jun 2026 14:35:33 -0600 Subject: [PATCH 5/5] bump up WW3 --- .gitmodules | 2 +- WW3 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index f885443..710f790 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "WW3"] path = WW3 url = https://github.com/ESCOMP/WW3.git -fxtag = dev/unified_0.0.15 +fxtag = dev/unified_0.1.0 fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/WW3.git diff --git a/WW3 b/WW3 index ff387d6..cc6f1a3 160000 --- a/WW3 +++ b/WW3 @@ -1 +1 @@ -Subproject commit ff387d68e1d2159f050e525f0e85aa33348a9397 +Subproject commit cc6f1a35661d0285eb8c6f7c36dcfe4c9bf9505f