Improve physical geometry, fluid solvers, audio, and profiling
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include "FluidSim/ScenarioCatalog.hpp"
|
||||
#include "FluidSim/TwoStrokeScenario.hpp"
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
@@ -24,22 +25,21 @@ public:
|
||||
if (!out_)
|
||||
throw std::runtime_error("cannot open WAV: " + path);
|
||||
out_.write("RIFF", 4);
|
||||
integer(36 + frames * 4, 4);
|
||||
integer(36 + frames * 8, 4);
|
||||
out_.write("WAVEfmt ", 8);
|
||||
integer(16, 4);
|
||||
integer(1, 2);
|
||||
integer(3, 2); // IEEE float preserves quiet diagnostic sources.
|
||||
integer(2, 2);
|
||||
integer(44100, 4);
|
||||
integer(44100 * 4, 4);
|
||||
integer(4, 2);
|
||||
integer(16, 2);
|
||||
integer(44100 * 8, 4);
|
||||
integer(8, 2);
|
||||
integer(32, 2);
|
||||
out_.write("data", 4);
|
||||
integer(frames * 4, 4);
|
||||
integer(frames * 8, 4);
|
||||
}
|
||||
void sample(AudioFrame f) {
|
||||
for (float x : {f.left, f.right}) {
|
||||
const auto v = static_cast<std::int16_t>(std::lround(std::clamp(x, -1.f, 1.f) * 32767));
|
||||
integer(static_cast<std::uint16_t>(v), 2);
|
||||
integer(std::bit_cast<std::uint32_t>(x), 4);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -66,7 +66,7 @@ struct Metrics {
|
||||
}
|
||||
};
|
||||
template <class Scenario>
|
||||
void capture(const std::string &prefix, int frames, float pedal, OutdoorScene scene, TwoStrokeConfig config, PipeSolver solver, float fixed_rpm, float warmup, const ScenarioExample* example=nullptr) {
|
||||
void capture(const std::string &prefix, int frames, float pedal, OutdoorScene scene, TwoStrokeConfig config, PipeSolver solver, float fixed_rpm, float warmup, const ScenarioExample* example=nullptr, const std::string& solo="all") {
|
||||
std::unique_ptr<Scenario> s;
|
||||
if constexpr (std::is_same_v<Scenario, TwoStrokeScenario>) s = std::make_unique<Scenario>(44100, config);
|
||||
else if constexpr (std::is_same_v<Scenario, FourStrokeScenario>) {
|
||||
@@ -77,17 +77,34 @@ void capture(const std::string &prefix, int frames, float pedal, OutdoorScene sc
|
||||
s->set_pipe_solver(solver);
|
||||
s->throttle = pedal;
|
||||
s->set_audio_scene(scene);
|
||||
bool valid_solo=solo=="all";
|
||||
for(std::size_t i=0;i<OutdoorAudio::source_names.size();++i) {
|
||||
const bool selected=solo==OutdoorAudio::source_names[i];
|
||||
valid_solo|=selected;
|
||||
s->set_audio_source_enabled(i,solo=="all" || selected);
|
||||
}
|
||||
if(!valid_solo) throw std::runtime_error("choose --solo all, intake, exhaust, exhaust-2, or valve-contact");
|
||||
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;
|
||||
Metrics m, d, r, tail_metrics;
|
||||
std::array<std::unique_ptr<Wav>,4> stems;
|
||||
std::array<Metrics,4> source_metrics;
|
||||
for(std::size_t i=0;i<stems.size();++i)
|
||||
stems[i]=std::make_unique<Wav>(prefix+"-"+OutdoorAudio::source_names[i]+".wav",frames);
|
||||
Wav tail(prefix+"-tail.wav",frames);
|
||||
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();
|
||||
for(std::size_t j=0;j<stems.size();++j) {
|
||||
const auto stem=s->source_audio()[j].rendered;
|
||||
stems[j]->sample(stem); source_metrics[j].add(stem);
|
||||
}
|
||||
tail.sample(s->tail_audio()); tail_metrics.add(s->tail_audio());
|
||||
m.add(f);
|
||||
d.add(df);
|
||||
r.add(rf);
|
||||
@@ -97,16 +114,27 @@ void capture(const std::string &prefix, int frames, float pedal, OutdoorScene sc
|
||||
if (i % 4410 == 0)
|
||||
cuts += s->snapshot().fuel_cut;
|
||||
}
|
||||
for(std::size_t j=0;j<stems.size();++j) source_metrics[j].print(OutdoorAudio::source_names[j]);
|
||||
tail_metrics.print("shared tail");
|
||||
m.print("rendered");
|
||||
d.print("dry filtered");
|
||||
r.print("unfiltered spatial");
|
||||
std::uint64_t repairs=0, fallbacks=0;
|
||||
for(const auto& pipe:s->pipes) { repairs+=pipe.positivity_repairs; fallbacks+=pipe.hllc_fallbacks; }
|
||||
if constexpr (std::is_same_v<Scenario, FourStrokeScenario> || std::is_base_of_v<FourStrokeScenario,Scenario>) {
|
||||
const auto diagnostics=s->snapshot();
|
||||
std::cout<<"junction_model="<<s->junction_config.model<<" junction_fallbacks="<<diagnostics.junction_fallbacks
|
||||
<<" junction_limited_fluxes="<<diagnostics.junction_limited_fluxes<<" junction_iterations="<<diagnostics.junction_iterations<<" limited_fluxes="<<diagnostics.boundary_limited_fluxes<<'\n';
|
||||
}
|
||||
std::cout<<"pipe_positivity_repairs="<<repairs<<" hllc_fallbacks="<<fallbacks<<'\n';
|
||||
std::cout << "fuel-cut checkpoints=" << cuts << " final_rpm=" << s->snapshot().rpm
|
||||
<< " scene=" << scene_name(scene) << '\n';
|
||||
}
|
||||
} // namespace
|
||||
int main(int argc, char **argv) {
|
||||
try {
|
||||
std::string example_id;
|
||||
std::string example_id, solo="all", junction_model;
|
||||
float junction_loss=-1;
|
||||
std::string scenario = "twin", prefix = "build/audio/twin", scene = "wall";
|
||||
float seconds = 6, pedal = 1, fixed_rpm = 0, warmup = 0;
|
||||
TwoStrokeConfig config;
|
||||
@@ -116,7 +144,16 @@ int main(int argc, char **argv) {
|
||||
if (i + 1 >= argc)
|
||||
throw std::runtime_error("missing option value");
|
||||
std::string value = argv[++i];
|
||||
if(key=="--example") example_id=value;
|
||||
if(key=="--junctions") {
|
||||
if(value!="volume" && value!="characteristic" && value!="legacy") throw std::runtime_error("choose volume, characteristic, or legacy junctions");
|
||||
junction_model=value;
|
||||
}
|
||||
else if(key=="--junction-loss") {
|
||||
junction_loss=std::stof(value);
|
||||
if(!std::isfinite(junction_loss) || junction_loss<0 || junction_loss>10) throw std::runtime_error("junction loss must be 0..10");
|
||||
}
|
||||
else if(key=="--solo") solo=value;
|
||||
else if(key=="--example") example_id=value;
|
||||
else if (key == "--scenario")
|
||||
scenario = value;
|
||||
else if (key == "--out")
|
||||
@@ -160,21 +197,30 @@ 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));
|
||||
const auto examples=scenario_examples();
|
||||
auto examples=scenario_examples();
|
||||
if(!junction_model.empty() || junction_loss>=0) {
|
||||
if(example_id.empty()) example_id=scenario=="v8"?"v8-h":scenario=="b205"?"saab-straight":scenario=="twin"?"twin":"yz-racing";
|
||||
for(auto& example:examples) {
|
||||
if(!junction_model.empty()) example.junctions.model=junction_model;
|
||||
if(junction_loss>=0) example.junctions.turning_loss=junction_loss;
|
||||
}
|
||||
}
|
||||
if(!example_id.empty()) {
|
||||
const auto example=std::find_if(examples.begin(),examples.end(),[&](const auto& e){return e.id==example_id;});
|
||||
if(example==examples.end()) throw std::runtime_error("unknown example: "+example_id);
|
||||
if(example->kind==ScenarioKind::TwoStroke && (!junction_model.empty() || junction_loss>=0))
|
||||
throw std::runtime_error("two-stroke exhaust has no configurable pipe junctions");
|
||||
if(example->kind==ScenarioKind::TwoStroke)
|
||||
capture<TwoStrokeScenario>(prefix,frames,pedal,selected,example->two,solver,fixed_rpm,warmup);
|
||||
else capture<FourStrokeScenario>(prefix,frames,pedal,selected,config,solver,fixed_rpm,warmup,&*example);
|
||||
capture<TwoStrokeScenario>(prefix,frames,pedal,selected,example->two,solver,fixed_rpm,warmup,nullptr,solo);
|
||||
else capture<FourStrokeScenario>(prefix,frames,pedal,selected,config,solver,fixed_rpm,warmup,&*example,solo);
|
||||
} else if (scenario == "twin")
|
||||
capture<FourStrokeTwinScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
capture<FourStrokeTwinScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup,nullptr,solo);
|
||||
else if (scenario == "b205")
|
||||
capture<SaabB205Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
capture<SaabB205Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup,nullptr,solo);
|
||||
else if (scenario == "two-stroke")
|
||||
capture<TwoStrokeScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
capture<TwoStrokeScenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup,nullptr,solo);
|
||||
else if (scenario == "v8")
|
||||
capture<AmericanV8Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup);
|
||||
capture<AmericanV8Scenario>(prefix, frames, pedal, selected, config, solver, fixed_rpm, warmup,nullptr,solo);
|
||||
else
|
||||
throw std::runtime_error("choose twin, two-stroke, b205 or v8");
|
||||
} catch (const std::exception &e) {
|
||||
|
||||
Reference in New Issue
Block a user