Skip to content

Add RANS turbulence models (k-epsilon, Spalart-Allmaras) with wall fu…#199

Merged
shaia merged 12 commits into
masterfrom
feature/rans-turbulence
Jul 9, 2026
Merged

Add RANS turbulence models (k-epsilon, Spalart-Allmaras) with wall fu…#199
shaia merged 12 commits into
masterfrom
feature/rans-turbulence

Conversation

@shaia

@shaia shaia commented Jul 7, 2026

Copy link
Copy Markdown
Owner

…nctions

Implements the v0.4.0 turbulence milestone: standard k-epsilon and Spalart-Allmaras RANS closures with log-law wall functions, so the solver can represent turbulent flows instead of laminar-only. Mirrors the energy-equation module architecture (per-backend kernels, workspace-aware step, in-module BCs).

  • New turbulence module on scalar/OMP/AVX2 backends: upwind advection, conservative face-averaged diffusion, semi-implicit Patankar sinks for positivity, production limiter, nu_t realizability clipping.
  • Log-law wall functions (BC_TYPE_NOSLIP faces): friction velocity from the log law, equilibrium k/eps (or nu_tilde) at the first interior node, wall-face viscosity set so the discrete wall shear equals u_tau^2 exactly.
  • Eddy-viscosity coupling into all projection/Euler/RK momentum paths via conservative nu_eff = nu + nu_t; laminar path stays bitwise identical. GPU paths return CFD_ERROR_UNSUPPORTED when turbulence is enabled.
  • Public API in turbulence_solver.h; turb_model/turb_bc in params; k/eps/ nu_tilde/nu_t added to flow_field and to VTK/CSV output.
  • Validated against turbulent channel flow at Re_tau=395 (k-eps u_tau error 2.9%, SA 3.1%; u+ within a few percent of the log law). Adds unit tests for decay, wall functions, SA closures, laminar regression, and cross-backend consistency, plus a turbulent_channel example.

2D uniform grids only in this version; GPU turbulence not yet implemented.

…nctions

Implements the v0.4.0 turbulence milestone: standard k-epsilon and
Spalart-Allmaras RANS closures with log-law wall functions, so the solver can
represent turbulent flows instead of laminar-only. Mirrors the energy-equation
module architecture (per-backend kernels, workspace-aware step, in-module BCs).

- New turbulence module on scalar/OMP/AVX2 backends: upwind advection,
  conservative face-averaged diffusion, semi-implicit Patankar sinks for
  positivity, production limiter, nu_t realizability clipping.
- Log-law wall functions (BC_TYPE_NOSLIP faces): friction velocity from the
  log law, equilibrium k/eps (or nu_tilde) at the first interior node, wall-face
  viscosity set so the discrete wall shear equals u_tau^2 exactly.
- Eddy-viscosity coupling into all projection/Euler/RK momentum paths via
  conservative nu_eff = nu + nu_t; laminar path stays bitwise identical. GPU
  paths return CFD_ERROR_UNSUPPORTED when turbulence is enabled.
- Public API in turbulence_solver.h; turb_model/turb_bc in params; k/eps/
  nu_tilde/nu_t added to flow_field and to VTK/CSV output.
- Validated against turbulent channel flow at Re_tau=395 (k-eps u_tau error
  2.9%, SA 3.1%; u+ within a few percent of the log law). Adds unit tests for
  decay, wall functions, SA closures, laminar regression, and cross-backend
  consistency, plus a turbulent_channel example.

2D uniform grids only in this version; GPU turbulence not yet implemented.
@shaia shaia self-assigned this Jul 7, 2026
shaia added 2 commits July 7, 2026 15:39
The old doc implied the parabolic component depends on the edge, but the
profile scales whatever base velocity the config holds; the factory just
defaults to left edge with +x flow. Document that and the profile formula.
…ut OpenMP

The cross-backend test takes the address of
turbulence_step_explicit_omp_with_workspace unconditionally, but the OMP
turbulence source was dropped from the build whenever OpenMP was unavailable,
producing an undefined-reference link failure on no-OpenMP toolchains (e.g.
clang without libomp).

Mirror the AVX2 backend instead of gating the symbol: guard the <omp.h>
include behind _OPENMP and compile the file in every configuration. It uses
only #pragma omp directives (no OpenMP runtime calls), so without -fopenmp the
pragmas no-op and the interior loops run serially — numerically identical to
the scalar reference. The OMP-named symbol is therefore always present, and the
kernel now gets serial correctness coverage even on no-OpenMP CI.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a full RANS turbulence capability to the CFD library (standard k-ε and Spalart–Allmaras) with log-law wall functions, integrates eddy-viscosity coupling into the Navier–Stokes solvers across scalar/OMP/AVX2 backends, and extends validation, examples, and documentation accordingly.

Changes:

  • Introduces a new turbulence module (k-ε, SA) with wall functions and workspace-aware backend entry points.
  • Couples turbulent eddy viscosity (nu_t) into momentum diffusion terms across solver families and documents backend support/limitations (GPU explicitly unsupported when turbulence enabled).
  • Adds extensive unit/validation tests plus a turbulent channel example; updates VTK/CSV output and docs/roadmap/readme.

Reviewed changes

Copilot reviewed 42 out of 42 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/validation/test_turbulent_channel.c Adds turbulent channel-flow validation for both RANS models.
tests/solvers/turbulence/test_turbulence_wall_functions.c Adds unit tests for log-law wall functions and BC application.
tests/solvers/turbulence/test_turbulence_sa.c Adds SA model unit tests (init, invariance, production, positivity, wall distance).
tests/solvers/turbulence/test_turbulence_kepsilon.c Adds k-ε model unit tests (decay, convergence, positivity, production, noop).
tests/solvers/turbulence/test_turbulence_disabled_regression.c Ensures laminar paths are bitwise unaffected when turbulence disabled.
tests/solvers/turbulence/test_turbulence_cross_backend.c Verifies scalar/OMP/AVX2 turbulence kernel + solver consistency.
ROADMAP.md Updates project roadmap to mark turbulence milestone complete.
README.md Documents turbulence capability and backend coverage at a high level.
lib/src/solvers/turbulence/turbulence_solver_internal.h Defines internal turbulence constants, workspace sizing, and backend interfaces.
lib/src/solvers/turbulence/omp/turbulence_solver_omp.c Implements OMP turbulence transport step with workspace support.
lib/src/solvers/turbulence/cpu/turbulence_solver.c Implements public turbulence API, wall functions, BCs, nu_t update, validation.
lib/src/solvers/turbulence/cpu/turbulence_sa.c Adds scalar SA transport kernel.
lib/src/solvers/turbulence/cpu/turbulence_kepsilon.c Adds scalar k-ε transport kernel.
lib/src/solvers/navier_stokes/omp/solver_rk4_omp.c Integrates turbulence step/BCs + passes nu_t into RHS for RK4 OMP.
lib/src/solvers/navier_stokes/omp/solver_rk2_omp.c Integrates turbulence step/BCs + passes nu_t into RHS for RK2 OMP.
lib/src/solvers/navier_stokes/omp/solver_projection_omp.c Adds turbulent viscous term option + turbulence step/BCs for projection OMP.
lib/src/solvers/navier_stokes/omp/solver_explicit_euler_omp.c Adds turbulent viscous term option + turbulence step/BCs for explicit Euler OMP.
lib/src/solvers/navier_stokes/momentum_rhs/ns_momentum_rhs_scalar.h Extends scalar momentum RHS to use nu_t when turbulence enabled.
lib/src/solvers/navier_stokes/momentum_rhs/ns_momentum_rhs_omp.h Extends OMP momentum RHS to use nu_t when turbulence enabled.
lib/src/solvers/navier_stokes/momentum_rhs/ns_momentum_rhs_avx2.h Extends AVX2 momentum RHS to use nu_t and routes turbulent case through scalar helper for identical numerics.
lib/src/solvers/navier_stokes/cpu/solver_rk4.c Integrates turbulence step/BCs + passes nu_t into RHS for RK4 scalar.
lib/src/solvers/navier_stokes/cpu/solver_rk2.c Integrates turbulence step/BCs + passes nu_t into RHS for RK2 scalar.
lib/src/solvers/navier_stokes/cpu/solver_projection.c Adds turbulent viscous term option + turbulence step/BCs for scalar projection.
lib/src/solvers/navier_stokes/cpu/solver_explicit_euler.c Adds turbulence params/field allocation, dt constraint with nu_t, turbulence step/BCs integration.
lib/src/solvers/navier_stokes/avx2/solver_rk4_avx2.c Adds turbulence coupling and persistent turbulence workspace in AVX2 RK4.
lib/src/solvers/navier_stokes/avx2/solver_rk2_avx2.c Adds turbulence coupling and persistent turbulence workspace in AVX2 RK2.
lib/src/solvers/navier_stokes/avx2/solver_projection_avx2.c Adds turbulent viscous term option + turbulence step/BCs for AVX2 projection.
lib/src/solvers/navier_stokes/avx2/solver_explicit_euler_avx2.c Adds turbulent viscous term option + turbulence step/BCs for AVX2 explicit Euler.
lib/src/solvers/gpu/solver_rk_gpu.cu Explicitly rejects turbulence on GPU RK solvers with CFD_ERROR_UNSUPPORTED.
lib/src/solvers/gpu/solver_projection_gpu.cu Explicitly rejects turbulence on GPU projection/NS solvers with CFD_ERROR_UNSUPPORTED.
lib/src/io/vtk_output.c Adds turbulence scalar fields to VTK output (k, ε, ν̃, ν_t).
lib/src/io/csv_output.c Adds turbulence columns to CSV centerline output.
lib/include/cfd/solvers/turbulence_solver.h Adds the public turbulence solver API header.
lib/include/cfd/solvers/navier_stokes_solver.h Extends flow_field and solver params with turbulence fields/config; adds max_nu_t to stats.
lib/include/cfd/boundary/boundary_conditions.h Updates inlet documentation text (non-functional change).
lib/CMakeLists.txt Adds turbulence sources to build for scalar/OMP/AVX2 and adjusts OMP build fallback logic.
examples/turbulent_channel.c Adds an executable example for turbulent channel flow using RANS + wall functions.
docs/reference/solvers.md Adds detailed turbulence model documentation and references.
docs/reference/api-reference.md Documents turbulence API additions and data outputs.
docs/guides/examples.md Documents the new turbulent channel example and expected outputs.
CMakeLists.txt Registers turbulence tests and example build targets.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/src/solvers/navier_stokes/cpu/solver_explicit_euler.c
Comment thread lib/src/solvers/turbulence/cpu/turbulence_solver.c Outdated
Comment thread lib/src/solvers/turbulence/cpu/turbulence_solver.c
Comment thread lib/include/cfd/solvers/navier_stokes_solver.h
shaia added 4 commits July 8, 2026 16:57
Callers relying on the default initializer would otherwise read an
uninitialized value for the new turbulence stat. Addresses PR #199
review comment.
…tive

nu = mu/rho is used in denominators (SA chi = nu_tilde/nu, wall
functions), so mu <= 0 silently produces Inf/NaN instead of an error.
Validate early with CFD_ERROR_INVALID. Addresses PR #199 review
comment.
The wall-shear-matching viscosity bypassed the global
TURB_NU_T_MAX_FACTOR * nu clamp applied everywhere else; on very coarse
grids or near-zero u_p it could produce huge nu_t and destabilize the
momentum step and dt estimation. Addresses PR #199 review comment.
rho[0] is not conservative when density varies: any cell with lower rho
has larger local nu = mu/rho, underestimating nu_eff_max and allowing an
unstable dt_visc. Track the minimum density (same floor) alongside the
nu_t maximum. Addresses PR #199 review comment.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated 3 comments.

Comment thread lib/src/solvers/navier_stokes/avx2/solver_projection_avx2.c Outdated
Comment thread lib/src/solvers/navier_stokes/cpu/solver_explicit_euler.c Outdated
Comment thread lib/include/cfd/solvers/navier_stokes_solver.h
shaia added 3 commits July 8, 2026 20:47
…eference

The AVX2 projection clamped face-averaged nu_eff to 1.0 while the
scalar/OMP projection backends do not, making results backend-dependent
and artificially capping turbulent diffusion. Scalar backends are the
reference implementations, so drop the AVX2-only clamp; nu_t is already
bounded by the realizability clamp. Addresses PR #199 review comment.
… limit

Replacing a tiny rho_min with 1.0 shrinks nu = mu/rho and overestimates
the stable dt exactly when low densities make diffusion stiffest. Floor
at the same 1e-10 the kernels use (local_nu) so degenerate densities
tighten the limit instead of loosening it. Addresses PR #199 review
comment.
max_nu_t was declared in ns_solver_stats_t and documented but never
written, so callers always saw 0.0. Fill it via a compute_max_nu_t
helper in the registry wrappers and in the RK2/RK4 AVX2 inline stats
reductions, mirroring max_temperature. Addresses PR #199 review
comment.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 43 out of 43 changed files in this pull request and generated 4 comments.

Comment thread lib/src/solvers/navier_stokes/avx2/solver_rk2_avx2.c
Comment thread lib/src/solvers/navier_stokes/momentum_rhs/ns_momentum_rhs_scalar.h Outdated
Comment thread lib/src/solvers/navier_stokes/momentum_rhs/ns_momentum_rhs_omp.h Outdated
Comment thread lib/src/solvers/navier_stokes/momentum_rhs/ns_momentum_rhs_avx2.h Outdated
shaia added 2 commits July 9, 2026 08:03
The turb_ws scratch is allocated unconditionally in rk2_avx2_init (and is
required non-NULL by the init check), matching the rk4/projection/euler AVX2
backends which pre-allocate all persistent workspaces at init. The comment
claimed it was NULL when turb_model==NONE, which was never true. Correct the
comment rather than making rk2 the lone AVX2 backend with conditional
allocation. Addresses PR #199 review comment.
…us kernels

The face-averaged effective viscosity nu_eff = nu + nu_t was clamped to 1.0 in
the RK2/RK4 momentum RHS kernels (scalar/omp/avx2) and the explicit-Euler inline
viscous kernels (cpu/omp/avx2). This under-diffused momentum whenever nu_t was
large or the flow was nondimensionalized with nu_eff > 1.0, and left these
solvers inconsistent with the projection backends, which already dropped the
clamp (9fc29b9). nu_t is bounded by the realizability clamp, and the RK/CPU-Euler
kernels additionally clamp the resulting flux, so the 1.0 cap only suppressed
legitimate turbulent diffusion. Drop it everywhere for consistent nu+nu_t
coupling across all backends and time integrators.

The explicit-Euler kernels were not flagged in review but carried the identical
clamp; fixing them together keeps turbulent diffusion consistent across solvers.
Addresses PR #199 review comments.
@shaia shaia merged commit b3c1a3b into master Jul 9, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants