// 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) #ifdef _WIN32 #define NOMINMAX #define WINDOWS_LEAN_AND_MEAN #endif #include #include "gui.hpp" #include "imnodes.hpp" #include "implot.h" #include "node-editor.hpp" #include #include #include #include #include #include #include #include namespace irt { void plot_output::operator()(const irt::observer& obs, const irt::time t, const irt::observer::status s) { 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(obs.msg[0]); min = std::min(min, value); max = std::max(max, value); for (auto to_fill = tl; to_fill < t; to_fill += time_step) { ys.emplace_back(value); xs.emplace_back(static_cast(t)); } tl = t; } break; case irt::observer::status::finalize: ys.emplace_back(static_cast(obs.msg[0])); xs.emplace_back(static_cast(t)); break; } } void file_output::operator()(const irt::observer& obs, const irt::time t, const irt::observer::status s) { std::filesystem::path file; 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; } } static void run_synchronized_simulation(window_logger& log_w, simulation& sim, double begin, double end, double synchronize_timestep, double& current, editor_status& st, status& sim_st, const bool& stop) noexcept { current = begin; st = editor_status::initializing; if (sim_st = sim.initialize(current); irt::is_bad(sim_st)) { log_w.log(3, "Simulation initialization failure (%s)\n", irt::status_string(sim_st)); st = editor_status::editing; return; } st = editor_status::running_thread; do { const double old = current; if (sim_st = sim.run(current); irt::is_bad(sim_st)) { log_w.log( 3, "Simulation failure (%s)\n", irt::status_string(sim_st)); st = editor_status::editing; return; } const auto duration = (current - old) / synchronize_timestep; if (duration > 0.) std::this_thread::sleep_for( std::chrono::duration(duration)); } while (current < end && !stop); sim.finalize(end); st = editor_status::running_thread_need_join; } static void run_simulation(window_logger& log_w, simulation& sim, double begin, double end, double& current, editor_status& st, status& sim_st, const bool& stop) noexcept { current = begin; st = editor_status::initializing; if (sim_st = sim.initialize(current); irt::is_bad(sim_st)) { log_w.log(3, "Simulation initialization failure (%s)\n", irt::status_string(sim_st)); st = editor_status::editing; return; } st = editor_status::running_thread; do { if (sim_st = sim.run(current); irt::is_bad(sim_st)) { log_w.log( 3, "Simulation failure (%s)\n", irt::status_string(sim_st)); st = editor_status::editing; return; } } while (current < end && !stop); sim.finalize(end); st = editor_status::running_thread_need_join; } static void show_simulation_run_once(window_logger& log_w, editor& ed) { if (ed.st == editor_status::running_thread_need_join) { if (ed.simulation_thread.joinable()) { ed.simulation_thread.join(); ed.st = editor_status::editing; } } else if (ed.st == editor_status::editing || ed.st == editor_status::running_debug) { ImGui::Checkbox("Time synchronization", &ed.use_real_time); if (ed.use_real_time) { ImGui::InputDouble("t/s", &ed.synchronize_timestep); if (ed.synchronize_timestep > 0. && ImGui::Button("run")) { // initialize_observation(log_w, ed); ed.stop = false; ed.simulation_thread = std::thread(&run_synchronized_simulation, std::ref(log_w), std::ref(ed.sim), ed.simulation_begin, ed.simulation_end, ed.synchronize_timestep, std::ref(ed.simulation_current), std::ref(ed.st), std::ref(ed.sim_st), std::cref(ed.stop)); } } else { if (ImGui::Button("run")) { // initialize_observation(log_w, ed); ed.stop = false; ed.simulation_thread = std::thread(&run_simulation, std::ref(log_w), std::ref(ed.sim), ed.simulation_begin, ed.simulation_end, std::ref(ed.simulation_current), std::ref(ed.st), std::ref(ed.sim_st), std::cref(ed.stop)); } } } if (ed.st == editor_status::running_thread) { ImGui::SameLine(); if (ImGui::Button("Force stop")) ed.stop = true; } } static void simulation_init(window_logger& log_w, editor& ed) { ed.sim.clean(); // initialize_observation(log_w, ed); ed.simulation_current = ed.simulation_begin; ed.simulation_during_date = ed.simulation_begin; ed.st = editor_status::initializing; ed.models_make_transition.resize(ed.sim.models.capacity(), false); if (ed.sim_st = ed.sim.initialize(ed.simulation_current); irt::is_bad(ed.sim_st)) { log_w.log(3, "Simulation initialisation failure (%s)\n", irt::status_string(ed.sim_st)); ed.st = editor_status::editing; } else { ed.simulation_next_time = ed.sim.sched.empty() ? time_domain