The WW3 package is the git repo plus a binary data bundle. The repo has the Fortran and the regression-test configurations; the bundle has the bathymetry, forcing, and reference output the tests need. The bundle lives on NOAA's FTP, not in git.
git clone --branch develop https://github.com/NOAA-EMC/WW3.git ~/src/WW3
cd ~/src/WW3
./model/bin/ww3_from_ftp.sh # the other half. Slow. Required for most regtests.
export WW3=$PWDjust get does the clone for you (into
~/src/WW3; WW3_DATA=1 just get also fetches
the bundle). The repo also carries a fork of WW3 as the
WW3/ submodule, pinned to one revision. That is the tree
the Kokkos port in lessons 12–13 is written against.
Don't use the GitHub release tarball. The newest
tagged release is 6.07.1, from April 2019. Real work happens on
develop and main, and the wider community is
running v7.14.x. Clone a branch.
ww3_ounf and friends need
netcdf.mod. On Debian/Ubuntu:
libnetcdff-dev.bash scripts/00_prereqs.sh (just prereqs)
installs all of it on Debian/Ubuntu. The recommended route, though, is
the next section: every number in this course was produced inside one
pinned toolchain, and "it works on my machine" is exactly the disease a
benchmarking project cannot afford.
The compilers and libraries come from one locked nixpkgs revision,
via the picasso/labs/pratico flake (a sparse git submodule;
just submodule-init after a fresh clone). Three recipes
cover almost everything:
just ww3 # enter the toolchain-only shell (== nix develop ./picasso/labs/pratico#ww3)
just toolchain # print the exact pinned versions
just build [switch] # full rebuild of $WW3 with a switch file (default: switches/switch_lab_shrd)What the shell pins (v) (this is
just toolchain on the lab machine; see the root
README.md):
| Component | Pinned |
|---|---|
| gfortran | GNU Fortran (GCC) 15.3.0 |
| MPI | Open MPI 5.0.10 |
| NetCDF | netcdf-c 4.10.1, netcdf-fortran 4.4.6-development, HDF5 1.14.6 |
| METIS / ParMETIS | 5.2.1 / 4.0.3 (for PDLIB unstructured runs) |
| ecCodes | 2.48.0 (GRIB → netCDF, lesson 04) |
| CMake | 4.4.2 |
| Kokkos / GoogleTest | 5.2.0 / 1.18.0 (lessons 11–12; see
kokkos/README.md) |
just build is scripts/02_build_ww3.sh run
inside that shell: it deletes build/, configures with
-DSWITCH=<file> -DCMAKE_BUILD_TYPE=Release, and runs
make -j. It always starts from scratch, on purpose (see the
next section for why). A third argument selects Debug.
just rt builds with a regtest's own switch file
and runs the test (~30 s for ww3_tp1.1), which is the
fastest "is the toolchain sane" check there is.
The same shell carries Kokkos and GoogleTest, so
just kokkos-test serial-debug (lesson 11) builds against
exactly the compilers WW3 was built with. That is not a convenience;
when lesson 12 claims the C++ kernel reproduces the Fortran bit for
bit, the claim is only meaningful because both sides came out of
the same pinned gfortran and the same flags.
Before you build you pick a switch file: a
whitespace-separated list of CPP keys that selects the physics and the
parallelism at compile time. See ../switches/README.md for
the full group-by-group breakdown. Here is
switches/switch_lab_shrd, the lab default, one key at a
time:
| Key | Group | What you are choosing |
|---|---|---|
F90 |
language | Fortran 90 style and system calls. Always. |
NOGRB |
GRIB output | None. The alternatives need NCEP's GRIB libraries. |
NOPA |
coupling | No external coupler (NUOPC/OASIS off). |
LRB4 |
record length | 4-byte record-length units for the binary files
(mod_def.ww3, restart.ww3). Must match between
programs. |
NC4 |
netCDF | Legacy "enable netCDF-4 output" key. Inert in 7.14
(v): absent from model/src/cmake/switches.json
and model/bin/all_switches, and no W3_NC4
guard exists anywhere in model/src, so neither the CMake
nor the classic build does anything with it.
ww3_ounf/ww3_ounp are built whenever CMake
finds netCDF; netCDF-3 vs -4 is the FILE%NETCDF key (3 or
4) of ww3_ounf.nml (NCTYPE inside the
program). Kept in the lab switch files because it is harmless and turns
up in older switch files. |
SHRD |
parallelism | Shared memory, i.e. a serial binary. The alternative is
DIST MPI; OMPG OMPH add OpenMP on top. |
PR3 UQ |
propagation | Third-order ULTIMATE QUICKEST with the Garden Sprinkler correction. The standard choice. |
FLX0 |
air–sea flux | No separate flux routine: ST4 computes its own stress
in W3SPR4, so upstream pairs ST4 with
FLX0: switch_NCEP_st4,
switch_Ifremer2, switch_NCEP_glwu and all 83
regtest switch files containing ST4 (v). The
lab switch files used to carry FLX2 (Tolman & Chalikov
1996, w3flx2md.F90, the companion of ST2);
that pairing was replaced because w3srcemd.F90 calls
W3FLX2 under W3_FLX2 right after
W3SPR4, overwriting the stress ST4 had just
computed (v). FLX4 goes with
ST6. |
LN1 |
linear input | Cavaleri & Malanotte-Rizzoli seeding, so a spectrum can grow from calm. |
ST4 |
source terms | Ardhuin et al. 2010 input and dissipation. Lesson 07. |
STAB0 |
stability | No air–sea stability correction on the wind input. |
NL1 |
nonlinear | The Discrete Interaction Approximation: W3SNL1, the
first kernel this course ports (lesson 12). |
BT1 |
bottom friction | JONSWAP empirical. |
DB1 |
depth breaking | Battjes–Janssen. |
MLIM |
limiter | Miche-style shallow-water Hs limiter. |
TR0 BS0 |
triads, bottom scattering | Off. |
IC0 IS0 |
sea ice | No ice dissipation, no ice scattering. |
REF0 |
reflection | No shoreline reflection. |
XX0 |
extra source term | No user-defined/experimental term compiled in. |
WNT1 WNX1 |
wind interpolation | Linear in time, linear in space. |
RWND |
wind | Wind is taken relative to the current. |
CRT1 CRX1 |
current interpolation | Linear in time, linear in space. |
O0–O7, O14 |
output/log verbosity | Extra diagnostics in log.ww3 and stdout. Harmless;
O7 gives point-output details. |
Two things to internalise:
.F90 sources against these keys, so
changing the switch file requires a full rebuild: not
make, a full rm -rf build (which is what
just build does). "I turned on ST4 and nothing changed" is
nearly always a stale build directory.SHRD vs DIST MPI vs
OMPG OMPH, -O2 vs
-O3 -march=native), and each cell of that matrix either
reproduces the reference run bit for bit or it doesn't. Lesson 09 builds
that matrix and shows how WW3's own regression suite is used as the
gate.If you would rather not use just:
cd $WW3
rm -rf build && mkdir build && cd build
cmake .. -DSWITCH=/abs/path/to/ww3-gpu/switches/switch_lab_shrd
make -j$(nproc)
ls bin/-DSWITCH takes either a bare name resolved inside
$WW3/model/bin/, or an absolute path to your own file.
Useful variants:
cmake --build . --target ww3_shel # rebuild one program
cmake .. -DCMAKE_BUILD_TYPE=Debug -DSWITCH=… # bounds checking, backtraces
export NetCDF_ROOT=$(nf-config --prefix) # if CMake can't find NetCDFjust regtest ww3_tp2.2 # or: bash scripts/03_run_regtest.sh $WW3 ww3_tp2.2That script runs each program in turn and tees its stdout, rather
than hiding everything behind the run_test harness. Watch
what each one prints. ww3_grid in particular emits a long,
genuinely useful summary of the grid it built and every namelist it
read. Always keep it: ww3_grid | tee ww3_grid.out.
| Symptom | Cause |
|---|---|
Cannot open include file 'netcdf.inc' / undefined
netCDF symbols |
NetCDF Fortran bindings missing, or built with a different
compiler. .mod files are compiler-specific and not
interchangeable. |
ww3_ounf/ww3_ounp are not built at
all |
CMake did not find netCDF: the five netCDF programs are only added
when NetCDF_Fortran_FOUND is true
(model/src/CMakeLists.txt). Adding NC4 to the
switch file changes nothing (v). |
ww3_grid demands an obstruction file you don't
have |
FLAGTR in namelists.nml isn't 0. |
| Model runs, output is all zeros | Forcing never arrived. Check log.ww3: it prints a
per-timestep table showing which inputs updated. |
| Changed physics, nothing changed | Stale build/. rm -rf build, or
just build. |
| Changed the grid, downstream programs behave oddly | Stale mod_def.ww3. Rerun ww3_grid. |
error reading input file |
.inp vs .nml mismatch. |
nix develop complains the submodule is missing |
just submodule-init. |
Possible and worth doing as a CPU build, but you must rebuild HDF5
and NetCDF with nvfortran first: distro packages are
gfortran-built and their .mod files are unusable. ../gpu/build_netcdf_nvfortran.sh
sketches it and ../gpu/README.md explains the
sandbox around it. Lesson 10 uses the gpu/ directive
examples as the contrast that motivates Kokkos; the GPU port itself
(lessons 11–13) does not need nvfortran at all: it is C++
compiled with nvcc inside the pinned #cuda
shell.