|
@@ -0,0 +1,375 @@
|
|
|
+/**
|
|
|
+ * @file kernel/devs/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 DEVS_COORDINATOR
|
|
|
+#define DEVS_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 <cassert>
|
|
|
+
|
|
|
+namespace artis {
|
|
|
+ namespace devs {
|
|
|
+
|
|
|
+ template<class Time,
|
|
|
+ class GraphManager,
|
|
|
+ class Select,
|
|
|
+ class Parameters = common::NoParameters,
|
|
|
+ class GraphParameters = common::NoParameters>
|
|
|
+ class Coordinator : public common::Coordinator<Time> {
|
|
|
+ typedef Coordinator<Time, GraphManager, 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),
|
|
|
+ _d_star(nullptr) { }
|
|
|
+
|
|
|
+ virtual ~Coordinator() = default;
|
|
|
+
|
|
|
+ GraphManager& get_graph_manager() { return _graph_manager; }
|
|
|
+
|
|
|
+ const GraphManager& 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) << "p-devs coordinator \""
|
|
|
+ << this->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;
|
|
|
+#else
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::FINISH,
|
|
|
+ common::LevelType::FORMALISM);
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ typename Time::type start(const typename Time::type& t)
|
|
|
+ {
|
|
|
+// When i-message (i, t) at time t
|
|
|
+// for-each d ∈ D do
|
|
|
+// send i-message (i, t) to child d
|
|
|
+// sort event-list according to tn,d (and select)
|
|
|
+// tl = t
|
|
|
+// tn = min{tn,d | d ∈ D}
|
|
|
+// End
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::I_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << "tl = " << this->_tl << " ; tn = "
|
|
|
+ << this->_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);
|
|
|
+ }
|
|
|
+ this->_tl = t;
|
|
|
+ this->_tn = _event_table.get_current_time();
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::I_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << "tl = " << this->_tl
|
|
|
+ << " ; tn = " << this->_tn;
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ return this->_tn;
|
|
|
+ }
|
|
|
+
|
|
|
+ void output(const typename Time::type& t)
|
|
|
+ {
|
|
|
+// When *-message (*, t)
|
|
|
+// if t != tn then Error
|
|
|
+// d* = first({d | (d, th,d) ∈ (event-list & tn,d = tn) })
|
|
|
+// send *-message (*, t) to d*
|
|
|
+// End
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << "tl = " << this->_tl << " ; tn = "
|
|
|
+ << this->_tn << " ; scheduler = " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ assert(t == this->_tn);
|
|
|
+
|
|
|
+ _d_star = Select()(_event_table.get_current_models(t));
|
|
|
+
|
|
|
+ assert(_d_star);
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": d* = " << _d_star->get_name();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ _d_star->output(t);
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << "tl = " << this->_tl << " ; tn = "
|
|
|
+ << this->_tn << " ; scheduler = " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ typename Time::type transition(const typename Time::type& t)
|
|
|
+ {
|
|
|
+// When x-message (x, t)
|
|
|
+// if not (tl <= t <= tn) then Error
|
|
|
+// receivers = { r | r ∈ D, N ∈ Ir, Z(N,r)(x) isn't empty }
|
|
|
+// for each r ∈ receivers
|
|
|
+// send x-message(Z(N,r)(x), t) with input value Z(N,r)(x) to r
|
|
|
+// for each r ∈ IMM and not in receivers
|
|
|
+// send x-message(empty, t) to r
|
|
|
+// sort event list according to tn (and select)
|
|
|
+// tl = t
|
|
|
+// tn = min(tn,d | d ∈ D)
|
|
|
+// End
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << "tl = " << this->_tl << " ; tn = "
|
|
|
+ << this->_tn << " ; scheduler = " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ assert(t >= this->_tl and t <= this->_tn);
|
|
|
+
|
|
|
+ common::Models<Time> receivers = get_receivers();
|
|
|
+ common::Models<Time> IMM = _event_table.get_current_models(t);
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": receivers = " << receivers.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ for (auto& model : receivers) {
|
|
|
+ _event_table.put(model->transition(t), model);
|
|
|
+ }
|
|
|
+ if (_d_star) {
|
|
|
+ _event_table.put(_d_star->transition(t), _d_star);
|
|
|
+ _d_star = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ update_event_table(t);
|
|
|
+ this->_tl = t;
|
|
|
+ this->_tn = _event_table.get_current_time();
|
|
|
+ this->clear_bag();
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::S_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << "tl = " << this->_tl << " ; tn = "
|
|
|
+ << this->_tn << " ; scheduler = " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ return this->_tn;
|
|
|
+ }
|
|
|
+
|
|
|
+ void post_event(const typename Time::type& t,
|
|
|
+ const common::ExternalEvent<Time>& event)
|
|
|
+ {
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::POST_EVENT,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << event.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ this->add_event(event);
|
|
|
+ _graph_manager.post_event(t, event);
|
|
|
+ update_event_table(t);
|
|
|
+ this->_tn = _event_table.get_current_time();
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ 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>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::Y_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": BEFORE => " << "tl = " << this->_tl << " ; tn = "
|
|
|
+ << this->_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);
|
|
|
+ this->_tn = _event_table.get_current_time();
|
|
|
+
|
|
|
+#ifdef WITH_TRACE
|
|
|
+ common::Trace<Time>::trace()
|
|
|
+ << common::TraceElement<Time>(this->get_name(), t,
|
|
|
+ common::FormalismType::DEVS,
|
|
|
+ common::FunctionType::Y_MESSAGE,
|
|
|
+ common::LevelType::FORMALISM)
|
|
|
+ << ": AFTER => " << "tl = " << this->_tl << " ; tn = " << this->_tn
|
|
|
+ << " ; " << _event_table.to_string();
|
|
|
+ common::Trace<Time>::trace().flush();
|
|
|
+#endif
|
|
|
+
|
|
|
+ return this->_tn;
|
|
|
+ }
|
|
|
+
|
|
|
+ common::Value observe(const typename Time::type& /* t */,
|
|
|
+ unsigned int /* index */) const
|
|
|
+ {
|
|
|
+ assert(false);
|
|
|
+ return common::Value();
|
|
|
+ }
|
|
|
+
|
|
|
+ common::Models<Time> get_imm_without_receivers(const common::Models<Time>& IMM,
|
|
|
+ const common::Models<Time>& receivers) const
|
|
|
+ {
|
|
|
+ common::Models<Time> imm;
|
|
|
+
|
|
|
+ for (auto& model : IMM) {
|
|
|
+ if (std::find(receivers.begin(), receivers.end(),
|
|
|
+ model) == receivers.end()) {
|
|
|
+ imm.push_back(model);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return imm;
|
|
|
+ }
|
|
|
+
|
|
|
+ common::Models<Time> get_receivers() const
|
|
|
+ {
|
|
|
+ common::Models<Time> receivers;
|
|
|
+
|
|
|
+ for (auto& model : _graph_manager.children()) {
|
|
|
+ if (model->event_number() > 0) {
|
|
|
+ receivers.push_back(model);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return receivers;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ common::SchedulerType _event_table;
|
|
|
+ common::Model<Time>* _d_star;
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+} // namespace artis devs
|
|
|
+
|
|
|
+#endif
|