all of the changes
This commit is contained in:
@@ -65,17 +65,23 @@ struct Metrics {
|
||||
}
|
||||
};
|
||||
template <class Scenario>
|
||||
void capture(const std::string &prefix, int frames, float pedal, OutdoorScene scene, TwoStrokeConfig config) {
|
||||
void capture(const std::string &prefix, int frames, float pedal, OutdoorScene scene, TwoStrokeConfig config, PipeSolver solver, float fixed_rpm, float warmup) {
|
||||
std::unique_ptr<Scenario> s;
|
||||
if constexpr (std::is_same_v<Scenario, TwoStrokeScenario>) s = std::make_unique<Scenario>(44100, config);
|
||||
else s = std::make_unique<Scenario>();
|
||||
s->set_pipe_solver(solver);
|
||||
s->throttle = pedal;
|
||||
s->set_audio_scene(scene);
|
||||
for(int i=0; i<int(std::lround(warmup*44100)); ++i) {
|
||||
if(fixed_rpm>0) s->crankshaft.omega=fixed_rpm*2*pi/60;
|
||||
s->process();
|
||||
}
|
||||
Wav rendered(prefix + "-rendered.wav", frames), dry(prefix + "-dry.wav", frames),
|
||||
raw(prefix + "-unfiltered.wav", frames);
|
||||
Metrics m, d, r;
|
||||
int cuts = 0;
|
||||
for (int i = 0; i < frames; i++) {
|
||||
if(fixed_rpm>0) s->crankshaft.omega=fixed_rpm*2*pi/60;
|
||||
auto f = s->process(), df = s->dry_audio(), rf = s->unfiltered_audio();
|
||||
m.add(f);
|
||||
d.add(df);
|
||||
@@ -96,10 +102,9 @@ void capture(const std::string &prefix, int frames, float pedal, OutdoorScene sc
|
||||
int main(int argc, char **argv) {
|
||||
try {
|
||||
std::string scenario = "twin", prefix = "build/audio/twin", scene = "wall";
|
||||
float seconds = 6, pedal = 1;
|
||||
float seconds = 6, pedal = 1, fixed_rpm = 0, warmup = 0;
|
||||
TwoStrokeConfig config;
|
||||
bool turbo_enabled = false;
|
||||
std::string turbo_name;
|
||||
PipeSolver solver=PipeSolver::Rusanov;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string key = argv[i];
|
||||
if (i + 1 >= argc)
|
||||
@@ -113,11 +118,9 @@ int main(int argc, char **argv) {
|
||||
seconds = std::stof(value);
|
||||
else if (key == "--throttle")
|
||||
pedal = std::stof(value);
|
||||
else if (key == "--turbo") {
|
||||
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 == "--warmup") warmup=std::stof(value);
|
||||
else if (key == "--rpm") fixed_rpm=std::stof(value);
|
||||
else if (key == "--solver") solver=parse_pipe_solver(value);
|
||||
else if (key == "--exhaust") {
|
||||
if (value == "racing") config.exhaust = TwoStrokeExhaust::Racing;
|
||||
else if (value == "straight") config.exhaust = TwoStrokeExhaust::Straight;
|
||||
@@ -131,6 +134,9 @@ int main(int argc, char **argv) {
|
||||
if (!std::isfinite(seconds) || seconds <= 0 || seconds > 600 || !std::isfinite(pedal) || pedal < 0 ||
|
||||
pedal > 1)
|
||||
throw std::runtime_error("invalid capture duration or throttle");
|
||||
if(!std::isfinite(fixed_rpm) || fixed_rpm<0 || fixed_rpm>30000)
|
||||
throw std::runtime_error("invalid capture RPM");
|
||||
if(!std::isfinite(warmup) || warmup<0 || warmup>600) throw std::runtime_error("invalid warmup");
|
||||
OutdoorScene selected;
|
||||
if (scene == "dry")
|
||||
selected = OutdoorScene::Dry;
|
||||
@@ -140,27 +146,21 @@ int main(int argc, char **argv) {
|
||||
selected = OutdoorScene::Wall;
|
||||
else if (scene == "woodland")
|
||||
selected = OutdoorScene::Woodland;
|
||||
else if (scene == "tunnel")
|
||||
selected = OutdoorScene::Tunnel;
|
||||
else
|
||||
throw std::runtime_error("invalid scene");
|
||||
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_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);
|
||||
if (scenario == "twin")
|
||||
capture<FourStrokeTwinScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
else if (scenario == "b205")
|
||||
capture<SaabB205Scenario>(prefix, frames, pedal, selected, config);
|
||||
capture<SaabB205Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
else if (scenario == "two-stroke")
|
||||
capture<TwoStrokeScenario>(prefix, frames, pedal, selected, config);
|
||||
capture<TwoStrokeScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
else if (scenario == "v8")
|
||||
capture<AmericanV8Scenario>(prefix, frames, pedal, selected, config);
|
||||
capture<AmericanV8Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
else
|
||||
throw std::runtime_error("choose twin, two-stroke, b205 or v8");
|
||||
} catch (const std::exception &e) {
|
||||
|
||||
@@ -2,12 +2,31 @@
|
||||
#include "FluidSim/TwoStrokeScenario.hpp"
|
||||
#include "FluidSim/HelmholtzScenario.hpp"
|
||||
#include "FluidSim/PulseTestScenario.hpp"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace fluidsim::port;
|
||||
static void set_uniform_pipe_resolution(std::vector<Pipe1D>& pipes, int cells_per_meter) {
|
||||
if (cells_per_meter <= 0) throw std::invalid_argument("cells per meter must be positive");
|
||||
for (auto& pipe : pipes) {
|
||||
const float length = std::accumulate(pipe.cell_lengths.begin(), pipe.cell_lengths.end(), 0.0f);
|
||||
const float damping = pipe.damping_multiplier;
|
||||
const float relaxation = pipe.energy_relaxation_rate;
|
||||
const float ambient = pipe.ambient_pressure;
|
||||
const int count = std::max(1, static_cast<int>(std::ceil(length * cells_per_meter)));
|
||||
pipe = Pipe1D(pipe.area, length, count);
|
||||
pipe.damping_multiplier = damping;
|
||||
pipe.energy_relaxation_rate = relaxation;
|
||||
pipe.ambient_pressure = ambient;
|
||||
}
|
||||
}
|
||||
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;
|
||||
@@ -30,6 +49,10 @@ template<class S, class Control> void run(const char* name, S& s, int seconds, C
|
||||
std::cout << name << ',' << second+1 << ',' << elapsed << ',' << checksum << std::endl;
|
||||
if constexpr (requires { s.pipes; }) {
|
||||
unsigned tiny = 0;
|
||||
std::uint64_t repairs=0, fallbacks=0;
|
||||
for(const auto& pipe:s.pipes) { repairs+=pipe.positivity_repairs; fallbacks+=pipe.hllc_fallbacks; }
|
||||
if(repairs) throw std::runtime_error("benchmark required pipe positivity repairs");
|
||||
std::cerr<<name<<" repairs="<<repairs<<" hllc_fallbacks="<<fallbacks<<" peak="<<peak<<"\n";
|
||||
for (const auto& pipe : s.pipes)
|
||||
for (const auto& cell : pipe.cells)
|
||||
for (float value : {cell.rho, cell.momentum, cell.energy, cell.air})
|
||||
@@ -49,10 +72,10 @@ template<class S, class Control> void run(const char* name, S& s, int seconds, C
|
||||
std::cerr << name << " substeps_per_frame=" << (state.solver_substeps-previous_substeps)/44100.0
|
||||
<< " limiting_pipe=" << limiting_pipe << " cfl_us=" << stable_dt*1e6f << '\n';
|
||||
previous_substeps = state.solver_substeps;
|
||||
unsigned long long repairs = 0;
|
||||
for (const auto& pipe : s.pipes) repairs += pipe.positivity_repairs;
|
||||
unsigned long long repairs = 0, fallbacks = 0;
|
||||
for (const auto& pipe : s.pipes) { repairs += pipe.positivity_repairs; fallbacks += pipe.hllc_fallbacks; }
|
||||
std::cerr << name << " rpm=" << state.rpm << " power_kW=" << state.average_power/1000
|
||||
<< " peak=" << peak << " pipe_repairs=" << repairs << '\n';
|
||||
<< " peak=" << peak << " hllc_fallbacks=" << fallbacks << " pipe_repairs=" << repairs << '\n';
|
||||
previous_iterations = state.boundary_iterations;
|
||||
}
|
||||
}
|
||||
@@ -61,20 +84,27 @@ 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";
|
||||
const int uniform_v8_cells_per_meter = argc > 4 ? std::stoi(argv[4]) : 0;
|
||||
const auto selected_solver=argc>5 ? parse_pipe_solver(argv[5]) : PipeSolver::Rusanov;
|
||||
std::cerr << "solver=" << pipe_solver_name(selected_solver) << "\n";
|
||||
auto pedal = [&](int second) {
|
||||
return mode == "idle" ? 0.0f : mode == "coast" ? (second >= 1 && second < 5 ? .7f : 0.f) :
|
||||
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", "v8"}) {
|
||||
for (auto name : {"twin", "b205", "v8"}) {
|
||||
if (only != "all" && only != name) continue;
|
||||
auto s = std::make_unique<FourStrokeScenario>(44100,
|
||||
std::string(name)=="v8" ? FourStrokePreset::AmericanV8 : std::string(name).starts_with("b205") ? FourStrokePreset::SaabB205 : FourStrokePreset::Twin,
|
||||
std::string(name)=="turbo" || std::string(name)=="b205-gt17");
|
||||
std::string(name)=="v8" ? FourStrokePreset::AmericanV8 : std::string(name)=="b205" ? FourStrokePreset::SaabB205 : FourStrokePreset::Twin);
|
||||
if (std::string(name) == "v8" && uniform_v8_cells_per_meter > 0) {
|
||||
set_uniform_pipe_resolution(s->pipes, uniform_v8_cells_per_meter);
|
||||
std::cerr << "v8 uniform_cells_per_meter=" << uniform_v8_cells_per_meter << '\n';
|
||||
}
|
||||
s->set_pipe_solver(selected_solver);
|
||||
s->throttle = .7f;
|
||||
run(name, *s, seconds, [&](int second) {
|
||||
s->throttle = pedal(second);
|
||||
if (mode == "loaded") s->crankshaft.omega = (std::string(name)=="v8" ? 4500 : std::string(name)=="b205-gt17" ? 5500 : 7000) * 2*pi/60;
|
||||
if (mode == "loaded") s->crankshaft.omega = (std::string(name)=="v8" ? 4500 : 7000) * 2*pi/60;
|
||||
});
|
||||
}
|
||||
for (bool racing : {true, false}) {
|
||||
@@ -82,6 +112,7 @@ int main(int argc, char** argv) {
|
||||
TwoStrokeConfig config;
|
||||
config.exhaust = racing ? TwoStrokeExhaust::Racing : TwoStrokeExhaust::Straight;
|
||||
TwoStrokeScenario s(44100, config);
|
||||
s.set_pipe_solver(selected_solver);
|
||||
s.set_throttle(.7f);
|
||||
run(racing ? "two-stroke-racing" : "two-stroke-straight", s, seconds, [&](int second) {
|
||||
s.set_throttle(pedal(second));
|
||||
|
||||
@@ -3,13 +3,31 @@
|
||||
#include "FluidSim/TwoStrokeScenario.hpp"
|
||||
#include "FluidSim/HelmholtzScenario.hpp"
|
||||
#include "FluidSim/PulseTestScenario.hpp"
|
||||
#include <algorithm>
|
||||
#include <barrier>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
using namespace fluidsim::port;
|
||||
int main() {
|
||||
for (std::string name : {"twin", "turbo", "b205", "two-stroke-racing", "two-stroke-straight", "helmholtz", "pulse", "large"}) {
|
||||
static void set_uniform_resolution(std::vector<Pipe1D>& pipes, int cells_per_meter) {
|
||||
if (cells_per_meter <= 0) throw std::invalid_argument("cells per meter must be positive");
|
||||
for (auto& pipe : pipes) {
|
||||
const float length = std::accumulate(pipe.cell_lengths.begin(), pipe.cell_lengths.end(), 0.0f);
|
||||
const int count = std::max(1, static_cast<int>(std::ceil(length * cells_per_meter)));
|
||||
const float damping = pipe.damping_multiplier;
|
||||
const float relaxation = pipe.energy_relaxation_rate;
|
||||
pipe = Pipe1D(pipe.area, length, count);
|
||||
pipe.damping_multiplier = damping;
|
||||
pipe.energy_relaxation_rate = relaxation;
|
||||
}
|
||||
}
|
||||
int main(int argc, char** argv) {
|
||||
const int uniform_cells_per_meter = argc > 1 ? std::stoi(argv[1]) : 0;
|
||||
for (std::string name : {"twin", "b205", "v8", "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);
|
||||
@@ -22,9 +40,11 @@ int main() {
|
||||
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");
|
||||
FourStrokeScenario s(44100, name == "v8" ? FourStrokePreset::AmericanV8 : name == "b205" ? FourStrokePreset::SaabB205 : FourStrokePreset::Twin);
|
||||
geometry = s.pipes;
|
||||
}
|
||||
if (name == "v8" && uniform_cells_per_meter > 0)
|
||||
set_uniform_resolution(geometry, uniform_cells_per_meter);
|
||||
const int steps = 4000;
|
||||
for (int workers : {1, 2, 4}) {
|
||||
auto p = geometry;
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "FluidSim/Scenario.hpp"
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
using namespace fluidsim::port;
|
||||
int main() {
|
||||
std::cout << "engine_rpm,turbo,MAP_kPa,exhaust_kPa,shaft_kW,turbo_rpm,charge_kPa,charge_K,turbine_power_ripple_W,gate_mm,limited,energy_residual_J,substeps_per_frame,iterations_per_frame,wall_s,cpu_s\n";
|
||||
for (float rpm : {4000.f, 7000.f}) {
|
||||
for (bool enabled : {false, true}) {
|
||||
FourStrokeScenario s(44100, FourStrokePreset::Twin, enabled);
|
||||
s.throttle = .7f;
|
||||
double map = 0, exhaust = 0, power = 0, turbo_rpm = 0, charge_p = 0, charge_t = 0, gate = 0;
|
||||
double min_power = 1e30, max_power = -1e30;
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
const auto cpu_start = std::clock();
|
||||
for (int i = 0; i < 2*44100; ++i) {
|
||||
// Ideal speed-holding dyno. The turbo remains completely free.
|
||||
s.crankshaft.omega = rpm*2*pi/60;
|
||||
s.process();
|
||||
if (i >= 3*44100/2) {
|
||||
constexpr double samples = 22050;
|
||||
map += s.intake_plenum.pressure()/samples/1000;
|
||||
exhaust += s.exhaust_collector.pressure()/samples/1000;
|
||||
power += s.crankshaft.average_power/samples/1000;
|
||||
if (s.turbo) {
|
||||
const auto t = s.turbo->snapshot();
|
||||
turbo_rpm += t.rpm/samples;
|
||||
charge_p += t.charge_pressure/samples/1000;
|
||||
charge_t += t.charge_temperature/samples;
|
||||
gate += t.wastegate_lift/samples*1000;
|
||||
min_power = std::min(min_power, t.turbine_power);
|
||||
max_power = std::max(max_power, t.turbine_power);
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto t = s.turbo ? s.turbo->snapshot() : TurboSnapshot{};
|
||||
const auto state = s.snapshot();
|
||||
const double cpu = double(std::clock()-cpu_start)/CLOCKS_PER_SEC;
|
||||
const auto wall = std::chrono::duration<double>(std::chrono::steady_clock::now()-start).count();
|
||||
std::cout << rpm << ',' << enabled << ',' << map << ',' << exhaust << ',' << power << ','
|
||||
<< turbo_rpm << ',' << charge_p << ',' << charge_t << ','
|
||||
<< (enabled ? max_power-min_power : 0) << ',' << gate << ',' << t.limited_transfers
|
||||
<< ',' << t.energy_residual << ',' << state.solver_substeps/88200.0 << ','
|
||||
<< state.boundary_iterations/88200.0 << ',' << wall << ',' << cpu << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user