Commit d152c2bb authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

core: add qss2 integrator

parent 2c2caa73
Pipeline #14778 passed with stage
in 53 seconds
......@@ -26,70 +26,6 @@ load_file_dialog(std::filesystem::path& out);
bool
save_file_dialog(std::filesystem::path& out);
static inline const char* simulation_status_string[] = {
"success",
"running",
"uninitialized",
"internal_error",
};
static inline const char* status_string[] = {
"success",
"unknown_dynamics",
"block_allocator_bad_capacity",
"block_allocator_not_enough_memory",
"head_allocator_bad_capacity",
"head_allocator_not_enough_memory",
"simulation_not_enough_model",
"simulation_not_enough_memory_message_list_allocator",
"simulation_not_enough_memory_input_port_list_allocator",
"simulation_not_enough_memory_output_port_list_allocator",
"data_array_init_capacity_error",
"data_array_not_enough_memory",
"data_array_archive_init_capacity_error",
"data_array_archive_not_enough_memory",
"array_init_capacity_zero",
"array_init_capacity_too_big",
"array_init_not_enough_memory",
"vector_init_capacity_zero",
"vector_init_capacity_too_big",
"vector_init_not_enough_memory",
"dynamics_unknown_id",
"dynamics_unknown_port_id",
"dynamics_not_enough_memory",
"model_connect_output_port_unknown",
"model_connect_input_port_unknown",
"model_connect_already_exist",
"model_connect_bad_dynamics",
"model_adder_empty_init_message",
"model_adder_bad_init_message",
"model_adder_bad_external_message",
"model_mult_empty_init_message",
"model_mult_bad_init_message",
"model_mult_bad_external_message",
"model_integrator_internal_error",
"model_integrator_output_error",
"model_integrator_running_without_x_dot",
"model_integrator_ta_with_bad_x_dot",
"model_integrator_bad_external_message",
"model_quantifier_bad_quantum_parameter",
"model_quantifier_bad_archive_length_parameter",
"model_quantifier_shifting_value_neg",
"model_quantifier_shifting_value_less_1",
"model_quantifier_bad_external_message",
"model_cross_bad_external_message",
"model_time_func_bad_init_message",
"model_accumulator_bad_external_message",
"gui_not_enough_memory",
"io_file_format_error",
"io_file_format_model_error",
"io_file_format_model_number_error",
"io_file_format_model_unknown",
"io_file_format_dynamics_unknown",
"io_file_format_dynamics_limit_reach",
"io_file_format_dynamics_init_error"
};
} // namespace irt
#endif
......@@ -38,8 +38,7 @@ static auto automatic_layout_y_distance = 350.f;
static auto grid_layout_x_distance = 250.f;
static auto grid_layout_y_distance = 250.f;
static ImVec4
operator*(const ImVec4& lhs, const float rhs) noexcept
static ImVec4 operator*(const ImVec4& lhs, const float rhs) noexcept
{
return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs);
}
......@@ -206,16 +205,14 @@ run_simulation(simulation& sim,
if (auto ret = sim.initialize(current); irt::is_bad(ret)) {
log_w.log(3,
"Simulation initialization failure (%s)\n",
irt::status_string[static_cast<int>(ret)]);
irt::status_string(ret));
st = simulation_status::internal_error;
return;
}
do {
if (auto ret = sim.run(current); irt::is_bad(ret)) {
log_w.log(3,
"Simulation failure (%s)\n",
irt::status_string[static_cast<int>(ret)]);
log_w.log(3, "Simulation failure (%s)\n", irt::status_string(ret));
st = simulation_status::internal_error;
return;
......@@ -665,48 +662,49 @@ struct copier
auto ret = sim.dispatch(
mdl->type,
[this, &sim, mdl, &mdl_id_dst]<typename DynamicsM>(
DynamicsM& dynamics_models) -> status {
using Dynamics = typename DynamicsM::value_type;
[ this, &sim, mdl, &
mdl_id_dst ]<typename DynamicsM>(DynamicsM & dynamics_models)
->status {
using Dynamics = typename DynamicsM::value_type;
irt_return_if_fail(dynamics_models.can_alloc(1),
status::dynamics_not_enough_memory);
irt_return_if_fail(dynamics_models.can_alloc(1),
status::dynamics_not_enough_memory);
auto* dyn_ptr = dynamics_models.try_to_get(mdl->id);
irt_return_if_fail(dyn_ptr, status::dynamics_unknown_id);
auto* dyn_ptr = dynamics_models.try_to_get(mdl->id);
irt_return_if_fail(dyn_ptr, status::dynamics_unknown_id);
auto& new_dyn = dynamics_models.alloc(*dyn_ptr);
auto new_dyn_id = dynamics_models.get_id(new_dyn);
auto& new_dyn = dynamics_models.alloc(*dyn_ptr);
auto new_dyn_id = dynamics_models.get_id(new_dyn);
if constexpr (is_detected_v<has_input_port_t, Dynamics>)
std::fill_n(new_dyn.x,
std::size(new_dyn.x),
static_cast<input_port_id>(0));
if constexpr (is_detected_v<has_input_port_t, Dynamics>)
std::fill_n(new_dyn.x,
std::size(new_dyn.x),
static_cast<input_port_id>(0));
if constexpr (is_detected_v<has_output_port_t, Dynamics>)
std::fill_n(new_dyn.y,
std::size(new_dyn.y),
static_cast<output_port_id>(0));
if constexpr (is_detected_v<has_output_port_t, Dynamics>)
std::fill_n(new_dyn.y,
std::size(new_dyn.y),
static_cast<output_port_id>(0));
irt_return_if_bad(
sim.alloc(new_dyn, new_dyn_id, mdl->name.c_str()));
irt_return_if_bad(
sim.alloc(new_dyn, new_dyn_id, mdl->name.c_str()));
*mdl_id_dst = new_dyn.id;
*mdl_id_dst = new_dyn.id;
if constexpr (is_detected_v<has_input_port_t, Dynamics>)
for (size_t j = 0, ej = std::size(new_dyn.x); j != ej;
++j)
this->c_input_ports.emplace_back(dyn_ptr->x[j],
new_dyn.x[j]);
if constexpr (is_detected_v<has_input_port_t, Dynamics>)
for (size_t j = 0, ej = std::size(new_dyn.x); j != ej;
++j)
this->c_input_ports.emplace_back(dyn_ptr->x[j],
new_dyn.x[j]);
if constexpr (is_detected_v<has_output_port_t, Dynamics>)
for (size_t j = 0, ej = std::size(new_dyn.y); j != ej;
++j)
this->c_output_ports.emplace_back(dyn_ptr->y[j],
new_dyn.y[j]);
if constexpr (is_detected_v<has_output_port_t, Dynamics>)
for (size_t j = 0, ej = std::size(new_dyn.y); j != ej;
++j)
this->c_output_ports.emplace_back(dyn_ptr->y[j],
new_dyn.y[j]);
return status::success;
});
return status::success;
});
irt_return_if_bad(ret);
}
......@@ -1398,621 +1396,561 @@ editor::show_model_cluster(cluster& mdl) noexcept
}
}
void
editor::show_model_dynamics(model& mdl) noexcept
static const char* str_empty[] = { "" };
static const char* str_integrator[] = { "x-dot", "reset" };
static const char* str_adaptative_integrator[] = { "quanta", "x-dot", "reset" };
static const char* str_in_1[] = { "in" };
static const char* str_in_2[] = { "in-1", "in-2" };
static const char* str_in_3[] = { "in-1", "in-2", "in-3" };
static const char* str_in_4[] = { "in-1", "in-2", "in-3", "in-4" };
static const char* str_value_if_else[] = { "value", "if", "else" };
static const char* str_in_2_nb_2[] = { "in-1", "in-2", "nb-1", "nb-2" };
static const char* str_out_1[] = { "out" };
static const char* str_out_2[] = { "out-1", "out-2" };
template<typename Dynamics>
static constexpr const char**
get_input_port_names()
{
ImGui::PushItemWidth(100.0f);
if constexpr (std::is_same_v<Dynamics, none>)
return str_empty;
else if constexpr (std::is_same_v<Dynamics, qss1_integrator>)
return str_integrator;
else if constexpr (std::is_same_v<Dynamics, qss2_integrator>)
return str_integrator;
else if constexpr (std::is_same_v<Dynamics, qss2_multiplier>)
return str_in_2;
else if constexpr (std::is_same_v<Dynamics, qss2_sum_2>)
return str_in_2;
else if constexpr (std::is_same_v<Dynamics, qss2_sum_3>)
return str_in_3;
else if constexpr (std::is_same_v<Dynamics, qss2_sum_4>)
return str_in_4;
else if constexpr (std::is_same_v<Dynamics, qss2_wsum_2>)
return str_in_2;
else if constexpr (std::is_same_v<Dynamics, qss2_wsum_3>)
return str_in_3;
else if constexpr (std::is_same_v<Dynamics, qss2_wsum_4>)
return str_in_4;
else if constexpr (std::is_same_v<Dynamics, integrator>)
return str_adaptative_integrator;
else if constexpr (std::is_same_v<Dynamics, quantifier>)
return str_in_1;
else if constexpr (std::is_same_v<Dynamics, adder_2>)
return str_in_2;
else if constexpr (std::is_same_v<Dynamics, adder_3>)
return str_in_3;
else if constexpr (std::is_same_v<Dynamics, adder_4>)
return str_in_4;
else if constexpr (std::is_same_v<Dynamics, mult_2>)
return str_in_2;
else if constexpr (std::is_same_v<Dynamics, mult_3>)
return str_in_3;
else if constexpr (std::is_same_v<Dynamics, mult_4>)
return str_in_4;
else if constexpr (std::is_same_v<Dynamics, counter>)
return str_in_1;
else if constexpr (std::is_same_v<Dynamics, generator>)
return str_empty;
else if constexpr (std::is_same_v<Dynamics, constant>)
return str_empty;
else if constexpr (std::is_same_v<Dynamics, cross>)
return str_value_if_else;
else if constexpr (std::is_same_v<Dynamics, accumulator_2>)
return str_in_2_nb_2;
else if constexpr (std::is_same_v<Dynamics, time_func>)
return str_empty;
}
{
const char* items[] = { "none", "plot", "file", "both" };
int current_item = 0; /* Default show none */
auto* obs = sim.observers.try_to_get(mdl.obs_id);
template<typename Dynamics>
static constexpr const char**
get_output_port_names()
{
if constexpr (std::is_same_v<Dynamics, none>)
return str_empty;
else if constexpr (std::is_same_v<Dynamics, qss1_integrator>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, qss2_integrator>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, qss2_multiplier>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, qss2_sum_2>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, qss2_sum_3>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, qss2_sum_4>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, qss2_wsum_2>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, qss2_wsum_3>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, qss2_wsum_4>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, integrator>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, quantifier>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, adder_2>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, adder_3>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, adder_4>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, mult_2>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, mult_3>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, mult_4>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, counter>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, generator>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, constant>)
return str_out_1;
else if constexpr (std::is_same_v<Dynamics, cross>)
return str_out_2;
else if constexpr (std::is_same_v<Dynamics, accumulator_2>)
return str_empty;
else if constexpr (std::is_same_v<Dynamics, time_func>)
return str_out_1;
}
if (obs)
current_item =
static_cast<int>(observation_types[get_index(mdl.obs_id)]);
template<typename Dynamics>
static void
add_input_attribute(editor& ed, const Dynamics& dyn) noexcept
{
if constexpr (is_detected_v<has_input_port_t, Dynamics>) {
const auto** names = get_input_port_names<Dynamics>();
if (ImGui::Combo(
"observation", &current_item, items, IM_ARRAYSIZE(items))) {
if (current_item == 0) {
if (obs) {
observation_types[get_index(mdl.obs_id)] =
observation_output::type::none;
sim.observers.free(*obs);
mdl.obs_id = static_cast<observer_id>(0);
}
} else {
if (!obs) {
auto& o =
sim.observers.alloc(0.01, mdl.name.c_str(), nullptr);
sim.observe(mdl, o);
}
for (size_t i = 0, e = std::size(dyn.x); i != e; ++i) {
imnodes::BeginInputAttribute(ed.get_in(dyn.x[i]));
ImGui::TextUnformatted(names[i]);
imnodes::EndAttribute();
}
}
}
observation_types[get_index(mdl.obs_id)] =
current_item == 1
? observation_output::type::plot
: current_item == 2 ? observation_output::type::file
: observation_output::type::both;
}
template<typename Dynamics>
static void
add_output_attribute(editor& ed, const Dynamics& dyn) noexcept
{
if constexpr (is_detected_v<has_output_port_t, Dynamics>) {
const auto** names = get_output_port_names<Dynamics>();
if (auto* o = sim.observers.try_to_get(mdl.obs_id); o) {
float v = static_cast<float>(o->time_step);
if (ImGui::InputFloat("freq.", &v, 0.001f, 0.1f, "%.3f", 0))
o->time_step = static_cast<double>(v);
}
for (size_t i = 0, e = std::size(dyn.y); i != e; ++i) {
imnodes::BeginOutputAttribute(ed.get_out(dyn.y[i]));
ImGui::TextUnformatted(names[i]);
imnodes::EndAttribute();
}
}
}
ImGui::PopItemWidth();
static void
show_dynamics_values(const none& /*dyn*/)
{}
if (simulation_show_value &&
match(st, simulation_status::success, simulation_status::running)) {
switch (mdl.type) {
case dynamics_type::none: /* none does not have input port. */
break;
case dynamics_type::integrator: {
auto& dyn = sim.integrator_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0]));
ImGui::TextUnformatted("quanta");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1]));
ImGui::TextUnformatted("x_dot");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[2]));
ImGui::TextUnformatted("reset");
imnodes::EndAttribute();
static void
show_dynamics_values(const qss1_integrator& dyn)
{
ImGui::Text("X %.3f", dyn.X);
ImGui::Text("dQ %.3f", dyn.dQ);
}
ImGui::PushItemWidth(120.0f);
ImGui::Text("value %.3f", dyn.current_value);
ImGui::PopItemWidth();
static void
show_dynamics_values(const qss2_integrator& dyn)
{
ImGui::Text("X %.3f", dyn.X);
ImGui::Text("dQ %.3f", dyn.dQ);
}
imnodes::BeginOutputAttribute(get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("x").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("quanta").x - text_width);
ImGui::TextUnformatted("x");
imnodes::EndAttribute();
} break;
case dynamics_type::quantifier: {
auto& dyn = sim.quantifier_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0]));
ImGui::TextUnformatted("x_dot");
imnodes::EndAttribute();
static void
show_dynamics_values(const qss2_sum_2& dyn)
{
ImGui::Text("%.3f %.3f", dyn.values[0], dyn.slopes[0]);
ImGui::Text("%.3f %.3f", dyn.values[1], dyn.slopes[1]);
}
ImGui::PushItemWidth(120.0f);
ImGui::Text("up threshold %.3f", dyn.m_upthreshold);
ImGui::Text("down threshold %.3f", dyn.m_downthreshold);
ImGui::PopItemWidth();
static void
show_dynamics_values(const qss2_sum_3& dyn)
{
ImGui::Text("%.3f %.3f", dyn.values[0], dyn.slopes[0]);
ImGui::Text("%.3f %.3f", dyn.values[1], dyn.slopes[1]);
ImGui::Text("%.3f %.3f", dyn.values[2], dyn.slopes[2]);
}
imnodes::BeginOutputAttribute(get_out(dyn.y[0]));
ImGui::TextUnformatted("quanta");
imnodes::EndAttribute();
} break;
case dynamics_type::adder_2: {
auto& dyn = sim.adder_2_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0]));
ImGui::TextUnformatted("x0");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1]));
ImGui::TextUnformatted("x1");
imnodes::EndAttribute();
static void
show_dynamics_values(const qss2_sum_4& dyn)
{
ImGui::Text("%.3f %.3f", dyn.values[0], dyn.slopes[0]);
ImGui::Text("%.3f %.3f", dyn.values[1], dyn.slopes[1]);
ImGui::Text("%.3f %.3f", dyn.values[2], dyn.slopes[2]);
ImGui::Text("%.3f %.3f", dyn.values[3], dyn.slopes[3]);
}
ImGui::PushItemWidth(120.0f);
ImGui::Text("%.3f * %.3f", dyn.values[0], dyn.input_coeffs[0]);
ImGui::Text("%.3f * %.3f", dyn.values[1], dyn.input_coeffs[1]);
ImGui::PopItemWidth();
static void
show_dynamics_values(const qss2_multiplier& dyn)
{
ImGui::Text("%.3f %.3f", dyn.values[0], dyn.slopes[0]);
ImGui::Text("%.3f %.3f", dyn.values[1], dyn.slopes[1]);
}
imnodes::BeginOutputAttribute(get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("sum").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x -
text_width);
ImGui::TextUnformatted("sum");
imnodes::EndAttribute();
} break;
case dynamics_type::adder_3: {
auto& dyn = sim.adder_3_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0]));
ImGui::TextUnformatted("x0");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1]));
ImGui::TextUnformatted("x1");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[2]));
ImGui::TextUnformatted("x2");
imnodes::EndAttribute();
static void
show_dynamics_values(const qss2_wsum_2& dyn)
{
ImGui::Text("%.3f %.3f", dyn.values[0], dyn.slopes[0]);
ImGui::Text("%.3f %.3f", dyn.values[1], dyn.slopes[1]);
}
ImGui::PushItemWidth(120.0f);
ImGui::Text("%.3f * %.3f", dyn.values[0], dyn.input_coeffs[0]);
ImGui::Text("%.3f * %.3f", dyn.values[1], dyn.input_coeffs[1]);
ImGui::Text("%.3f * %.3f", dyn.values[2], dyn.input_coeffs[2]);
ImGui::PopItemWidth();
static void
show_dynamics_values(const qss2_wsum_3& dyn)
{
ImGui::Text("%.3f %.3f", dyn.values[0], dyn.slopes[0]);
ImGui::Text("%.3f %.3f", dyn.values[1], dyn.slopes[1]);
ImGui::Text("%.3f %.3f", dyn.values[2], dyn.slopes[2]);
}
imnodes::BeginOutputAttribute(get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("sum").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x -
text_width);
ImGui::TextUnformatted("sum");
imnodes::EndAttribute();
} break;
case dynamics_type::adder_4: {
auto& dyn = sim.adder_4_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0]));
ImGui::TextUnformatted("x0");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1]));
ImGui::TextUnformatted("x1");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[2]));
ImGui::TextUnformatted("x2");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[3]));
ImGui::TextUnformatted("x3");
imnodes::EndAttribute();
static void
show_dynamics_values(const qss2_wsum_4& dyn)
{
ImGui::Text("%.3f %.3f", dyn.values[0], dyn.slopes[0]);
ImGui::Text("%.3f %.3f", dyn.values[1], dyn.slopes[1]);
ImGui::Text("%.3f %.3f", dyn.values[2], dyn.slopes[2]);
ImGui::Text("%.3f %.3f", dyn.values[3], dyn.slopes[3]);
}
ImGui::PushItemWidth(120.0f);
ImGui::Text("%.3f * %.3f", dyn.values[0], dyn.input_coeffs[0]);
ImGui::Text("%.3f * %.3f", dyn.values[1], dyn.input_coeffs[1]);
ImGui::Text("%.3f * %.3f", dyn.values[2], dyn.input_coeffs[2]);
ImGui::Text("%.3f * %.3f", dyn.values[3], dyn.input_coeffs[3]);
ImGui::PopItemWidth();
static void
show_dynamics_values(const integrator& dyn)
{
ImGui::Text("value %.3f", dyn.current_value);
}
imnodes::BeginOutputAttribute(get_out(dyn.y[0]));
const float text_width = ImGui::CalcTextSize("sum").x;
ImGui::Indent(120.f + ImGui::CalcTextSize("coeff-0").x -
text_width);
ImGui::TextUnformatted("sum");
imnodes::EndAttribute();
} break;
case dynamics_type::mult_2: {
auto& dyn = sim.mult_2_models.get(mdl.id);
imnodes::BeginInputAttribute(get_in(dyn.x[0]));
ImGui::TextUnformatted("x0");
imnodes::EndAttribute();
imnodes::BeginInputAttribute(get_in(dyn.x[1]));
ImGui::TextUnformatted("x1");
imnodes::EndAttribute();
static void
show_dynamics_values(const quantifier& dyn)
{
ImGui::Text("up threshold %.3f", dyn.m_upthreshold);
ImGui::Text("down threshold %.3f", dyn.m_downthreshold);
}
ImGui::PushItemWidth(120.0f);
ImGui::Text("%.3f * %.3f", dyn.values[0], dyn.input_coeffs[0]);
ImGui::Text("%.3f * %.3f", dyn.values[1], dyn.input_coeffs[1]);
ImGui::PopItemWidth();
static void
show_dynamics_values(const adder_2& dyn)
{
ImGui::Text("%.3f * %.3f", dyn.values[0], dyn.input_coeffs[0]);
ImGui::Text("%.3f * %.3f", dyn.values[1], dyn.input_coeffs[1]);
}