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

@@ -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");
}