Commit 33b0e646 authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

core: add buffer and update generator with external sources

parent b5cdce84
......@@ -1591,10 +1591,18 @@ show_dynamics_values(const counter& dyn)
ImGui::Text("number %ld", static_cast<long>(dyn.number));
}
static void
show_dynamics_values(const buffer& dyn)
{
ImGui::Text("next %.3f", dyn.sigma);
ImGui::Text("value %.3f", dyn.value);
}
static void
show_dynamics_values(const generator& dyn)
{
ImGui::Text("next %.3f", dyn.sigma);
ImGui::Text("value %.3f", dyn.value);
}
static void
......@@ -1897,11 +1905,17 @@ static void
show_dynamics_inputs(counter& /*dyn*/)
{}
static void
show_dynamics_inputs(buffer& dyn)
{
ImGui::InputDouble("value", &dyn.default_value);
ImGui::InputDouble("offset", &dyn.default_offset);
}
static void
show_dynamics_inputs(generator& dyn)
{
ImGui::InputDouble("value", &dyn.default_value);
ImGui::InputDouble("period", &dyn.default_period);
ImGui::InputDouble("offset", &dyn.default_offset);
}
......@@ -2582,6 +2596,7 @@ editor::show_editor() noexcept
}
add_popup_menuitem(*this, dynamics_type::counter, &new_model);
add_popup_menuitem(*this, dynamics_type::buffer, &new_model);
add_popup_menuitem(*this, dynamics_type::generator, &new_model);
add_popup_menuitem(*this, dynamics_type::constant, &new_model);
add_popup_menuitem(*this, dynamics_type::time_func, &new_model);
......
......@@ -49,12 +49,18 @@ status_string(const status s) noexcept
"model_connect_input_port_unknown",
"model_connect_already_exist",
"model_connect_bad_dynamics",
"model_buffer_null_ta_source",
"model_buffer_empty_ta_source",
"model_integrator_dq_error",
"model_integrator_X_error",
"model_integrator_internal_error",
"model_integrator_output_error",
"model_integrator_running_without_x_dot",
"model_integrator_ta_with_bad_x_dot",
"model_generator_null_ta_source",
"model_generator_empty_ta_source",
"model_generator_null_value_source",
"model_generator_empty_value_source",
"model_quantifier_bad_quantum_parameter",
"model_quantifier_bad_archive_length_parameter",
"model_quantifier_shifting_value_neg",
......
......@@ -173,12 +173,22 @@ enum class status
model_connect_input_port_unknown,
model_connect_already_exist,
model_connect_bad_dynamics,
model_buffer_null_ta_source,
model_buffer_empty_ta_source,
model_integrator_dq_error,
model_integrator_X_error,
model_integrator_internal_error,
model_integrator_output_error,
model_integrator_running_without_x_dot,
model_integrator_ta_with_bad_x_dot,
model_generator_null_ta_source,
model_generator_empty_ta_source,
model_generator_null_value_source,
model_generator_empty_value_source,
model_quantifier_bad_quantum_parameter,
model_quantifier_bad_archive_length_parameter,
model_quantifier_shifting_value_neg,
......@@ -2433,6 +2443,7 @@ enum class dynamics_type : i8
mult_4,
counter,
buffer,
generator,
constant,
cross,
......@@ -2476,9 +2487,11 @@ struct observer
finalize
};
using update_fn =
function_ref<void(const observer&, const dynamics_type,
const time, const time, const observer::status)>;
using update_fn = function_ref<void(const observer&,
const dynamics_type,
const time,
const time,
const observer::status)>;
observer(const char* name_, update_fn cb_) noexcept
: cb(cb_)
......@@ -2558,6 +2571,9 @@ using has_output_port_t = decltype(&T::y);
template<typename T>
using has_init_port_t = decltype(&T::init);
template<typename T>
using has_sim_attribute_t = decltype(&T::sim);
struct simulation;
struct none
......@@ -4584,37 +4600,99 @@ struct counter
}
};
struct generator
struct external_source
{
double* data = nullptr; // @todo use a std::span<double> instead
sz index = 0; // of data and size.
sz size = 0;
u64 id = 0;
function_ref<bool(external_source& src)> expand;
bool next(double& value) noexcept
{
irt_assert(data);
if (index >= size) {
if (expand.empty() || !expand(*this))
return false;
}
value = data[index++];
return true;
}
};
enum class external_source_id : u64;
struct buffer
{
model_id id;
input_port_id x[1];
output_port_id y[1];
time sigma;
external_source_id default_lambda_source_id = external_source_id{ 0 };
simulation* sim = nullptr;
double default_offset = 0.0;
double default_value = 0.0;
double default_period = 1.0;
double default_offset = 1.0;
double value = 0.0;
double period = 1.0;
double offset = 1.0;
double value;
status initialize() noexcept
{
sigma = default_offset;
value = default_value;
period = default_period;
offset = default_offset;
sigma = offset;
return status::success;
}
status transition(data_array<input_port, input_port_id>& /*input_ports*/,
status transition(data_array<input_port, input_port_id>& input_ports,
time /*t*/,
time /*e*/,
time /*r*/) noexcept
time r) noexcept;
status lambda(
data_array<output_port, output_port_id>& output_ports) noexcept
{
sigma = period;
output_ports.get(y[0]).messages.emplace_front(value);
return status::success;
}
message observation(const time /*e*/) const noexcept
{
return { value };
}
};
struct generator
{
model_id id;
output_port_id y[1];
time sigma;
external_source_id default_lambda_source_id = external_source_id{ 0 };
external_source_id default_value_source_id = external_source_id{ 0 };
simulation* sim = nullptr;
double default_offset = 1.0;
double default_value = 0.0;
double value;
status initialize() noexcept
{
sigma = default_offset;
value = default_value;
return status::success;
}
status transition(data_array<input_port, input_port_id>& /*input_ports*/,
time /*t*/,
time /*e*/,
time /*r*/) noexcept;
status lambda(
data_array<output_port, output_port_id>& output_ports) noexcept
{
......@@ -5414,6 +5492,8 @@ dynamics_typeof() noexcept
if constexpr (std::is_same_v<Dynamics, counter>)
return dynamics_type::counter;
if constexpr (std::is_same_v<Dynamics, buffer>)
return dynamics_type::buffer;
if constexpr (std::is_same_v<Dynamics, generator>)
return dynamics_type::generator;
if constexpr (std::is_same_v<Dynamics, constant>)
......@@ -5492,6 +5572,7 @@ struct simulation
data_array<mult_3, dynamics_id> mult_3_models;
data_array<mult_4, dynamics_id> mult_4_models;
data_array<counter, dynamics_id> counter_models;
data_array<buffer, dynamics_id> buffer_models;
data_array<generator, dynamics_id> generator_models;
data_array<constant, dynamics_id> constant_models;
data_array<cross, dynamics_id> cross_models;
......@@ -5501,6 +5582,8 @@ struct simulation
data_array<observer, observer_id> observers;
data_array<external_source, external_source_id> external_sources;
scheduller sched;
time begin = time_domain<time>::zero;
......@@ -5615,6 +5698,8 @@ struct simulation
if constexpr (std::is_same_v<Dynamics, counter>)
return counter_models;
if constexpr (std::is_same_v<Dynamics, buffer>)
return buffer_models;
if constexpr (std::is_same_v<Dynamics, generator>)
return generator_models;
if constexpr (std::is_same_v<Dynamics, constant>)
......@@ -5732,6 +5817,8 @@ struct simulation
return f(mult_4_models, args...);
case dynamics_type::counter:
return f(counter_models, args...);
case dynamics_type::buffer:
return f(buffer_models, args...);
case dynamics_type::generator:
return f(generator_models, args...);
case dynamics_type::constant:
......@@ -5845,6 +5932,8 @@ struct simulation
return f(mult_4_models, args...);
case dynamics_type::counter:
return f(counter_models, args...);
case dynamics_type::buffer:
return f(buffer_models, args...);
case dynamics_type::generator:
return f(generator_models, args...);
case dynamics_type::constant:
......@@ -6068,6 +6157,7 @@ public:
irt_return_if_bad(mult_3_models.init(model_capacity));
irt_return_if_bad(mult_4_models.init(model_capacity));
irt_return_if_bad(counter_models.init(model_capacity));
irt_return_if_bad(buffer_models.init(model_capacity));
irt_return_if_bad(generator_models.init(model_capacity));
irt_return_if_bad(constant_models.init(model_capacity));
irt_return_if_bad(cross_models.init(model_capacity));
......@@ -6077,6 +6167,8 @@ public:
irt_return_if_bad(observers.init(model_capacity));
irt_return_if_bad(external_sources.init(ten * ten));
irt_return_if_bad(flat_double_list_shared_allocator.init(
integrator_models.capacity() * ten));
......@@ -6371,6 +6463,7 @@ public:
case dynamics_type::mult_3:
case dynamics_type::mult_4:
case dynamics_type::counter:
case dynamics_type::buffer:
case dynamics_type::generator:
case dynamics_type::constant:
case dynamics_type::cross:
......@@ -6477,7 +6570,8 @@ public:
while (observers.next(obs)) {
if (auto* mdl = models.try_to_get(obs->model); mdl) {
obs->msg.reset();
obs->cb(*obs, mdl->type, mdl->tl, t, observer::status::initialize);
obs->cb(
*obs, mdl->type, mdl->tl, t, observer::status::initialize);
}
}
......@@ -6532,6 +6626,9 @@ public:
if constexpr (is_detected_v<initialize_function_t, Dynamics>)
irt_return_if_bad(dyn.initialize());
if constexpr (is_detected_v<has_sim_attribute_t, Dynamics>)
dyn.sim = this;
mdl.tl = t;
mdl.tn = t + dyn.sigma;
mdl.handle = nullptr;
......@@ -6657,6 +6754,61 @@ public:
}
};
inline status
buffer::transition(data_array<input_port, input_port_id>& input_ports,
time /*t*/,
time /*e*/,
time r) noexcept
{
irt_assert(sim);
bool have_message = false;
auto& port = input_ports.get(x[0]);
for (const auto& msg : port.messages) {
value = msg[0];
have_message = true;
}
if (time_domain<time>::is_zero(r)) {
auto* src_v =
sim->external_sources.try_to_get(default_lambda_source_id);
if (!src_v)
irt_bad_return(status::model_buffer_null_ta_source);
if (!src_v->next(sigma))
irt_bad_return(status::model_buffer_empty_ta_source);
} else {
sigma = r;
}
return status::success;
}
inline status
generator::transition(data_array<input_port, input_port_id>& /*input_ports*/,
time /*t*/,
time /*e*/,
time /*r*/) noexcept
{
irt_assert(sim);
auto* src_l = sim->external_sources.try_to_get(default_lambda_source_id);
if (!src_l)
irt_bad_return(status::model_generator_null_ta_source);
if (!src_l->next(sigma))
irt_bad_return(status::model_generator_empty_ta_source);
auto* src_v = sim->external_sources.try_to_get(default_value_source_id);
if (!src_v)
irt_bad_return(status::model_generator_null_value_source);
if (!src_v->next(value))
irt_bad_return(status::model_generator_empty_value_source);
return status::success;
}
} // namespace irt
#endif
// Copyright (c) 2020 INRA Distributed under the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef ORG_VLEPROJECT_IRRITATOR_EXTERNAL_SOURCE_2021
#define ORG_VLEPROJECT_IRRITATOR_EXTERNAL_SOURCE_2021
#include <irritator/core.hpp>
#include <array>
#include <filesystem>
#include <fstream>
namespace irt::source {
struct binary_file
{
std::array<char, 1024 * 1024> buffer;
std::ifstream ifs;
sz buffer_size = 0;
bool use_rewind = false;
binary_file() = default;
bool init(external_source& src)
{
if (!read(src))
return false;
}
bool operator()(external_source& src)
{
if (!ifs.good() && !use_rewind)
return false;
if (!ifs.good())
ifs.seekg(0);
if (!read(src))
return false;
return true;
}
private:
bool read(external_source& src)
{
ifs.read(buffer.data(), std::size(buffer));
buffer_size = ifs.gcount();
if (buffer_size % 8 != 0)
return false;
src.data = reinterpret_cast<double*>(buffer.data());
src.index = 0;
src.size = buffer_size / 8;
return true;
}
};
struct text_file
{
std::array<double, 1024 * 1024 / 8> buffer;
std::ifstream ifs;
bool use_rewind = false;
text_file() = default;
bool init(external_source& src)
{
if (!read(src))
return false;
}
bool operator()(external_source& src)
{
if (!ifs.good() && !use_rewind)
return false;
if (!ifs.good())
ifs.seekg(0);
if (!read(src))
return false;
return true;
}
private:
bool read(external_source& src)
{
size_t i = 0;
for (; i < std::size(buffer) && ifs.good(); ++i) {
if (!(ifs >> buffer[i]))
break;
}
src.data = buffer.data();
src.index = 0;
src.size = i;
return true;
}
};
struct random_source
{
double* buffer = nullptr;
sz size = 0;
bool use_rewind;
random_source() = default;
~random_source() noexcept
{
if (buffer)
g_free_fn(buffer);
}
template<typename RandomGenerator, typename Distribution>
bool init(const sz size_, RandomGenerator& gen, Distribution& dist) noexcept
{
if (!size_)
return false;
if (buffer)
g_free_fn(buffer);
size = 0;
buffer = g_alloc_fn(sizeof(double) * size_);
if (buffer) {
std::generate_n(buffer, size, (*dist)(*gen));
size = size_;
return true;
}
return false;
}
bool operator()(external_source& src)
{
if (!use_rewind)
return false;
size = 0;
return true;
}
};
enum class random_file_type
{
binary,
text,
};
template<typename RandomGenerator, typename Distribution>
inline int
generate_random_file(std::ostream& os,
RandomGenerator& gen,
Distribution& dist,
const std::size_t size,
const random_file_type type) noexcept
{
switch (type) {
case random_file_type::text: {
if (!os)
return -1;
for (std::size_t sz = 0; sz < size; ++sz)
if (!(os << dist(gen) << '\n'))
return -2;
} break;
case random_file_type::binary: {
if (!os)
return -1;
for (std::size_t sz = 0; sz < size; ++sz) {
const double value = dist(gen);
os.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
} break;
}
return 0;
}
} // namespace irt::source
#endif
......@@ -58,6 +58,7 @@ static inline const char* dynamics_type_names[] = { "none",
"mult_3",
"mult_4",
"counter",
"buffer",
"generator",
"constant",
"cross",
......@@ -133,6 +134,7 @@ get_input_port_names() noexcept
if constexpr (std::is_same_v<Dynamics, quantifier> ||
std::is_same_v<Dynamics, counter> ||
std::is_same_v<Dynamics, buffer> ||
std::is_same_v<Dynamics, qss1_power> ||
std::is_same_v<Dynamics, qss2_power> ||
std::is_same_v<Dynamics, qss3_power> ||
......@@ -287,6 +289,7 @@ get_output_port_names() noexcept
std::is_same_v<Dynamics, mult_3> ||
std::is_same_v<Dynamics, mult_4> ||
std::is_same_v<Dynamics, counter> ||
std::is_same_v<Dynamics, buffer> ||
std::is_same_v<Dynamics, generator> ||
std::is_same_v<Dynamics, constant> ||
std::is_same_v<Dynamics, time_func> ||
......@@ -351,6 +354,7 @@ get_output_port_names(const dynamics_type type) noexcept
case dynamics_type::mult_3:
case dynamics_type::mult_4:
case dynamics_type::counter:
case dynamics_type::buffer:
case dynamics_type::generator:
case dynamics_type::constant:
case dynamics_type::time_func:
......@@ -619,6 +623,7 @@ private:
{ "adder_2", dynamics_type::adder_2 },
{ "adder_3", dynamics_type::adder_3 },
{ "adder_4", dynamics_type::adder_4 },
{ "buffer", dynamics_type::buffer },