Skip to content

Developer Guide

LiranOG edited this page May 9, 2026 · 9 revisions

👨‍💻 Developer Guide

GRANITE v0.6.8 | ← CHANGELOG Summary | Documentation Index & Master Reference →

Condensed developer reference. For the full 52 KB guide see docs/developer_guide/DEVELOPER_GUIDE.md.


1. Coding Standards

Language

  • C++17 exclusively. No C++20 until v1.0 (HPC cluster compiler compatibility).
  • No exceptions in library code. Use GRANITE_ASSERT(cond, msg) and return codes.
  • No std::cout in library code. Use the Logger class (MPI rank-aware).

Naming Conventions

Category Convention Examples
Namespaces snake_case granite::, granite::spacetime, granite::grmhd
Classes PascalCase GridBlock, GRMetric3, CCZ4Solver
Functions camelCase computeRHS(), fillGhostZones()
Variables snake_case conformal_factor, dt_local
Constants UPPER_SNAKE MAX_AMR_LEVELS, NGHOST

Physical Units

Always document units in comments: // [M, G=c=1]
Physical constants must be in include/granite/constants.hpp — never magic numbers.

Formatting

python3 scripts/run_granite.py format  # LLVM clang-format, 100-char limit

2. Pre-PR Checklist

[ ] Full test suite passes: python3 scripts/run_granite.py test
[ ] health_check.py passes
[ ] Dev pipeline passes in < 5 minutes: python3 scripts/run_granite.py dev
[ ] granite_analysis package works: python3 -m granite_analysis.cli.dev_benchmark --help
[ ] CHANGELOG.md updated under ## [Unreleased]
[ ] New physics: paper citation in comment (Author Year, Journal Vol, Page)
[ ] No ko_sigma > 0.1 in any YAML or code
[ ] Known Fixed Bugs (C1, C3, H1, H2, H3, TOV, KO-σ, Sommerfeld+BL) verified intact
[ ] No regression in constraint norm growth rate vs. baseline

3. Adding a New Physics Module

Step 1: RFC
  Open GitHub Discussion: "[RFC] New Feature: <name>"
  Include: governing equations, paper references, impact estimate

Step 2: Branch
  git checkout -b feature/<descriptive-name>

Step 3: Implement
  src/<subsystem>/<feature>.cpp
  Follow existing patterns: no exceptions, Logger not cout, units documented

Step 4: Public Interface
  include/granite/<subsystem>/<feature>.hpp
  Only expose what users of the module need

Step 5: Tests
  tests/<subsystem>/test_<feature>.cpp
  Minimum: one unit test + one convergence order test

Step 6: YAML Support
  Add parameters to YAML parser + document in Parameter-Reference wiki

Step 7: Update CHANGELOG.md
  Under ## [Unreleased]

Step 8: PR
  Use the PR template. Include benchmark results showing no regression.

Test Template

TEST(NewFeatureSuite, PhysicsCorrectness) {
    GridBlock state = createTestBlock(32, 32, 32, /*dx=*/0.1);
    initializeMinkowski(state);
    double result = computeNewObservable(state);
    EXPECT_NEAR(result, expected_analytic_value, 1e-10)
        << "Must match analytic value to roundoff";
}

TEST(NewFeatureSuite, ConvergenceOrder) {
    double err_coarse = runAndMeasureError(/*dx=*/0.2);
    double err_fine   = runAndMeasureError(/*dx=*/0.1);
    double order = std::log2(err_coarse / err_fine);
    EXPECT_NEAR(order, 4.0, 0.1) << "Should converge at 4th order";
}

4. Test Suite Structure

tests/
├── core/
│   ├── test_grid.cpp         # GridBlock memory, buffer, MPI neighbor (22 tests)
│   └── test_types.cpp        # Type sizes, NUM_VARS constants (7 tests)
├── spacetime/
│   ├── test_ccz4_flat.cpp    # Flat spacetime RHS=0, KO, selective advection (10 tests)
│   └── test_gauge_wave.cpp   # CCZ4 gauge wave convergence (4 tests)
├── initial_data/
│   ├── test_brill_lindquist.cpp  # BL conformal factor (5 tests)
│   └── test_polytrope.cpp        # TOV solver: M≈1.4M☉, R≈10km (7 tests)
├── amr/
│   └── test_amr_basic.cpp   # AMR hierarchy init, subcycling smoke (5 tests)
├── horizon/
│   └── test_schwarzschild_horizon.cpp  # AH finder on Schwarzschild (3 tests)
├── io/
│   └── test_hdf5_roundtrip.cpp  # HDF5 write+read roundtrip (3 tests)
├── radiation/
│   └── test_m1_diffusion.cpp   # M1 diffusion limit, opacity (4 tests)
└── grmhd/
    ├── test_grmhd_gr.cpp    # GR-aware HLLE, MP5 accuracy (5 tests)
    ├── test_hlld_ct.cpp     # HLLD + CT ∇·B preservation (7 tests)
    ├── test_ppm.cpp         # PPM reconstruction (5 tests)
    └── test_tabulated_eos.cpp # Nuclear EOS full suite (20 tests)

Total: 107 tests across 20 suites (105 passed, 2 skipped), GoogleTest v1.14

5. Build System Reference

# Development cycle
python3 scripts/run_granite.py build             # Production build (Release is default)
python3 scripts/run_granite.py build --build-type Debug  # Debug + ASan/UBSan
python3 scripts/run_granite.py test              # Run all 107 C++ tests via CTest
python3 scripts/run_granite.py test              # Run Python analysis tests (pytest)
python3 scripts/run_granite.py docs              # Build Sphinx HTML docs
python3 scripts/run_granite.py docs --open       # Build + open in browser
python3 scripts/run_granite.py format            # clang-format all C++
python3 scripts/run_granite.py clean             # Remove build/

# Direct CMake
cmake -B build -DCMAKE_BUILD_TYPE=Release \
    -DGRANITE_ENABLE_MPI=ON \
    -DGRANITE_ENABLE_OMP=ON \
    -DGRANITE_ENABLE_HDF5=ON
cmake --build build -j$(nproc)
ctest --test-dir build --output-on-failure

CMake Options:

Option Default Purpose
GRANITE_ENABLE_MPI ON MPI parallelism
GRANITE_ENABLE_OMP ON OpenMP threading
GRANITE_ENABLE_HDF5 ON HDF5 I/O + checkpoints
GRANITE_ENABLE_CUDA OFF GPU kernels (v0.7 roadmap)
GRANITE_ENABLE_SANITIZERS OFF ASan + UBSan (Debug only)

6. CI/CD Pipeline

GitHub Actions (.github/workflows/ci.yml) runs on every push and PR to main:

  1. Install: gcc-12, openmpi-dev, hdf5-parallel, libomp-dev, yaml-cpp
  2. CMake configure with -DGRANITE_ENABLE_OPENMP=ON
  3. Build Release target
  4. ctest --output-on-failure — must show 107/107 passing
  5. cppcheck --error-exitcode=1 static analysis

All PRs block on CI failure. No exceptions.


See also: Architecture Overview | Parameter Reference | Known Fixed Bugs

Clone this wiki locally