125 lines
6.8 KiB
Markdown
125 lines
6.8 KiB
Markdown
# Pipe solver comparison — 2026-10-23
|
||
|
||
The original Rusanov/local Lax–Friedrichs flux, HLLE and HLLC are selectable
|
||
with `--solver` in the desktop, engine CLI, and audio capture tool. Press S
|
||
in the desktop to cycle all engine pipes together; the dashboard shows the
|
||
selected solver. The existing simulation lock serializes a change between
|
||
samples. Rusanov remains the startup default. Live switching keeps the ongoing
|
||
engine and acoustic state, so it is a listening convenience rather than a
|
||
repeatable experiment. The WAVs below use independent, matching initial states.
|
||
|
||
All three use the existing per-pipe meshes, first-order spatial update, Euler
|
||
thermodynamics, CFL limit, and new radiating mouth boundaries. HLLE uses wave
|
||
bounds enclosing both endpoints and the Roe acoustic estimates. HLLC restores
|
||
the intermediate contact wave and uses HLLE if its selected star state is
|
||
nonphysical. Fallback counts refer to internal pipe faces. Pipe junctions share
|
||
one flux; differently configured participants use the shared Rusanov flux.
|
||
No global fast-math, CPU-specific flags or multithreaded pipe updates were added.
|
||
|
||
## Performance
|
||
|
||
Intel Core i5-12600K, Linux, GCC 16.2.1, the existing `build-desktop`
|
||
RelWithDebInfo configuration (`-O2 -g -DNDEBUG`, SIMD enabled). Timed runs were
|
||
sequential, without a desktop or concurrent build. Each loaded run lasts eight
|
||
simulated seconds, repeated three times in rotating solver order. The table
|
||
reports the median of each run's mean for seconds 2–8. Transients last twelve
|
||
seconds: released pedal, then 70 percent, then release for the last two seconds.
|
||
Their means also exclude the first second. All work includes normal audio rendering.
|
||
|
||
Values are **wall seconds per simulated second**, so less than 1 allows real time
|
||
in these headless measurements. Loaded RPM is held at 10000 for the YZ125 racing
|
||
exhaust and 4500 for the V8 with 70 percent pedal.
|
||
|
||
| Scenario | Solver | Loaded | Worst loaded second | Transient |
|
||
|---|---|---:|---:|---:|
|
||
| two-stroke-racing | rusanov | 0.548 | 0.568 | 0.547 |
|
||
| two-stroke-racing | hlle | 0.794 | 0.874 | 0.795 |
|
||
| two-stroke-racing | hllc | 0.893 | 0.916 | 0.898 |
|
||
| v8 | rusanov | 0.378 | 0.400 | 0.382 |
|
||
| v8 | hlle | 0.460 | 0.487 | 0.470 |
|
||
| v8 | hllc | 0.497 | 0.542 | 0.499 |
|
||
|
||
All benchmark runs completed with finite audio, zero pipe positivity repairs,
|
||
and zero HLLC fallbacks. This covers the measured windows rather than every
|
||
possible operating condition. HLLC has the least two-stroke real-time headroom.
|
||
The original HLLC experiment took 1.014 s/s on the loaded two-stroke. Caching Roe
|
||
root-density/enthalpy data once per cell, specializing the flux loop by solver,
|
||
and evaluating only the star state selected by the contact speed brought this
|
||
to 0.893 s/s. The cache is allocated at construction and reused at every substep;
|
||
there are no allocations in the new flux routines.
|
||
|
||
Raw measurements: [initial.csv](solver-comparison/initial.csv),
|
||
[final.csv](solver-comparison/final.csv), and
|
||
[diagnostics.log](solver-comparison/diagnostics.log). `summary.json` contains
|
||
per-run means. The benchmark fourth argument is optional uniform V8 cells/m
|
||
(0 preserves the existing mesh); the fifth selects the solver.
|
||
|
||
```sh
|
||
cmake --build build-desktop -j 8
|
||
./build-desktop/fluidsim_scenario_benchmark 8 loaded two-stroke-racing 0 hllc
|
||
./build-desktop/fluidsim_scenario_benchmark 8 loaded v8 0 hllc
|
||
./build-desktop/fluidsim_scenario_benchmark 12 transient v8 0 hllc
|
||
```
|
||
|
||
## Numerical checks
|
||
|
||
All nine CTest suites passed on the final build (26.96 seconds). The fluid
|
||
validation runs separately with Rusanov, HLLE and HLLC, with 36 checks per run.
|
||
The lossless pipe cases exercise the selected solver: closed/profiled mass and
|
||
energy conservation, acoustic reflection, strong pressure pulses, near-vacuum
|
||
expansion and Sod convergence. Additional checks cover uniform fluxes,
|
||
orientation symmetry for all transported quantities, a stationary HLLC contact,
|
||
and intentional HLLE fallback during a strong expansion.
|
||
[validation.log](solver-comparison/validation.log) records their output.
|
||
Passing these checks does not establish complete engine or acoustic accuracy.
|
||
|
||
At 400 cells, the Sod density L1 error was about 0.01595 for Rusanov,
|
||
0.00702 for HLLE, and 0.00654 for HLLC. This is a shock-tube result; contact
|
||
resolution and sound quality are different questions. With first-order meshes,
|
||
changing the flux alone still leaves considerable numerical acoustic damping.
|
||
|
||
## Listening
|
||
|
||
The controlled recordings are six seconds each, after two seconds of warmup,
|
||
with the same dry scene, 70 percent pedal, per-pipe geometry, monitor filter,
|
||
and capture gain. An ideal speed-holding dyno fixes the two-stroke at 10000 RPM
|
||
and V8 at 4500 RPM. The recordings have no desktop automatic gain and no
|
||
normalization. Numerical fuel/temperature transport can change the subsequent
|
||
combustion, so these compare complete engine simulations with different fluxes.
|
||
|
||
Files are under `build-desktop/audio/solvers/`, named
|
||
`two-stroke-{rusanov,hlle,hllc}-rendered.wav` and
|
||
`v8-{rusanov,hlle,hllc}-rendered.wav`. Dry and unfiltered versions are also
|
||
available; each capture's `.log` records its measurements.
|
||
|
||
| Scenario | Solver | Rendered peak | Rendered RMS | Clipped samples |
|
||
|---|---|---:|---:|---:|
|
||
| two-stroke | rusanov | 0.1416 | 0.01795 | 0 |
|
||
| two-stroke | hlle | 0.1467 | 0.01836 | 0 |
|
||
| two-stroke | hllc | 0.1489 | 0.01815 | 0 |
|
||
| v8 | rusanov | 0.0650 | 0.02452 | 0 |
|
||
| v8 | hlle | 0.0904 | 0.02746 | 0 |
|
||
| v8 | hllc | 0.1204 | 0.03318 | 0 |
|
||
|
||
```sh
|
||
./build-desktop/fluidsim_audio_capture --scenario two-stroke --solver hllc --scene dry --throttle .7 --rpm 10000 --warmup 2 --seconds 6 --out build-desktop/audio/solvers/two-stroke-hllc
|
||
./build-desktop/fluidsim_audio_capture --scenario v8 --solver hllc --scene dry --throttle .7 --rpm 4500 --warmup 2 --seconds 6 --out build-desktop/audio/solvers/v8-hllc
|
||
./build-desktop/fluidsim_desktop --scenario two-stroke --scene dry --solver hlle
|
||
./build-desktop/fluidsim_desktop --scenario v8 --scene dry --solver hllc
|
||
```
|
||
|
||
Both desktop scenarios were actually launched with audio streams visible in
|
||
PipeWire. A two-stroke HLLE-to-HLLC switch was exercised live; its dashboard
|
||
showed 1.000x playback and zero underruns. The V8 was then launched with HLLC
|
||
and a later snapshot showed live HLLE at 6544 RPM, 100 percent
|
||
throttle, 1.000x playback and zero underruns. These are spot observations;
|
||
both desktop processes subsequently exited cleanly. Screenshots are
|
||
`build-desktop/audio/solvers/two-stroke-live.png` and `v8-live.png`.
|
||
Use S to cycle solvers and G to toggle automatic gain during listening.
|
||
|
||
## Method references
|
||
|
||
- [Clawpack: approximate Euler solvers](https://www.clawpack.org/riemann_book/html/Euler_approximate.html)
|
||
- [Toro, Spruce and Speares: restoration of the contact surface in HLL](https://doi.org/10.1007/BF01414629)
|
||
- [Athena solver documentation](https://princetonuniversity.github.io/Athena-Cversion/AthenaDocsUGRiemann.html)
|