|
@@ -0,0 +1,392 @@
|
|
|
+/**
|
|
|
+ * @file kernel/dsde/Coordinator.hpp
|
|
|
+ * @author The ARTIS Development Team
|
|
|
+ * See the AUTHORS or Authors.txt file
|
|
|
+ */
|
|
|
+
|
|
|
+/*
|
|
|
+ * ARTIS - the multimodeling and simulation environment
|
|
|
+ * This file is a part of the ARTIS environment
|
|
|
+ *
|
|
|
+ * Copyright (C) 2013-2019 ULCO http://www.univ-littoral.fr
|
|
|
+ *
|
|
|
+ * This program is free software: you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
|
+ * the Free Software Foundation, either version 3 of the License, or
|
|
|
+ * (at your option) any later version.
|
|
|
+ *
|
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+ * GNU General Public License for more details.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU General Public License
|
|
|
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
+ */
|
|
|
+
|
|
|
+#ifndef DSDE_COORDINATOR
|
|
|
+#define DSDE_COORDINATOR 1
|
|
|
+
|
|
|
+#include <artis-star/common/Coordinator.hpp>
|
|
|
+#include <artis-star/common/Parameters.hpp>
|
|
|
+#include <artis-star/common/Scheduler.hpp>
|
|
|
+#include <artis-star/common/utils/String.hpp>
|
|
|
+#include <artis-star/common/utils/Trace.hpp>
|
|
|
+#include <artis-star/kernel/pdevs/Simulator.hpp>
|
|
|
+#include <artis-star/kernel/dsde/Executive.hpp>
|
|
|
+#include <artis-star/kernel/dsde/GraphManager.hpp>
|
|
|
+
|
|
|
+#include <cassert>
|
|
|
+
|
|
|
+namespace artis {
|
|
|
+ namespace dsde {
|
|
|
+
|
|
|
+ template<class Time,
|
|
|
+ class GraphManager,
|
|
|
+ class Executive,
|
|
|
+ class Parameters = common::NoParameters,
|
|
|
+ class GraphParameters = common::NoParameters>
|
|
|
+ class Coordinator : public common::Coordinator<Time> {
|
|
|
+ typedef Coordinator<Time, GraphManager, Executive, Parameters, GraphParameters> type;
|
|
|
+
|
|
|
+ public:
|
|
|
+ typedef Parameters parameters_type;
|
|
|
+ typedef GraphParameters graph_parameters_type;
|
|
|
+
|
|
|
+ Coordinator(const std::string& name, const Parameters& parameters,
|
|
|
+ const GraphParameters& graph_parameters)
|
|
|
+ :
|
|
|
+ common::Model<Time>(name),
|
|
|
+ common::Coordinator<Time>(name),
|
|
|
+ _graph_manager(this, parameters, graph_parameters),
|
|
|
+ _executive(parameters, graph_parameters, _graph_manager)
|
|
|
+ {
|
|
|
+ _graph_manager.add_child(0, &_executive);
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual ~Coordinator() { }
|
|
|
+
|
|
|
+ common::GraphManager<Time>& get_graph_manager() { return _graph_manager; }
|
|
|
+
|
|
|
+ const common::GraphManager<Time>& get_graph_manager() const { return _graph_manager; }
|
|
|
+
|
|
|
+ virtual std::string to_string(int level) const
|
|
|
+ {
|
|
|
+ std::ostringstream ss;
|
|
|
+
|
|
|
+ ss << common::String::make_spaces(level * 2) << "dsde coordinator \""
|
|
|
+ << type::get_name() << "\":" << std::endl;
|
|
|
+ ss << _graph_manager.to_string(level + 1);
|
|
|
+ return ss.str();
|
|
|
+ }
|
|
|
+
|
|
|
+ void restore(const common::context::State<Time>& state)
|
|
|
+ {
|
|
|
+ common::Coordinator<Time>::restore(state);
|
|
|
+ for (auto& child : _graph_manager.children()) {
|
|
|
+ _event_table.init(child->get_tn(), child);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void finish(const typename Time::type& t)
|
|
|
+ {
|
|
|
+#ifndef WITH_TRACE
|
|
|
+ (void) t;
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::DSDE,
|
|
|
+ common::FunctionType::FINISH,
|
|
|
+ common::LevelType::FORMALISM);
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ typename Time::type start(const typename Time::type& t)
|
|
|
+ {
|
|
|
+// Network Simulator Start Message
|
|
|
+// When receive (START,t)
|
|
|
+// send (START,t) to {I | I ∈ C}
|
|
|
+// tl ← t
|
|
|
+// tn ← min{tn,I | I ∈ C}
|
|
|
+// End
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::DSDE,
|
|
|
+ common::FunctionType::I_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << "tl = " << type::_tl << " ; tn = "
|
|
|
+ << type::_tn;
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ assert(_graph_manager.children().size() > 0);
|
|
|
+
|
|
|
+ for (auto& child : _graph_manager.children()) {
|
|
|
+ _event_table.init(child->start(t), child);
|
|
|
+ }
|
|
|
+ type::_tl = t;
|
|
|
+ type::_tn = _event_table.get_current_time();
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::DSDE,
|
|
|
+ common::FunctionType::I_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << "tl = " << type::_tl
|
|
|
+ << " ; tn = " << type::_tn;
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ return type::_tn;
|
|
|
+ }
|
|
|
+
|
|
|
+ void output(const typename Time::type& t)
|
|
|
+ {
|
|
|
+// Network Simulator Output Function
|
|
|
+// When receive (OUTPUT,t)
|
|
|
+// if t = tn then
|
|
|
+// send (OUTPUT,t) to {I | I ∈ C}
|
|
|
+// y ← Zn (× I ∈ In (y_t))
|
|
|
+// else
|
|
|
+// y ← φ
|
|
|
+// endIf
|
|
|
+// End
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << "tl = " << type::_tl << " ; tn = "
|
|
|
+ << type::_tn << " ; scheduler = " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ assert(t == type::_tn);
|
|
|
+
|
|
|
+ common::Models<Time> I_N = _event_table.get_current_models(t);
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": I_N = " << I_N.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ for (auto& model : I_N) {
|
|
|
+ model->output(t);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << "tl = " << type::_tl << " ; tn = "
|
|
|
+ << type::_tn << " ; scheduler = " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ typename Time::type transition(const typename Time::type& t)
|
|
|
+ {
|
|
|
+// Network Simulator Transition
|
|
|
+// When receive (TRANSITION,t,x)
|
|
|
+// if t ∉ [tl ,tn ] then ERROR endIf
|
|
|
+// if t < tn and x = φ then RETURN endIf
|
|
|
+// D' ← D
|
|
|
+// send (TRANSITION,t,Z_I ( × j ∈ I_I(v_j))) to {I | I ∈ D}
|
|
|
+// send (TRANSITION,t,Z_χ ( × j ∈ I_χ(v_j))) to χ
|
|
|
+// send (START,t) to {I | I ∈ D − D' }
|
|
|
+// tl ← t
|
|
|
+// tn ← min{tn,I | I ∈ C}
|
|
|
+// End
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << "tl = " << type::_tl << " ; tn = "
|
|
|
+ << type::_tn << " ; scheduler = " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ assert(t >= type::_tl and t <= type::_tn);
|
|
|
+
|
|
|
+ common::Models<Time> receivers = _event_table.get_current_models(t);
|
|
|
+
|
|
|
+ add_models_with_inputs(receivers);
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": receivers = " << receivers.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ bool found = false;
|
|
|
+
|
|
|
+ for (auto& model : receivers) {
|
|
|
+ if (model != &_executive) {
|
|
|
+ _event_table.put(model->transition(t), model);
|
|
|
+ } else {
|
|
|
+ found = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (found) {
|
|
|
+ _event_table.put(_executive.transition(t), &_executive);
|
|
|
+
|
|
|
+ if (not _graph_manager.new_models().empty()) {
|
|
|
+ for (auto& child : _graph_manager.new_models()) {
|
|
|
+ _event_table.init(child->start(t), child);
|
|
|
+ }
|
|
|
+ _graph_manager.clear_new_models();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ update_event_table(t);
|
|
|
+ type::_tl = t;
|
|
|
+ type::_tn = _event_table.get_current_time();
|
|
|
+ type::clear_bag();
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << "tl = " << type::_tl << " ; tn = "
|
|
|
+ << type::_tn << " ; scheduler = " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ return type::_tn;
|
|
|
+ }
|
|
|
+
|
|
|
+ void post_event(const typename Time::type& t,
|
|
|
+ const common::ExternalEvent<Time>& event)
|
|
|
+ {
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::POST_EVENT,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << event.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ type::add_event(event);
|
|
|
+ _graph_manager.post_event(t, event);
|
|
|
+ update_event_table(t);
|
|
|
+ type::_tn = _event_table.get_current_time();
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::POST_EVENT,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << event.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ typename Time::type dispatch_events(
|
|
|
+ const common::Bag<Time>& bag,
|
|
|
+ const typename Time::type& t)
|
|
|
+ {
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::Y_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << "tl = " << type::_tl << " ; tn = "
|
|
|
+ << type::_tn << " ; bag = " << bag.to_string()
|
|
|
+ << " ; " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ _graph_manager.dispatch_events(bag, t);
|
|
|
+ update_event_table(t);
|
|
|
+ type::_tn = _event_table.get_current_time();
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(type::get_name(), t,
|
|
|
+ common::FormalismType::PDEVS,
|
|
|
+ common::FunctionType::Y_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << "tl = " << type::_tl << " ; tn = " << type::_tn
|
|
|
+ << " ; " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ return type::_tn;
|
|
|
+ }
|
|
|
+
|
|
|
+ common::Value observe(const typename Time::type& /* t */,
|
|
|
+ unsigned int /* index */) const
|
|
|
+ {
|
|
|
+ assert(false);
|
|
|
+ return common::Value();
|
|
|
+ }
|
|
|
+
|
|
|
+ void add_models_with_inputs(common::Models<Time>& receivers)
|
|
|
+ {
|
|
|
+ for (auto& model : _graph_manager.children()) {
|
|
|
+ if (model->event_number() > 0) {
|
|
|
+ if (std::find(receivers.begin(), receivers.end(), model)
|
|
|
+ == receivers.end()) {
|
|
|
+ receivers.push_back(model);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void remove_model(const typename Time::type& t, common::Model<Time>* model) override
|
|
|
+ {
|
|
|
+ common::Coordinator<Time>::remove_model(t, model);
|
|
|
+ _event_table.remove_model(model);
|
|
|
+ }
|
|
|
+
|
|
|
+ void update_event_table(typename Time::type t)
|
|
|
+ {
|
|
|
+ for (auto& model : _graph_manager.children()) {
|
|
|
+ if (model->event_number() > 0) {
|
|
|
+ _event_table.put(t, model);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected:
|
|
|
+ GraphManager _graph_manager;
|
|
|
+ dsde::ExecutiveSimulator<Time, Executive, Parameters, GraphParameters> _executive;
|
|
|
+ common::SchedulerType _event_table;
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+} // namespace artis dsde
|
|
|
+
|
|
|
+#endif
|