Files
FluidSimCpp/verification/FLUID_PHYSICS_AUDIT.md

15 KiB
Raw Permalink Blame History

Fluid physics audit — 23 October 2026

This pass repairs conservation and boundary coupling, establishes repeatable physical tests, and measures kernel and threading performance. It is not a certification that every engine or acoustic subsystem is physically validated.

Findings and changes

  1. Pipe–volume mass/energy mismatch. Previously, the volume used an orifice's requested discharge while the pipe used a different Rusanov ghost-cell flux. Each boundary now supplies one integrated mass, energy and fresh-air flux; the volume receives the exact opposite exchange. Stationary walls transfer momentum but no mass or energy. Open-end audio reports the mass flux actually applied by the finite-volume update.
  2. Substep integration. Components previously received only the final boundary flow after several pipe substeps. Every component now updates after every pipe substep. CFL is recalculated as the solution evolves.
  3. Profiled pipes. Geometry was stored but absent from the conservation update. Shared face fluxes now include face area and divide by cell volume; momentum includes the quasi-1D pressure source p dA/dx. Constant-pressure rest remains stationary while closed profiled pipes conserve mass/energy.
  4. Orifice choking. The old formula used the upstream sound speed with throat Mach number, overestimating discharge. The nozzle calculation now uses the isentropic throat temperature and satisfies the sonic-flow test.
  5. Unstable small-signal boundary. Evaluating sqrt(dp) using only the adjacent cell-centre pressure destabilized a small Helmholtz excitation. The nozzle discharge is now matched to the outgoing duct characteristic using a safeguarded analytic Newton solve of a squared-flow residual. Bisection remains the fallback. Subsonic, isentropic characteristic and quasi-steady nozzle assumptions still limit this model.
  6. Inertance units. For mass flow, d(mdot)/dt = A dp/L, not A dp/(rho L). Dimensionless quadratic resistance is integrated with a dissipative semi-implicit term. Removed the additional lumped inertance in the Helmholtz scenario: its resolved neck already carries inertance.
  7. Moving volumes. Volume0D previously applied work without changing its geometric volume. Closed adiabatic work now follows E V^(gamma-1)=constant and updates volume. Crankcase geometry work is applied once per geometry change rather than again for each solver substep. Removed its five-bar cap, which silently deleted gas during high compression.
  8. Invalid configurations. Reject invalid geometry, timesteps, duplicate or missing endpoints and incompatible gas constants. A pressure-only boundary cannot specify a supersonic inlet; that case now fails explicitly. Direct pipe joints support equal endpoint areas and all orientation combinations; unequal-area direct joints are rejected. Use a profiled transition instead.
  9. Performance. Cache primitive states/wave speeds, evaluate each shared interior face once, and hoist uniform relaxation outside the cell loop. Compiler SIMD is enabled without fast-math. No per-step allocations were introduced into the pipe/boundary kernels.

Validation

fluidsim_fluid_validation contains 29 named cases, in addition to the existing physics/audio/ECU regression executable. Coverage includes:

  • Closed pipes, variable-area equilibrium/conservation, stationary hot contacts.
  • Sealed volume–pipe exchange, several volumes and a shared tiny donor.
  • Direct joints in four orientations and split/unsplit equivalence.
  • Fresh-air species conservation, actual open-end mass accounting on both ends.
  • Sonic choking against the analytic ideal-gas formula; inertance units and steady quadratic resistance.
  • Adiabatic moving volumes, thermal exponential relaxation and sealed crankcase compression beyond five bar without mass deletion.
  • Closed/open acoustic reflection signs, closed-duct mode frequencies at 50/100/200 cells, and small-signal cavity resonance.
  • Sod shock-tube density error at 100/200/400 cells, strong pressure pulses, expanding-flow near-vacuum states, positivity-repair checks.
  • Invalid geometry/configuration, incompatible gas coupling, unsupported supersonic inlet and missing/duplicate endpoint rejection.

Representative measured results:

Check Result
Sod density L1, 100 / 200 / 400 cells 0.02332 / 0.01595 / 0.01052
Closed-duct fundamental approximately 171.9 Hz; analytic 171.91 Hz
Cavity fundamental approximately 136.2 Hz; lumped estimate 138.51 Hz
Closed mass/energy relative tolerances 2e-5 to 5e-5, depending on case
Cavity frequency tolerance 5%, with growth and positivity checks
Closed-duct frequency tolerance 1% across three resolutions

The cavity estimate assumes a compact, lossless neck without radiation end correction; the discretized model includes neck compressibility and numerical losses. These comparisons are verification of stated assumptions, not a comparison with measured engine hardware.

Benchmarks and SIMD

Machine: Intel Core i5-12600K, GCC 16.2.1, Linux x86-64, Release. These are local wall-clock microbenchmarks; CPU frequency and background load affect timings. The pipe benchmark advances an equilibrium lossless duct with reflected ends; the twin benchmark runs one simulated second including its nonlinear boundaries.

Before this audit, isolated kernels measured about 49–52 million cell updates/s and the twin about 3.84 times real time. Cached shared-face evaluation raised pipe throughput to roughly 110–140 million updates/s. The final twin is around 1.7 times real time: it does substantially more boundary work than the original, physically inconsistent solver. Early faster twin numbers from before the characteristic/nozzle correction must not be treated as final results.

A SIMD comparison measured roughly 111–139 million updates/s with compiler vectorization versus 84–102 million with vectorization disabled. GCC's vectorization report confirms 16-byte SIMD in the primitive-state and face-flux loops. FLUIDSIM_ENABLE_SIMD=ON permits vectorization and disables math errno; it does not enable fast-math, approximate reciprocal/square-root intrinsics, or machine-specific instruction sets. OFF disables compiler vectorization for repeatable comparison. Scalar and SIMD builds run the same physics tests. Windows/MSVC settings are provided but were not executed in this Linux audit.

Multithreading investigation

fluidsim_thread_benchmark measures persistent workers with two barriers per iteration. Boundaries/components must remain in ordered phases; pipes can be advanced independently only after all boundary fluxes are resolved.

Independent pipe workload, 1000 steps Serial 2 workers 4 workers
6 pipes × 10 cells 0.00093 s 0.00272 s 0.00625 s
64 pipes × 256 cells 0.1275 s 0.0700 s 0.0410 s

This is an optimistic stage-only benchmark with equilibrium data, excluding worker startup and a real graph's serial boundary work. It supports further work on persistent pools for large networks; it does not justify threading the current small twin. No fluid worker pool is enabled in production. The existing simulation/audio/UI separation remains.

Reproduce

cmake -S . -B build-audit -DFLUIDSIM_BUILD_DESKTOP=OFF -DCMAKE_BUILD_TYPE=Release
cmake --build build-audit -j 4
ctest --test-dir build-audit --output-on-failure
./build-audit/fluidsim_physics_benchmark 44100
./build-audit/fluidsim_thread_benchmark

For a scalar comparison configure a separate directory with -DFLUIDSIM_ENABLE_SIMD=OFF. On GCC/Clang, use another directory with -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" to reproduce the sanitizer run. Final Linux desktop regressions, all 29 scalar fluid cases, and both test executables under AddressSanitizer/UndefinedBehaviorSanitizer passed. The final sanitizer run completed in about 13 seconds.

Compiler vectorization diagnostics can be produced with GCC -fopt-info-vec-optimized.

Remaining limits and next work

  • First-order Rusanov flux is dissipative. Spatial/time resolution convergence and attenuation across the full audible band are not yet established. A higher-order limited scheme is a separate change, not silently enabled here.
  • The default four-substep floor was retained: removing it failed a tiny-volume stress case. CFL alone is not a positivity guarantee for arbitrary stiff pipe/volume networks. Conservative donor budgets can limit transfer; inspect BoundarySystem::limited_fluxes and refine time resolution when they activate. Budgets for shared donors are allocated in registration order. Pipe positivity repairs are counted by Pipe1D::positivity_repairs; a nonzero count invalidates a claim of exact conservation for that run.
  • Pipe geometry/cell storage remains public for initialization. Changing its topology or resizing cells after connections have been built is unsupported.
  • The pressure-only open boundary extrapolates interior entropy. It is an ideal pressure-release model, not a complete external atmosphere, anechoic boundary, or frequency-dependent radiation impedance. Strong inlet flows need richer thermodynamic boundary data.
  • Junctions and orifices are quasi-1D approximations. Jet separation, vena contracta, discharge coefficients and strong multidimensional area changes need validation; equal-area joint tests do not validate arbitrary fittings.
  • The optional lumped inertance law is dimensionally checked, but its stored neck kinetic energy is not a separately tracked thermodynamic state. Use resolved pipe cells when evaluating physical neck acoustics and energy.
  • Core pipe damping and volume thermal relaxation default to zero. Explicit scenario damping/relaxation still represents empirical source terms and must be calibrated before claiming real dissipation or heat transfer.
  • Engine cylinders retain pressure/temperature safety clamps, approximate combustion/species bookkeeping and unvalidated mechanical work integration. ECU behavior and the broader engine model are not certified by this audit.
  • Sound radiation remains the documented compact-source approximation. These fluid tests do not establish microphone SPL, high-frequency radiation, thermoviscous losses or full mechanical/chemical energy conservation.

Physical references

Sustained-load follow-up

A one-second run missed a runtime deadline problem: at full throttle the heated gas raised average CFL work from 4 to approximately 7 substeps per audio frame. By simulated second 5, each second needed about 1.04 seconds of CPU time, so a finite startup buffer could not prevent eventual underruns. Idle stayed near 0.6 seconds per simulated second.

The solver now reuses its CFL primitive-state/wave-speed preparation in the finite-volume update. Boundary Newton residual tolerance is matched to the single-precision conserved state (4e-7 in the normalized squared-flow residual), rather than solving to 1e-12 relative residual each time. The same CFL limits and four-substep floor remain. On the same machine, a nine-second full-throttle run measured approximately 0.74–0.81 seconds per simulated second in the hot portion; idle measured approximately 0.49–0.52 seconds. All 29 fluid cases and existing regressions still pass. This is measured headroom, not a hard real-time guarantee on other workloads or machines.

Reproduce sustained-load timings with:

./build-audit/fluidsim_physics_benchmark --soak 12

The benchmark reports each simulated second, average substeps/frame and boundary iterations/frame. Desktop audio also counts underrun blocks; the counter is shown with the audio-buffer status when a UI font is available.

Intake reservoir and repeated-blip regression

The twin's upstream pressure-only boundary inherited pipe entropy during inflow. Repeated blips could therefore admit progressively hotter gas rather than fresh ambient air: a captured sequence reached approximately 1140 K in the plenum at wide-open throttle and lost fresh charge density. The intake now connects to an explicit infinite Atmosphere reservoir (101325 Pa, 300 K, fresh-air fraction one), updated on every fluid substep. Intake radiation uses that reservoir's actual signed mass exchange. The remaining pressure-release open-end index now refers only to the exhaust.

The twin also disables pipe relaxation toward ambient pressure energy. That source can heat low-density evacuated cells without a physical wall heat transfer law. This does not impose any pressure floor or artificial manifold refill. Hot residual-gas reversion, closed-throttle pumping and pressure waves remain possible; their engine-model accuracy still needs further validation.

fluidsim_intake_regression runs 16 simulated seconds: idle, an 80% blip, recovery, a full-throttle opening, and return to idle. It checks pressure recovery, fresh-air temperature/composition, finite audio, zero pipe positivity repairs and final idle recovery. Representative results after the fix:

  • Before the second opening: 35.76 kPa manifold absolute pressure.
  • After opening: 85.45 kPa near 9950 RPM; manifold 298.96 K, inlet 296.92 K.
  • After return to idle: 34.51 kPa at 1820 RPM.

Manifold vacuum at small/closed throttle is expected and is not removed by the fix. An actual obstruction/regression is distinguished by failure to recover pressure and fresh-charge density when reopening the throttle. The inlet reservoir controls the upstream gas state; it does not thermostat the manifold. See AEM's engine-management manual for the qualitative throttle-angle/manifold-pressure relationship. These are scenario regression bounds, not universal pressure limits for real engines.

All three CTest executables pass after this change (existing regressions, 29-case fluid suite, and the new intake transient). A six-second sustained full-throttle follow-up stayed at four substeps/frame and approximately 0.51–0.53 seconds of wall time per simulated second, with RPM around the ECU rev limit. This also identifies the earlier hot-gas CFL growth as a consequence of the incorrect inlet thermodynamic state, not solely an unavoidable engine workload increase. The earlier timing sections are historical measurements of those intermediate implementations.