Installation

Prerequisites

Compilers

Cocoa requires a C++20 compatible compiler. The minimum versions are dictated by Kokkos 5.0 (included with Trilinos 17), which sets stricter requirements than C++20 alone.

Table 1 Minimum Compiler Requirements

Compiler

Minimum Version

Notes

GCC

11.1.0

Recommended for CPU and as CUDA host compiler. The first release whose standard library parses floating-point numbers with std::from_chars; CMake rejects older versions.

Clang (CPU)

14.0.0

For CPU-only builds, with libstdc++ from GCC 11 or newer

Clang (CUDA host)

15.0.0

When used as nvcc host compiler

NVIDIA nvcc

12.2

Requires CUDA Toolkit 12.2+

Intel icpx (CPU)

2022.0.0

Intel oneAPI DPC++/C++ Compiler

Intel icpx (SYCL)

2024.2.1

For SYCL backend builds

ROCm (HIPCC)

6.2.0

For AMD GPU builds

NVIDIA HPC SDK (NVC++)

22.3

Alternative to nvcc for NVIDIA GPUs

Note

See the Kokkos Requirements documentation for the most up-to-date information.

Build System

  • CMake 3.23 or later

  • GNU Make or Ninja build system

Required Libraries

Install these before configuring:

  • Trilinos 17.0 or later (with Kokkos, KokkosKernels, Tpetra, Belos, Ifpack2, Zoltan2, Intrepid2 and Shards enabled)

  • NetCDF-C (4.9.3+ recommended; for mesh and output I/O)

  • HDF5 (development headers required; installed automatically as a NetCDF-C dependency)

Warning

NetCDF-C versions prior to 4.9.3 have a bug (#2674) that causes spurious HDF5 error messages on stderr when reading variables. Ubuntu 24.04 ships NetCDF-C 4.9.2; if using that distribution, build NetCDF-C 4.9.3+ from source.

  • ParMETIS (for mesh partitioning, required via Zoltan2 for MPI builds)

Note

Trilinos 17.0+ is required because it ships Kokkos 5.0+, whose APIs Cocoa depends on.

Automatically Fetched Dependencies

CMake configuration downloads and builds these through CPM:

  • yaml-cpp (configuration file parsing)

  • valijson (configuration schema validation)

  • CLI11 (command-line parsing)

  • spdlog (logging)

  • fmt (string formatting)

  • Catch2 (unit testing, with BUILD_TESTING)

  • Google Benchmark (with cocoa_ENABLE_BENCHMARKS)

Optional Dependencies

  • CUDA Toolkit (for NVIDIA GPUs; required by a Trilinos CUDA build)

  • ROCm (for AMD GPUs; required by a Trilinos HIP build)

  • MPI (for distributed runs, if Trilinos was built with MPI)

Building from Source

Clone the Repository

git clone https://github.com/zcobell/cocoa.git
cd cocoa

Configure with a Preset

CMakePresets.json at the repository root holds the configurations CI builds plus two developer ones. Presets locate Trilinos and NetCDF through the TRILINOS_DIR and NETCDF_DIR environment variables; export them once for your machine:

export TRILINOS_DIR=/path/to/trilinos/lib/cmake/Trilinos
export NETCDF_DIR=/path/to/netcdf-c

cmake --preset release
cmake --build --preset release
ctest --preset release

cmake --list-presets lists them; cmake --build --list-presets and ctest --list-presets do the same for the build and test presets of the same names.

Preset

Purpose

release

Optimized build, for running the model.

dev

Debug build with the unit tests. cocoa_BACKEND auto-selects, so a GPU box builds for its GPU. GRIB is off because it needs an ecCodes install.

dev-maintainer

Release build with cocoa_MAINTAINER_MODE, the integration tests and the benchmarks. Run it before pushing.

ci

What the serial CI job configures, GRIB included.

ci-cuda

The CUDA compile check. Its Trilinos_DIR names the CI image’s CUDA Trilinos install; pass -DTrilinos_DIR=... to point it elsewhere.

ci-tidy

Compile database for the clang-tidy gate; configures into build-tidy and is never built.

ci-coverage

The instrumented build behind the coverage job.

Every preset but ci-tidy configures into build/, so switching between them reconfigures that one tree rather than creating a second one. Pass -B to put a preset somewhere else.

A -D on the command line overrides the preset, so cmake --preset release -Dcocoa_ENABLE_GRIB=ON is enough for a one-off change. For a permanent one, put a CMakeUserPresets.json beside CMakePresets.json (it is untracked) and inherit:

{
  "version": 4,
  "configurePresets": [
    {
      "name": "my-release",
      "inherits": "release",
      "cacheVariables": {
        "Trilinos_DIR": "/home/me/trilinos/lib64/cmake/Trilinos",
        "NETCDF_DIR": "/home/me/spack/opt/spack/netcdf-c-4.9.3"
      }
    }
  ]
}

Configure with CMake

Every option below can also be passed without a preset. A basic build:

mkdir build && cd build
cmake .. \
    -DCMAKE_BUILD_TYPE=Release \
    -DNETCDF_DIR=/path/to/netcdf-c \
    -DTrilinos_DIR=/path/to/trilinos/lib/cmake/Trilinos

CMake Options

Option

Description

Default

NETCDF_DIR

Hint path for CMake’s FindNetCDF module. Point to the NetCDF-C installation prefix.

(auto-detected; required if not in system paths)

Trilinos_DIR

Path to the Trilinos CMake config directory (e.g., <prefix>/lib/cmake/Trilinos).

(auto-detected; required if not in system paths)

cocoa_BACKEND

Combined execution space and MPI configuration. Available options depend on the Trilinos build. Examples: CUDA+MPI, CUDA, HIP+MPI, OPENMP+MPI, OPENMP, SERIAL+MPI, SERIAL.

DEFAULT: picks a backend from the Trilinos build (prefers GPU over CPU, MPI over non-MPI, and Serial over OpenMP, so request OPENMP+MPI explicitly for threaded CPU runs)

CMAKE_BUILD_TYPE

Build type. Options: Release, Debug, RelWithDebInfo, MinSizeRel.

RelWithDebInfo (if not specified)

CMAKE_INSTALL_PREFIX

Installation directory for cmake --install.

/usr/local

BUILD_TESTING

Build the unit test suite (requires Catch2, fetched automatically).

ON when Cocoa is the top-level project, OFF when vendored

cocoa_MAINTAINER_MODE

Enable strict compiler warnings, sanitizers, cppcheck, and hardening. Must be requested explicitly; developer builds and CI pass it.

OFF

cocoa_CUDA_MEMORY_SPACE

CUDA memory space. CUDA for device memory, CUDAUVM for unified virtual memory. Only applies to CUDA backends.

CUDA

cocoa_USE_THRUST

Use thrust::copy_if for the wet/dry stream compaction on OpenMP and Serial backends (advanced). See Stream Compaction below. Requires a Thrust/CCCL installation. CUDA builds always use CUB and ignore this option.

OFF

cocoa_ENABLE_GRIB

Enable GRIB2 meteorological forcing (GFS, HRRR, …). Requires an installed ECMWF ecCodes (found via eccodes_DIR) built with the JPEG2000 (Jasper or OpenJPEG) and CCSDS/AEC codecs that NCEP products use; cocoa checks for those features at configure time. See Meteorological Forcing.

OFF

eccodes_DIR

Path to the ecCodes CMake config directory (e.g., <prefix>/lib/cmake/eccodes). Required with cocoa_ENABLE_GRIB=ON if ecCodes is not in the default search paths. Install a suitable build with, e.g., spack install eccodes +memfs +aec jp2k=openjpeg.

(auto-detected)

cocoa_PRINT_LOG_TIME

Prefix each screen log line with the wall-clock date and time.

OFF

cocoa_ENABLE_INTEGRATION_TESTS

Add the end-to-end integration tests to ctest. Each test runs in its own copy of its fixture directory, so the suite runs in parallel (ctest -j). Needs Python 3 with numpy, xarray and netCDF4.

OFF

cocoa_ENABLE_BENCHMARKS

Build the benchmark executables (fetches Google Benchmark).

OFF

cocoa_LINK_JOBS

Maximum concurrent link steps under Ninja; bounds peak memory when many test binaries link at once. The CI presets set it to 1.

(empty: no limit)

Floating-Point Precision

Cocoa computes in double precision (FP64). There is no build-time precision option: to reduce GPU memory traffic, a fixed set of bandwidth-sensitive fields is stored as float and promoted to double on read, while all arithmetic stays in double. See Numerical Methods for the list of mixed-precision fields and the rationale.

Stream Compaction

Each step, the wet/dry solver rebuilds compacted lists of the currently wet elements and nodes, a stream compaction (copy_if over an index range). The backend picks the implementation:

  • CUDA: cub::DeviceSelect::If on the Kokkos execution-space stream, with the algorithm’s temporary storage allocated once at setup and reused every step (no per-step cudaMalloc/cudaFree). CUB ships with the CUDA Toolkit, so no extra setup is needed.

  • OpenMP or Serial with cocoa_USE_THRUST=ON: thrust::copy_if through the matching thrust host device system.

  • Otherwise: a fused Kokkos parallel_scan.

All implementations use the same selection predicate and produce identical results.

Enabling cocoa_USE_THRUST requires a Thrust installation, typically via NVIDIA CCCL, with CMake pointed at it:

cmake .. \
    -Dcocoa_BACKEND=OPENMP+MPI \
    -Dcocoa_USE_THRUST=ON \
    -DCCCL_DIR=/path/to/cccl/lib/cmake/cccl
    # or, for a standalone Thrust:
    # -DThrust_DIR=/path/to/thrust/lib/cmake/thrust

If cocoa_USE_THRUST=ON is requested but no Thrust/CCCL installation is found, or the backend is neither OpenMP nor Serial (and not CUDA, where the option is ignored), configuration fails with an explanatory error.

Compile

cmake --build --preset release    # or, from the build directory, make -j$(nproc)

Install

cmake --install build

Python Tools

Mesh conversion, baroclinic forcing preparation and plotting use the cocoa-tools Python package (Python 3.10 or newer), which installs the cocoa-mesh-tools, cocoa-ocean3d and cocoa-plot commands and their dependencies:

pip install utils/cocoa_tools

Use the package from the same release or checkout as the model. See Cocoa Tools (Python).

Verifying the Installation

Run the test suite:

ctest --preset release        # or, from the build directory, ctest --output-on-failure

The test presets exclude the validation label, which covers the channel studies that compare against analytic solutions rather than committed references. Run those with ctest -L validation.