Skip to content

Commit

Permalink
app: make live modeling enable
Browse files Browse the repository at this point in the history
  • Loading branch information
quesnel committed Jun 28, 2024
1 parent 50dfae6 commit cabee69
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 82 deletions.
23 changes: 12 additions & 11 deletions app/gui/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
namespace irt {

template<class T, class M>
constexpr std::ptrdiff_t offset_of(const M T::* member)
constexpr std::ptrdiff_t offset_of(const M T::*member)
{
return reinterpret_cast<std::ptrdiff_t>(
&(reinterpret_cast<T*>(0)->*member));
Expand All @@ -44,7 +44,7 @@ constexpr std::ptrdiff_t offset_of(const M T::* member)
//! }
//! @endcode
template<class T, class M>
constexpr T& container_of(M* ptr, const M T::* member)
constexpr T& container_of(M* ptr, const M T::*member)
{
return *reinterpret_cast<T*>(reinterpret_cast<intptr_t>(ptr) -
offset_of(member));
Expand Down Expand Up @@ -520,9 +520,6 @@ struct simulation_editor {

enum class visualization_mode { flat, tree };

//! 0.1s between each run thread task.
static constexpr i64 thread_frame_duration = 100000;

simulation_editor() noexcept;
~simulation_editor() noexcept;

Expand Down Expand Up @@ -579,13 +576,17 @@ struct simulation_editor {

timeline tl;

real simulation_begin = 0;
real simulation_end = 100;
real simulation_current = 0;
real simulation_begin = 0;
real simulation_end = 100;
real simulation_current = 0;
real simulation_display_current = 0;

/** Number of microsecond to run 1 unit of simulation time. The default is
* to run 1 unit of simulation per second. */
i64 nb_microsecond_per_simulation_time = 1000000;

//! Number of microsecond to run 1 unit of simulation time
//! Default 1 unit of simulation in 1 second.
i64 simulation_real_time_relation = 1000000;
/** Simulation duraction between each run task. The default is 100ms. */
static inline constexpr i64 thread_frame_duration = 100000;

tree_node_id head = undefined<tree_node_id>();
tree_node_id current = undefined<tree_node_id>();
Expand Down
144 changes: 83 additions & 61 deletions app/gui/simulation-component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,40 @@ static status run(simulation_editor& sim_ed) noexcept
return success();
}

static status debug_live_run(simulation_editor& sim_ed) noexcept
{
auto& app = container_of(&sim_ed, &application::simulation_ed);

if (auto ret = run(sim_ed.tl, app.sim, sim_ed.simulation_current); !ret) {
app.notifications.try_insert(
log_level::error, [&](auto& title, auto& msg) {
title = "Live debug run error";
msg = "Error during the simulation bag run";
});
sim_ed.simulation_state = simulation_status::finish_requiring;
return ret.error();
}

return success();
}

static status live_run(simulation_editor& sim_ed) noexcept
{
auto& app = container_of(&sim_ed, &application::simulation_ed);

if (auto ret = app.sim.run(sim_ed.simulation_current); !ret) {
app.notifications.try_insert(
log_level::error, [&](auto& title, auto& msg) {
title = "Live run error";
msg = "Error during the simulation bag run";
});
sim_ed.simulation_state = simulation_status::finish_requiring;
return ret.error();
}

return success();
}

void simulation_editor::start_simulation_static_run() noexcept
{
auto& app = container_of(this, &application::simulation_ed);
Expand Down Expand Up @@ -246,88 +280,76 @@ void simulation_editor::start_simulation_live_run() noexcept
{
auto& app = container_of(this, &application::simulation_ed);

app.add_simulation_task([&app]() noexcept {
app.simulation_ed.simulation_state = simulation_status::running;
namespace stdc = std::chrono;
namespace stdc = std::chrono;

app.add_simulation_task([&]() noexcept {
if (force_pause) {
force_pause = false;
simulation_state = simulation_status::pause_forced;
return;
} else if (force_stop) {
force_stop = false;
simulation_state = simulation_status::finish_requiring;
return;
}

const auto max_sim_duration =
static_cast<real>(simulation_editor::thread_frame_duration) /
static_cast<real>(app.simulation_ed.simulation_real_time_relation);
constexpr stdc::microseconds thread_frame_duration_ms(
thread_frame_duration);

const auto sim_start_at = app.simulation_ed.simulation_current;
auto start_at = stdc::high_resolution_clock::now();
auto end_at = stdc::high_resolution_clock::now();
auto duration = end_at - start_at;
const auto sim_max_duration =
static_cast<time>(thread_frame_duration) /
static_cast<time>(nb_microsecond_per_simulation_time);

auto duration_cast = stdc::duration_cast<stdc::microseconds>(duration);
auto duration_since_start = duration_cast.count();
simulation_state = simulation_status::running;

bool stop_or_pause;
const auto sim_start_at = simulation_current;
auto sim_duration = 0.;
const auto start_at = stdc::high_resolution_clock::now();
auto duration = stdc::high_resolution_clock::now() - start_at;

do {
if (app.simulation_ed.simulation_state !=
simulation_status::running)
while (duration < thread_frame_duration_ms) {
if (simulation_state != simulation_status::running)
return;

if (app.simulation_ed.store_all_changes) {
if (auto ret = debug_run(app.simulation_ed); !ret) {
app.simulation_ed.simulation_state =
simulation_status::finish_requiring;
if (store_all_changes) {
if (auto ret = debug_live_run(app.simulation_ed); !ret) {
simulation_state = simulation_status::finish_requiring;
return;
}
} else {
if (auto ret = run(app.simulation_ed); !ret) {
app.simulation_ed.simulation_state =
simulation_status::finish_requiring;
if (auto ret = live_run(app.simulation_ed); !ret) {
simulation_state = simulation_status::finish_requiring;
return;
}
}

if (!app.sim.immediate_observers.empty())
app.simulation_ed.start_simulation_observation();

const auto sim_end_at = app.simulation_ed.simulation_current;
const auto sim_duration = sim_end_at - sim_start_at;

if (!app.simulation_ed.infinity_simulation &&
app.simulation_ed.simulation_current >=
app.simulation_ed.simulation_end) {
app.simulation_ed.simulation_current =
app.simulation_ed.simulation_end;
app.simulation_ed.simulation_state =
simulation_status::finish_requiring;
return;
}
start_simulation_observation();

end_at = stdc::high_resolution_clock::now();
duration = end_at - start_at;
duration_cast = stdc::duration_cast<stdc::microseconds>(duration);
duration_since_start = duration_cast.count();
duration = stdc::high_resolution_clock::now() - start_at;
sim_duration = app.simulation_ed.simulation_current - sim_start_at;

if (sim_duration > max_sim_duration) {
auto remaining =
stdc::microseconds(simulation_editor::thread_frame_duration) -
duration_cast;
if (time_domain<time>::is_infinity(sim_duration)) {
const auto remaining =
stdc::microseconds(thread_frame_duration) - duration;
if (remaining > stdc::nanoseconds::zero()) {
std::this_thread::sleep_for(remaining);
duration = thread_frame_duration_ms;
}

std::this_thread::sleep_for(remaining);
simulation_current = sim_start_at + sim_max_duration;
simulation_display_current = simulation_current;
}

stop_or_pause =
app.simulation_ed.force_pause || app.simulation_ed.force_stop;
} while (!stop_or_pause && duration_since_start <
app.simulation_ed.thread_frame_duration);

if (app.simulation_ed.force_pause) {
app.simulation_ed.force_pause = false;
app.simulation_ed.simulation_state =
simulation_status::pause_forced;
} else if (app.simulation_ed.force_stop) {
app.simulation_ed.force_stop = false;
app.simulation_ed.simulation_state =
simulation_status::finish_requiring;
} else {
app.simulation_ed.simulation_state = simulation_status::paused;
if (simulation_current >= simulation_end) {
simulation_current = simulation_end;
simulation_display_current = simulation_current;
simulation_state = simulation_status::finish_requiring;
return;
}
}

app.simulation_ed.simulation_state = simulation_status::paused;
});
}

Expand Down
25 changes: 15 additions & 10 deletions app/gui/simulation-editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,12 @@ void simulation_editor::clear() noexcept

tl.reset();

simulation_begin = 0;
simulation_end = 100;
simulation_current = 0;
simulation_begin = 0;
simulation_end = 100;
simulation_current = 0;
simulation_display_current = 0;

simulation_real_time_relation = 1000000;
nb_microsecond_per_simulation_time = 1000000;

head = undefined<tree_node_id>();
current = undefined<tree_node_id>();
Expand Down Expand Up @@ -209,7 +210,7 @@ static void show_simulation_action_buttons(simulation_editor& ed,
ed.start_simulation_advance();
ImGui::EndDisabled();

ImGui::TextFormat("Current time {:.6f}", ed.simulation_current);
ImGui::TextFormat("Current time {:.6f}", ed.simulation_display_current);

ImGui::SameLine();

Expand Down Expand Up @@ -240,7 +241,10 @@ static bool show_project_simulation_settings(application& app) noexcept
is_modified +=
ImGui::Checkbox("Edit", &app.simulation_ed.allow_user_changes);

ImGui::BeginDisabled(app.simulation_ed.infinity_simulation);
is_modified += ImGui::InputReal("End", &app.simulation_ed.simulation_end);
ImGui::EndDisabled();

ImGui::SameLine(ImGui::GetContentRegionAvail().x * 0.5f);
if (ImGui::Checkbox("Debug", &app.simulation_ed.store_all_changes)) {
is_modified = true;
Expand All @@ -250,18 +254,19 @@ static bool show_project_simulation_settings(application& app) noexcept
}
}

ImGui::BeginDisabled(!app.simulation_ed.real_time);
ImGui::BeginDisabled(not app.simulation_ed.real_time);
is_modified +=
ImGui::InputScalar("Micro second for 1 unit time",
ImGuiDataType_S64,
&app.simulation_ed.simulation_real_time_relation);
&app.simulation_ed.nb_microsecond_per_simulation_time);
ImGui::EndDisabled();

ImGui::SameLine(ImGui::GetContentRegionAvail().x * 0.5f);
is_modified +=
ImGui::Checkbox("No time limit", &app.simulation_ed.infinity_simulation);

ImGui::TextFormat("Current time {:.6f}",
app.simulation_ed.simulation_current);
app.simulation_ed.simulation_display_current);
ImGui::SameLine(ImGui::GetContentRegionAvail().x * 0.5f);
is_modified += ImGui::Checkbox("Real time", &app.simulation_ed.real_time);

Expand Down Expand Up @@ -455,8 +460,8 @@ static bool show_local_simulation_plot_observers_table(application& app,
return is_modified > 0;
}

static auto get_global_parameter(const auto& tn,
const u64 uid) noexcept -> global_parameter_id
static auto get_global_parameter(const auto& tn, const u64 uid) noexcept
-> global_parameter_id
{
auto* ptr = tn.parameters_ids.get(uid);
return ptr ? *ptr : undefined<global_parameter_id>();
Expand Down

0 comments on commit cabee69

Please sign in to comment.