This commit is contained in:
2026-10-23 03:00:20 +02:00
parent 589d22aa5e
commit 7a5c77c1c8
31 changed files with 1196 additions and 44 deletions

View File

@@ -100,6 +100,11 @@ else()
endif()
include(CTest)
if(BUILD_TESTING)
add_executable(fluidsim_saab_turbo_regression tests/saab_turbo_regression.cpp)
target_link_libraries(fluidsim_saab_turbo_regression PRIVATE fluidsim_core)
add_test(NAME fluidsim_saab_turbo_regression COMMAND fluidsim_saab_turbo_regression)
endif()
if(BUILD_TESTING)
add_executable(fluidsim_physics_tests tests/physics_tests.cpp)
target_link_libraries(fluidsim_physics_tests PRIVATE fluidsim_core)
@@ -108,6 +113,8 @@ endif()
add_executable(fluidsim_physics_benchmark tools/physics_benchmark.cpp)
target_link_libraries(fluidsim_physics_benchmark PRIVATE fluidsim_core)
add_executable(fluidsim_scenario_benchmark tools/scenario_benchmark.cpp)
target_link_libraries(fluidsim_scenario_benchmark PRIVATE fluidsim_core)
if(BUILD_TESTING)
add_executable(fluidsim_fluid_validation tests/fluid_validation.cpp)
target_link_libraries(fluidsim_fluid_validation PRIVATE fluidsim_core)

View File

@@ -1,5 +1,10 @@
# FluidSimCpp
Solver performance measurements and reproducible SIMD/threading experiments are
documented in [the optimization audit](verification/OPTIMIZATION.md). Current
scenarios use serial pipe execution because per-substep threading costs more than
it saves at their graph sizes. Portable compiler SIMD remains enabled by default.
FluidSimCpp aims to reproduce sound from a physically accurate simulation of
compressible flow in pipes and connected volumes, sampled at 44,100 Hz. Each
audio sample advances physical time by 1/44100 second; adaptive internal
@@ -157,13 +162,19 @@ unboosted twin is unchanged unless `--turbo vz21` is selected.
This is an estimated VZ21-size model, not a measured turbo map. Engine exhaust
pulses are implemented; blade-passing whistle/wakes are still pending. The
seven-second twin transient and all nine CTest suites passed. Sustained high-load
performance is close to, or slower than, real time in the current benchmark;
watch the underrun counter during testing. See
seven-second twin transient and all nine CTest suites passed. The optimized
7,000-RPM workload takes about 0.65 wall seconds per simulated second on the audit
machine; actual playback headroom depends on the computer. See
[turbo verification](verification/TURBO_VZ21.md) for assumptions and results.
## Saab B205 / 9-5 wagon baseline
The Saab menu entry now includes an estimated GT17 turbo and ECU wastegate boost
control (up to 0.45 bar gauge). Launch with `--scenario b205 --turbo gt17`, or use
`--turbo none` for the naturally aspirated baseline. See [GT17 verification](verification/SAAB_GT17.md)
for controller behavior, assumptions and tests. Charge heating and backpressure
are simulated; an intercooler is not yet included.
Select **Saab B205 / 9-5 wagon** from the desktop menu, or launch directly:
```sh
@@ -177,10 +188,10 @@ cylinder and 1-3-4-2 firing order. Four intake runners and four exhaust headers
connect shared plenums and a tailpipe. The vehicle approximates a 9-5 wagon:
1675 kg with driver, five-speed manual, FM55 B05 overall ratios
13.70 / 7.12 / 4.77 / 3.62 / 2.67, and 4.05 final drive. No sixth gear is offered.
Controls and dyno match the other scenarios. There is no turbo system yet;
this is an atmospheric-breathing B205 geometry baseline. Pipe/cam dimensions,
Controls and dyno match the other scenarios. The original atmospheric-breathing
geometry baseline remains available with `--turbo none`. Pipe/cam dimensions,
friction, idle/ignition maps, clutch, drag and loaded tire radius are estimates.
It does not reproduce factory turbo power or turbo/exhaust acoustics.
Turbo calibration and acoustics are approximate; factory power is not validated.
See [B205 verification](verification/B205_BASELINE.md) for sources and checks.
## Current port status

View File

@@ -9,12 +9,12 @@ namespace fluidsim::port {
// the twin already protects its own simulation state.
class DesktopScenario {
public:
explicit DesktopScenario(ScenarioKind kind, TwoStrokeConfig config = {}) {
explicit DesktopScenario(ScenarioKind kind, TwoStrokeConfig config = {}, bool saab_turbo = true) {
if (kind == ScenarioKind::TwoStroke)
two_ = std::make_unique<TwoStrokeScenario>(44100, config);
else
twin_ = std::make_unique<FourStrokeScenario>(44100, kind == ScenarioKind::SaabB205 ?
FourStrokePreset::SaabB205 : FourStrokePreset::Twin, kind == ScenarioKind::TurboTwin);
FourStrokePreset::SaabB205 : FourStrokePreset::Twin, kind == ScenarioKind::TurboTwin || (kind == ScenarioKind::SaabB205 && saab_turbo));
}
AudioFrame process() {
if (twin_)

View File

@@ -17,6 +17,12 @@ public:
float overrun_cut_rpm{3500.0f}, overrun_resume_rpm{2400.0f};
float idle_spark_gain{0.0f}, idle_minimum_advance{-5.0f}; // degrees/RPM, degrees BTDC
float stoichiometric_afr{14.7f}, power_afr{12.8f};
bool boost_control_enabled{false};
float maximum_boost{45000}; // Pa gauge, estimated low-pressure B205 calibration
float boost_kp{1e-5f}, boost_ki{4e-6f};
void control_boost(float dt, float pedal, float rpm, float manifold, float charge, float ambient = 101325);
float boost_target() const { return boost_target_; }
float wastegate_duty() const { return boost_duty_; }
void step(float dt, float pedal, float rpm);
float fuel_for_air(float trapped_air_mass) const;
@@ -24,12 +30,14 @@ public:
float throttle_target() const { return target_; }
float target_afr() const { return afr_; }
float spark_advance() const { return spark_; }
bool fuel_cut() const { return limiter_ || overrun_ || fault_; }
bool fuel_cut() const { return limiter_ || overrun_ || fault_ || boost_cut_; }
bool rev_limited() const { return limiter_; }
bool idle_active() const { return idle_; }
bool sensor_fault() const { return fault_; }
private:
float boost_target_{}, boost_duty_{}, boost_integral_{}, filtered_boost_{};
bool boost_cut_{};
float filtered_rpm_{};
bool initialized_{};
float opening_{}, target_{}, integral_{}, afr_{14.7f}, spark_{10.0f};

View File

@@ -189,10 +189,14 @@ public:
float dt = std::numeric_limits<float>::max();
for (std::size_t i = 0; i < cells.size(); ++i) {
states_[i] = primitive(cells[i]);
waves_[i] = wave(states_[i]);
}
// Keep the arithmetic loop free of exceptional control flow so SIMD
// can evaluate independent cells, then validate before any flux update.
for (std::size_t i = 0; i < cells.size(); ++i) {
const auto &s = states_[i];
if (!(s.rho > 0) || !(s.pressure > 0) || !std::isfinite(s.velocity) || !std::isfinite(s.pressure))
throw std::runtime_error("nonphysical pipe state in preparation");
waves_[i] = wave(s);
dt = std::min(dt, cfl * cell_lengths[i] / waves_[i]);
}
prepared_ = true;
@@ -265,7 +269,12 @@ public:
en = minimum;
++positivity_repairs;
}
next_cells_[i] = {rho, mom, en, std::clamp(air / rho, 0.0f, 1.0f)};
// Purged tracer tails below the smallest normal float carry less
// than 1.18e-38 of the gas mass. Avoid repeatedly transporting
// subnormal concentrations; total gas mass and energy are unchanged.
const float fraction = std::clamp(air / rho, 0.0f, 1.0f);
next_cells_[i] = {rho, mom, en,
fraction < std::numeric_limits<float>::min() ? 0.0f : fraction};
}
cells.swap(next_cells_);
prepared_ = false;
@@ -399,6 +408,7 @@ private:
float *area{};
float cd{1}, length{}, loss{}, mdot{};
std::size_t budget{std::numeric_limits<std::size_t>::max()};
double previous_pressure{};
};
struct Open {
int pipe;
@@ -491,7 +501,8 @@ private:
const double zero_pressure = s.pressure * std::pow(zero_sound / c, 2 * g / (g - 1));
double low = std::min(zero_pressure, double(v.pressure));
double high = std::max(zero_pressure, double(v.pressure));
double duct_pressure = .5 * (low + high);
double duct_pressure = o.length == 0 && o.previous_pressure > low && o.previous_pressure < high
? o.previous_pressure : .5 * (low + high);
const double flow_sign = v.pressure >= zero_pressure ? 1 : -1;
const double flow_scale = area * o.cd;
const double density_ratio_scale = std::pow(double(s.pressure) / v.pressure, 1 / g);
@@ -537,6 +548,7 @@ private:
? candidate
: .5 * (low + high);
}
o.previous_pressure = duct_pressure;
float mdot = static_cast<float>(nozzle_flow(duct_pressure));
const bool upstream_port = mdot >= 0;
const float pup = upstream_port ? v.pressure : static_cast<float>(duct_pressure);

View File

@@ -24,6 +24,7 @@ enum class FourStrokePreset { Twin, SaabB205 };
struct ScenarioSnapshot {
bool turbo_enabled{};
float boost_target{}, wastegate_duty{};
TurboSnapshot turbo{};
int cylinder_count{2};
float rev_limit_rpm{10000};
@@ -115,5 +116,9 @@ class SaabB205Scenario : public FourStrokeScenario {
public:
explicit SaabB205Scenario(int sample_rate = 44100) : FourStrokeScenario(sample_rate, FourStrokePreset::SaabB205) {}
};
class SaabTurboScenario : public FourStrokeScenario {
public:
explicit SaabTurboScenario(int sample_rate = 44100) : FourStrokeScenario(sample_rate, FourStrokePreset::SaabB205, true) {}
};
} // namespace fluidsim::port

View File

@@ -9,6 +9,7 @@ namespace fluidsim::port {
// RHB31/VZ21-size mean-line approximation. Geometry, losses and coefficients
// are estimates, not a digitized or validated manufacturer performance map.
struct TurboConfig {
static TurboConfig gt17(); // estimated Saab GT1752-size calibration
double shaft_inertia{4e-6}; // kg m^2, compressor+turbine+shaft rigid rotor
double compressor_radius{.018}, turbine_radius{.0135};
double compressor_head_coefficient{.60}, compressor_efficiency{.65};
@@ -58,6 +59,7 @@ public:
double fluid_energy() const;
// Intended for standalone initialization/tests, never an imposed running speed.
void set_initial_rpm(double rpm);
void set_wastegate_duty(double duty) { gate_duty_ = std::isfinite(duty) ? std::clamp(duty, 0., .85) : 0.; }
private:
std::array<Port*, 4> internal_;
@@ -68,6 +70,7 @@ private:
double wastegate_flow_{}, wastegate_lift_{};
std::uint64_t limited_transfers_{};
bool connected_{};
double gate_duty_{}; // pneumatic bleed fraction; zero restores spring boost
static double nozzle(double upstream_pressure, double upstream_temperature,
double downstream_pressure, double area);
double transfer_flow(Volume0D& inlet, Volume0D& outlet, Port& inlet_external,

View File

@@ -63,7 +63,7 @@ std::optional<ScenarioKind> choose_scenario(sf::RenderWindow& window, const sf::
const std::array<const char*, 4> descriptions{
"Four-stroke twin, motorcycle test and dyno",
"125 cc single, expansion chamber, motorcycle test and dyno",
"2.0 litre inline-four, no turbo yet, five-speed wagon and dyno",
"2.0 litre inline-four, GT17 turbo, ECU boost control and five-speed wagon",
"Coupled turbine/compressor, shaft inertia and pressure diagnostics"};
int selected = 0;
while (window.isOpen()) {
@@ -330,7 +330,7 @@ void draw_dashboard(sf::RenderWindow& window, const sf::Font* font, const Scenar
if (state.turbo_enabled) {
const auto& t = state.turbo;
std::ostringstream text;
text << std::fixed << std::setprecision(0) << "VZ21-size: " << t.rpm << " rpm "
text << std::fixed << std::setprecision(0) << (state.cylinder_count==4 ? "GT17-size: " : "VZ21-size: ") << t.rpm << " rpm "
<< std::setprecision(2) << "CPR " << t.compressor_pressure_ratio
<< " Charge " << t.charge_pressure/1000 << " kPa / " << std::setprecision(0) << t.charge_temperature << " K"
<< "\nTurbine inlet " << t.turbine_inlet_pressure/1000 << " kPa Outlet " << t.turbine_outlet_pressure/1000 << " kPa"
@@ -416,9 +416,15 @@ void draw_twin_scene(sf::RenderWindow& window, const sf::Font* font, const Scena
void draw_b205_scene(sf::RenderWindow& window, const sf::Font* font, const ScenarioSnapshot& s) {
window.clear({9, 12, 17});
draw_label(window, font, "SAAB B205 | 1985 cc inline-four | firing 1-3-4-2 | no turbo yet",
draw_label(window, font, s.turbo_enabled ? "SAAB B205 | GT17 turbo | ECU wastegate control" : "SAAB B205 | naturally aspirated baseline",
{260, 181}, sf::Color::White, 16);
draw_pipe(window, s, 0, 215, 25, 110);
if (s.turbo_enabled) {
draw_pipe(window, s, 10, 320, 25, 70);
draw_volume(window, float(s.turbo.charge_pressure), {{75, 300}, {35, 38}});
draw_graph_line(window, {90, 300}, {25, 215}, {80,145,200});
draw_label(window, font, "COMP", {75, 345}, sf::Color::White, 11);
}
draw_volume(window, s.intake_pressure, {{120, 195}, {65, 65}});
draw_label(window, font, "PLENUM", {120, 270}, sf::Color::White, 12);
draw_graph_line(window, {190, 211}, {820, 211}, {80, 145, 200});
@@ -436,8 +442,15 @@ void draw_b205_scene(sf::RenderWindow& window, const sf::Font* font, const Scena
{x, 445}, {180,190,205}, 12);
}
draw_volume(window, s.exhaust_pressure, {{850, 393}, {65, 48}});
draw_pipe(window, s, 9, 420, 920, 1240);
draw_label(window, font, "COLLECTOR / OPEN EXHAUST", {930, 390}, sf::Color::White, 12);
draw_pipe(window, s, 9, 420, 920, s.turbo_enabled ? 990 : 1240);
if (s.turbo_enabled) {
draw_volume(window, float(s.turbo.turbine_inlet_pressure), {{995, 397}, {55, 45}});
draw_pipe(window, s, 11, 420, 1055, 1240);
draw_label(window, font, "GT17", {1000, 450}, sf::Color::White, 12);
draw_label(window, font, "Boost target " + std::to_string(int(s.boost_target/1000)) + " kPa gauge | WG duty " + std::to_string(int(100*s.wastegate_duty)) + "%",
{25, 515}, sf::Color::White, 14);
}
draw_label(window, font, s.turbo_enabled ? "COLLECTOR / GT17 / EXHAUST" : "COLLECTOR / OPEN EXHAUST", {930, 375}, sf::Color::White, 12);
draw_label(window, font, "9-5 wagon baseline: 1675 kg with driver, five-speed manual, 4.05 final drive",
{25, 550}, sf::Color::White, 14);
draw_label(window, font, "Engine dimensions/firing from Saab WIS. Manifolds, cams, losses and ECU are estimates.",
@@ -465,6 +478,7 @@ int main(int argc, char** argv) {
ScenarioKind selected_kind=ScenarioKind::Twin;
bool scenario_from_args=false;
bool turbo_from_args=false;
std::string turbo_name;
TwoStrokeConfig two_stroke_config;
OutdoorScene selected_scene=OutdoorScene::Wall;
for(int i=1;i<argc;++i){
@@ -477,8 +491,9 @@ int main(int argc, char** argv) {
(value=="two-stroke" ? ScenarioKind::TwoStroke : ScenarioKind::Twin);
scenario_from_args=true;
}else if(option=="--turbo"){
if(value!="none"&&value!="vz21"){std::cerr<<"Choose none or vz21 turbo\n";return 2;}
turbo_from_args=value=="vz21";
if(value!="none"&&value!="vz21"&&value!="gt17"){std::cerr<<"Choose none, vz21 or gt17 turbo\n";return 2;}
turbo_name=value;
turbo_from_args=value!="none";
}else if(option=="--exhaust"){
if(value=="racing") two_stroke_config.exhaust=TwoStrokeExhaust::Racing;
else if(value=="straight") two_stroke_config.exhaust=TwoStrokeExhaust::Straight;
@@ -490,7 +505,7 @@ int main(int argc, char** argv) {
else if(value=="woodland")selected_scene=OutdoorScene::Woodland;
else {std::cerr<<"Choose dry, field, wall or woodland\n";return 2;}
}
}else{std::cerr<<"Usage: fluidsim_desktop [--scenario twin|two-stroke|b205] [--scene dry|field|wall|woodland] [--exhaust racing|straight] [--turbo none|vz21]\n";return 2;}
}else{std::cerr<<"Usage: fluidsim_desktop [--scenario twin|two-stroke|b205] [--scene dry|field|wall|woodland] [--exhaust racing|straight] [--turbo none|vz21|gt17]\n";return 2;}
}
const sf::Vector2u initial_size = scenario_from_args ? sf::Vector2u{window_width, window_height}
: sf::Vector2u{720, 606};
@@ -519,14 +534,17 @@ int main(int argc, char** argv) {
window.setView(sf::View(sf::FloatRect({0, 0}, {float(window_width), float(window_height)})));
}
if(turbo_from_args) {
if(selected_kind!=ScenarioKind::Twin && selected_kind!=ScenarioKind::TurboTwin) {
std::cerr<<"The VZ21 turbo test uses the twin scenario\n";return 2;
}
if(turbo_name=="gt17" && selected_kind==ScenarioKind::SaabB205) {
// Saab preset selects its GT17 calibration.
} else if(turbo_name=="vz21" && (selected_kind==ScenarioKind::Twin || selected_kind==ScenarioKind::TurboTwin)) {
selected_kind=ScenarioKind::TurboTwin;
} else {
std::cerr<<"Use gt17 with b205 or vz21 with twin\n";return 2;
}
}
window.setTitle(selected_kind == ScenarioKind::TurboTwin ? "FluidSim - twin + VZ21 turbo" : selected_kind == ScenarioKind::SaabB205 ? "FluidSim - Saab B205 / 9-5 wagon" :
(selected_kind == ScenarioKind::TwoStroke ? "FluidSim - YZ125 two-stroke" : "FluidSim - parallel twin"));
DesktopScenario scenario(selected_kind, two_stroke_config);
DesktopScenario scenario(selected_kind, two_stroke_config, turbo_name!="none");
scenario.set_audio_scene(selected_scene);
SimulationRingBuffer ring(ring_capacity);
for (std::size_t i = 0; i < preroll_samples; ++i) {

View File

@@ -3,6 +3,27 @@
#include <cmath>
namespace fluidsim::port {
void Ecu::control_boost(float dt, float pedal, float rpm, float manifold, float charge, float ambient) {
boost_target_ = boost_duty_ = 0;
if (!boost_control_enabled) { boost_integral_ = 0; boost_cut_ = false; return; }
if (!std::isfinite(dt) || dt <= 0 || !std::isfinite(pedal) || !std::isfinite(rpm) ||
!std::isfinite(manifold) || !std::isfinite(charge) || !std::isfinite(ambient) ||
manifold <= 0 || charge <= 0 || ambient <= 0) {
boost_integral_ = 0; boost_cut_ = true; return;
}
const float boost = manifold-ambient;
filtered_boost_ += (boost-filtered_boost_)*(-std::expm1(-dt/.05f));
if (std::max(manifold, charge)-ambient > maximum_boost+30000) boost_cut_ = true;
else if (std::max(manifold, charge)-ambient < maximum_boost+10000) boost_cut_ = false;
boost_target_ = maximum_boost*std::clamp((pedal-.5f)/.5f, 0.f, 1.f)*std::clamp((rpm-1500)/1500, 0.f, 1.f);
if (boost_target_ <= 0 || fuel_cut()) { boost_integral_ = 0; return; }
const float error = boost_target_-filtered_boost_;
const float proposed = boost_integral_+boost_ki*error*dt;
const float command = .3f+boost_kp*error+proposed;
if ((command >= 0 && command <= .85f) || (command > .85f && error < 0) || (command < 0 && error > 0))
boost_integral_ = proposed;
boost_duty_ = std::clamp(.3f+boost_kp*error+boost_integral_, 0.f, .85f);
}
void Ecu::step(float dt, float pedal, float rpm) {
fault_ = !std::isfinite(dt) || dt <= 0.0f || !std::isfinite(pedal) || !std::isfinite(rpm) || rpm < 0.0f;
if (fault_) { target_ = 0.0f; idle_ = false; return; }

View File

@@ -17,6 +17,7 @@ int main(int argc, char** argv) {
std::string scenario_name = "twin";
TwoStrokeConfig two_stroke_config;
bool turbo_enabled = false;
std::string turbo_name;
for (int i = 1; i + 1 < argc; ++i) {
const std::string option = argv[i];
if (option == "--seconds") duration_seconds = std::max(0.0f, std::strtof(argv[++i], nullptr));
@@ -24,8 +25,9 @@ int main(int argc, char** argv) {
else if (option == "--scenario") scenario_name = argv[++i];
else if (option == "--turbo") {
const std::string value = argv[++i];
if (value != "none" && value != "vz21") { std::cerr << "Choose none or vz21 turbo\n"; return 2; }
turbo_enabled = value == "vz21";
if (value != "none" && value != "vz21" && value != "gt17") { std::cerr << "Choose none, vz21 or gt17 turbo\n"; return 2; }
turbo_name = value;
turbo_enabled = value != "none";
}
else if (option == "--exhaust") {
const std::string value = argv[++i];
@@ -35,14 +37,19 @@ int main(int argc, char** argv) {
}
}
if (turbo_enabled && scenario_name != "twin") { std::cerr << "The turbo test preset uses --scenario twin\n"; return 2; }
if (turbo_name.empty() && scenario_name == "b205") turbo_enabled = true;
if ((!turbo_name.empty() && turbo_name != "none" &&
!((turbo_name == "gt17" && scenario_name == "b205") || (turbo_name == "vz21" && scenario_name == "twin"))) ||
(turbo_enabled && scenario_name != "twin" && scenario_name != "b205")) {
std::cerr << "Use gt17 with b205 or vz21 with twin\n"; return 2;
}
constexpr int sample_rate = 44100;
const auto total_samples = static_cast<std::uint64_t>(duration_seconds * sample_rate);
const auto report_interval = static_cast<std::uint64_t>(sample_rate / 10);
if (scenario_name == "twin" || scenario_name == "b205") {
FourStrokeScenario scenario(sample_rate, scenario_name == "b205" ? FourStrokePreset::SaabB205 : FourStrokePreset::Twin, turbo_enabled);
scenario.throttle = throttle;
std::cout << (scenario_name == "b205" ? "FluidSimCpp | Saab B205 / 9-5 wagon (no turbo) | throttle " : "FluidSimCpp | 600 cc parallel twin | throttle ") << std::fixed << std::setprecision(0)
std::cout << (scenario_name == "b205" ? "FluidSimCpp | Saab B205 / 9-5 wagon | throttle " : "FluidSimCpp | 600 cc parallel twin | throttle ") << std::fixed << std::setprecision(0)
<< throttle * 100.0f << "%\n";
for (std::uint64_t i = 0; i < total_samples; ++i) {
scenario.process();

View File

@@ -81,7 +81,8 @@ FourStrokeScenario::FourStrokeScenario(int sample_rate, FourStrokePreset selecte
solver_.add_component(intake_plenum);
solver_.add_component(exhaust_collector);
if (turbo_enabled) {
turbo = std::make_unique<Turbocharger>();
turbo = std::make_unique<Turbocharger>(saab ? TurboConfig::gt17() : TurboConfig{});
ecu.boost_control_enabled = saab;
const int fresh = 2+2*count, exhaust_exit = fresh+1;
boundaries_.add_orifice(intake_atmosphere.port, fresh, true, intake_boundary_area_);
turbo->connect(boundaries_, pipes, fresh, false, 0, true, 1+2*count, false, exhaust_exit, true);
@@ -109,6 +110,10 @@ AudioFrame FourStrokeScenario::process() {
const std::lock_guard guard(mutex_);
step_motorcycle(crankshaft, dt_, preset == FourStrokePreset::SaabB205 ? 200.f : 30.f);
ecu.step(dt_, throttle, crankshaft.omega * 60 / (2*pi));
if (turbo) {
ecu.control_boost(dt_, throttle, crankshaft.omega * 60/(2*pi), intake_plenum.pressure(), turbo->compressor_outlet.pressure());
turbo->set_wastegate_duty(ecu.wastegate_duty());
}
const auto engines = cylinders();
for (int i = 0; i < cylinder_count(); ++i) {
auto& c = *engines[i];
@@ -180,6 +185,8 @@ ScenarioSnapshot FourStrokeScenario::snapshot() const {
const std::lock_guard<std::mutex> guard(mutex_);
ScenarioSnapshot result;
result.turbo_enabled = bool(turbo);
result.boost_target = ecu.boost_target();
result.wastegate_duty = ecu.wastegate_duty();
if (turbo) result.turbo = turbo->snapshot();
result.solver_substeps = solver_.substep_count();
result.boundary_iterations = boundaries_.nonlinear_iterations;
@@ -240,7 +247,7 @@ std::vector<Pipe1D> FourStrokeScenario::create_pipes(FourStrokePreset preset, bo
result.emplace_back(area_for_diameter(saab ? .032f : .0275f), saab ? .25f : .12f, 10);
for (int i = 0; i < count; ++i)
result.emplace_back(area_for_diameter(saab ? .034f : .028f), saab ? .28f : .20f, saab ? 10 : 6);
result.emplace_back(area_for_diameter(saab ? .060f : .028f), turbo_enabled ? .12f : (saab ? 1.4f : .40f), saab ? 40 : 10);
result.emplace_back(area_for_diameter(saab ? .060f : .028f), turbo_enabled ? .12f : (saab ? 1.4f : .40f), saab ? (turbo_enabled ? 8 : 40) : 10);
if (turbo_enabled) {
result.emplace_back(area_for_diameter(saab ? .060f : .0275f), .10f, 8);
result.emplace_back(area_for_diameter(saab ? .060f : .032f), .60f, 24);

View File

@@ -22,6 +22,26 @@ TurboConfig checked(TurboConfig c) {
return c;
}
}
TurboConfig TurboConfig::gt17() {
TurboConfig c;
c.shaft_inertia = 2.0e-5;
c.compressor_radius = .026;
c.turbine_radius = .019;
c.compressor_efficiency = .70;
c.turbine_peak_efficiency = .70;
c.compressor_effective_area = 420e-6;
c.turbine_effective_area = 350e-6;
c.bearing_viscous = 2e-7;
c.windage = 5e-11;
c.gate_diaphragm_area = .001;
c.gate_spring_preload = 25;
c.gate_diameter = .024;
c.gate_maximum_lift = .007;
c.compressor_inlet_volume = c.compressor_outlet_volume = 100e-6f;
c.turbine_inlet_volume = c.turbine_outlet_volume = 100e-6f;
c.connection_diameters = {.045f, .045f, .040f, .050f};
return c;
}
Turbocharger::Turbocharger(TurboConfig configuration)
: config(checked(configuration)),
compressor_inlet(config.compressor_inlet_volume), compressor_outlet(config.compressor_outlet_volume),
@@ -114,7 +134,7 @@ void Turbocharger::update_state(float timestep) {
const double tp = turbine_inlet.pressure(), tout = turbine_outlet.pressure();
const double can_force = std::max(0., double(compressor_outlet.pressure())-config.reference_pressure)*
config.gate_diaphragm_area;
config.gate_diaphragm_area*(1-gate_duty_);
const double equilibrium_lift = (can_force-config.gate_spring_preload)/config.gate_spring_stiffness;
// Overdamped spring-can linkage: b*dx/dt + k*x = F-Fpreload, with seats.
wastegate_lift_ = std::clamp(equilibrium_lift+(wastegate_lift_-equilibrium_lift)*

View File

@@ -48,6 +48,23 @@ int main() {
std::cout << "FAIL " << n << ": " << e.what() << '\n';
}
};
test("tracer underflow preserves bulk gas and normal concentrations", [] {
for (float fraction : {1e-40f, 1e-30f, .5f}) {
Pipe1D p(.001f, 1, 8);
for (int i=0; i<8; ++i) set(p, i, 101325, 1.2f, 0, fraction);
p.left_ghost = p.state(0);
p.right_ghost = p.state(7);
const double before_mass = mass(p), before_energy = energy(p);
p.advance(1e-6f);
near(mass(p), before_mass, 0, "tracer truncation changed total mass");
near(energy(p), before_energy, 0, "tracer truncation changed energy");
for (auto cell : p.cells) {
check(std::fpclassify(cell.air) != FP_SUBNORMAL, "subnormal tracer survived");
near(cell.air, fraction < std::numeric_limits<float>::min() ? 0 : fraction,
fraction * 1e-6, "normal tracer concentration changed");
}
}
});
test("invalid uniform geometry", [] {
bool caught = false;
try {

View File

@@ -0,0 +1,46 @@
#include "FluidSim/Scenario.hpp"
#include <cmath>
#include <iostream>
#include <stdexcept>
using namespace fluidsim::port;
void check(bool ok, const char* message) { if (!ok) throw std::runtime_error(message); }
int main() {
Ecu ecu;
ecu.boost_control_enabled = true;
ecu.step(.001f, 1, 3500);
for (int i=0;i<1000;++i) ecu.control_boost(.001f,1,3500,110000,115000);
check(ecu.wastegate_duty()>0 && ecu.wastegate_duty()<=.85f,"no spool duty");
ecu.control_boost(.001f,1,3500,190000,190000);
check(ecu.fuel_cut() && ecu.wastegate_duty()==0,"overboost protection failed");
ecu.control_boost(.001f,1,3500,140000,140000);
check(!ecu.fuel_cut(),"overboost recovery failed");
ecu.control_boost(.001f,0,3500,100000,100000);
check(ecu.wastegate_duty()==0 && ecu.boost_target()==0,"lift-off did not restore spring control");
ecu.control_boost(.001f,1,3500,NAN,100000);
check(ecu.fuel_cut() && ecu.wastegate_duty()==0,"boost sensor fail-safe failed");
FourStrokeScenario s(44100,FourStrokePreset::SaabB205,true);
check(s.pipes.size()==12 && s.turbo && s.ecu.boost_control_enabled,"Saab turbo topology missing");
double peak_rpm=0, peak_map=0, peak_audio=0, settled_pressure=0;
for(int second=0;second<10;++second) {
for(int i=0;i<44100;++i) {
s.throttle = second>=1 && second<7 ? 1.f : 0.f;
if(second<7) s.crankshaft.omega=3500*2*pi/60;
const auto a=s.process();
if(second>=4 && second<7) settled_pressure+=s.intake_plenum.pressure()/(3.*44100);
check(std::isfinite(a.left) && std::isfinite(a.right),"nonfinite audio");
peak_audio=std::max(peak_audio,double(std::abs(a.left)));
}
auto t=s.turbo->snapshot();
peak_rpm=std::max(peak_rpm,t.rpm);
peak_map=std::max(peak_map,double(s.intake_plenum.pressure()));
check(std::isfinite(t.rpm) && std::abs(t.energy_residual)<.1,"turbo energy balance failed");
check(t.limited_transfers==0,"housing donor limit hit");
std::cout<<second+1<<" MAP="<<s.intake_plenum.pressure()/1000<<" charge="<<t.charge_pressure/1000
<<" rpm="<<t.rpm<<" duty="<<s.ecu.wastegate_duty()<<" gate_mm="<<t.wastegate_lift*1000<<'\n';
}
check(peak_rpm>50000 && peak_map>110000,"GT17 failed to spool/boost");
check(peak_audio<1,"audio exceeds monitoring range");
check(std::abs(settled_pressure-146325)<8000,"boost did not settle near target");
check(s.ecu.wastegate_duty()==0 && s.turbo->snapshot().rpm<peak_rpm,"lift-off control/spool-down failed");
for(auto& p:s.pipes) check(p.positivity_repairs==0,"pipe state repaired");
}

View File

@@ -99,6 +99,7 @@ int main(int argc, char **argv) {
float seconds = 6, pedal = 1;
TwoStrokeConfig config;
bool turbo_enabled = false;
std::string turbo_name;
for (int i = 1; i < argc; i++) {
std::string key = argv[i];
if (i + 1 >= argc)
@@ -113,8 +114,9 @@ int main(int argc, char **argv) {
else if (key == "--throttle")
pedal = std::stof(value);
else if (key == "--turbo") {
if (value != "none" && value != "vz21") throw std::runtime_error("choose none or vz21 turbo");
turbo_enabled = value == "vz21";
if (value != "none" && value != "vz21" && value != "gt17") throw std::runtime_error("choose none, vz21 or gt17 turbo");
turbo_name = value;
turbo_enabled = value != "none";
}
else if (key == "--exhaust") {
if (value == "racing") config.exhaust = TwoStrokeExhaust::Racing;
@@ -143,11 +145,16 @@ int main(int argc, char **argv) {
if (!std::filesystem::path(prefix).parent_path().empty())
std::filesystem::create_directories(std::filesystem::path(prefix).parent_path());
const int frames = int(std::lround(seconds * 44100));
if (turbo_enabled && scenario != "twin") throw std::runtime_error("turbo test uses the twin scenario");
if (turbo_name.empty() && scenario == "b205") turbo_enabled = true;
if (!turbo_name.empty() && turbo_name!="none" &&
!((turbo_name=="vz21" && scenario=="twin") || (turbo_name=="gt17" && scenario=="b205")))
throw std::runtime_error("use gt17 with b205 or vz21 with twin");
if (scenario == "twin" && turbo_enabled)
capture<TurboTwinScenario>(prefix, frames, pedal, selected, config);
else if (scenario == "twin")
capture<FourStrokeTwinScenario>(prefix, frames, pedal, selected, config);
else if (scenario == "b205" && turbo_enabled)
capture<SaabTurboScenario>(prefix, frames, pedal, selected, config);
else if (scenario == "b205")
capture<SaabB205Scenario>(prefix, frames, pedal, selected, config);
else if (scenario == "two-stroke")

View File

@@ -0,0 +1,75 @@
#include "FluidSim/Scenario.hpp"
#include "FluidSim/TwoStrokeScenario.hpp"
#include "FluidSim/HelmholtzScenario.hpp"
#include "FluidSim/PulseTestScenario.hpp"
#include <chrono>
#include <iostream>
#include <memory>
#include <string>
using namespace fluidsim::port;
template<class S, class Control> void run(const char* name, S& s, int seconds, Control control) {
double checksum = 0;
std::uint64_t previous_iterations = 0;
for (int second = 0; second < seconds; ++second) {
const auto begin = std::chrono::steady_clock::now();
for (int i = 0; i < 44100; ++i) {
control(second);
auto value = s.process();
if constexpr (requires { value.left; }) checksum += value.left;
else checksum += value;
}
const double elapsed = std::chrono::duration<double>(std::chrono::steady_clock::now()-begin).count();
std::cout << name << ',' << second+1 << ',' << elapsed << ',' << checksum << std::endl;
if constexpr (requires { s.pipes; }) {
unsigned tiny = 0;
for (const auto& pipe : s.pipes)
for (const auto& cell : pipe.cells)
for (float value : {cell.rho, cell.momentum, cell.energy, cell.air})
tiny += std::fpclassify(value) == FP_SUBNORMAL;
std::cerr << name << " second=" << second+1 << " subnormal_cell_fields=" << tiny << '\n';
}
if constexpr (requires { s.snapshot().boundary_iterations; }) {
const auto state = s.snapshot();
std::cerr << name << " iterations_per_frame="
<< (state.boundary_iterations-previous_iterations)/44100.0 << '\n';
previous_iterations = state.boundary_iterations;
}
}
}
int main(int argc, char** argv) {
const int seconds = argc > 1 ? std::stoi(argv[1]) : 6;
const std::string mode = argc > 2 ? argv[2] : "pedal";
const std::string only = argc > 3 ? argv[3] : "all";
auto pedal = [&](int second) {
return mode == "idle" ? 0.0f : mode == "transient" && (second == 0 || second >= seconds-2) ? 0.0f : .7f;
};
std::cout << "scenario,second,wall_seconds,checksum\n";
for (auto name : {"twin", "turbo", "b205", "b205-gt17"}) {
if (only != "all" && only != name) continue;
auto s = std::make_unique<FourStrokeScenario>(44100,
std::string(name).starts_with("b205") ? FourStrokePreset::SaabB205 : FourStrokePreset::Twin,
std::string(name)=="turbo" || std::string(name)=="b205-gt17");
s->throttle = .7f;
run(name, *s, seconds, [&](int second) {
s->throttle = pedal(second);
if (mode == "loaded") s->crankshaft.omega = (std::string(name)=="b205-gt17" ? 5500 : 7000) * 2*pi/60;
});
}
for (bool racing : {true, false}) {
if (only != "all" && only != (racing ? "two-stroke-racing" : "two-stroke-straight")) continue;
TwoStrokeConfig config;
config.exhaust = racing ? TwoStrokeExhaust::Racing : TwoStrokeExhaust::Straight;
TwoStrokeScenario s(44100, config);
s.set_throttle(.7f);
run(racing ? "two-stroke-racing" : "two-stroke-straight", s, seconds, [&](int second) {
s.set_throttle(pedal(second));
if (mode == "loaded") s.crankshaft.omega = 10000 * 2*pi/60;
});
}
if (only == "all" || only == "helmholtz") {
HelmholtzScenario helmholtz; run("helmholtz", helmholtz, seconds, [](int){});
}
if (only == "all" || only == "pulse") {
PulseTestScenario pulse; run("pulse", pulse, seconds, [](int){});
}
}

View File

@@ -1,20 +1,37 @@
#include "FluidSim/Fluid.hpp"
#include "FluidSim/Scenario.hpp"
#include "FluidSim/TwoStrokeScenario.hpp"
#include "FluidSim/HelmholtzScenario.hpp"
#include "FluidSim/PulseTestScenario.hpp"
#include <barrier>
#include <chrono>
#include <iostream>
#include <thread>
using namespace fluidsim::port;
int main() {
for (auto size : {std::pair{6, 10}, std::pair{64, 256}}) {
const int steps = 1000;
for (std::string name : {"twin", "turbo", "b205", "two-stroke-racing", "two-stroke-straight", "helmholtz", "pulse", "large"}) {
std::vector<Pipe1D> geometry;
if (name == "large") {
for (int i=0; i<64; ++i) geometry.emplace_back(.001f, 2, 256);
} else if (name == "helmholtz") {
HelmholtzScenario s; geometry.push_back(s.neck());
} else if (name == "pulse") {
PulseTestScenario s; geometry.push_back(s.pipe());
} else if (name.starts_with("two-stroke")) {
TwoStrokeConfig config;
config.exhaust = name == "two-stroke-straight" ? TwoStrokeExhaust::Straight : TwoStrokeExhaust::Racing;
TwoStrokeScenario s(44100, config); geometry = s.pipes;
} else {
FourStrokeScenario s(44100, name == "b205" ? FourStrokePreset::SaabB205 : FourStrokePreset::Twin, name == "turbo");
geometry = s.pipes;
}
const int steps = 4000;
for (int workers : {1, 2, 4}) {
std::vector<Pipe1D> p;
for (int i = 0; i < size.first; i++)
p.emplace_back(.001f, 2, size.second);
auto p = geometry;
auto advance = [&](int worker) {
for (int k = worker; k < size.first; k += workers) {
for (int k = worker; k < static_cast<int>(p.size()); k += workers) {
auto &a = p[k];
auto l = a.state(0), r = a.state(size.second - 1);
auto l = a.state(0), r = a.state(static_cast<int>(a.cells.size()) - 1);
l.velocity = -l.velocity;
r.velocity = -r.velocity;
a.left_ghost = l;
@@ -47,7 +64,7 @@ int main() {
double sum = 0;
for (auto &q : p)
sum += q.state(0).pressure;
std::cout << "pipes=" << size.first << " cells/pipe=" << size.second << " workers=" << workers
std::cout << "scenario=" << name << " pipes=" << p.size() << " workers=" << workers
<< " steps=" << steps << " seconds=" << sec << " checksum=" << sum << '\n';
}
}

View File

@@ -0,0 +1,109 @@
# Solver optimization audit
Measured on an Intel Core i5-12600K, Linux, GCC 16.2.1, Release (`-O3`,
no fast-math). Reference is commit `589d22a`. Performance results are specific
to this machine; Windows/MSVC runtime measurements remain pending. The retained
changes use portable C++ and compiler vectorization, with no new CPU requirement.
## Retained changes
* Boundary solves start from the previous converged face pressure when it is
inside the new physical bracket. Otherwise they start at the bracket midpoint.
The safeguarded Newton solver, residual tolerance, iteration cap, choking,
reverse flow, donor budgets and inertance calculation remain unchanged.
* Pipe preparation computes primitive states and wave speeds in an independent
loop, then validates states and reduces the CFL timestep. GCC confirms 128-bit
vectorization of the arithmetic loop. Invalid states still throw before flux
updates. No approximate reciprocal/square root or relaxed arithmetic is used.
* Pipe fresh-air tracer fractions smaller than the smallest **normal** float
(approximately 1.175e-38) are rounded to zero. Previously, purged intake/exhaust
tracer tails persisted as subnormals, causing severe sustained-load slowdown.
This affects species attribution below that precision, not total density,
momentum or energy. The regression suite checks bulk conservation and retention
of normal tracer concentrations. Global flush-to-zero modes are not enabled.
Starting guesses change numerical trajectories within the existing convergence
tolerance; long engine/audio traces need not be bit-identical to the reference.
## Profiling and experiments
A `-pg` build running every scenario for two simulated seconds attributed about
39% of sampled executable time to pipe advancement, 38% to orifice boundary
solves, and 13% to Solver::step (including inlined preparation). Turbo mechanics
were under 1% and outdoor emitter rendering about 1%. These are sampled gprof
results, not precise attribution of time inside dynamically linked math functions.
`fluidsim_thread_benchmark` now uses each scenario's actual pipe geometry and
compares persistent 1/2/4-worker execution with barriers per substep. This isolates
the parallelizable pipe work; boundary/component work would remain serial. Every
current scenario loses with workers, so production remains serial. The synthetic
64-pipe, 256-cells-per-pipe case benefits from workers, confirming that this
strategy has a useful scale threshold. It does not justify adding its scheduling
and synchronization cost to the current small graphs.
SIMD-disabled and `-march=native` builds are comparison experiments. Native
compilation is not enabled in the project defaults, since the executable could
then require instructions missing on another machine.
## Results
Mean wall seconds per simulated second, six-second sustained-load runs:
| Scenario | Reference | Optimized | Time reduction | SIMD disabled |
|---|---:|---:|---:|---:|
| Twin | .528 | .405 | 23% | .423 |
| Turbo twin | 1.368 | .649 | 53% | .684 |
| B205 | .884 | .689 | 22% | .737 |
| Two-stroke racing | .561 | .470 | 16% | .535 |
| Two-stroke straight | .539 | .464 | 14% | .525 |
| Helmholtz | .167 | .141 | 16% | .160 |
| Pulse | .256 | .238 | 7% | .315 |
Idle/transient optimized means (seconds per simulated second): twin .394/.399,
turbo .627/.651, B205 .666/.683, racing two-stroke .450/.459, straight two-stroke
.452/.453, Helmholtz .141/.140, and pulse .238/.238.
The pulse scenario has no orifice, so its improvement isolates the SIMD-friendly
preparation change. Disabling SIMD increases time in every scenario. An optional
native-instruction build improves some timings further, but is not shipped as
the default: FMA also changes rounding and the binary is CPU-specific.
Initial isolated changes measured approximately .40 seconds for the twin after
boundary warm starts alone (previously .53). The sustained turbo still took
about 1.2 seconds after that change; eliminating subnormal tracer tails brought
it to about .65. The diagnostic found 22 subnormal pipe fields before truncation
and zero afterwards. This is distinct from reducing CFL substeps or geometry;
neither was changed. Six-second idle and throttle/release runs also complete
for every scenario. These are finite test windows, not a guarantee of real-time
performance for every user configuration or arbitrarily long simulation.
## Reproduction
Final validation: all nine CTest suites passed both with SIMD enabled (28.50 s)
and disabled (30.86 s). The fluid validation executable includes 30 checks,
including tracer underflow conservation. The Release SFML desktop target also
rebuilt successfully. This audit verifies desktop compilation and headless audio
rendering; interactive playback underrun testing remains a separate user check.
```sh
cmake -S . -B build-opt -DCMAKE_BUILD_TYPE=Release -DFLUIDSIM_BUILD_DESKTOP=OFF
cmake --build build-opt -j
ctest --test-dir build-opt --output-on-failure
./build-opt/fluidsim_scenario_benchmark 6 loaded
./build-opt/fluidsim_scenario_benchmark 6 idle
./build-opt/fluidsim_scenario_benchmark 6 transient
./build-opt/fluidsim_thread_benchmark
```
The scenario benchmark runs twin, turbo twin, B205, racing and straight-pipe
two-strokes, Helmholtz and pulse scenarios, including their normal audio path.
`loaded` holds four-strokes at 7,000 RPM and two-strokes at 10,000 RPM using an
ideal speed-holding dyno; engine throttle is 70%. `idle` releases the pedal;
`transient` starts released, applies 70%, then releases for the last two seconds.
The optional final argument selects one scenario, e.g. `6 loaded turbo`.
CSV timing/checksum goes to stdout; subnormal and iteration diagnostics go to
stderr. Inspection happens outside the timed sample-processing loop.
Use `-DFLUIDSIM_ENABLE_SIMD=OFF` in a separate build for scalar comparisons.
Run timed experiments sequentially, without concurrent builds or simulations.
The raw final measurements are retained in `verification/optimization/`.

46
verification/SAAB_GT17.md Normal file
View File

@@ -0,0 +1,46 @@
# Saab B205 with GT17 and ECU boost control
The desktop Saab menu entry and `--scenario b205` now select an estimated GT1752
turbo configuration. `--turbo gt17` makes that choice explicit; `--turbo none`
selects the previous naturally aspirated baseline. CLI and WAV capture follow
the same defaults. `SaabB205Scenario` preserves its baseline API;
`SaabTurboScenario` is the boosted convenience class.
The GT17 calibration uses a 26 mm compressor tip radius, 19 mm effective turbine
radius, 2e-5 kg m² rotor inertia, 420/350 mm² effective compressor/turbine areas,
70% efficiencies, 100 cc housing volumes and a 24 mm wastegate. These are model
estimates, not a measured Saab map or verified rotor inertia. The Garrett catalog
identifies the Saab GT1752 application:
https://www.turbomaster.info/eng/downloads/catalog_garrett.pdf
The ECU requests up to 45 kPa gauge boost, ramping with pedal and RPM. A PI
controller uses manifold pressure filtered over 50 ms, conditional integration,
and bounded pneumatic bleed duty (0–85%). Duty reduces the pressure signal to
the existing spring/diaphragm actuator. Actual valve travel remains damped and
boost emerges from the physical rotor, restrictions and conserved gas transfers.
Zero duty restores the mechanical pressure-can response; it does not forcibly
open the valve or impose a manifold pressure. Targets below spring boost cannot
be achieved by wastegate bleed alone.
Lift-off, fuel cut and invalid sensor data request zero duty and clear the PI
integral. Invalid boost sensors cut fuel. Manifold or charge pressure above
75 kPa gauge triggers fuel cut, recovering below 55 kPa gauge. This is a basic
estimated safety calibration, not a reproduction of Saab Trionic software.
No intercooler, compressor surge/BOV model or knock model has been added;
charge heating and exhaust backpressure remain present.
The regression holds the engine at 3,500 RPM, applies full pedal for six seconds,
then releases for three. It checks boost settling within 8 kPa of the 45 kPa
target, shaft spool-up/down, finite audio, no pipe positivity repairs, no housing
donor limiting, and gas/rotor energy residual below 0.1 J. Controller checks cover
overboost, recovery, pedal release and an invalid sensor. The HUD shows target
gauge boost, actuator bleed duty, turbo RPM and absolute gas pressures.
```sh
cmake --build build-desktop --target fluidsim_desktop -j4
./build-desktop/fluidsim_desktop --scenario b205 --turbo gt17
./build-audit/fluidsim_scenario_benchmark 6 loaded b205-gt17
```
All ten CTest suites pass, including the new ten-second Saab turbo regression.
The GT17 benchmark holds 5,500 RPM, below the Saab's 6,500 RPM limiter.

View File

@@ -88,11 +88,13 @@ shaft power. There is no forced power gain. Effective area/efficiency, gas
properties and the base engine's approximate combustion/overlap affect these
numbers strongly. They are prototype comparisons, not real engine predictions.
The benchmark used four solver substeps per output frame. The turbo cost .81
The original benchmark used four solver substeps per output frame. The turbo cost .81
CPU seconds per simulated second at 4000 RPM and 1.28 at 7000 RPM, versus .53
for the unboosted twin. Sustained high-load real-time playback is an open issue;
monitor underruns. The mixed transient cost .84 wall seconds per simulated
second. Tests run headlessly; latest Windows runtime is unverified.
second. The subsequent [optimization audit](OPTIMIZATION.md) resolves the
subnormal-tracer slowdown and measures about .65 seconds per simulated second
in its 7,000-RPM workload. Tests run headlessly; latest Windows runtime is unverified.
## Run

View File

@@ -0,0 +1,30 @@
twin second=1 subnormal_cell_fields=0
twin second=2 subnormal_cell_fields=0
twin second=3 subnormal_cell_fields=0
twin second=4 subnormal_cell_fields=0
twin second=5 subnormal_cell_fields=0
twin second=6 subnormal_cell_fields=0
turbo second=1 subnormal_cell_fields=22
turbo second=2 subnormal_cell_fields=22
turbo second=3 subnormal_cell_fields=22
turbo second=4 subnormal_cell_fields=22
turbo second=5 subnormal_cell_fields=22
turbo second=6 subnormal_cell_fields=22
b205 second=1 subnormal_cell_fields=0
b205 second=2 subnormal_cell_fields=0
b205 second=3 subnormal_cell_fields=0
b205 second=4 subnormal_cell_fields=0
b205 second=5 subnormal_cell_fields=0
b205 second=6 subnormal_cell_fields=0
two-stroke-racing second=1 subnormal_cell_fields=0
two-stroke-racing second=2 subnormal_cell_fields=0
two-stroke-racing second=3 subnormal_cell_fields=0
two-stroke-racing second=4 subnormal_cell_fields=0
two-stroke-racing second=5 subnormal_cell_fields=0
two-stroke-racing second=6 subnormal_cell_fields=0
two-stroke-straight second=1 subnormal_cell_fields=0
two-stroke-straight second=2 subnormal_cell_fields=0
two-stroke-straight second=3 subnormal_cell_fields=0
two-stroke-straight second=4 subnormal_cell_fields=0
two-stroke-straight second=5 subnormal_cell_fields=0
two-stroke-straight second=6 subnormal_cell_fields=0

View File

@@ -0,0 +1,43 @@
scenario,second,wall_seconds,checksum
twin,1,0.541263,-0.474995
twin,2,0.528657,0.56663
twin,3,0.5197,-0.445512
twin,4,0.524947,-0.457089
twin,5,0.525219,0.543696
twin,6,0.525349,-0.453353
turbo,1,1.15992,-0.310561
turbo,2,1.40615,0.239385
turbo,3,1.41159,0.0378158
turbo,4,1.40703,-0.317772
turbo,5,1.40288,0.217977
turbo,6,1.42287,0.0202671
b205,1,0.89491,0.37201
b205,2,0.892261,-0.672984
b205,3,0.879947,-0.0819311
b205,4,0.87503,0.383653
b205,5,0.879982,-0.660539
b205,6,0.880262,-0.105939
two-stroke-racing,1,0.559599,0.0799002
two-stroke-racing,2,0.557103,-0.446533
two-stroke-racing,3,0.562561,-0.0135526
two-stroke-racing,4,0.56292,0.0502098
two-stroke-racing,5,0.566538,-0.436311
two-stroke-racing,6,0.556811,0.0131825
two-stroke-straight,1,0.54203,0.451678
two-stroke-straight,2,0.53757,-0.576794
two-stroke-straight,3,0.539195,0.301482
two-stroke-straight,4,0.537166,0.436597
two-stroke-straight,5,0.538783,-0.56488
two-stroke-straight,6,0.539518,0.317271
helmholtz,1,0.16266,0.000610898
helmholtz,2,0.156802,0.000204372
helmholtz,3,0.161843,-9.63693e-05
helmholtz,4,0.175722,4.28612e-07
helmholtz,5,0.173455,4.28612e-07
helmholtz,6,0.17374,4.28612e-07
pulse,1,0.256065,0.155302
pulse,2,0.25603,-0.0240824
pulse,3,0.256108,-0.00420275
pulse,4,0.255712,0.00691116
pulse,5,0.255998,-0.00446426
pulse,6,0.256098,0.00211677
1 scenario second wall_seconds checksum
2 twin 1 0.541263 -0.474995
3 twin 2 0.528657 0.56663
4 twin 3 0.5197 -0.445512
5 twin 4 0.524947 -0.457089
6 twin 5 0.525219 0.543696
7 twin 6 0.525349 -0.453353
8 turbo 1 1.15992 -0.310561
9 turbo 2 1.40615 0.239385
10 turbo 3 1.41159 0.0378158
11 turbo 4 1.40703 -0.317772
12 turbo 5 1.40288 0.217977
13 turbo 6 1.42287 0.0202671
14 b205 1 0.89491 0.37201
15 b205 2 0.892261 -0.672984
16 b205 3 0.879947 -0.0819311
17 b205 4 0.87503 0.383653
18 b205 5 0.879982 -0.660539
19 b205 6 0.880262 -0.105939
20 two-stroke-racing 1 0.559599 0.0799002
21 two-stroke-racing 2 0.557103 -0.446533
22 two-stroke-racing 3 0.562561 -0.0135526
23 two-stroke-racing 4 0.56292 0.0502098
24 two-stroke-racing 5 0.566538 -0.436311
25 two-stroke-racing 6 0.556811 0.0131825
26 two-stroke-straight 1 0.54203 0.451678
27 two-stroke-straight 2 0.53757 -0.576794
28 two-stroke-straight 3 0.539195 0.301482
29 two-stroke-straight 4 0.537166 0.436597
30 two-stroke-straight 5 0.538783 -0.56488
31 two-stroke-straight 6 0.539518 0.317271
32 helmholtz 1 0.16266 0.000610898
33 helmholtz 2 0.156802 0.000204372
34 helmholtz 3 0.161843 -9.63693e-05
35 helmholtz 4 0.175722 4.28612e-07
36 helmholtz 5 0.173455 4.28612e-07
37 helmholtz 6 0.17374 4.28612e-07
38 pulse 1 0.256065 0.155302
39 pulse 2 0.25603 -0.0240824
40 pulse 3 0.256108 -0.00420275
41 pulse 4 0.255712 0.00691116
42 pulse 5 0.255998 -0.00446426
43 pulse 6 0.256098 0.00211677

View File

@@ -0,0 +1,43 @@
scenario,second,wall_seconds,checksum
twin,1,0.39941,-0.0283469
twin,2,0.39433,0.0344893
twin,3,0.392258,0.0739791
twin,4,0.39095,0.0786597
twin,5,0.392216,-0.0207043
twin,6,0.393483,-0.195189
turbo,1,0.660359,-0.0302299
turbo,2,0.618997,-0.0283187
turbo,3,0.616863,-0.0501136
turbo,4,0.622639,0.00249347
turbo,5,0.622078,-0.0029317
turbo,6,0.619506,0.0828663
b205,1,0.668236,0.274864
b205,2,0.663904,-1.06343
b205,3,0.675893,-0.186468
b205,4,0.664992,-0.896026
b205,5,0.675325,-1.3108
b205,6,0.650313,1.14027
two-stroke-racing,1,0.433659,-0.00810563
two-stroke-racing,2,0.458929,-0.0171482
two-stroke-racing,3,0.451155,-0.0116779
two-stroke-racing,4,0.451558,-0.00741182
two-stroke-racing,5,0.449763,-0.0575893
two-stroke-racing,6,0.455667,0.0116538
two-stroke-straight,1,0.455246,-0.00988272
two-stroke-straight,2,0.452271,-0.145458
two-stroke-straight,3,0.450603,-0.0420168
two-stroke-straight,4,0.451646,0.115697
two-stroke-straight,5,0.453984,0.104074
two-stroke-straight,6,0.45035,-0.169018
helmholtz,1,0.139612,0.000636785
helmholtz,2,0.150413,0.00020821
helmholtz,3,0.146235,2.83233e-05
helmholtz,4,0.15035,2.23088e-05
helmholtz,5,0.140412,-1.88624e-07
helmholtz,6,0.117403,-1.88624e-07
pulse,1,0.236966,0.155302
pulse,2,0.237632,-0.0240824
pulse,3,0.238374,-0.00420275
pulse,4,0.238214,0.00691116
pulse,5,0.236785,-0.00446426
pulse,6,0.238714,0.00211677
1 scenario second wall_seconds checksum
2 twin 1 0.39941 -0.0283469
3 twin 2 0.39433 0.0344893
4 twin 3 0.392258 0.0739791
5 twin 4 0.39095 0.0786597
6 twin 5 0.392216 -0.0207043
7 twin 6 0.393483 -0.195189
8 turbo 1 0.660359 -0.0302299
9 turbo 2 0.618997 -0.0283187
10 turbo 3 0.616863 -0.0501136
11 turbo 4 0.622639 0.00249347
12 turbo 5 0.622078 -0.0029317
13 turbo 6 0.619506 0.0828663
14 b205 1 0.668236 0.274864
15 b205 2 0.663904 -1.06343
16 b205 3 0.675893 -0.186468
17 b205 4 0.664992 -0.896026
18 b205 5 0.675325 -1.3108
19 b205 6 0.650313 1.14027
20 two-stroke-racing 1 0.433659 -0.00810563
21 two-stroke-racing 2 0.458929 -0.0171482
22 two-stroke-racing 3 0.451155 -0.0116779
23 two-stroke-racing 4 0.451558 -0.00741182
24 two-stroke-racing 5 0.449763 -0.0575893
25 two-stroke-racing 6 0.455667 0.0116538
26 two-stroke-straight 1 0.455246 -0.00988272
27 two-stroke-straight 2 0.452271 -0.145458
28 two-stroke-straight 3 0.450603 -0.0420168
29 two-stroke-straight 4 0.451646 0.115697
30 two-stroke-straight 5 0.453984 0.104074
31 two-stroke-straight 6 0.45035 -0.169018
32 helmholtz 1 0.139612 0.000636785
33 helmholtz 2 0.150413 0.00020821
34 helmholtz 3 0.146235 2.83233e-05
35 helmholtz 4 0.15035 2.23088e-05
36 helmholtz 5 0.140412 -1.88624e-07
37 helmholtz 6 0.117403 -1.88624e-07
38 pulse 1 0.236966 0.155302
39 pulse 2 0.237632 -0.0240824
40 pulse 3 0.238374 -0.00420275
41 pulse 4 0.238214 0.00691116
42 pulse 5 0.236785 -0.00446426
43 pulse 6 0.238714 0.00211677

View File

@@ -0,0 +1,30 @@
twin second=1 subnormal_cell_fields=0
twin second=2 subnormal_cell_fields=0
twin second=3 subnormal_cell_fields=0
twin second=4 subnormal_cell_fields=0
twin second=5 subnormal_cell_fields=0
twin second=6 subnormal_cell_fields=0
turbo second=1 subnormal_cell_fields=0
turbo second=2 subnormal_cell_fields=0
turbo second=3 subnormal_cell_fields=0
turbo second=4 subnormal_cell_fields=0
turbo second=5 subnormal_cell_fields=0
turbo second=6 subnormal_cell_fields=0
b205 second=1 subnormal_cell_fields=0
b205 second=2 subnormal_cell_fields=0
b205 second=3 subnormal_cell_fields=0
b205 second=4 subnormal_cell_fields=0
b205 second=5 subnormal_cell_fields=0
b205 second=6 subnormal_cell_fields=0
two-stroke-racing second=1 subnormal_cell_fields=0
two-stroke-racing second=2 subnormal_cell_fields=0
two-stroke-racing second=3 subnormal_cell_fields=0
two-stroke-racing second=4 subnormal_cell_fields=0
two-stroke-racing second=5 subnormal_cell_fields=0
two-stroke-racing second=6 subnormal_cell_fields=0
two-stroke-straight second=1 subnormal_cell_fields=0
two-stroke-straight second=2 subnormal_cell_fields=0
two-stroke-straight second=3 subnormal_cell_fields=0
two-stroke-straight second=4 subnormal_cell_fields=0
two-stroke-straight second=5 subnormal_cell_fields=0
two-stroke-straight second=6 subnormal_cell_fields=0

View File

@@ -0,0 +1,43 @@
scenario,second,wall_seconds,checksum
twin,1,0.406471,-0.474996
twin,2,0.399598,0.566629
twin,3,0.404976,-0.445512
twin,4,0.406038,-0.457089
twin,5,0.407558,0.543696
twin,6,0.406988,-0.453352
turbo,1,0.681746,-0.310561
turbo,2,0.643922,0.239385
turbo,3,0.646531,0.037816
turbo,4,0.639071,-0.317772
turbo,5,0.64264,0.217976
turbo,6,0.641204,0.0202668
b205,1,0.684996,0.372009
b205,2,0.687167,-0.672981
b205,3,0.686279,-0.0819324
b205,4,0.685947,0.383653
b205,5,0.703778,-0.660537
b205,6,0.684529,-0.105941
two-stroke-racing,1,0.471101,0.0798995
two-stroke-racing,2,0.4718,-0.446533
two-stroke-racing,3,0.469381,-0.0135509
two-stroke-racing,4,0.469582,0.0502136
two-stroke-racing,5,0.468865,-0.436305
two-stroke-racing,6,0.468437,0.0131878
two-stroke-straight,1,0.464019,0.45168
two-stroke-straight,2,0.460395,-0.576791
two-stroke-straight,3,0.463492,0.301486
two-stroke-straight,4,0.463567,0.436602
two-stroke-straight,5,0.465461,-0.564872
two-stroke-straight,6,0.464165,0.317279
helmholtz,1,0.140996,0.000636785
helmholtz,2,0.150978,0.00020821
helmholtz,3,0.146364,2.83233e-05
helmholtz,4,0.150862,2.23088e-05
helmholtz,5,0.139892,-1.88624e-07
helmholtz,6,0.116593,-1.88624e-07
pulse,1,0.237912,0.155302
pulse,2,0.23779,-0.0240824
pulse,3,0.236885,-0.00420275
pulse,4,0.238309,0.00691116
pulse,5,0.238156,-0.00446426
pulse,6,0.238296,0.00211677
1 scenario second wall_seconds checksum
2 twin 1 0.406471 -0.474996
3 twin 2 0.399598 0.566629
4 twin 3 0.404976 -0.445512
5 twin 4 0.406038 -0.457089
6 twin 5 0.407558 0.543696
7 twin 6 0.406988 -0.453352
8 turbo 1 0.681746 -0.310561
9 turbo 2 0.643922 0.239385
10 turbo 3 0.646531 0.037816
11 turbo 4 0.639071 -0.317772
12 turbo 5 0.64264 0.217976
13 turbo 6 0.641204 0.0202668
14 b205 1 0.684996 0.372009
15 b205 2 0.687167 -0.672981
16 b205 3 0.686279 -0.0819324
17 b205 4 0.685947 0.383653
18 b205 5 0.703778 -0.660537
19 b205 6 0.684529 -0.105941
20 two-stroke-racing 1 0.471101 0.0798995
21 two-stroke-racing 2 0.4718 -0.446533
22 two-stroke-racing 3 0.469381 -0.0135509
23 two-stroke-racing 4 0.469582 0.0502136
24 two-stroke-racing 5 0.468865 -0.436305
25 two-stroke-racing 6 0.468437 0.0131878
26 two-stroke-straight 1 0.464019 0.45168
27 two-stroke-straight 2 0.460395 -0.576791
28 two-stroke-straight 3 0.463492 0.301486
29 two-stroke-straight 4 0.463567 0.436602
30 two-stroke-straight 5 0.465461 -0.564872
31 two-stroke-straight 6 0.464165 0.317279
32 helmholtz 1 0.140996 0.000636785
33 helmholtz 2 0.150978 0.00020821
34 helmholtz 3 0.146364 2.83233e-05
35 helmholtz 4 0.150862 2.23088e-05
36 helmholtz 5 0.139892 -1.88624e-07
37 helmholtz 6 0.116593 -1.88624e-07
38 pulse 1 0.237912 0.155302
39 pulse 2 0.23779 -0.0240824
40 pulse 3 0.236885 -0.00420275
41 pulse 4 0.238309 0.00691116
42 pulse 5 0.238156 -0.00446426
43 pulse 6 0.238296 0.00211677

View File

@@ -0,0 +1,43 @@
scenario,second,wall_seconds,checksum
twin,1,0.404945,-0.474997
twin,2,0.394585,0.566634
twin,3,0.392608,-0.445506
twin,4,0.393395,-0.457098
twin,5,0.390801,0.543708
twin,6,0.391814,-0.453348
turbo,1,0.666509,-0.310561
turbo,2,0.614616,0.239377
turbo,3,0.623926,0.0378054
turbo,4,0.623417,-0.317773
turbo,5,0.624208,0.217954
turbo,6,0.623219,0.0202511
b205,1,0.669162,0.372021
b205,2,0.667619,-0.672981
b205,3,0.666157,-0.0819704
b205,4,0.663694,0.383699
b205,5,0.66461,-0.660516
b205,6,0.660155,-0.106025
two-stroke-racing,1,0.450183,0.079881
two-stroke-racing,2,0.43969,-0.446531
two-stroke-racing,3,0.43438,-0.0135516
two-stroke-racing,4,0.435173,0.0501685
two-stroke-racing,5,0.439108,-0.436284
two-stroke-racing,6,0.436695,0.0132443
two-stroke-straight,1,0.430592,0.451674
two-stroke-straight,2,0.431947,-0.576801
two-stroke-straight,3,0.435235,0.301495
two-stroke-straight,4,0.43456,0.436544
two-stroke-straight,5,0.434657,-0.564871
two-stroke-straight,6,0.434816,0.317316
helmholtz,1,0.132025,0.000620049
helmholtz,2,0.141761,0.000208197
helmholtz,3,0.137805,-0.00013923
helmholtz,4,0.136093,-7.93035e-05
helmholtz,5,0.123899,-9.85328e-07
helmholtz,6,0.107671,-9.85328e-07
pulse,1,0.205303,0.155306
pulse,2,0.206141,-0.0240772
pulse,3,0.204146,-0.00422162
pulse,4,0.204149,0.00692384
pulse,5,0.205064,-0.00446612
pulse,6,0.205247,0.0021024
1 scenario second wall_seconds checksum
2 twin 1 0.404945 -0.474997
3 twin 2 0.394585 0.566634
4 twin 3 0.392608 -0.445506
5 twin 4 0.393395 -0.457098
6 twin 5 0.390801 0.543708
7 twin 6 0.391814 -0.453348
8 turbo 1 0.666509 -0.310561
9 turbo 2 0.614616 0.239377
10 turbo 3 0.623926 0.0378054
11 turbo 4 0.623417 -0.317773
12 turbo 5 0.624208 0.217954
13 turbo 6 0.623219 0.0202511
14 b205 1 0.669162 0.372021
15 b205 2 0.667619 -0.672981
16 b205 3 0.666157 -0.0819704
17 b205 4 0.663694 0.383699
18 b205 5 0.66461 -0.660516
19 b205 6 0.660155 -0.106025
20 two-stroke-racing 1 0.450183 0.079881
21 two-stroke-racing 2 0.43969 -0.446531
22 two-stroke-racing 3 0.43438 -0.0135516
23 two-stroke-racing 4 0.435173 0.0501685
24 two-stroke-racing 5 0.439108 -0.436284
25 two-stroke-racing 6 0.436695 0.0132443
26 two-stroke-straight 1 0.430592 0.451674
27 two-stroke-straight 2 0.431947 -0.576801
28 two-stroke-straight 3 0.435235 0.301495
29 two-stroke-straight 4 0.43456 0.436544
30 two-stroke-straight 5 0.434657 -0.564871
31 two-stroke-straight 6 0.434816 0.317316
32 helmholtz 1 0.132025 0.000620049
33 helmholtz 2 0.141761 0.000208197
34 helmholtz 3 0.137805 -0.00013923
35 helmholtz 4 0.136093 -7.93035e-05
36 helmholtz 5 0.123899 -9.85328e-07
37 helmholtz 6 0.107671 -9.85328e-07
38 pulse 1 0.205303 0.155306
39 pulse 2 0.206141 -0.0240772
40 pulse 3 0.204146 -0.00422162
41 pulse 4 0.204149 0.00692384
42 pulse 5 0.205064 -0.00446612
43 pulse 6 0.205247 0.0021024

View File

@@ -0,0 +1,43 @@
scenario,second,wall_seconds,checksum
twin,1,0.429083,-0.474996
twin,2,0.425191,0.566629
twin,3,0.422704,-0.445512
twin,4,0.422067,-0.457089
twin,5,0.423142,0.543696
twin,6,0.417602,-0.453352
turbo,1,0.722612,-0.310561
turbo,2,0.678594,0.239385
turbo,3,0.676959,0.037816
turbo,4,0.675587,-0.317772
turbo,5,0.677697,0.217976
turbo,6,0.674842,0.0202668
b205,1,0.733499,0.372009
b205,2,0.738059,-0.672981
b205,3,0.739555,-0.0819324
b205,4,0.733441,0.383653
b205,5,0.737382,-0.660537
b205,6,0.740199,-0.105941
two-stroke-racing,1,0.532053,0.0798995
two-stroke-racing,2,0.530479,-0.446533
two-stroke-racing,3,0.535284,-0.0135509
two-stroke-racing,4,0.538289,0.0502136
two-stroke-racing,5,0.537818,-0.436305
two-stroke-racing,6,0.536216,0.0131878
two-stroke-straight,1,0.526753,0.45168
two-stroke-straight,2,0.530518,-0.576791
two-stroke-straight,3,0.515521,0.301486
two-stroke-straight,4,0.531466,0.436602
two-stroke-straight,5,0.523436,-0.564872
two-stroke-straight,6,0.522323,0.317279
helmholtz,1,0.160304,0.000636785
helmholtz,2,0.171026,0.00020821
helmholtz,3,0.166819,2.83233e-05
helmholtz,4,0.172109,2.23088e-05
helmholtz,5,0.159173,-1.88624e-07
helmholtz,6,0.130939,-1.88624e-07
pulse,1,0.30969,0.155302
pulse,2,0.314339,-0.0240824
pulse,3,0.318903,-0.00420275
pulse,4,0.317587,0.00691116
pulse,5,0.317432,-0.00446426
pulse,6,0.313647,0.00211677
1 scenario second wall_seconds checksum
2 twin 1 0.429083 -0.474996
3 twin 2 0.425191 0.566629
4 twin 3 0.422704 -0.445512
5 twin 4 0.422067 -0.457089
6 twin 5 0.423142 0.543696
7 twin 6 0.417602 -0.453352
8 turbo 1 0.722612 -0.310561
9 turbo 2 0.678594 0.239385
10 turbo 3 0.676959 0.037816
11 turbo 4 0.675587 -0.317772
12 turbo 5 0.677697 0.217976
13 turbo 6 0.674842 0.0202668
14 b205 1 0.733499 0.372009
15 b205 2 0.738059 -0.672981
16 b205 3 0.739555 -0.0819324
17 b205 4 0.733441 0.383653
18 b205 5 0.737382 -0.660537
19 b205 6 0.740199 -0.105941
20 two-stroke-racing 1 0.532053 0.0798995
21 two-stroke-racing 2 0.530479 -0.446533
22 two-stroke-racing 3 0.535284 -0.0135509
23 two-stroke-racing 4 0.538289 0.0502136
24 two-stroke-racing 5 0.537818 -0.436305
25 two-stroke-racing 6 0.536216 0.0131878
26 two-stroke-straight 1 0.526753 0.45168
27 two-stroke-straight 2 0.530518 -0.576791
28 two-stroke-straight 3 0.515521 0.301486
29 two-stroke-straight 4 0.531466 0.436602
30 two-stroke-straight 5 0.523436 -0.564872
31 two-stroke-straight 6 0.522323 0.317279
32 helmholtz 1 0.160304 0.000636785
33 helmholtz 2 0.171026 0.00020821
34 helmholtz 3 0.166819 2.83233e-05
35 helmholtz 4 0.172109 2.23088e-05
36 helmholtz 5 0.159173 -1.88624e-07
37 helmholtz 6 0.130939 -1.88624e-07
38 pulse 1 0.30969 0.155302
39 pulse 2 0.314339 -0.0240824
40 pulse 3 0.318903 -0.00420275
41 pulse 4 0.317587 0.00691116
42 pulse 5 0.317432 -0.00446426
43 pulse 6 0.313647 0.00211677

View File

@@ -0,0 +1,24 @@
scenario=twin pipes=6 workers=1 steps=4000 seconds=0.00275881 checksum=607950
scenario=twin pipes=6 workers=2 steps=4000 seconds=0.00970369 checksum=607950
scenario=twin pipes=6 workers=4 steps=4000 seconds=0.00580565 checksum=607950
scenario=turbo pipes=8 workers=1 steps=4000 seconds=0.00438693 checksum=810600
scenario=turbo pipes=8 workers=2 steps=4000 seconds=0.0124137 checksum=810600
scenario=turbo pipes=8 workers=4 steps=4000 seconds=0.00970905 checksum=810600
scenario=b205 pipes=10 workers=1 steps=4000 seconds=0.00516911 checksum=1.01325e+06
scenario=b205 pipes=10 workers=2 steps=4000 seconds=0.014045 checksum=1.01325e+06
scenario=b205 pipes=10 workers=4 steps=4000 seconds=0.0101158 checksum=1.01325e+06
scenario=two-stroke-racing pipes=4 workers=1 steps=4000 seconds=0.00631318 checksum=405300
scenario=two-stroke-racing pipes=4 workers=2 steps=4000 seconds=0.0129319 checksum=405300
scenario=two-stroke-racing pipes=4 workers=4 steps=4000 seconds=0.0219618 checksum=405300
scenario=two-stroke-straight pipes=4 workers=1 steps=4000 seconds=0.0120785 checksum=405300
scenario=two-stroke-straight pipes=4 workers=2 steps=4000 seconds=0.0213055 checksum=405300
scenario=two-stroke-straight pipes=4 workers=4 steps=4000 seconds=0.0239495 checksum=405300
scenario=helmholtz pipes=1 workers=1 steps=4000 seconds=0.000931972 checksum=101325
scenario=helmholtz pipes=1 workers=2 steps=4000 seconds=0.00404044 checksum=101325
scenario=helmholtz pipes=1 workers=4 steps=4000 seconds=0.00449503 checksum=101325
scenario=pulse pipes=1 workers=1 steps=4000 seconds=0.00689863 checksum=125674
scenario=pulse pipes=1 workers=2 steps=4000 seconds=0.0155282 checksum=125674
scenario=pulse pipes=1 workers=4 steps=4000 seconds=0.0233903 checksum=125674
scenario=large pipes=64 workers=1 steps=4000 seconds=0.577183 checksum=6.4848e+06
scenario=large pipes=64 workers=2 steps=4000 seconds=0.321996 checksum=6.4848e+06
scenario=large pipes=64 workers=4 steps=4000 seconds=0.186585 checksum=6.4848e+06

View File

@@ -0,0 +1,43 @@
scenario,second,wall_seconds,checksum
twin,1,0.409869,-0.0283469
twin,2,0.402371,0.80967
twin,3,0.403052,-0.911818
twin,4,0.402699,0.534151
twin,5,0.400457,0.207363
twin,6,0.373759,0.0279407
turbo,1,0.659625,-0.0302299
turbo,2,0.644645,-0.0319911
turbo,3,0.651985,0.186487
turbo,4,0.638045,-0.153387
turbo,5,0.681532,-0.0672159
turbo,6,0.632109,-0.00641479
b205,1,0.676147,0.274864
b205,2,0.689301,-0.142368
b205,3,0.683649,-1.24857
b205,4,0.684867,0.692396
b205,5,0.691513,-0.277036
b205,6,0.671074,3.18497
two-stroke-racing,1,0.439156,-0.00810563
two-stroke-racing,2,0.476664,-0.0454537
two-stroke-racing,3,0.491684,0.182272
two-stroke-racing,4,0.481265,0.0605218
two-stroke-racing,5,0.460421,-0.042154
two-stroke-racing,6,0.404627,-0.0445087
two-stroke-straight,1,0.462682,-0.00988272
two-stroke-straight,2,0.465014,0.834933
two-stroke-straight,3,0.463,-0.788353
two-stroke-straight,4,0.462517,-0.624996
two-stroke-straight,5,0.447777,-0.229619
two-stroke-straight,6,0.416485,0.0188991
helmholtz,1,0.141009,0.000636785
helmholtz,2,0.150956,0.00020821
helmholtz,3,0.146729,2.83233e-05
helmholtz,4,0.148541,2.23088e-05
helmholtz,5,0.138622,-1.88624e-07
helmholtz,6,0.116949,-1.88624e-07
pulse,1,0.238432,0.155302
pulse,2,0.238248,-0.0240824
pulse,3,0.236267,-0.00420275
pulse,4,0.236616,0.00691116
pulse,5,0.237568,-0.00446426
pulse,6,0.237908,0.00211677
1 scenario second wall_seconds checksum
2 twin 1 0.409869 -0.0283469
3 twin 2 0.402371 0.80967
4 twin 3 0.403052 -0.911818
5 twin 4 0.402699 0.534151
6 twin 5 0.400457 0.207363
7 twin 6 0.373759 0.0279407
8 turbo 1 0.659625 -0.0302299
9 turbo 2 0.644645 -0.0319911
10 turbo 3 0.651985 0.186487
11 turbo 4 0.638045 -0.153387
12 turbo 5 0.681532 -0.0672159
13 turbo 6 0.632109 -0.00641479
14 b205 1 0.676147 0.274864
15 b205 2 0.689301 -0.142368
16 b205 3 0.683649 -1.24857
17 b205 4 0.684867 0.692396
18 b205 5 0.691513 -0.277036
19 b205 6 0.671074 3.18497
20 two-stroke-racing 1 0.439156 -0.00810563
21 two-stroke-racing 2 0.476664 -0.0454537
22 two-stroke-racing 3 0.491684 0.182272
23 two-stroke-racing 4 0.481265 0.0605218
24 two-stroke-racing 5 0.460421 -0.042154
25 two-stroke-racing 6 0.404627 -0.0445087
26 two-stroke-straight 1 0.462682 -0.00988272
27 two-stroke-straight 2 0.465014 0.834933
28 two-stroke-straight 3 0.463 -0.788353
29 two-stroke-straight 4 0.462517 -0.624996
30 two-stroke-straight 5 0.447777 -0.229619
31 two-stroke-straight 6 0.416485 0.0188991
32 helmholtz 1 0.141009 0.000636785
33 helmholtz 2 0.150956 0.00020821
34 helmholtz 3 0.146729 2.83233e-05
35 helmholtz 4 0.148541 2.23088e-05
36 helmholtz 5 0.138622 -1.88624e-07
37 helmholtz 6 0.116949 -1.88624e-07
38 pulse 1 0.238432 0.155302
39 pulse 2 0.238248 -0.0240824
40 pulse 3 0.236267 -0.00420275
41 pulse 4 0.236616 0.00691116
42 pulse 5 0.237568 -0.00446426
43 pulse 6 0.237908 0.00211677

View File

@@ -0,0 +1,186 @@
Start testing: Oct 23 02:38 CEST
----------------------------------------------------------
1/9 Testing: fluidsim_physics_tests
1/9 Test: fluidsim_physics_tests
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_physics_tests"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_physics_tests" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
FluidSim C++ physics tests passed
<end of output>
Test time = 2.67 sec
----------------------------------------------------------
Test Passed.
"fluidsim_physics_tests" end time: Oct 23 02:38 CEST
"fluidsim_physics_tests" time elapsed: 00:00:02
----------------------------------------------------------
2/9 Testing: fluidsim_fluid_validation
2/9 Test: fluidsim_fluid_validation
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_fluid_validation"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_fluid_validation" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
PASS tracer underflow preserves bulk gas and normal concentrations
PASS invalid uniform geometry
PASS closed pipe conservation
PASS profiled pipe conservation
PASS volume pipe sealed conservation
PASS equal pressure hot contact
PASS NASA choked nozzle mass flow
PASS inertance units
PASS moving volume adiabatic law
PASS profile at rest is well balanced
PASS pipe connection all four orientations
PASS split pipe matches unsplit pipe
PASS three volumes shared donor conservation
PASS open boundary reports actual conserved flux both ends
PASS duplicate and invalid boundary rejection
PASS supersonic outlet extrapolates
PASS underdefined supersonic inlet rejected
PASS closed and open acoustic reflection signs
Sod n=100 density L1=0.0233209
Sod n=200 density L1=0.0159539
Sod n=400 density L1=0.0105216
PASS Sod shock tube convergence
PASS strong pulse and near-vacuum rarefaction
Helmholtz frequency=135.6 analytic lumped=138.508
PASS small-signal Helmholtz resonance
PASS invalid volume and timestep rejection
PASS fresh-air species conservation across connection
PASS unsupported unequal junction rejected
PASS unconnected endpoint rejected by solver
closed mode n=50 f=171.897 analytic=171.91
closed mode n=100 f=171.914 analytic=171.91
closed mode n=200 f=171.911 analytic=171.91
PASS closed duct acoustic eigenfrequency
PASS inertance impulse and dissipative resistance
PASS incompatible gas coupling rejected
PASS thermal relaxation matches analytic energy decay
PASS sealed crankcase compression conserves mass above five bar
30/30 passed
<end of output>
Test time = 0.12 sec
----------------------------------------------------------
Test Passed.
"fluidsim_fluid_validation" end time: Oct 23 02:38 CEST
"fluidsim_fluid_validation" time elapsed: 00:00:00
----------------------------------------------------------
3/9 Testing: fluidsim_intake_regression
3/9 Test: fluidsim_intake_regression
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_intake_regression"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_intake_regression" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Intake regression passed: idle_MAP=35.764 kPa, open_MAP=85.4564 kPa, open_T=298.957 K, inlet_T=296.92 K, recovered_MAP=34.502 kPa, recovered_RPM=1820.05
<end of output>
Test time = 6.61 sec
----------------------------------------------------------
Test Passed.
"fluidsim_intake_regression" end time: Oct 23 02:38 CEST
"fluidsim_intake_regression" time elapsed: 00:00:06
----------------------------------------------------------
4/9 Testing: fluidsim_outdoor_audio_tests
4/9 Test: fluidsim_outdoor_audio_tests
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_outdoor_audio_tests"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_outdoor_audio_tests" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Outdoor audio tests passed: direct=385 samples, ground=463 samples, filtered step ratio=0.155034, stereo lead=7 samples
<end of output>
Test time = 0.02 sec
----------------------------------------------------------
Test Passed.
"fluidsim_outdoor_audio_tests" end time: Oct 23 02:38 CEST
"fluidsim_outdoor_audio_tests" time elapsed: 00:00:00
----------------------------------------------------------
5/9 Testing: fluidsim_two_stroke_regression
5/9 Test: fluidsim_two_stroke_regression
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_two_stroke_regression"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_two_stroke_regression" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Two-stroke regression passed: peak=0.2566, maximum RPM=16127.3, recovered RPM=3158.32, bike speed=61.2948 km/h
<end of output>
Test time = 10.39 sec
----------------------------------------------------------
Test Passed.
"fluidsim_two_stroke_regression" end time: Oct 23 02:38 CEST
"fluidsim_two_stroke_regression" time elapsed: 00:00:10
----------------------------------------------------------
6/9 Testing: fluidsim_two_stroke_physics
6/9 Test: fluidsim_two_stroke_physics
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_two_stroke_physics"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_two_stroke_physics" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Two-stroke physics passed: diffuser reflection=-34.3281 Pa, baffle reflection=27.5234 Pa, first reduction=30.2759
<end of output>
Test time = 0.01 sec
----------------------------------------------------------
Test Passed.
"fluidsim_two_stroke_physics" end time: Oct 23 02:38 CEST
"fluidsim_two_stroke_physics" time elapsed: 00:00:00
----------------------------------------------------------
7/9 Testing: fluidsim_b205_regression
7/9 Test: fluidsim_b205_regression
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_b205_regression"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_b205_regression" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
B205 passed: firing events=33, wagon speed=56.5685 km/h, recovered RPM=1311.5, audio peak=0.186449, wall seconds=5.89428 for 8 simulated seconds
<end of output>
Test time = 5.90 sec
----------------------------------------------------------
Test Passed.
"fluidsim_b205_regression" end time: Oct 23 02:38 CEST
"fluidsim_b205_regression" time elapsed: 00:00:05
----------------------------------------------------------
8/9 Testing: fluidsim_turbo_physics
8/9 Test: fluidsim_turbo_physics
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_turbo_physics"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_turbo_physics" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Closed balance initial_rpm=0 mass_error=0 energy_error=-1.59125e-07 J
Closed balance initial_rpm=120000 mass_error=0 energy_error=-7.09297e-07 J
Turbo pipe bench passed: rpm=189122 compressor flow=0.0306693 kg/s, charge T=375.978 K, turbine power range=1189.38..4022.29 W, residual=-5.44049e-06 J
<end of output>
Test time = 0.32 sec
----------------------------------------------------------
Test Passed.
"fluidsim_turbo_physics" end time: Oct 23 02:38 CEST
"fluidsim_turbo_physics" time elapsed: 00:00:00
----------------------------------------------------------
9/9 Testing: fluidsim_turbo_twin_regression
9/9 Test: fluidsim_turbo_twin_regression
Command: "/home/grillkol/repos/FluidSimCpp/build-simd-off/fluidsim_turbo_twin_regression"
Directory: /home/grillkol/repos/FluidSimCpp/build-simd-off
"fluidsim_turbo_twin_regression" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Turbo twin passed: max_rpm=236218, max_charge=181.458 kPa, max_turbine_pressure=674.103 kPa, gate=2.7762 mm, final_rpm=151754, peak_audio=0.0293228, energy_residual=2.16491e-06 J
<end of output>
Test time = 4.83 sec
----------------------------------------------------------
Test Passed.
"fluidsim_turbo_twin_regression" end time: Oct 23 02:38 CEST
"fluidsim_turbo_twin_regression" time elapsed: 00:00:04
----------------------------------------------------------
End testing: Oct 23 02:38 CEST

View File

@@ -0,0 +1,186 @@
Start testing: Oct 23 02:37 CEST
----------------------------------------------------------
1/9 Testing: fluidsim_physics_tests
1/9 Test: fluidsim_physics_tests
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_physics_tests"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_physics_tests" start time: Oct 23 02:37 CEST
Output:
----------------------------------------------------------
FluidSim C++ physics tests passed
<end of output>
Test time = 2.51 sec
----------------------------------------------------------
Test Passed.
"fluidsim_physics_tests" end time: Oct 23 02:37 CEST
"fluidsim_physics_tests" time elapsed: 00:00:02
----------------------------------------------------------
2/9 Testing: fluidsim_fluid_validation
2/9 Test: fluidsim_fluid_validation
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_fluid_validation"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_fluid_validation" start time: Oct 23 02:37 CEST
Output:
----------------------------------------------------------
PASS tracer underflow preserves bulk gas and normal concentrations
PASS invalid uniform geometry
PASS closed pipe conservation
PASS profiled pipe conservation
PASS volume pipe sealed conservation
PASS equal pressure hot contact
PASS NASA choked nozzle mass flow
PASS inertance units
PASS moving volume adiabatic law
PASS profile at rest is well balanced
PASS pipe connection all four orientations
PASS split pipe matches unsplit pipe
PASS three volumes shared donor conservation
PASS open boundary reports actual conserved flux both ends
PASS duplicate and invalid boundary rejection
PASS supersonic outlet extrapolates
PASS underdefined supersonic inlet rejected
PASS closed and open acoustic reflection signs
Sod n=100 density L1=0.0233209
Sod n=200 density L1=0.0159539
Sod n=400 density L1=0.0105216
PASS Sod shock tube convergence
PASS strong pulse and near-vacuum rarefaction
Helmholtz frequency=135.6 analytic lumped=138.508
PASS small-signal Helmholtz resonance
PASS invalid volume and timestep rejection
PASS fresh-air species conservation across connection
PASS unsupported unequal junction rejected
PASS unconnected endpoint rejected by solver
closed mode n=50 f=171.897 analytic=171.91
closed mode n=100 f=171.914 analytic=171.91
closed mode n=200 f=171.911 analytic=171.91
PASS closed duct acoustic eigenfrequency
PASS inertance impulse and dissipative resistance
PASS incompatible gas coupling rejected
PASS thermal relaxation matches analytic energy decay
PASS sealed crankcase compression conserves mass above five bar
30/30 passed
<end of output>
Test time = 0.10 sec
----------------------------------------------------------
Test Passed.
"fluidsim_fluid_validation" end time: Oct 23 02:37 CEST
"fluidsim_fluid_validation" time elapsed: 00:00:00
----------------------------------------------------------
3/9 Testing: fluidsim_intake_regression
3/9 Test: fluidsim_intake_regression
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_intake_regression"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_intake_regression" start time: Oct 23 02:37 CEST
Output:
----------------------------------------------------------
Intake regression passed: idle_MAP=35.764 kPa, open_MAP=85.4564 kPa, open_T=298.957 K, inlet_T=296.92 K, recovered_MAP=34.502 kPa, recovered_RPM=1820.05
<end of output>
Test time = 6.26 sec
----------------------------------------------------------
Test Passed.
"fluidsim_intake_regression" end time: Oct 23 02:38 CEST
"fluidsim_intake_regression" time elapsed: 00:00:06
----------------------------------------------------------
4/9 Testing: fluidsim_outdoor_audio_tests
4/9 Test: fluidsim_outdoor_audio_tests
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_outdoor_audio_tests"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_outdoor_audio_tests" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Outdoor audio tests passed: direct=385 samples, ground=463 samples, filtered step ratio=0.155034, stereo lead=7 samples
<end of output>
Test time = 0.02 sec
----------------------------------------------------------
Test Passed.
"fluidsim_outdoor_audio_tests" end time: Oct 23 02:38 CEST
"fluidsim_outdoor_audio_tests" time elapsed: 00:00:00
----------------------------------------------------------
5/9 Testing: fluidsim_two_stroke_regression
5/9 Test: fluidsim_two_stroke_regression
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_two_stroke_regression"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_two_stroke_regression" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Two-stroke regression passed: peak=0.2566, maximum RPM=16127.3, recovered RPM=3158.32, bike speed=61.2948 km/h
<end of output>
Test time = 9.18 sec
----------------------------------------------------------
Test Passed.
"fluidsim_two_stroke_regression" end time: Oct 23 02:38 CEST
"fluidsim_two_stroke_regression" time elapsed: 00:00:09
----------------------------------------------------------
6/9 Testing: fluidsim_two_stroke_physics
6/9 Test: fluidsim_two_stroke_physics
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_two_stroke_physics"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_two_stroke_physics" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Two-stroke physics passed: diffuser reflection=-34.3281 Pa, baffle reflection=27.5234 Pa, first reduction=30.2759
<end of output>
Test time = 0.00 sec
----------------------------------------------------------
Test Passed.
"fluidsim_two_stroke_physics" end time: Oct 23 02:38 CEST
"fluidsim_two_stroke_physics" time elapsed: 00:00:00
----------------------------------------------------------
7/9 Testing: fluidsim_b205_regression
7/9 Test: fluidsim_b205_regression
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_b205_regression"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_b205_regression" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
B205 passed: firing events=33, wagon speed=56.5685 km/h, recovered RPM=1311.5, audio peak=0.186449, wall seconds=5.48769 for 8 simulated seconds
<end of output>
Test time = 5.49 sec
----------------------------------------------------------
Test Passed.
"fluidsim_b205_regression" end time: Oct 23 02:38 CEST
"fluidsim_b205_regression" time elapsed: 00:00:05
----------------------------------------------------------
8/9 Testing: fluidsim_turbo_physics
8/9 Test: fluidsim_turbo_physics
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_turbo_physics"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_turbo_physics" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Closed balance initial_rpm=0 mass_error=0 energy_error=-1.59125e-07 J
Closed balance initial_rpm=120000 mass_error=0 energy_error=-7.09297e-07 J
Turbo pipe bench passed: rpm=189122 compressor flow=0.0306693 kg/s, charge T=375.978 K, turbine power range=1189.38..4022.29 W, residual=-5.44049e-06 J
<end of output>
Test time = 0.31 sec
----------------------------------------------------------
Test Passed.
"fluidsim_turbo_physics" end time: Oct 23 02:38 CEST
"fluidsim_turbo_physics" time elapsed: 00:00:00
----------------------------------------------------------
9/9 Testing: fluidsim_turbo_twin_regression
9/9 Test: fluidsim_turbo_twin_regression
Command: "/home/grillkol/repos/FluidSimCpp/build-audit/fluidsim_turbo_twin_regression"
Directory: /home/grillkol/repos/FluidSimCpp/build-audit
"fluidsim_turbo_twin_regression" start time: Oct 23 02:38 CEST
Output:
----------------------------------------------------------
Turbo twin passed: max_rpm=236218, max_charge=181.458 kPa, max_turbine_pressure=674.103 kPa, gate=2.7762 mm, final_rpm=151754, peak_audio=0.0293228, energy_residual=2.16491e-06 J
<end of output>
Test time = 4.61 sec
----------------------------------------------------------
Test Passed.
"fluidsim_turbo_twin_regression" end time: Oct 23 02:38 CEST
"fluidsim_turbo_twin_regression" time elapsed: 00:00:04
----------------------------------------------------------
End testing: Oct 23 02:38 CEST