Add turbocharged twin scenario and cross-platform test harness

This commit is contained in:
2026-10-23 02:27:03 +02:00
parent a859740a95
commit 589d22aa5e
63 changed files with 4903 additions and 771 deletions

View File

@@ -0,0 +1,261 @@
# 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
```sh
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
- [Clawpack: approximate Euler Riemann solvers](https://www.clawpack.org/riemann_book/html/Euler_approximate.html)
— conservative Euler fluxes and total-energy equation of state.
- [Clawpack: Euler equations and exact Riemann solutions](https://www.clawpack.org/riemann_book/html/Euler.html)
— shock/contact/rarefaction verification and the Sod problem.
- [NASA Glenn: mass-flow choking](https://www.grc.nasa.gov/www/k-12/BGP/mflchk.html)
— isentropic throat relations and maximum mass flow at Mach one.
- [EPFL: quasi-1D Laval nozzle model](https://www.epfl.ch/labs/mathicse/wp-content/uploads/2018/10/25.2016_MP-FN-PL.pdf)
— variable-area Euler fluxes and geometric pressure source.
## 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:
```sh
./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](https://documents.aemelectronics.com/techlibrary_30-6905_universal_programmable_engine_management_system.pdf)
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.