Parcourir la source

Add new formalism: devs

Eric Ramat il y a 4 ans
Parent
commit
81e75cb90e

+ 4 - 2
src/artis-star/common/Bag.hpp

@@ -44,9 +44,11 @@ namespace artis {
         template<class Time>
         class Bag : public std::vector<ExternalEvent<Time> > {
         public:
-            Bag() { }
+            Bag() = default;
 
-            virtual ~Bag() { }
+            Bag(const ExternalEvent<Time>& event) { this->push_back(event); }
+
+            virtual ~Bag() = default;
 
             std::string to_string() const
             {

+ 43 - 9
src/artis-star/common/ExternalEvent.hpp

@@ -50,7 +50,11 @@ namespace artis {
         template<class Time>
         class ExternalEvent {
         public:
-            ExternalEvent(unsigned int port_index, const Value& data)
+            ExternalEvent(const Value& data)
+                    :
+                    _port_index(-1), _model(nullptr), _data(data) { }
+
+            ExternalEvent(int port_index, const Value& data)
                     :
                     _port_index(port_index), _model(nullptr), _data(data) { }
 
@@ -66,19 +70,41 @@ namespace artis {
                     _data(event._data) { }
 
             ExternalEvent()
-                    :_model(nullptr) { }
+                    :_port_index(-2), _model(nullptr) { }
 
-            virtual ~ExternalEvent() { }
+            virtual ~ExternalEvent() = default;
 
             const Value& data() const { return _data; }
 
-            unsigned int port_index() const { return _port_index; }
-
             void data(const Value& data) { _data = data; }
 
             Model<Time>* get_model() const { return _model; }
 
-            bool on_port(unsigned int port_index) const { return _port_index == port_index; }
+            bool is_void() const { return _port_index == -2; }
+
+            bool on_port(int port_index) const
+            {
+
+                assert(_port_index != -1);
+
+                return _port_index == port_index;
+            }
+
+            ExternalEvent& operator=(const ExternalEvent& e)
+            {
+                _port_index = e._port_index;
+                _model = e._model;
+                _data = e._data;
+                return *this;
+            }
+
+            int port_index() const
+            {
+
+                assert(_port_index != -1);
+
+                return _port_index;
+            }
 
             void set_model(Model<Time>* model) { _model = model; }
 
@@ -86,8 +112,11 @@ namespace artis {
             {
                 std::ostringstream ss;
 
-                ss << "( " << _port_index << " , "
-                   << (_model ? _model->get_name() : "<>")
+                ss << "( ";
+                if (_port_index != -1) {
+                    ss << _port_index << " , ";
+                }
+                ss << (_model ? _model->get_name() : "<>")
                    << " , ";
                 if (not _data.empty()) {
                     ss << _data.to_string();
@@ -98,6 +127,8 @@ namespace artis {
                 return ss.str();
             }
 
+            static ExternalEvent Void;
+
         private:
             friend class boost::serialization::access;
 
@@ -113,11 +144,14 @@ namespace artis {
                 // ar & _model->get_name();
             }
 
-            unsigned int _port_index;
+            int _port_index;
             Model<Time>* _model;
             Value _data;
         };
 
+        template<class Time>
+        ExternalEvent<Time> ExternalEvent<Time>::Void;
+
     }
 } // namespace artis common
 

+ 3 - 3
src/artis-star/common/Links.hpp

@@ -108,7 +108,8 @@ namespace artis {
             void remove(common::Model<Time>* src_model, unsigned int src_port_index,
                     common::Model<Time>* dst_model, unsigned int dst_port_index)
             {
-                typename Links<Time>::const_iterator result = find(src_model, src_port_index, dst_model, dst_port_index);
+                typename Links<Time>::const_iterator result = find(src_model, src_port_index,
+                        dst_model, dst_port_index);
 
                 this->erase(result);
             }
@@ -132,8 +133,7 @@ namespace artis {
                 std::stringstream ss;
 
                 ss << common::String::make_spaces(level * 2) << "Links:" << std::endl;
-                for (typename Links<Time>::const_iterator it =
-                        Links<Time>::begin();
+                for (typename Links<Time>::const_iterator it = Links<Time>::begin();
                      it != Links<Time>::end(); ++it) {
                     ss << common::String::make_spaces((level + 1) * 2)
                        << it->first.get_model()->get_name() << "::"

+ 3 - 1
src/artis-star/common/Value.hpp

@@ -96,7 +96,9 @@ namespace artis {
 
             std::string to_string() const
             {
-                if (is_type<double>()) {
+                if (empty()) {
+                    return "<null>";
+                } else if (is_type<double>()) {
                     double v;
 
                     operator()(v);

+ 1 - 0
src/artis-star/kernel/CMakeLists.txt

@@ -1,3 +1,4 @@
+ADD_SUBDIRECTORY(devs)
 ADD_SUBDIRECTORY(dsde)
 ADD_SUBDIRECTORY(dtss)
 ADD_SUBDIRECTORY(fddevs)

+ 11 - 0
src/artis-star/kernel/devs/CMakeLists.txt

@@ -0,0 +1,11 @@
+INCLUDE_DIRECTORIES(
+        ${ARTIS_BINARY_DIR}/src
+        ${ARTIS_SOURCE_DIR}/src
+        ${Boost_INCLUDE_DIRS})
+
+LINK_DIRECTORIES(
+        ${Boost_LIBRARY_DIRS})
+
+SET(DEVS_HPP Coordinator.hpp Dynamics.hpp GraphManager.hpp Simulator.hpp)
+
+INSTALL(FILES ${DEVS_HPP} DESTINATION ${ARTIS_INCLUDE_DIRS}/kernel/devs)

+ 375 - 0
src/artis-star/kernel/devs/Coordinator.hpp

@@ -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

+ 115 - 0
src/artis-star/kernel/devs/Dynamics.hpp

@@ -0,0 +1,115 @@
+/**
+ * @file kernel/devs/Dynamics.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_DYNAMICS
+#define DEVS_DYNAMICS
+
+#include <artis-star/common/Bag.hpp>
+#include <artis-star/common/ExternalEvent.hpp>
+#include <artis-star/common/Parameters.hpp>
+#include <artis-star/common/States.hpp>
+#include <artis-star/kernel/devs/Simulator.hpp>
+
+namespace artis {
+    namespace devs {
+
+        template<class Time, class Dyn, class Parameters = common::NoParameters>
+        class Dynamics : public common::States<Time, Dyn> {
+            typedef devs::Simulator<Time, Dyn, Parameters> Simulator;
+
+        public:
+            struct Observable {
+                unsigned int index;
+                std::string name;
+            };
+
+            typedef std::map<unsigned int, std::string> Observables;
+
+            Dynamics(const std::string& name, const Context<Time, Dyn, Parameters>& context)
+                    :
+                    _name(name), _simulator(context.simulator()) { }
+
+            virtual ~Dynamics() { }
+
+            virtual void dint(typename Time::type /* t */) { }
+
+            virtual void dext(typename Time::type /* t */, typename Time::type /* e */,
+                    const common::ExternalEvent<Time>& /* event */) { }
+
+            virtual void start(typename Time::type /* time */) { }
+
+            virtual typename Time::type
+            ta(typename Time::type /* time */) const { return Time::infinity; }
+
+            virtual common::ExternalEvent<Time>
+            lambda(typename Time::type /* time */) const { return common::ExternalEvent<Time>(); }
+
+            virtual common::Value observe(const typename Time::type& /* t */,
+                    unsigned int /* index */) const { return common::Value(); }
+
+            const std::string& get_name() const { return _name; }
+
+            void observable(Observable observable)
+            {
+                _observables[observable.index] = observable.name;
+            }
+
+            void observables(std::initializer_list<Observable> list)
+            {
+                for (typename std::initializer_list<Observable>::iterator it = list.begin();
+                     it != list.end();
+                     ++it) {
+                    _observables[it->index] = it->name;
+                }
+            }
+
+            virtual std::string observable_name(unsigned int observable_index) const
+            {
+                assert(_observables.find(observable_index) != _observables.end());
+
+                return _observables.find(observable_index)->second;
+            }
+
+            void restore(const common::context::State<Time>& state)
+            {
+                common::States<Time, Dyn>::restore(static_cast<Dyn*>(this), state);
+            }
+
+            void save(common::context::State<Time>& state) const
+            {
+                common::States<Time, Dyn>::save(static_cast<const Dyn*>(this), state);
+            }
+
+        private:
+            std::string _name;
+            Simulator* _simulator;
+            Observables _observables;
+        };
+
+    }
+} // namespace artis devs
+
+#endif

+ 142 - 0
src/artis-star/kernel/devs/GraphManager.hpp

@@ -0,0 +1,142 @@
+/**
+ * @file kernel/devs/GraphManager.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_GRAPH_MANAGER
+#define DEVS_GRAPH_MANAGER
+
+#include <artis-star/common/Coordinator.hpp>
+#include <artis-star/common/GraphManager.hpp>
+#include <artis-star/common/Model.hpp>
+#include <artis-star/common/Parameters.hpp>
+#include <artis-star/common/utils/String.hpp>
+
+#include <sstream>
+
+namespace artis {
+    namespace devs {
+
+        template<class Time,
+                class Parameters = common::NoParameters,
+                class GraphParameters = common::NoParameters>
+        class GraphManager : public common::GraphManager<Time> {
+        public:
+            typedef GraphManager<Time, Parameters, GraphParameters> type;
+            typedef std::pair<common::Model<Time>*, common::Model<Time>*> Link;
+            typedef std::vector<Link> Links;
+
+            GraphManager(common::Coordinator<Time>* coordinator,
+                    const Parameters& /* parameters */,
+                    const GraphParameters& /* graph_parameters */)
+                    :
+                    common::GraphManager<Time>(coordinator) { }
+
+            ~GraphManager() override = default;
+
+            void dispatch_events(common::Bag<Time> bag, typename Time::type t)
+            {
+                for (auto& ymsg : bag) {
+                    auto it = std::find_if(_links.begin(), _links.end(),
+                            [&ymsg](const Link& link) { return link.first == ymsg.get_model(); });
+
+                    if (it != _links.end()) {
+                        // event on output port of coupled Model
+                        if (it->second == common::GraphManager<Time>::_coordinator) {
+                            dispatch_events_to_parent(ymsg.data(), t);
+                        } else { // event on input port of internal model
+                            it->second->post_event(t, common::ExternalEvent<Time>(ymsg.data()));
+                        }
+                    }
+                }
+            }
+
+            virtual void
+            dispatch_events_to_parent(const common::Value& content, typename Time::type t)
+            {
+                common::Bag<Time> ymessages;
+
+                ymessages.push_back(common::ExternalEvent<Time>(content));
+                if (common::GraphManager<Time>::_coordinator->get_parent()) {
+                    dynamic_cast < common::Coordinator<Time>* >(common::GraphManager<Time>::_coordinator->get_parent())
+                            ->dispatch_events(ymessages, t);
+                }
+            }
+
+            bool exist_link(common::Model<Time>* src_model, common::Model<Time>* dst_model) const
+            {
+                return _links.find(std::make_pair(src_model, dst_model));
+            }
+
+            void post_event(typename Time::type t, const common::ExternalEvent<Time>& event)
+            {
+                auto it = std::find_if(_links.begin(), _links.end(),
+                        [this](const Link& link) {
+                            return link.first == common::GraphManager<Time>::_coordinator;
+                        });
+
+                if (it != _links.end()) {
+                    it->second->post_event(t,
+                            common::ExternalEvent<Time>(event.data()));
+                }
+            }
+
+            virtual std::string to_string(int level) const
+            {
+                std::ostringstream ss;
+
+                ss << common::String::make_spaces(level * 2) << "Children :" << std::endl;
+                for (auto& child : common::GraphManager<Time>::_children) {
+                    ss << child->to_string(level + 1);
+                }
+                ss << common::String::make_spaces(level * 2) << "Links:" << std::endl;
+                for (typename Links::const_iterator it = _links.begin(); it != _links.end(); ++it) {
+                    ss << common::String::make_spaces((level + 1) * 2)
+                       << it->first->get_name() << " -> "
+                       << it->second->get_name() << std::endl;
+                }
+                return ss.str();
+            }
+
+            void add_link(common::Model<Time>* src_model, common::Model<Time>* dst_model)
+            {
+                assert((src_model != common::GraphManager<Time>::_coordinator and
+                        dst_model != common::GraphManager<Time>::_coordinator and
+                        src_model != dst_model) or
+                        (src_model == common::GraphManager<Time>::_coordinator and
+                                dst_model != common::GraphManager<Time>::_coordinator) or
+                        (src_model != common::GraphManager<Time>::_coordinator and
+                                dst_model == common::GraphManager<Time>::_coordinator));
+
+                _links.push_back(std::make_pair(src_model, dst_model));
+            }
+
+        private:
+            Links _links;
+        };
+
+    }
+} // namespace artis devs
+
+#endif

+ 278 - 0
src/artis-star/kernel/devs/Simulator.hpp

@@ -0,0 +1,278 @@
+/**
+ * @file kernel/devs/Simulator.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_SIMULATOR
+#define DEVS_SIMULATOR
+
+#include <artis-star/common/Coordinator.hpp>
+#include <artis-star/common/Parameters.hpp>
+#include <artis-star/common/Simulator.hpp>
+#include <artis-star/common/utils/String.hpp>
+#include <artis-star/common/utils/Trace.hpp>
+
+namespace artis {
+    namespace devs {
+
+        template<class Time, class Dynamics, class Parameters>
+        class Simulator;
+
+        template<class Time, class Dynamics,
+                class Parameters = common::NoParameters>
+        class Context {
+            typedef devs::Simulator<Time, Dynamics, Parameters> Simulator;
+
+        public:
+            Context(const Parameters& parameters, Simulator* simulator)
+                    :
+                    _parameters(parameters), _simulator(simulator) { }
+
+            virtual ~Context() { }
+
+            const Parameters& parameters() const { return _parameters; }
+
+            Simulator* simulator() const { return _simulator; }
+
+        private:
+            const Parameters& _parameters;
+            Simulator* _simulator;
+        };
+
+        template<class Time, class Dynamics,
+                class Parameters = common::NoParameters>
+        class Simulator : public common::Simulator<Time> {
+            typedef Simulator<Time, Dynamics, Parameters> type;
+
+        public :
+            Simulator(const std::string& name, const Parameters& parameters)
+                    :
+                    common::Model<Time>(name),
+                    common::Simulator<Time>(name),
+                    _dynamics(name, Context<Time, Dynamics, Parameters>(parameters, this)) { }
+
+            ~Simulator() override { }
+
+            const Dynamics& dynamics() const { return _dynamics; }
+
+            virtual void restore(const common::context::State<Time>& state)
+            {
+                common::Simulator<Time>::restore(state);
+                _dynamics.restore(state);
+            }
+
+            virtual void save(common::context::State<Time>& state) const
+            {
+                common::Simulator<Time>::save(state);
+                _dynamics.save(state);
+            }
+
+            virtual std::string to_string(int level) const
+            {
+                std::ostringstream ss;
+
+                ss << common::String::make_spaces(level * 2) << "p-devs simulator \""
+                   << type::get_name() << "\"" << std::endl;
+                return ss.str();
+            }
+
+            virtual void finish(const typename Time::type& t)
+            {
+#ifndef WITH_TRACE
+                (void) t;
+#else
+                common::Trace<Time>::trace()
+                        << common::TraceElement<Time>(type::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(t)
+//                  tl = t - e
+//                  tn = tl + ta(s)
+//                End
+
+#ifdef WITH_TRACE
+                common::Trace<Time>::trace()
+                        << common::TraceElement<Time>(type::get_name(), t,
+                                common::FormalismType::DEVS,
+                                common::FunctionType::I_MESSAGE,
+                                common::LevelType::FORMALISM)
+                        << ": BEFORE => " << "tl = " << type::_tl << " ; tn = "
+                        << type::_tn;
+                common::Trace<Time>::trace().flush();
+#endif
+
+                _dynamics.start(t);
+                type::_tl = t;
+                type::_tn = type::_tl + _dynamics.ta(t);
+
+#ifdef WITH_TRACE
+                common::Trace<Time>::trace()
+                        << common::TraceElement<Time>(type::get_name(), t,
+                                common::FormalismType::DEVS,
+                                common::FunctionType::I_MESSAGE,
+                                common::LevelType::FORMALISM)
+                        << ": AFTER => " << "tl = " << type::_tl << " ; tn = "
+                        << type::_tn;
+                common::Trace<Time>::trace().flush();
+#endif
+
+                return type::_tn;
+            }
+
+            common::Value observe(const typename Time::type& t,
+                    unsigned int index) const { return _dynamics.observe(t, index); }
+
+            virtual std::string observable_name(unsigned int observable_index) const
+            {
+                return _dynamics.observable_name(observable_index);
+            }
+
+            void output(const typename Time::type& t)
+            {
+//                When *-message(t)
+//                  if (t != tn) then Error
+//                  y = lambda(s)
+//                  send y-message(y,t) to parent coordinator
+//                End
+
+#ifdef WITH_TRACE
+                common::Trace<Time>::trace()
+                        << common::TraceElement<Time>(type::get_name(), t,
+                                common::FormalismType::DEVS,
+                                common::FunctionType::OUTPUT,
+                                common::LevelType::FORMALISM)
+                                << ": BEFORE";
+                common::Trace<Time>::trace().flush();
+#endif
+
+                assert(t == type::_tn);
+
+                common::ExternalEvent<Time> event(_dynamics.lambda(t));
+
+                if (not event.is_void()) {
+                    event.set_model(this);
+                    dynamic_cast < common::Coordinator<Time>* >(
+                            type::get_parent())->dispatch_events(common::Bag<Time>(event), t);
+                }
+
+#ifdef WITH_TRACE
+                common::Trace<Time>::trace()
+                        << common::TraceElement<Time>(type::get_name(), t,
+                                common::FormalismType::DEVS,
+                                common::FunctionType::OUTPUT,
+                                common::LevelType::FORMALISM)
+                                << ": AFTER";
+                common::Trace<Time>::trace().flush();
+#endif
+
+            }
+
+            void post_event(const typename Time::type& t, const common::ExternalEvent<Time>& event)
+            {
+
+#ifndef WITH_TRACE
+                (void) t;
+#else
+                common::Trace<Time>::trace()
+                        << common::TraceElement<Time>(type::get_name(), t,
+                                common::FormalismType::DEVS,
+                                common::FunctionType::POST_EVENT,
+                                common::LevelType::FORMALISM)
+                        << ": event = " << event.to_string();
+                common::Trace<Time>::trace().flush();
+#endif
+
+                type::add_event(event);
+            }
+
+            typename Time::type transition(const typename Time::type& t)
+            {
+//                When x-message(t)
+//                  if not (tl <= t <= tn) then Error
+//                  if (x is empty and t = tn) then
+//                    s = delta_int(s)
+//                  else if (x isn't empty and t < tn)
+//                    e = t - tl
+//                    s = delta_ext(s,e,x)
+//                  tl = t
+//                  tn = tl + ta(s)
+//                End
+
+#ifdef WITH_TRACE
+                common::Trace<Time>::trace()
+                        << common::TraceElement<Time>(type::get_name(), t,
+                                common::FormalismType::DEVS,
+                                common::FunctionType::S_MESSAGE,
+                                common::LevelType::FORMALISM)
+                        << ": BEFORE => " << "tl = " << type::_tl << " ; tn = "
+                        << type::_tn;
+                common::Trace<Time>::trace().flush();
+#endif
+
+                assert(type::_tl <= t and t <= type::_tn);
+
+                if (t == type::_tn) {
+                    if (type::event_number() == 0) {
+                        _dynamics.dint(t);
+                    } else {
+                        assert(false);
+                    }
+                } else {
+
+                    assert(type::get_bag().size() == 1);
+
+                    _dynamics.dext(t, t - type::_tl, type::get_bag().at(0));
+                }
+                type::_tl = t;
+                type::_tn = type::_tl + _dynamics.ta(t);
+                type::clear_bag();
+
+#ifdef WITH_TRACE
+                common::Trace<Time>::trace()
+                        << common::TraceElement<Time>(type::get_name(), t,
+                                common::FormalismType::DEVS,
+                                common::FunctionType::S_MESSAGE,
+                                common::LevelType::FORMALISM)
+                        << ": AFTER => " << "tl = " << type::_tl << " ; tn = " << type::_tn;
+                common::Trace<Time>::trace().flush();
+#endif
+
+                return type::_tn;
+            }
+
+        private :
+            Dynamics _dynamics;
+        };
+
+    }
+} // namespace artis devs
+
+#endif

+ 15 - 11
src/artis-star/kernel/pdevs/Coordinator.hpp

@@ -217,9 +217,8 @@ namespace artis {
 
                 assert(t >= type::_tl and t <= type::_tn);
 
-                common::Models<Time> receivers = _event_table.get_current_models(t);
-
-                add_models_with_inputs(receivers);
+                common::Models<Time> receivers = get_receivers();
+                common::Models<Time> IMM = _event_table.get_current_models(t);
 
 #ifdef WITH_TRACE
                 common::Trace<Time>::trace()
@@ -227,14 +226,20 @@ namespace artis {
                                 common::FormalismType::PDEVS,
                                 common::FunctionType::S_MESSAGE,
                                 common::LevelType::FORMALISM)
-                        << ": receivers = " << receivers.to_string();
+                        << ": receivers = " << receivers.to_string()
+                        << " ; IMM = " << IMM.to_string();
                 common::Trace<Time>::trace().flush();
 #endif
 
                 for (auto& model : receivers) {
                     _event_table.put(model->transition(t), model);
                 }
-
+                for (auto& model : IMM) {
+                    if (std::find(receivers.begin(), receivers.end(),
+                            model) == receivers.end()) {
+                        _event_table.put(model->transition(t), model);
+                    }
+                }
                 update_event_table(t);
                 type::_tl = t;
                 type::_tn = _event_table.get_current_time();
@@ -326,17 +331,16 @@ namespace artis {
                 return common::Value();
             }
 
-            void add_models_with_inputs(
-                    common::Models<Time>& receivers)
+            common::Models<Time> get_receivers() const
             {
+                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);
-                        }
+                        receivers.push_back(model);
                     }
                 }
+                return receivers;
             }
 
             void update_event_table(typename Time::type t)

+ 1 - 2
src/artis-star/kernel/pdevs/Dynamics.hpp

@@ -65,8 +65,7 @@ namespace artis {
             virtual void dext(typename Time::type /* t */, typename Time::type /* e */,
                     const common::Bag<Time>& /* bag */) { }
 
-            virtual typename Time::type
-            start(typename Time::type /* time */) { return Time::infinity; }
+            virtual void start(typename Time::type /* time */) { }
 
             virtual typename Time::type
             ta(typename Time::type /* time */) const { return Time::infinity; }

+ 4 - 7
src/artis-star/kernel/pdevs/Simulator.hpp

@@ -103,9 +103,7 @@ namespace artis {
             {
 #ifndef WITH_TRACE
                 (void) t;
-#endif
-
-#ifdef WITH_TRACE
+#else
                 common::Trace<Time>::trace()
                         << common::TraceElement<Time>(type::get_name(), t,
                                 common::FormalismType::PDEVS,
@@ -133,8 +131,9 @@ namespace artis {
                 common::Trace<Time>::trace().flush();
 #endif
 
+                _dynamics.start(t);
                 type::_tl = t;
-                type::_tn = type::_tl + _dynamics.start(t);
+                type::_tn = type::_tl + _dynamics.ta(t);
 
 #ifdef WITH_TRACE
                 common::Trace<Time>::trace()
@@ -206,9 +205,7 @@ namespace artis {
 
 #ifndef WITH_TRACE
                 (void) t;
-#endif
-
-#ifdef WITH_TRACE
+#else
                 common::Trace<Time>::trace()
                         << common::TraceElement<Time>(type::get_name(), t,
                                 common::FormalismType::PDEVS,