Changelog

All notable changes to Cocoa will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[0.4.0] - 2026-08-15

Added

  • Baroclinic coupling. Nodal baroclinic pressure gradient forcing with the elemental free-surface correction (Crank-Nicolson centered, ramped), internal-tide wave drag computed from a de-tided velocity (Nycander, Lyard and scalar formulations, with the de-tiding window carried across restarts), and momentum dispersion as an additive friction contribution in mixed_layer_ratio and dispersion_cd modes. Configured under forcing.baroclinic; the friction tensor closes with a positive-semidefinite eigenvalue clamp. bpg_effective_x/y are available as inspection output.

  • cocoa_ocean3d, an installable Python preprocessor that turns HYCOM GOFS 3.1 fields into the nodal baroclinic forcing file: TEOS-10 density, column-integrated pressure gradient, mixed-layer and dispersion products, mesh regridding, and download.

  • Sea-ice concentration as a first-class meteorological field: CF NetCDF and GRIB ingestion, composition across multi-domain sources, and attenuation of the wind drag coefficient via the Lupkes (2012) parameterization.

  • Elevation slope limiter (numeric.elemental_slope_limiter), an optional post-GWCE pass that replaces zeta at nodes whose surrounding elemental elevation gradient exceeds a per-node threshold with the area-weighted average of the node’s element patch.

  • GAHM2026 conformance for weak and degenerate tracks: ambient pressure from the ATCF RADP column, a clamped Holland B, minimum-strength gates, neighbor fill for unreported quadrant radii instead of fabricated ones, and snapshots with missing scalars skipped with a warning rather than aborting the run. Preprocessed fort.22 input (aswip NWS=19/20) is now rejected.

  • Configurable output compression (output.compression level and shuffle); the default is deflate level 1 without shuffle, chosen by measurement.

  • utils/plot_cocoa.py, a single plotter for output, peak and mesh files that discovers the mesh and the plottable variables from the file’s UGRID/CF attributes. Handles global and regional meshes, vector pairs, and frame series or movies; shipped in the containers.

  • Nightly and release container publication for the CPU, CUDA and ROCm families.

Changed

  • Output field variables are written as single precision. Coordinates, bathymetry, the time axis and checkpoints are unchanged.

  • simulation.start_time is optional when checkpoint.restart_file is set; the cold-start clock is recovered from the checkpoint, and a configured value that disagrees with it is rejected rather than silently re-anchoring every forcing ramp.

  • Checkpoint format version 4: baroclinic Crank-Nicolson levels and the de-tiding window are persisted, so a restart resumes them mid-window rather than rebuilding them. Version 3 checkpoints are refused.

  • Checkpoint restart compares mesh identity per section. Node positions, connectivity and boundaries must match; bathymetry, nodal attributes and self-attraction/loading may change between segments.

  • Profiling regions are nested rather than spelling the hierarchy in labels, and the per-step time-level advance, field extrema and checkpoint write are timed for the first time.

  • Run progress and the time-to-completion estimate are reported against the work this run performs, so a restart no longer starts at the resumed percentage.

  • Error and critical messages print from every MPI rank, prefixed with the rank id; lower levels stay rank-0-only.

Fixed

  • On rotated-pole meshes, wind stress and the baroclinic pressure gradient are rotated into the computational frame, and the spherical metric term in momentum is evaluated from the rotated coordinates. Previously geographic vectors reached the equations untransformed.

  • MPI runs wrote solver-frame velocity to output; velocity rotation to the geographic frame now applies in serial and distributed runs alike.

  • Flux boundary state is checkpointed in the mesh’s global ordering, so a checkpoint no longer depends on rank count. Truncated files written by earlier versions are refused.

  • The internal_tide_friction nodal attribute’s column count is validated at load, repairing an out-of-bounds read of a single-column attribute.

  • The JSONL step log is written by one writer, one record per step.

  • Non-binary canopy values are resolved during fort.13 conversion.

Performance

  • Output staging is device-resident, packed on device and copied back on a dedicated execution-space instance so the transfer overlaps compute. With single-precision storage, the cost of 2-minute output on a 1.57M-node hurricane case (V100, one simulated day) falls from roughly 26% to 3.3% of runtime, and the file halves in size.

[0.3.1] - 2026-07-27

A maintenance release; no new model capability.

Changed

  • -i (now also spelled --input) is required and must name an existing file; the implicit cocoa_config.yaml default is gone. --partition gains the short spelling -p.

Fixed

  • Registering more extrema fields than the maximum truncated silently, and a sources/configs size mismatch indexed out of range. Both now throw at the boundary, naming the actual and allowed counts.

  • cocoa_mesh_tools.py runs in a container with no username populated.

[0.3.0] - 2026-07-20

Added

  • GAHM parametric hurricane vortex forcing (cocoa_vortex), with ATCF b-deck parsing and missing-central-pressure estimation.

  • GRIB2 meteorological forcing via ecCodes (cocoa_ENABLE_GRIB).

  • Multi-source meteorological composition: self-contained domains: entries, per-source wind reduction, and per-source activation ramps.

  • Configuration schema validation on valijson (JSON Schema draft-07), with the schema embedded in the binary and reproduced in the user guide.

  • External YAML inclusion at designated configuration nodes.

  • Checkpoint format version 3: peaks are preserved across a restart, mesh identity is verified before restoring, and the end-of-run checkpoint is gated on solution stability.

  • Google Benchmark suite with scaling analysis, compile-gated in CI.

  • New dependencies: valijson and CLI11 (CPM-fetched); ecCodes (optional, GRIB builds only).

Changed

  • Asynchronous I/O is now always on. Output is delivered on a background writer thread and meteorological input is pre-read ahead of need, overlapping file access with computation in every run. MPI is initialized with MPI_THREAD_FUNNELED to support this; a run aborts at startup if the MPI build cannot provide it.

  • Command-line parsing moved to CLI11: --option=value spellings now work, malformed values fail loudly, and --help/--version follow standard Unix formatting.

  • Boolean configuration values must be true/false; the YAML 1.1 spellings are rejected.

  • CF NetCDF pressure units are read from the file and required.

Performance

  • Explicit solver per-step host stalls eliminated, worth roughly 13-15% throughput on a 1.57M-node hurricane case with meteorology; momentum nodal assembly reduced from three sweeps to one; wet/dry list compaction with no per-step device allocation; cached MPI ghost staging and device-direct boundary forcing scatter.

Removed

  • The --asyncio command-line flag and its modes. Asynchronous output is now unconditional, so there is no mode to select. The dedicated-MPI-I/O-rank mode (--asyncio=mpi) has been removed; all ranks now participate in computation.

Fixed

  • MPI runs fail fast on rank-local errors instead of hanging peers until walltime.

  • Land-boundary normals at multi-string junction nodes average the per-string normals (a documented deviation from ADCIRC’s last-wins).

  • Binary-inexact time steps (e.g. 0.1 s) no longer drop the final step.

[0.2.0b0] - 2026-06-29

Added

  • Full OWI NWS13 support, with Lagrangian moving-vortex interpolation for moving grids.

  • Grouped mesh NetCDF format carrying boundaries, nodal attributes and self-attraction/loading in one file, identified by a BLAKE2 content fingerprint (mesh_id) that is stamped onto model output. The mesh tooling is consolidated into utils/cocoa_mesh_tools.py.

  • Checkpoint format version 2: timestamped single files, written at the end of a run by default, with a warning when a run would accumulate many of them.

Changed

  • “Hot start” is now “checkpoint” throughout the configuration and docs.

  • Container images moved to the cocoaorg Docker Hub namespace.

Removed

  • The A/B checkpoint file pair and the FNV-1a mesh topology checksum, superseded by timestamped checkpoints and mesh_id.

Fixed

  • OWI uniform-grid detection is de-biased with average spacing, so a grid that is regular within round-off is no longer misread as irregular.

  • Kokkos and KokkosKernels are found as standalone packages, and the diagnostics-color flag is selected per language, fixing the ROCm build.

  • Multi-value nodal attributes get their secondary dimension when a mesh is converted to the grouped format.

Performance

  • The static OWI grid is cached rather than reparsed, regular moving grids are read by corners, and the continuity diagonal solve is fused into one kernel.

Migration Guide

Migrating from ADCIRC

Converting Mesh Files

Cocoa uses NetCDF format for mesh files instead of ADCIRC’s fort.14/fort.13 format. A conversion script is provided in the utils directory:

python utils/cocoa_mesh_tools.py from_adcirc \
    --mesh fort.14 \
    --attributes fort.13 \
    --output mesh.nc

Arguments:

  • --mesh: ADCIRC mesh file (fort.14) - required

  • --attributes: ADCIRC nodal attributes file (fort.13) - optional

  • --output: Output NetCDF file path - required

Configuration Files

Cocoa uses YAML configuration files instead of ADCIRC’s fort.15 format. Key differences:

ADCIRC Parameter

Cocoa Equivalent

DT

simulation.time_step

TAU0

physics.tau0

STATIM

simulation.start_time

RNDAY

simulation.end_time

Note

In ADCIRC, a negative TAU0 value triggers spatially-varying computation. In Cocoa, tau0 must always be a positive constant value.

Example conversion:

ADCIRC fort.15:

DT = 2.0
TAU0 = 0.005
RNDAY = 1.0

Cocoa YAML:

simulation:
  time_step: 2s
  start_time: 2025-01-01
  end_time: 2025-01-02

physics:
  tau0: 0.005