Add machine workshop, typed logic, mechanics and sensor-driven ECUs

This commit is contained in:
max
2026-11-02 07:27:13 +01:00
parent eb2b6366c2
commit abfcce0f46
99 changed files with 28835 additions and 145 deletions

View File

@@ -0,0 +1,41 @@
#include "MachineBench.hpp"
#include "FluidSim/Desktop/MachineBuilder.hpp"
#include "FluidSim/ScenarioCatalog.hpp"
#include <SFML/OpenGL.hpp>
#include <chrono>
#include <iostream>
#include <stdexcept>
using namespace fluidsim::port;
using namespace fluidsim::port::desktop;
int main(int argc,char** argv)try{
const int frames=argc>1?std::stoi(argv[1]):120;
const bool play=argc>2&&std::string(argv[2])=="--play";
const double speed=argc>3?std::stod(argv[3]):1.;
if(!std::isfinite(speed)||speed<.01||speed>1)throw std::invalid_argument("Playback speed must be 0.01..1");
if(frames<1)throw std::invalid_argument("frame count must be positive");
sf::ContextSettings context;context.depthBits=24;context.majorVersion=2;context.minorVersion=1;
sf::RenderWindow window(sf::VideoMode({1440,900}),"Workshop render benchmark",sf::Style::Default,sf::State::Windowed,context);
window.setVisible(false);window.setVerticalSyncEnabled(false);
sf::Font font;bool loaded=false;
for(const auto* path:{"C:/Windows/Fonts/consola.ttf","/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf"})if(std::filesystem::exists(path)&&font.openFromFile(path)){loaded=true;break;}
std::cout<<(play?"scenario,speed,frames,wall_seconds,sim_seconds,sim_per_wall,underruns,buffered\n":"scenario,frames,ms_per_frame,render_fps\n");
for(const char* id:{"flat6","v8-h"}){
MachineBuilder builder;auto design=machine_from_engine(scenario_example(id));if(play){bench::set_rpm(design,3000);unsigned cylinder=0,pipe=0;for(const auto& p:design.parts){if(!cylinder&&p.kind==MachinePartKind::Cylinder)cylinder=p.id;if(p.name=="Exhaust atmosphere")for(const auto& link:design.links){const auto other=link.a.part==p.id?link.b.part:link.b.part==p.id?link.a.part:0;if(const auto part=design.find(other);part&&part->kind==MachinePartKind::Pipe)pipe=other;}}
design.probes={{1,cylinder,"Cylinder pressure",MachineQuantity::Pressure},{2,pipe,"Downpipe lambda",MachineQuantity::Lambda},{3,cylinder,"Fresh charge",MachineQuantity::ChargeAfr},{4,pipe,"Downpipe AFR",MachineQuantity::AirFuelRatio},{5,pipe,"Downpipe flow",MachineQuantity::MassFlow},{6,0,"Shaft RPM",MachineQuantity::Rpm},{7,0,"Shaft torque",MachineQuantity::Torque},{8,0,"Shaft power",MachineQuantity::Power}};}
builder.set_document(std::move(design));builder.set_test_speed(speed);
if(play){window.setFramerateLimit(60);builder.start_test();if(!builder.testing())throw std::runtime_error("Could not start workshop playback");builder.handle_event(sf::Event::KeyPressed{.code=sf::Keyboard::Key::M},window.getSize());
for(int i=0;i<16;++i){builder.update();builder.draw(window,loaded?&font:nullptr);window.display();}
const auto before=builder.playback_stats();const auto begin=std::chrono::steady_clock::now();
for(int i=0;i<frames;++i){builder.update();if(!builder.testing())throw std::runtime_error("Workshop playback stopped");builder.draw(window,loaded?&font:nullptr);window.display();}
builder.update();const auto after=builder.playback_stats();const auto wall=std::chrono::duration<double>(std::chrono::steady_clock::now()-begin).count();
std::cout<<id<<','<<speed<<','<<frames<<','<<wall<<','<<after.simulation_seconds-before.simulation_seconds<<','<<(after.simulation_seconds-before.simulation_seconds)/wall<<','<<after.underruns-before.underruns<<','<<after.buffered<<std::endl;
builder.stop_test();continue;
}
for(int i=0;i<8;++i){builder.draw(window,loaded?&font:nullptr);glFinish();}
const auto begin=std::chrono::steady_clock::now();
for(int i=0;i<frames;++i){builder.draw(window,loaded?&font:nullptr);glFinish();}
const auto elapsed=std::chrono::duration<double>(std::chrono::steady_clock::now()-begin).count();
std::cout<<id<<','<<frames<<','<<elapsed*1000/frames<<','<<frames/elapsed<<std::endl;
}
return 0;
}catch(const std::exception& error){std::cerr<<error.what()<<'\n';return 1;}