#include "FluidSim/ScenarioCatalog.hpp" #include "FluidSim/Scenario.hpp" #include "FluidSim/TwoStrokeScenario.hpp" #include #include #include using namespace fluidsim::port; int main(int argc,char** argv) { const bool sweep=argc>1 && std::string(argv[1])=="--sweep"; const bool check=argc>1 && std::string(argv[1])=="--check"; bool failed=false; int examples_checked=0; std::cout<<"example,pedal,rpm,opening,carb_afr,charge_afr,free_idle_rpm,free_idle_afr,repairs\n"; for(auto e:scenario_examples()) { if(e.kind!=ScenarioKind::TwoStroke && !e.engine.carbureted) continue; if(sweep && argc>2 && e.id!=argv[2]) continue; if(argc>1 && !check && !sweep && e.id!=argv[1]) continue; ++examples_checked; const bool two=e.kind==ScenarioKind::TwoStroke; if(!sweep && argc>2) {float k=std::stof(argv[2]);e.two.pilot_jet_scale*=k;e.engine.fuel.pilot_jet_diameter*=k;} if(!sweep && argc>3) {float k=std::stof(argv[3]);e.two.main_jet_scale*=k;e.engine.fuel.main_jet_diameter*=k;} if(!sweep && argc>4) {float k=std::stof(argv[4]);e.two.needle_jet_scale*=k;e.engine.fuel.needle_jet_diameter*=k;} if(!sweep && argc>5) {float k=std::stof(argv[5]);e.two.idle_slide_opening=k;e.engine.ecu.idle_base_opening=k;} if(!sweep && argc>6) {float k=std::stof(argv[6]);e.two.needle_low_scale*=k;e.engine.fuel.needle_low_scale*=k;} if(!sweep && argc>7) {float k=std::stof(argv[7]);e.two.needle_mid_scale*=k;e.engine.fuel.needle_mid_scale*=k;} for(int index=0;index<((sweep||check)?8:4);++index) { const float pedal=(sweep||check)?std::array{0,.05f,.1f,.15f,.25f,.5f,.75f,1}[index]:std::array{0,.15f,.5f,1}[index]; const int point=pedal==0?0:pedal<.3f?1:pedal<.8f?2:3; const float rpm=two?std::array{3000,4000,6500,9000}[point]: e.engine.cylinders==1?std::array{1400,2500,4000,6000}[point]:std::array{800,1800,3000,5000}[point]; std::unique_ptr t; std::unique_ptr f; if(two) {t=std::make_unique(44100,e.two);t->set_controls(pedal,0,1);} else {f=std::make_unique(44100,e);f->set_controls(pedal,0,1);} double afr=0,charge=0,opening=0;std::uint64_t repairs=0; for(int i=0;i<55125;++i) { if(two) {t->crankshaft.omega=rpm*2*pi/60;t->process();} else {f->crankshaft.omega=rpm*2*pi/60;f->process();} if(i>=44100 && i%10==0) { afr+=(two?t->carburetor.indicated_afr():f->snapshot().target_afr)/1103.; charge+=(two?t->crankcase.mass()*t->crankcase.air_fraction()/std::max(t->crankcase.fuel_mass(),1e-12f):f->intake_plenum.mass()*f->intake_plenum.air_fraction()/std::max(f->intake_plenum.fuel_mass(),1e-12f))/1103.; opening+=(two?t->ecu.throttle_opening():f->ecu.throttle_opening())/1103.; } } if(!std::isfinite(afr) || afr<11.5 || afr>(point==3?14.5:15.5)) { std::cerr<process();else f->process(); if(i>=110250 && i%10==0) free_afr+=(two?t->carburetor.indicated_afr():f->snapshot().target_afr)/2205.; } free_rpm=(two?t->crankshaft.omega:f->crankshaft.omega)*60/(2*pi); } for(const auto& p:two?t->pipes:f->pipes)repairs+=p.positivity_repairs; if(point==0) { float idle_min=3000, idle_max=4000; if(e.id=="fifty") {idle_min=3200;idle_max=4000;} if(e.id=="fivehundred") {idle_min=2800;idle_max=3500;} if(e.id=="single-450") {idle_min=1200;idle_max=1600;} if(e.id=="big-carb") {idle_min=700;idle_max=900;} if(!std::isfinite(free_rpm) || free_rpmidle_max || !std::isfinite(free_afr) || free_afr<11.5 || free_afr>15.5) { std::cerr<1e-6) { if(point==0) {std::cerr<<"two-stroke idle stop did not reach its catalog setting\n";failed=true;} } if(e.id=="single-450" && (!f->cylinder1.transported_fuel || !e.engine.carbureted)) { std::cerr<<"450 single must transport carburetor fuel\n";failed=true; } std::cout<