Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
build/
build*/
exe/
*.o
ww4_log.txt
ww4_local_config.cmake
verify_ww4.py
test_format
test_format.cpp
Expand All @@ -15,6 +14,3 @@ __pycache__/
*.py[cod]
*$py.class

# Externals
externals/*
!externals/README.md
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "externals/yaml-cpp"]
path = externals/yaml-cpp
url = https://github.com/jbeder/yaml-cpp.git
[submodule "externals/googletest"]
path = externals/googletest
url = https://github.com/google/googletest.git
156 changes: 75 additions & 81 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
#+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +
#
#@file CMakeLists.txt
#@brief CMake build configuration for WAVEWATCH IV (WW4) Utilities.
#@details This file defines the project structure, dependencies (GTest),
#and build targets for the WW4_Utils library and its tests.
#@brief CMake build configuration for WAVEWATCH IV (WW4).
#@details This file defines the project structure, dependencies (yaml-cpp, GTest),
#and build targets for the WW4 libraries, standalone application, and tests.
#
#@copyright © 2026 National Weather Service, National Oceanic and Atmospheric
#Administration. WAVEWATCH IV (TM) and WW4 (TM) are trademarks
Expand All @@ -14,13 +14,10 @@
#@author Main Author(s) : Aldgisl (AI Persona), Hendrik L. Tolman
#@author Contributors : Jules (Agentic AI), Kit Stokes, Jessica Meixner
#@date Initial : 2026-07-09
#@date Last update : 2026-07-13
#@date Last update : 2026-08-21

cmake_minimum_required(VERSION 3.25)

# Optional local configuration file generated by the setup tool.
include(${CMAKE_SOURCE_DIR}/ww4_local_config.cmake OPTIONAL)

project(WW4_Utils VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
Expand All @@ -30,9 +27,10 @@ set(CMAKE_CXX_EXTENSIONS OFF)
# Set default output directory for executables
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# Options for strict warnings and sanitizers
# Options for strict warnings, sanitizers, and testing
option(WW4_STRICT_WARNINGS "Enable strict compiler warnings and treat as errors" OFF)
option(WW4_USE_SANITIZERS "Enable address and undefined behavior sanitizers" OFF)
option(WW4_ENABLE_TESTING "Enable WAVEWATCH IV test suite" ON)

# Define common compile options for WW4 targets
set(WW4_COMMON_COMPILE_OPTIONS "")
Expand Down Expand Up @@ -61,43 +59,14 @@ else()
endif()
endif()

# Google Test
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
SYSTEM
)

# yaml-cpp for configuration parsing
FetchContent_Declare(
yaml-cpp
URL https://github.com/jbeder/yaml-cpp/archive/refs/tags/0.8.0.zip
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
SYSTEM
)

# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)

FetchContent_MakeAvailable(googletest yaml-cpp)

# Suppress warnings from GTest itself for Clang/IntelLLVM during compilation
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
set(GTEST_SUPPRESS_FLAGS -Wno-unknown-warning-option -Wno-character-conversion)
if(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
list(APPEND GTEST_SUPPRESS_FLAGS -diag-disable=10430)
endif()
foreach(target gtest gtest_main gmock gmock_main)
if(TARGET ${target})
target_compile_options(${target} INTERFACE ${GTEST_SUPPRESS_FLAGS})
target_compile_options(${target} PRIVATE ${GTEST_SUPPRESS_FLAGS})
endif()
endforeach()
if(EXISTS "${CMAKE_SOURCE_DIR}/externals/yaml-cpp/CMakeLists.txt")
add_subdirectory(externals/yaml-cpp EXCLUDE_FROM_ALL SYSTEM)
else()
message(FATAL_ERROR "yaml-cpp submodule not found in externals/yaml-cpp. Please run: git submodule update --init --recursive")
endif()

# Library
# Library: ww4_utils
add_library(
ww4_utils
src/ww4_utils/time_management.cpp
Expand All @@ -115,6 +84,7 @@ target_link_libraries(ww4_utils PRIVATE yaml-cpp)
target_compile_options(ww4_utils PRIVATE ${WW4_COMMON_COMPILE_OPTIONS})
target_link_options(ww4_utils PRIVATE ${WW4_COMMON_LINK_OPTIONS})

# Library: ww4_core
add_library(
ww4_core
src/ww4_core/w4core_init.cpp
Expand All @@ -126,7 +96,7 @@ target_link_libraries(ww4_core PUBLIC ww4_utils)
target_compile_options(ww4_core PRIVATE ${WW4_COMMON_COMPILE_OPTIONS})
target_link_options(ww4_core PRIVATE ${WW4_COMMON_LINK_OPTIONS})

# Executables
# Executable: ww4_standalone
add_executable(ww4_standalone src/ww4_progs/ww4_standalone.cpp)
target_link_libraries(ww4_standalone PRIVATE ww4_core ww4_utils)
target_compile_options(ww4_standalone PRIVATE ${WW4_COMMON_COMPILE_OPTIONS})
Expand All @@ -138,41 +108,65 @@ set_target_properties(
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/exe
)

# Tests
enable_testing()
include(GoogleTest)

# Helper function to define tests
function(ww4_add_test test_name source_file dependency_lib)
add_executable(${test_name} ${source_file})
target_link_libraries(${test_name} PRIVATE ${dependency_lib} GTest::gtest_main)
target_compile_options(${test_name} PRIVATE ${WW4_COMMON_COMPILE_OPTIONS})
target_link_options(${test_name} PRIVATE ${WW4_COMMON_LINK_OPTIONS})
gtest_discover_tests(${test_name})
endfunction()

# Utils tests
ww4_add_test(test_time_management tests/ww4_utils/L1_test_time_management.cpp ww4_utils)
ww4_add_test(test_memory_utils tests/ww4_utils/L1_test_memory_utils.cpp ww4_utils)
ww4_add_test(test_ww4_std_out tests/ww4_utils/L1_test_ww4_std_out.cpp ww4_utils)
ww4_add_test(test_ww4_logfile tests/ww4_utils/L1_test_ww4_logfile.cpp ww4_utils)
ww4_add_test(test_ww4_standalone_config tests/ww4_utils/L1_test_ww4_standalone_config.cpp ww4_utils)
ww4_add_test(test_ww4_run_config tests/ww4_utils/L1_test_ww4_run_config.cpp ww4_utils)
ww4_add_test(test_ww4_input_utils tests/ww4_utils/L1_test_ww4_input_utils.cpp ww4_utils)
ww4_add_test(test_ww4_output_utils tests/ww4_utils/L1_test_ww4_output_utils.cpp ww4_utils)
ww4_add_test(test_ww4_service tests/ww4_utils/L1_test_ww4_service.cpp ww4_utils)
ww4_add_test(test_ww4_constants tests/ww4_utils/L1_test_ww4_constants.cpp ww4_utils)

# Core tests
ww4_add_test(test_ww4_standalone tests/ww4_core/L1_test_ww4_standalone.cpp ww4_core)
target_compile_definitions(test_ww4_standalone PRIVATE STANDALONE_EXE_PATH="${CMAKE_SOURCE_DIR}/exe/ww4_standalone")
ww4_add_test(test_w4core_init tests/ww4_core/L1_test_w4core_init.cpp ww4_core)
ww4_add_test(test_w4core_wave tests/ww4_core/L1_test_w4core_wave.cpp ww4_core)
ww4_add_test(test_w4core_finalize tests/ww4_core/L1_test_w4core_finalize.cpp ww4_core)
ww4_add_test(test_w4core_time tests/ww4_core/L2_test_w4core_time.cpp ww4_core)
ww4_add_test(test_w4core_wave_output tests/ww4_core/L2_test_w4core_wave_output.cpp ww4_core)
ww4_add_test(test_w4core_zero_step tests/ww4_core/L2_test_w4core_zero_step.cpp ww4_core)
ww4_add_test(test_w4core_hom_input tests/ww4_core/L2_test_w4core_hom_input.cpp ww4_core)
ww4_add_test(test_w4core_input_cycling tests/ww4_core/L2_test_w4core_input_cycling.cpp ww4_core)
ww4_add_test(test_interpolation_output tests/ww4_core/L2_test_interpolation_output.cpp ww4_core)
ww4_add_test(test_w4core_screen_output tests/ww4_core/L2_test_w4core_screen_output.cpp ww4_core)
# Tests (skipped when WW4_ENABLE_TESTING is OFF for operational builds)
if(WW4_ENABLE_TESTING)
if(EXISTS "${CMAKE_SOURCE_DIR}/externals/googletest/CMakeLists.txt")
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(externals/googletest EXCLUDE_FROM_ALL SYSTEM)
else()
message(FATAL_ERROR "googletest submodule not found in externals/googletest. Please run: git submodule update --init --recursive")
endif()

# Suppress warnings from GTest itself for Clang/IntelLLVM during compilation
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
set(GTEST_SUPPRESS_FLAGS -Wno-unknown-warning-option -Wno-character-conversion)
if(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
list(APPEND GTEST_SUPPRESS_FLAGS -diag-disable=10430)
endif()
foreach(target gtest gtest_main gmock gmock_main)
if(TARGET ${target})
target_compile_options(${target} INTERFACE ${GTEST_SUPPRESS_FLAGS})
target_compile_options(${target} PRIVATE ${GTEST_SUPPRESS_FLAGS})
endif()
endforeach()
endif()

enable_testing()
include(GoogleTest)

# Helper function to define tests
function(ww4_add_test test_name source_file dependency_lib)
add_executable(${test_name} ${source_file})
target_link_libraries(${test_name} PRIVATE ${dependency_lib} GTest::gtest_main)
target_compile_options(${test_name} PRIVATE ${WW4_COMMON_COMPILE_OPTIONS})
target_link_options(${test_name} PRIVATE ${WW4_COMMON_LINK_OPTIONS})
gtest_discover_tests(${test_name})
endfunction()

# Utils tests
ww4_add_test(test_time_management tests/ww4_utils/L1_test_time_management.cpp ww4_utils)
ww4_add_test(test_memory_utils tests/ww4_utils/L1_test_memory_utils.cpp ww4_utils)
ww4_add_test(test_ww4_std_out tests/ww4_utils/L1_test_ww4_std_out.cpp ww4_utils)
ww4_add_test(test_ww4_logfile tests/ww4_utils/L1_test_ww4_logfile.cpp ww4_utils)
ww4_add_test(test_ww4_standalone_config tests/ww4_utils/L1_test_ww4_standalone_config.cpp ww4_utils)
ww4_add_test(test_ww4_run_config tests/ww4_utils/L1_test_ww4_run_config.cpp ww4_utils)
ww4_add_test(test_ww4_input_utils tests/ww4_utils/L1_test_ww4_input_utils.cpp ww4_utils)
ww4_add_test(test_ww4_output_utils tests/ww4_utils/L1_test_ww4_output_utils.cpp ww4_utils)
ww4_add_test(test_ww4_service tests/ww4_utils/L1_test_ww4_service.cpp ww4_utils)
ww4_add_test(test_ww4_constants tests/ww4_utils/L1_test_ww4_constants.cpp ww4_utils)

# Core tests
ww4_add_test(test_ww4_standalone tests/ww4_core/L1_test_ww4_standalone.cpp ww4_core)
target_compile_definitions(test_ww4_standalone PRIVATE STANDALONE_EXE_PATH="${CMAKE_SOURCE_DIR}/exe/ww4_standalone")
ww4_add_test(test_w4core_init tests/ww4_core/L1_test_w4core_init.cpp ww4_core)
ww4_add_test(test_w4core_wave tests/ww4_core/L1_test_w4core_wave.cpp ww4_core)
ww4_add_test(test_w4core_finalize tests/ww4_core/L1_test_w4core_finalize.cpp ww4_core)
ww4_add_test(test_w4core_time tests/ww4_core/L2_test_w4core_time.cpp ww4_core)
ww4_add_test(test_w4core_wave_output tests/ww4_core/L2_test_w4core_wave_output.cpp ww4_core)
ww4_add_test(test_w4core_zero_step tests/ww4_core/L2_test_w4core_zero_step.cpp ww4_core)
ww4_add_test(test_w4core_hom_input tests/ww4_core/L2_test_w4core_hom_input.cpp ww4_core)
ww4_add_test(test_w4core_input_cycling tests/ww4_core/L2_test_w4core_input_cycling.cpp ww4_core)
ww4_add_test(test_interpolation_output tests/ww4_core/L2_test_interpolation_output.cpp ww4_core)
ww4_add_test(test_w4core_screen_output tests/ww4_core/L2_test_w4core_screen_output.cpp ww4_core)
endif()
66 changes: 64 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,71 @@ The documentation files (i.e. files with capitalized names and .md extensions) r
[CONTRIBUTORS.md](./CONTRIBUTORS.md) identifying those who have made significant contributions to WW4,
and [TRADEMARK.md](./TRADEMARK.md) documenting the Trademark Status of WW4.

The only other file in this format is [AGENTS.md](./AGENTS.md), which contains information defining an agentic AI approach used to create, translate or refactor code using AI agents such as Copilot or Jules, the latter of which has been used extensively in developing the WW4 code from WW3. Note that this AI agent is set up to automate coding standards, doxygen documentation and unit testing as mandated for WW4.
The only other file in this format is [AGENTS.md](./AGENTS.md), which contains information defining an agentic AI approach used to create, translate or refactor code using AI agents such as Copilot or Jules, the latter of which has been used extensively in developing the WW4 code from WW3. Note that this AI agent is set up to automate coding standards, doxygen documentation and unit testing as mandated for WW4.

The only other file that could be construed as “documentation” in the home directory of the repository is the VERSION file.
The only other file that could be construed as “documentation” in the home directory of the repository is the VERSION file.

## Compilation and Environment Setup

WAVEWATCH IV uses a standard CMake build system (v3.25+). All compilation is local to the active repository clone. The build process does not modify the user's interactive shell environment or profile scripts.

### 1. Setting up the Compile Environment

Environment parameters needed for CMake are set externally by the user, depending on the target system hardware and software configuration.

#### On Linux (GCC, Clang, or Intel LLVM):
Set the C++ compiler via environment variables or CMake definitions:
```bash
# Using GCC
export CXX=g++
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release

# Or specifying the compiler explicitly via CMake
cmake -B build -S . -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release
```

#### On macOS (Apple Clang or Homebrew LLVM/GCC):
Ensure Xcode Command Line Tools are installed (`xcode-select --install`) or Homebrew compilers are available:
```bash
# Using default Apple Clang
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release

# Using Homebrew GCC or LLVM
export CXX=/opt/homebrew/bin/g++-13
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
```

### 2. Building the Project

Standard development build (includes tests):
```bash
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
cmake --build build
```

### 3. NOAA Operational Builds (Disabling Testing)

For NOAA operational environments, testing dependencies and test executables can be completely disabled using the `-DWW4_ENABLE_TESTING=OFF` flag:
```bash
cmake -B build_ops -S . -DWW4_ENABLE_TESTING=OFF
cmake --build build_ops
```
When `WW4_ENABLE_TESTING=OFF`, GoogleTest dependencies and test targets are completely skipped during build configuration and execution.

### 4. Git Submodules for External Dependencies

WAVEWATCH IV includes required external dependencies as Git submodules in the `externals/` directory:
- `externals/yaml-cpp` (version 0.8.0)
- `externals/googletest` (version 1.14.0)

When cloning the repository, initialize submodules using:
```bash
git clone --recursive https://github.com/NOAA-EMC/WW4.git
```
Or if already cloned, initialize and update submodules using:
```bash
git submodule update --init --recursive
```

#
<p align="right">
Expand Down
14 changes: 11 additions & 3 deletions externals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,19 @@

# External libraries used in WW4

Copies of external libraries used by WW4 are gathered here in the **./externals** directory. We chose to keep copies of these libraries here to allow for off-line development work for WW4.
External libraries used by WW4 are included as Git submodules in the `./externals` directory:
- `externals/yaml-cpp` (version 0.8.0) - Configuration file parsing
- `externals/googletest` (version 1.14.0) - C++ unit testing framework (when testing is enabled)

The libraries are gathered here but are not part of the repository to avoid unnecessary growth of the size of the repository.
To clone WW4 with external dependencies included, use:
```bash
git clone --recursive https://github.com/NOAA-EMC/WW4.git
```

The libraries and their version used for WW4 are documented `*** add the YAML file for this ***`, and their inclusion in this directory is automated using the `*** add script name ***` in the **./bin** directory of the repository.
If the repository was cloned without `--recursive`, initialize and update submodules using:
```bash
git submodule update --init --recursive
```

#
<p align="right">
Expand Down
1 change: 1 addition & 0 deletions externals/googletest
Submodule googletest added at f8d7d7
1 change: 1 addition & 0 deletions externals/yaml-cpp
Submodule yaml-cpp added at f73201
24 changes: 12 additions & 12 deletions templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@

# <p align="center"> WAVEWATCH IV<sup> TM</sup> (WW4<sup> TM</sup>) Configuration Templates </p>

This directory contains template files for configuring the WAVEWATCH IV build environment. These templates provide a starting point for users to set up their local compilation environment.
This directory contains template files for configuring WAVEWATCH IV runtime environments. These templates provide a starting point for users to set up simulation parameters.

## Interactive usage
## Usage

Users can manually copy the templates from this directory to the desired location (typically the repository root) and modify them as needed.
Users can copy templates from this directory to the desired working directory (typically the repository root or execution directory) and modify them as needed:

1. Copy `templates/ww4_compile_config.yaml` to the root directory:
```bash
cp templates/ww4_compile_config.yaml ./ww4_compile_config.yaml
```
2. Edit `ww4_compile_config.yaml` to specify your compiler and preferred options.
3. Copy `templates/ww4_run_config.yaml` to the root directory and modify run-time settings.
1. Copy `templates/ww4_standalone.yaml` to configure simulation start/end times:
```bash
cp templates/ww4_standalone.yaml ./ww4_standalone.yaml
```
2. Copy `templates/ww4_run_config.yaml` to configure general, physics, forcing, and output settings:
```bash
cp templates/ww4_run_config.yaml ./ww4_run_config.yaml
```

## Automatic usage

Build scripts or CI/CD pipelines can use these templates to generate default configurations if a user-specified configuration is not found.
Note: Runtime YAML configuration files created in the repository root are ignored by Git.

#
<p align="right">
Expand Down
27 changes: 0 additions & 27 deletions templates/ww4_compile_config.yaml

This file was deleted.

Loading
Loading