Add RANS turbulence models (k-epsilon, Spalart-Allmaras) with wall fu…#199
Merged
Conversation
…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.
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.
Contributor
There was a problem hiding this comment.
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.
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.
…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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…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).
2D uniform grids only in this version; GPU turbulence not yet implemented.