-
Notifications
You must be signed in to change notification settings - Fork 1
Style Guide
The Tiger HLM routing code is written in C++ with GPU acceleration provided by CUDA. It uses a hybrid parallel design where the CPU is responsible for managing simulation setup, configuration, file I/O, and MPI communication, while the GPU handles the core numerical integration of hydrologic equations.
Although the project is still growing, the current modular structure enables efficient scaling across compute clusters and supports long-term maintainability. To ensure the code remains performant, readable, and extensible, the following guidelines should be followed when editing or contributing to the codebase:
- All host-side code must conform to the C++17 standard.
- The code must compile cleanly with
g++(host) andnvcc(device) without warnings or errors. - All device code must target CUDA compute capability 8.0 or higher (e.g., NVIDIA A100).
- Use
-rdc=truefor compiling device code when using separate compilation and linking.
- Declare all reusable types, functions, and constants in header (
.hpp) files. - Place host-only logic in
.cppfiles and GPU kernels or device utilities in.cu/.cuhfiles. - Keep functions short and well-scoped. Avoid mixing I/O, MPI, and model logic in a single function.
- The
main.cppfile acts as the program entry point and should remain stable—avoid placing custom logic here.
-
All file input/output is handled on the CPU side, including:
- Reading YAML configuration files
- Loading hillslope parameters from CSV
- Ingesting forcing data (e.g., precipitation, temperature) from NetCDF files
- Writing simulation outputs (final states, hydrographs) to NetCDF
-
MPI is initialized and managed on the host, with Rank 0 coordinating spatial parameter distribution and global outputs.
-
Prefer
std::vector,std::array, and other STL containers for host-side memory management. -
Use
constandconstexprwhere appropriate to clarify intent and avoid accidental mutation.
- Device-side logic is isolated to CUDA kernels that solve ODEs for hillslope systems.
- All GPU buffers must be explicitly allocated and freed, with error checking using the
CUDA_CHECK()macro. - Kernel launches should be occupancy-aware and avoid excessive branching within warps.
- Use
__constant__memory for global, read-only data such as model parameters or forcing metadata. - Kernels should be templated by model type, and all device-side indexing must be bounds-safe.
- Document each function with a brief comment explaining its purpose and key arguments.
- Use inline comments to explain non-obvious or performance-critical logic, especially within CUDA kernels.
- Do not duplicate what is already clear from variable names or function signatures.
- Use visual separators (e.g.,
// ── Step 1: Load Forcings ──) in longer functions for readability.
- Use descriptive and consistent names for variables and functions.
- Device buffers must be prefixed with
d_(e.g.,d_y_final_all), and shared memory withsm_if applicable. - Constants should use
UPPER_CASE_WITH_UNDERSCORES. - Avoid overly short or cryptic names unless they are standard (e.g.,
i,jfor loop indices).
- Avoid global variables unless explicitly required (e.g., device pointers to constants).
- Avoid
using namespace std;in headers or shared files. Prefer explicitstd::prefixes for clarity. - Separate I/O, MPI, and model logic into distinct modules.
- Initialize all variables and avoid magic numbers.
- All contributions must be submitted through pull requests with clear commit messages.
- Keep commits focused and logical — avoid lumping unrelated changes together.
Maintaining a clean and consistent code style across both host and device components ensures the Tiger HLM routing model remains stable and scalable. As new models and solver types are introduced, these practices will make it easier to integrate new features without compromising performance or clarity.
Getting Started
User Guide
Programmer Guide