Commit 90ed4b96 authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

core: fix finalize observation

There is missing call to the finalize callback in observation system.
This patch fix the problem and provides new observation callback systems
based on function_ref. (Closes: #29).
parent 3d065e53
Pipeline #29519 passed with stage
in 1 minute and 36 seconds
......@@ -2746,11 +2746,8 @@ editor::show_editor() noexcept
tf.ed = this;
plot = &tf;
out.plot_id = plot_outs.get_id(tf);
auto& o = sim.observers.alloc(
0.01, names[i].c_str(), (void*)plot);
o.initialize = &observation_plot_output_initialize;
o.observe = &observation_plot_output_observe;
o.free = &observation_plot_output_free;
auto& o =
sim.observers.alloc(0.01, names[i].c_str(), tf);
sim.observe(*mdl, o);
}
......@@ -2767,11 +2764,8 @@ editor::show_editor() noexcept
tf.ed = this;
file = &tf;
out.file_id = file_outs.get_id(tf);
auto& o = sim.observers.alloc(
0.01, names[i].c_str(), (void*)file);
o.initialize = &observation_file_output_initialize;
o.observe = &observation_file_output_observe;
o.free = &observation_file_output_free;
auto& o =
sim.observers.alloc(0.01, names[i].c_str(), tf);
sim.observe(*mdl, o);
}
ImGui::InputText(
......
......@@ -218,6 +218,9 @@ static inline window_logger log_w;
struct editor;
enum class plot_output_id : u64;
enum class file_output_id : u64;
struct plot_output
{
plot_output() = default;
......@@ -226,6 +229,10 @@ struct plot_output
: name(name_)
{}
void operator()(const irt::observer& obs,
const irt::time t,
const irt::observer::status s);
editor* ed = nullptr;
std::vector<float> xs;
std::vector<float> ys;
......@@ -243,38 +250,16 @@ struct file_output
: name(name_)
{}
void operator()(const irt::observer& obs,
const irt::time t,
const irt::observer::status s);
editor* ed = nullptr;
std::ofstream ofs;
small_string<24u> name;
double tl = 0.0;
};
void
observation_plot_output_initialize(const irt::observer& obs,
const irt::time t) noexcept;
void
observation_file_output_initialize(const irt::observer& obs,
const irt::time t) noexcept;
void
observation_plot_output_observe(const irt::observer& obs,
const irt::time t,
const irt::message& msg) noexcept;
void
observation_file_output_observe(const irt::observer& obs,
const irt::time t,
const irt::message& msg) noexcept;
void
observation_plot_output_free(const irt::observer& /*obs*/,
const irt::time /*t*/) noexcept;
void
observation_file_output_free(const irt::observer& obs,
const irt::time /*t*/) noexcept;
enum class plot_output_id : u64;
enum class file_output_id : u64;
struct observation_output
{
constexpr observation_output() = default;
......
......@@ -16,6 +16,7 @@
#include <chrono>
#include <fstream>
#include <filesystem>
#include <string>
#include <fmt/format.h>
......@@ -27,100 +28,72 @@
namespace irt {
void
observation_plot_output_initialize(const irt::observer& obs,
const irt::time t) noexcept
plot_output::operator()(const irt::observer& obs,
const irt::time t,
const irt::observer::status s)
{
// const auto diff = ed.simulation_end - ed.simulation_begin;
// const auto freq = diff / obs->time_step;
// const auto length = std::min((size_t)freq, (size_t)4096);
if (!obs.user_data)
return;
switch (s) {
case irt::observer::status::initialize:
xs.clear();
ys.clear();
xs.reserve(4096u);
ys.reserve(4096u);
tl = t;
min = -1.f;
max = +1.f;
break;
case irt::observer::status::run: {
const float value = static_cast<float>(obs.msg[0]);
min = std::min(min, value);
max = std::max(max, value);
for (auto to_fill = tl; to_fill < t; to_fill += obs.time_step) {
ys.emplace_back(value);
xs.emplace_back(static_cast<float>(t));
}
auto* output = reinterpret_cast<plot_output*>(obs.user_data);
output->xs.clear();
output->ys.clear();
output->xs.reserve(4096u);
output->ys.reserve(4096u);
output->tl = t;
output->min = -1.f;
output->max = +1.f;
tl = t;
} break;
case irt::observer::status::finalize:
ys.emplace_back(static_cast<float>(obs.msg[0]));
xs.emplace_back(static_cast<float>(t));
break;
}
}
void
observation_file_output_initialize(const irt::observer& obs,
const irt::time t) noexcept
file_output::operator()(const irt::observer& obs,
const irt::time t,
const irt::observer::status s)
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
output->tl = t;
std::filesystem::path file;
if (output->ed && !output->ed->observation_directory.empty())
file = output->ed->observation_directory;
file.append(obs.name.begin());
file.replace_extension(".dat");
output->ofs.open(file);
if (output->ofs.is_open())
fmt::print(output->ofs, "t,{}\n", output->name.c_str());
}
void
observation_plot_output_observe(const irt::observer& obs,
const irt::time t,
const irt::message& msg) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<plot_output*>(obs.user_data);
const auto value = static_cast<float>(msg[0]);
output->min = std::min(output->min, value);
output->max = std::max(output->max, value);
for (auto to_fill = output->tl; to_fill < t; to_fill += obs.time_step) {
output->ys.emplace_back(value);
output->xs.emplace_back(static_cast<float>(t));
switch (s) {
case irt::observer::status::initialize:
tl = t;
if (ed && !ed->observation_directory.empty())
file = ed->observation_directory;
file.append(obs.name.begin());
file.replace_extension(".dat");
ofs.open(file);
if (ofs.is_open())
fmt::print(ofs, "t,{}\n", name.c_str());
break;
case irt::observer::status::run:
if (ofs.is_open())
fmt::print(ofs, "{},{}\n", t, obs.msg[0]);
tl = t;
break;
case irt::observer::status::finalize:
if (ofs.is_open()) {
fmt::print(ofs, "{},{}\n", t, obs.msg[0]);
ofs.close();
}
break;
}
output->tl = t;
}
void
observation_file_output_observe(const irt::observer& obs,
const irt::time t,
const irt::message& msg) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
const auto value = static_cast<float>(msg[0]);
fmt::print(output->ofs, "{},{}\n", t, value);
output->tl = t;
}
void
observation_plot_output_free(const irt::observer& /*obs*/,
const irt::time /*t*/) noexcept
{}
void
observation_file_output_free(const irt::observer& obs,
const irt::time /*t*/) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
output->ofs.close();
}
static void
......@@ -161,6 +134,8 @@ run_synchronized_simulation(window_logger& log_w,
std::chrono::duration<double>(duration));
} while (current < end && !stop);
sim.finalize(end);
st = editor_status::running_thread_need_join;
}
......@@ -194,6 +169,8 @@ run_simulation(window_logger& log_w,
}
} while (current < end && !stop);
sim.finalize(end);
st = editor_status::running_thread_need_join;
}
......
......@@ -18,40 +18,39 @@ using namespace std;
struct file_output
{
file_output(const char* file_path) noexcept
: os(std::fopen(file_path, "w"))
{}
std::FILE* os = nullptr;
std::string filename;
~file_output() noexcept
file_output(const std::string_view name)
: filename(name)
{
os = std::fopen(filename.c_str(), "w");
}
~file_output()
{
if (os)
std::fclose(os);
}
std::FILE* os = nullptr;
};
void
file_output_initialize(const irt::observer& obs, const irt::time /*t*/) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
fmt::print(output->os, "t,{}\n", obs.name.c_str());
}
void
file_output_observe(const irt::observer& obs,
void operator()(const irt::observer& obs,
const irt::time t,
const irt::message& msg) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
fmt::print(output->os, "{},{}\n", t, msg.real[0]);
}
const irt::observer::status s) noexcept
{
switch (s) {
case irt::observer::status::initialize:
fmt::print(os, "t,{}\n", obs.name.c_str());
break;
case irt::observer::status::run:
fmt::print(os, "{},{}\n", t, obs.msg.real[0]);
break;
case irt::observer::status::finalize:
break;
}
}
};
struct neuron
{
......@@ -148,12 +147,7 @@ lif_benchmark(double simulation_duration, double quantum)
file_output fo_a(file_name.c_str());
expect(fo_a.os != nullptr);
auto& obs_a = sim.observers.alloc(0.01,
"A",
static_cast<void*>(&fo_a),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_a = sim.observers.alloc(0.01, "A", fo_a);
sim.observe(sim.models.get(
sim.qss2_integrator_models.get(neuron_model.integrator).id),
obs_a);
......@@ -317,12 +311,7 @@ izhikevich_benchmark(double simulation_duration,
file_output fo_a(file_name.c_str());
expect(fo_a.os != nullptr);
auto& obs_a = sim.observers.alloc(0.01,
"A",
static_cast<void*>(&fo_a),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_a = sim.observers.alloc(0.01, "A", fo_a);
file_name = "output_izhikevitch_aqss_b_sd_" +
std::to_string(simulation_duration) + "_q_" +
std::to_string(quantum) + "_a_" + std::to_string(a) + "_b_" +
......@@ -330,12 +319,7 @@ izhikevich_benchmark(double simulation_duration,
std::to_string(d) + ".csv";
file_output fo_b(file_name.c_str());
expect(fo_b.os != nullptr);
auto& obs_b = sim.observers.alloc(0.01,
"B",
static_cast<void*>(&fo_b),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_b = sim.observers.alloc(0.01, "B", fo_b);
sim.observe(sim.models.get(integrator_a.id), obs_a);
sim.observe(sim.models.get(integrator_b.id), obs_b);
......
......@@ -18,40 +18,39 @@ using namespace std;
struct file_output
{
file_output(const char* file_path) noexcept
: os(std::fopen(file_path, "w"))
{}
std::FILE* os = nullptr;
std::string filename;
~file_output() noexcept
file_output(const std::string_view name)
: filename(name)
{
os = std::fopen(filename.c_str(), "w");
}
~file_output()
{
if (os)
std::fclose(os);
}
std::FILE* os = nullptr;
};
void
file_output_initialize(const irt::observer& obs, const irt::time /*t*/) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
fmt::print(output->os, "t,{}\n", obs.name.c_str());
}
void
file_output_observe(const irt::observer& obs,
void operator()(const irt::observer& obs,
const irt::time t,
const irt::message& msg) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
fmt::print(output->os, "{},{}\n", t, msg.real[0]);
}
const irt::observer::status s)
{
switch (s) {
case irt::observer::status::initialize:
fmt::print(os, "t,{}\n", obs.name.c_str());
break;
case irt::observer::status::run:
fmt::print(os, "{},{}\n", t, obs.msg.real[0]);
break;
case irt::observer::status::finalize:
break;
}
}
};
struct neuron
{
......@@ -138,12 +137,7 @@ lif_benchmark(double simulation_duration, double quantum)
file_output fo_a(file_name.c_str());
expect(fo_a.os != nullptr);
auto& obs_a = sim.observers.alloc(0.1,
"A",
static_cast<void*>(&fo_a),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_a = sim.observers.alloc(0.1, "A", fo_a);
sim.observe(sim.models.get(
sim.qss1_integrator_models.get(neuron_model.integrator).id),
obs_a);
......@@ -261,12 +255,8 @@ izhikevich_benchmark(double simulation_duration,
file_output fo_a(file_name.c_str());
expect(fo_a.os != nullptr);
auto& obs_a = sim.observers.alloc(0.01,
"A",
static_cast<void*>(&fo_a),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_a = sim.observers.alloc(0.01, "A", fo_a);
file_name = "output_izhikevitch_qss1_b_sd_" +
std::to_string(simulation_duration) + "_q_" +
std::to_string(quantum) + "_a_" + std::to_string(a) + "_b_" +
......@@ -274,12 +264,7 @@ izhikevich_benchmark(double simulation_duration,
std::to_string(d) + ".csv";
file_output fo_b(file_name.c_str());
expect(fo_b.os != nullptr);
auto& obs_b = sim.observers.alloc(0.01,
"B",
static_cast<void*>(&fo_b),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_b = sim.observers.alloc(0.01, "B", fo_b);
sim.observe(sim.models.get(integrator_a.id), obs_a);
sim.observe(sim.models.get(integrator_b.id), obs_b);
......
......@@ -18,40 +18,39 @@ using namespace std;
struct file_output
{
file_output(const char* file_path) noexcept
: os(std::fopen(file_path, "w"))
{}
std::FILE* os = nullptr;
std::string filename;
~file_output() noexcept
file_output(const std::string_view name)
: filename(name)
{
os = std::fopen(filename.c_str(), "w");
}
~file_output()
{
if (os)
std::fclose(os);
}
std::FILE* os = nullptr;
};
void
file_output_initialize(const irt::observer& obs, const irt::time /*t*/) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
fmt::print(output->os, "t,{}\n", obs.name.c_str());
}
void
file_output_observe(const irt::observer& obs,
void operator()(const irt::observer& obs,
const irt::time t,
const irt::message& msg) noexcept
{
if (!obs.user_data)
return;
auto* output = reinterpret_cast<file_output*>(obs.user_data);
fmt::print(output->os, "{},{}\n", t, msg.real[0]);
}
const irt::observer::status s)
{
switch (s) {
case irt::observer::status::initialize:
fmt::print(os, "t,{}\n", obs.name.c_str());
break;
case irt::observer::status::run:
fmt::print(os, "{},{}\n", t, obs.msg.real[0]);
break;
case irt::observer::status::finalize:
break;
}
}
};
struct neuron
{
......@@ -137,12 +136,8 @@ lif_benchmark(double simulation_duration, double quantum)
file_output fo_a(file_name.c_str());
expect(fo_a.os != nullptr);
auto& obs_a = sim.observers.alloc(0.01,
"A",
static_cast<void*>(&fo_a),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_a = sim.observers.alloc(0.01, "A", fo_a);
sim.observe(sim.models.get(
sim.qss2_integrator_models.get(neuron_model.integrator).id),
obs_a);
......@@ -260,12 +255,7 @@ izhikevich_benchmark(double simulation_duration,
file_output fo_a(file_name.c_str());
expect(fo_a.os != nullptr);
auto& obs_a = sim.observers.alloc(0.01,
"A",
static_cast<void*>(&fo_a),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_a = sim.observers.alloc(0.01, "A", fo_a);
file_name = "output_izhikevitch_qss2_b_sd_" +
std::to_string(simulation_duration) + "_q_" +
std::to_string(quantum) + "_a_" + std::to_string(a) + "_b_" +
......@@ -273,12 +263,7 @@ izhikevich_benchmark(double simulation_duration,
std::to_string(d) + ".csv";
file_output fo_b(file_name.c_str());
expect(fo_b.os != nullptr);
auto& obs_b = sim.observers.alloc(0.01,
"B",
static_cast<void*>(&fo_b),
&file_output_initialize,
&file_output_observe,
nullptr);
auto& obs_b = sim.observers.alloc(0.01, "B", fo_b);
sim.observe(sim.models.get(integrator_a.id), obs_a);
sim.observe(sim.models.get(integrator_b.id), obs_b);
......