Commit 7090552a authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

core: reorder model components

parent 3a9b0bae
......@@ -3019,1143 +3019,1143 @@ using has_init_port_t = decltype(&T::init);
struct simulation;
template<size_t PortNumber>
struct adder
struct none
{
static_assert(PortNumber > 1, "adder model need at least two input port");
model_id id;
time sigma = time_domain<time>::infinity;
};
struct integrator
{
model_id id;
input_port_id x[PortNumber];
input_port_id x[3];
output_port_id y[1];
time sigma;
double default_values[PortNumber];
double default_input_coeffs[PortNumber];
double values[PortNumber];
double input_coeffs[PortNumber];
time sigma = time_domain<time>::zero;
adder() noexcept
enum port_name
{
std::fill_n(std::begin(default_values),
PortNumber,
1.0 / static_cast<double>(PortNumber));
std::fill_n(std::begin(default_input_coeffs), PortNumber, 0.0);
}
port_quanta,
port_x_dot,
port_reset
};
status initialize(data_array<message, message_id>& /*init*/) noexcept
enum class state
{
std::copy_n(std::begin(default_values), PortNumber, std::begin(values));
init,
wait_for_quanta,
wait_for_x_dot,
wait_for_both,
running
};
std::copy_n(std::begin(default_input_coeffs),
PortNumber,
std::begin(input_coeffs));
double default_current_value = 0.0;
double default_reset_value = 0.0;
flat_double_list<record> archive;
sigma = time_domain<time>::infinity;
double current_value = 0.0;
double reset_value = 0.0;
double up_threshold = 0.0;
double down_threshold = 0.0;
double last_output_value = 0.0;
double expected_value = 0.0;
bool reset = false;
state st = state::init;
return status::success;
}
integrator() = default;
status lambda(
data_array<output_port, output_port_id>& output_ports) noexcept
{
double to_send = 0.0;
integrator(const integrator& other) noexcept
: default_current_value(other.default_current_value)
, default_reset_value(other.default_reset_value)
, archive(other.archive.get_allocator())
, current_value(other.current_value)
, reset_value(other.reset_value)
, up_threshold(other.up_threshold)
, down_threshold(other.down_threshold)
, last_output_value(other.last_output_value)
, expected_value(other.expected_value)
, reset(other.reset)
, st(other.st)
{}
if (auto* port = output_ports.try_to_get(y[0]); port) {
for (size_t i = 0; i != PortNumber; ++i)
to_send += input_coeffs[i] * values[i];
status initialize(data_array<message, message_id>& /*init*/) noexcept
{
current_value = default_current_value;
reset_value = default_reset_value;
up_threshold = 0.0;
down_threshold = 0.0;
last_output_value = 0.0;
expected_value = 0.0;
reset = false;
archive.clear();
st = state::init;
port->messages.emplace_front(to_send);
}
sigma = time_domain<time>::zero;
return status::success;
}
status transition(data_array<input_port, input_port_id>& input_ports,
time /*t*/,
time /*e*/,
time /*r*/) noexcept
status external(input_port& port_quanta,
input_port& port_x_dot,
input_port& port_reset,
time t) noexcept
{
bool have_message = false;
for (const auto& msg : port_quanta.messages) {
irt_return_if_fail(msg.type == value_type::real_64 &&
msg.size() == 2,
status::model_integrator_bad_external_message);
for (size_t i = 0; i != PortNumber; ++i) {
if (auto* port = input_ports.try_to_get(x[i]); port) {
for (const auto& msg : port->messages) {
irt_return_if_fail(
msg.type == value_type::real_64,
status::model_adder_bad_external_message);
irt_return_if_fail(
msg.size() == 1,
status::model_adder_bad_external_message);
up_threshold = msg.to_real_64(0);
down_threshold = msg.to_real_64(1);
values[i] = msg.to_real_64(0);
if (st == state::wait_for_quanta)
st = state::running;
have_message = true;
}
}
if (st == state::wait_for_both)
st = state::wait_for_x_dot;
}
sigma =
have_message ? time_domain<time>::zero : time_domain<time>::infinity;
return status::success;
}
for (const auto& msg : port_x_dot.messages) {
irt_return_if_fail(msg.type == value_type::real_64 &&
msg.size() == 1,
status::model_integrator_bad_external_message);
message observation(time /*t*/) const noexcept
{
double ret = 0.0;
archive.emplace_back(msg.to_real_64(0), t);
for (size_t i = 0; i != PortNumber; ++i)
ret += input_coeffs[i] * values[i];
if (st == state::wait_for_x_dot)
st = state::running;
return message(ret);
}
};
if (st == state::wait_for_both)
st = state::wait_for_quanta;
}
template<size_t PortNumber>
struct mult
{
static_assert(PortNumber > 1, "mult model need at least two input port");
for (const auto& msg : port_reset.messages) {
irt_return_if_fail(msg.type == value_type::real_64 &&
msg.size() == 1,
status::model_integrator_bad_external_message);
model_id id;
input_port_id x[PortNumber];
output_port_id y[1];
time sigma;
reset_value = msg.to_real_64(0);
reset = true;
}
double default_values[PortNumber];
double default_input_coeffs[PortNumber];
if (st == state::running) {
current_value = compute_current_value(t);
expected_value = compute_expected_value();
}
double values[PortNumber];
double input_coeffs[PortNumber];
return status::success;
}
mult() noexcept
status internal(time t) noexcept
{
std::fill_n(std::begin(default_values), PortNumber, 1.0);
std::fill_n(std::begin(default_input_coeffs), PortNumber, 0.0);
switch (st) {
case state::running: {
last_output_value = expected_value;
const double last_derivative_value = archive.back().x_dot;
archive.clear();
archive.emplace_back(last_derivative_value, t);
current_value = expected_value;
st = state::wait_for_quanta;
return status::success;
}
case state::init:
st = state::wait_for_both;
last_output_value = current_value;
return status::success;
default:
return status::model_integrator_internal_error;
}
}
status initialize(data_array<message, message_id>& /*init*/) noexcept
status transition(data_array<input_port, input_port_id>& input_ports,
time t,
time /*e*/,
time r) noexcept
{
std::copy_n(std::begin(default_values), PortNumber, std::begin(values));
auto* port_1 = input_ports.try_to_get(x[port_quanta]);
auto* port_2 = input_ports.try_to_get(x[port_x_dot]);
auto* port_3 = input_ports.try_to_get(x[port_reset]);
std::copy_n(std::begin(default_input_coeffs),
PortNumber,
std::begin(input_coeffs));
if (port_1->messages.empty() && port_2->messages.empty() &&
port_3->messages.empty()) {
irt_return_if_bad(internal(t));
} else {
if (time_domain<time>::is_zero(r))
irt_return_if_bad(internal(t));
sigma = time_domain<time>::infinity;
irt_return_if_bad(external(*port_1, *port_2, *port_3, t));
}
return status::success;
return ta();
}
status lambda(
data_array<output_port, output_port_id>& output_ports) noexcept
{
double to_send = 1.0;
if (auto* port = output_ports.try_to_get(y[0]); port) {
for (size_t i = 0; i != PortNumber; ++i)
to_send *= std::pow(values[i], input_coeffs[i]);
port->messages.emplace_front(to_send);
switch (st) {
case state::running:
port->messages.emplace_front(expected_value);
return status::success;
case state::init:
port->messages.emplace_front(current_value);
return status::success;
default:
return status::model_integrator_output_error;
}
}
return status::success;
}
status transition(data_array<input_port, input_port_id>& input_ports,
time /*t*/,
time /*e*/,
time /*r*/) noexcept
message observation(time /*t*/) const noexcept
{
bool have_message = false;
for (size_t i = 0; i != PortNumber; ++i) {
if (auto* port = input_ports.try_to_get(x[i]); port) {
for (const auto& msg : port->messages) {
irt_return_if_fail(msg.type == value_type::real_64,
status::model_mult_bad_external_message);
irt_return_if_fail(msg.size() == 1,
status::model_mult_bad_external_message);
values[i] = msg.to_real_64(0);
have_message = true;
}
}
}
return message(last_output_value);
}
sigma =
have_message ? time_domain<time>::zero : time_domain<time>::infinity;
return status::success;
}
message observation(time /*t*/) const noexcept
{
double ret = 1.0;
for (size_t i = 0; i != PortNumber; ++i)
ret *= std::pow(values[i], input_coeffs[i]);
return message(ret);
}
};
template<size_t PortNumber>
struct accumulator
{
model_id id;
input_port_id x[2 * PortNumber];
time sigma;
double number;
double numbers[PortNumber];
status initialize(
data_array<message, message_id>& /*init_messages*/) noexcept
status ta() noexcept
{
number = 0.0;
std::fill_n(numbers, PortNumber, 0.0);
if (st == state::running) {
irt_return_if_fail(!archive.empty(),
status::model_integrator_running_without_x_dot);
sigma = time_domain<time>::infinity;
const auto current_derivative = archive.back().x_dot;
return status::success;
}
if (current_derivative == time_domain<time>::zero) {
sigma = time_domain<time>::infinity;
return status::success;
}
status transition(data_array<input_port, input_port_id>& input_ports,
time /*t*/,
time /*e*/,
time /*r*/) noexcept
{
if (current_derivative > 0) {
irt_return_if_fail((up_threshold - current_value) >= 0,
status::model_integrator_ta_with_bad_x_dot);
for (size_t i = 0; i != PortNumber; ++i) {
if (auto* port = input_ports.try_to_get(x[i + PortNumber]); port) {
for (const auto& msg : port->messages) {
irt_return_if_fail(
msg.type == value_type::real_64,
status::model_accumulator_bad_external_message);
irt_return_if_fail(
msg.size() == 1,
status::model_accumulator_bad_external_message);
numbers[i] = msg.to_real_64(0);
}
sigma = (up_threshold - current_value) / current_derivative;
return status::success;
}
}
for (size_t i = 0; i != PortNumber; ++i) {
if (auto* port = input_ports.try_to_get(x[i]); port) {
for (const auto& msg : port->messages) {
irt_return_if_fail(
msg.type == value_type::real_64,
status::model_accumulator_bad_external_message);
irt_return_if_fail(
msg.size() == 1,
status::model_accumulator_bad_external_message);
irt_return_if_fail((down_threshold - current_value) <= 0,
status::model_integrator_ta_with_bad_x_dot);
if (msg.to_real_64(0) != 0.0) {
number += numbers[i];
}
}
}
sigma = (down_threshold - current_value) / current_derivative;
return status::success;
}
sigma = time_domain<time>::infinity;
return status::success;
}
};
using adder_2 = adder<2>;
using adder_3 = adder<3>;
using adder_4 = adder<4>;
double compute_current_value(time t) const noexcept
{
if (archive.empty())
return reset ? reset_value : last_output_value;
using mult_2 = mult<2>;
using mult_3 = mult<3>;
using mult_4 = mult<4>;
auto val = reset ? reset_value : last_output_value;
auto end = archive.end();
auto it = archive.begin();
auto next = archive.begin();
using accumulator_2 = accumulator<2>;
if (next != end)
++next;
struct counter
{
model_id id;
input_port_id x[1];
time sigma;
i64 number;
for (; next != end; it = next++)
val += (next->date - it->date) * it->x_dot;
status initialize(
data_array<message, message_id>& /*init_messages*/) noexcept
{
number = { 0 };
sigma = time_domain<time>::infinity;
val += (t - archive.back().date) * archive.back().x_dot;
return status::success;
return up_threshold < val ? reset_value : val;
}
status transition(data_array<input_port, input_port_id>& input_ports,
time /*t*/,
time /*e*/,
time /*r*/) noexcept
double compute_expected_value() const noexcept
{
std::ptrdiff_t diff{ 0 };
if (auto* port = input_ports.try_to_get(x[0]); port)
diff += std::distance(std::begin(port->messages),
std::end(port->messages));
const auto current_derivative = archive.back().x_dot;
number += static_cast<i64>(diff);
if (current_derivative == 0)
return current_value;
return status::success;
}
if (current_derivative > 0)
return up_threshold;
message observation(time /*t*/) const noexcept
{
return message(number);
return down_threshold;
}
};
struct generator
struct quantifier
{
model_id id;
input_port_id x[1];
output_port_id y[1];
time sigma;
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;
time sigma = time_domain<time>::infinity;
status initialize(
data_array<message, message_id>& /*init_messages*/) noexcept
enum class state
{
value = default_value;
period = default_period;
offset = default_offset;
sigma = offset;
init,
idle,
response
};
return status::success;
}
status transition(data_array<input_port, input_port_id>& /*input_ports*/,
time /*t*/,
time /*e*/,
time /*r*/) noexcept
enum class adapt_state
{
sigma = period;
return status::success;
}
impossible,
possible,
done
};
status lambda(
data_array<output_port, output_port_id>& output_ports) noexcept
enum class direction
{
output_ports.get(y[0]).messages.emplace_front(value);
return status::success;
}
up,
down
};
message observation(time /*t*/) const noexcept
{
return message(value);
}
};
double default_step_size = 0.001;
int default_past_length = 3;
adapt_state default_adapt_state = adapt_state::possible;
bool default_zero_init_offset = false;
flat_double_list<record> archive;
struct constant
{
model_id id;
output_port_id y[1];
time sigma;
double m_upthreshold = 0.0;
double m_downthreshold = 0.0;
double m_offset = 0.0;
double m_step_size = 0.0;
int m_step_number = 0;
int m_past_length = 0;
bool m_zero_init_offset = false;
state m_state = state::init;
adapt_state m_adapt_state = adapt_state::possible;
double default_value = 0.0;
quantifier() noexcept = default;
double value = 0.0;
quantifier(const quantifier& other) noexcept
: default_step_size(other.default_step_size)
, default_past_length(other.default_past_length)
, default_adapt_state(other.default_adapt_state)
, default_zero_init_offset(other.default_zero_init_offset)
, archive(other.archive.get_allocator())
, m_upthreshold(other.m_upthreshold)
, m_downthreshold(other.m_downthreshold)
, m_offset(other.m_offset)
, m_step_size(other.m_step_size)
, m_step_number(other.m_step_number)
, m_past_length(other.m_past_length)
, m_zero_init_offset(other.m_zero_init_offset)
, m_state(other.m_state)
, m_adapt_state(other.m_adapt_state)
{}
status initialize(data_array<message, message_id>& /*init*/) noexcept
{
sigma = time_domain<time>::zero;
m_step_size = default_step_size;
m_past_length = default_past_length;
m_zero_init_offset = default_zero_init_offset;
m_adapt_state = default_adapt_state;
m_upthreshold = 0.0;
m_downthreshold = 0.0;
m_offset = 0.0;
m_step_number = 0;
archive.clear();