diff --git a/CMakeLists.txt b/CMakeLists.txt index 07f65ff..e75df6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/README.md b/README.md index 6f66abb..df3eb70 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/include/FluidSim/DesktopScenario.hpp b/include/FluidSim/DesktopScenario.hpp index 009991d..3e9fd4c 100644 --- a/include/FluidSim/DesktopScenario.hpp +++ b/include/FluidSim/DesktopScenario.hpp @@ -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(44100, config); else twin_ = std::make_unique(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_) diff --git a/include/FluidSim/Ecu.hpp b/include/FluidSim/Ecu.hpp index 01c6a24..61b3f1e 100644 --- a/include/FluidSim/Ecu.hpp +++ b/include/FluidSim/Ecu.hpp @@ -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}; diff --git a/include/FluidSim/Fluid.hpp b/include/FluidSim/Fluid.hpp index 880a897..2064d01 100644 --- a/include/FluidSim/Fluid.hpp +++ b/include/FluidSim/Fluid.hpp @@ -189,10 +189,14 @@ public: float dt = std::numeric_limits::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::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::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(nozzle_flow(duct_pressure)); const bool upstream_port = mdot >= 0; const float pup = upstream_port ? v.pressure : static_cast(duct_pressure); diff --git a/include/FluidSim/Scenario.hpp b/include/FluidSim/Scenario.hpp index fed1c79..8929162 100644 --- a/include/FluidSim/Scenario.hpp +++ b/include/FluidSim/Scenario.hpp @@ -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 diff --git a/include/FluidSim/Turbocharger.hpp b/include/FluidSim/Turbocharger.hpp index 3998eeb..0912dfd 100644 --- a/include/FluidSim/Turbocharger.hpp +++ b/include/FluidSim/Turbocharger.hpp @@ -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 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, diff --git a/src/desktop_main.cpp b/src/desktop_main.cpp index 79cc543..4735804 100644 --- a/src/desktop_main.cpp +++ b/src/desktop_main.cpp @@ -63,7 +63,7 @@ std::optional choose_scenario(sf::RenderWindow& window, const sf:: const std::array 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 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; } diff --git a/src/main.cpp b/src/main.cpp index 9bb3d65..263aecc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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(duration_seconds * sample_rate); const auto report_interval = static_cast(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(); diff --git a/src/scenario.cpp b/src/scenario.cpp index b35e4e8..8e3e95e 100644 --- a/src/scenario.cpp +++ b/src/scenario.cpp @@ -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(); + turbo = std::make_unique(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 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 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); diff --git a/src/turbocharger.cpp b/src/turbocharger.cpp index 4651d39..5848709 100644 --- a/src/turbocharger.cpp +++ b/src/turbocharger.cpp @@ -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)* diff --git a/tests/fluid_validation.cpp b/tests/fluid_validation.cpp index 774ccd0..0be24ff 100644 --- a/tests/fluid_validation.cpp +++ b/tests/fluid_validation.cpp @@ -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::min() ? 0 : fraction, + fraction * 1e-6, "normal tracer concentration changed"); + } + } + }); test("invalid uniform geometry", [] { bool caught = false; try { diff --git a/tests/saab_turbo_regression.cpp b/tests/saab_turbo_regression.cpp new file mode 100644 index 0000000..8ec1563 --- /dev/null +++ b/tests/saab_turbo_regression.cpp @@ -0,0 +1,46 @@ +#include "FluidSim/Scenario.hpp" +#include +#include +#include +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<snapshot().rpm= 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(prefix, frames, pedal, selected, config); else if (scenario == "twin") capture(prefix, frames, pedal, selected, config); + else if (scenario == "b205" && turbo_enabled) + capture(prefix, frames, pedal, selected, config); else if (scenario == "b205") capture(prefix, frames, pedal, selected, config); else if (scenario == "two-stroke") diff --git a/tools/scenario_benchmark.cpp b/tools/scenario_benchmark.cpp new file mode 100644 index 0000000..b4efe38 --- /dev/null +++ b/tools/scenario_benchmark.cpp @@ -0,0 +1,75 @@ +#include "FluidSim/Scenario.hpp" +#include "FluidSim/TwoStrokeScenario.hpp" +#include "FluidSim/HelmholtzScenario.hpp" +#include "FluidSim/PulseTestScenario.hpp" +#include +#include +#include +#include +using namespace fluidsim::port; +template 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(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(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){}); + } +} diff --git a/tools/thread_benchmark.cpp b/tools/thread_benchmark.cpp index 92c9f97..c93a5a6 100644 --- a/tools/thread_benchmark.cpp +++ b/tools/thread_benchmark.cpp @@ -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 #include #include #include 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 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 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(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(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'; } } diff --git a/verification/OPTIMIZATION.md b/verification/OPTIMIZATION.md new file mode 100644 index 0000000..d56cdab --- /dev/null +++ b/verification/OPTIMIZATION.md @@ -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/`. diff --git a/verification/SAAB_GT17.md b/verification/SAAB_GT17.md new file mode 100644 index 0000000..1e031f7 --- /dev/null +++ b/verification/SAAB_GT17.md @@ -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. diff --git a/verification/TURBO_VZ21.md b/verification/TURBO_VZ21.md index ffa8f22..9ecf460 100644 --- a/verification/TURBO_VZ21.md +++ b/verification/TURBO_VZ21.md @@ -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 diff --git a/verification/optimization/baseline-loaded-diagnostics.txt b/verification/optimization/baseline-loaded-diagnostics.txt new file mode 100644 index 0000000..a057c2a --- /dev/null +++ b/verification/optimization/baseline-loaded-diagnostics.txt @@ -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 diff --git a/verification/optimization/baseline-loaded.csv b/verification/optimization/baseline-loaded.csv new file mode 100644 index 0000000..c8b04e3 --- /dev/null +++ b/verification/optimization/baseline-loaded.csv @@ -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 diff --git a/verification/optimization/final-idle.csv b/verification/optimization/final-idle.csv new file mode 100644 index 0000000..8402df2 --- /dev/null +++ b/verification/optimization/final-idle.csv @@ -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 diff --git a/verification/optimization/final-loaded-diagnostics.txt b/verification/optimization/final-loaded-diagnostics.txt new file mode 100644 index 0000000..f3d6e88 --- /dev/null +++ b/verification/optimization/final-loaded-diagnostics.txt @@ -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 diff --git a/verification/optimization/final-loaded.csv b/verification/optimization/final-loaded.csv new file mode 100644 index 0000000..9c49c70 --- /dev/null +++ b/verification/optimization/final-loaded.csv @@ -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 diff --git a/verification/optimization/final-native-loaded.csv b/verification/optimization/final-native-loaded.csv new file mode 100644 index 0000000..e869d58 --- /dev/null +++ b/verification/optimization/final-native-loaded.csv @@ -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 diff --git a/verification/optimization/final-scalar-loaded.csv b/verification/optimization/final-scalar-loaded.csv new file mode 100644 index 0000000..86f95d8 --- /dev/null +++ b/verification/optimization/final-scalar-loaded.csv @@ -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 diff --git a/verification/optimization/final-threads.txt b/verification/optimization/final-threads.txt new file mode 100644 index 0000000..326f618 --- /dev/null +++ b/verification/optimization/final-threads.txt @@ -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 diff --git a/verification/optimization/final-transient.csv b/verification/optimization/final-transient.csv new file mode 100644 index 0000000..9b257cd --- /dev/null +++ b/verification/optimization/final-transient.csv @@ -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 diff --git a/verification/optimization/scalar-tests.log b/verification/optimization/scalar-tests.log new file mode 100644 index 0000000..c5ca1b2 --- /dev/null +++ b/verification/optimization/scalar-tests.log @@ -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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 diff --git a/verification/optimization/simd-tests.log b/verification/optimization/simd-tests.log new file mode 100644 index 0000000..c830ad8 --- /dev/null +++ b/verification/optimization/simd-tests.log @@ -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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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