1 /* Siconos is a program dedicated to modeling, simulation and control
2  * of non smooth dynamical systems.
3  *
4  * Copyright 2021 INRIA.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17 */
18 /*! \file EventsManager.hpp
19   \brief Management of a Set (STL) of Events for the Simulation process
20 */
21 
22 #ifndef EventsManager_H
23 #define EventsManager_H
24 
25 #include <vector>
26 #include <limits>
27 #include "SiconosFwd.hpp"
28 #include "TimeDiscretisation.hpp"
29 
30 const unsigned long int GAPLIMIT_DEFAULT = 100;
31 
32 /** set of events, with an ordering based on Event time value (mpz_t) to compare Events */
33 typedef std::vector<SP::Event> EventsContainer; // Event are already sorted
34 
35 /** Tools to handle a set of Events for the Simulation
36 
37    The EventsManager handles a set of events (from user time-discretisation, sensors, non-smooth ...),
38    and is supposed to provide to the simulation the values of "current" and "next" events to define
39    the time-integration interval.
40 
41    Events:
42    - currentEvent: starting time for integration. Initialized with t0 of the simulation time-discretisation.
43    - ETD: corresponds to the instant t[k+1] of the Simulation (user) TimeDiscretisation.
44    - ENonSmooth: for EventDriven simulation only. Present only if one or more non-smooth events have been
45    detected between currentEvent and the next event.
46    - Sensor or Actuators Events. To each Sensor or Actuator declared in the ControlManager, corresponds
47    an Event in the manager. When this event is processed, its time value is increased to next instant
48    in the time-discretisation of the sensor/actuator.
49 
50    Examples:
51    - for a TimeStepping, with one Sensor, the EventsManager looks like:\n
52    {currentEvent(tk), ESensor(tsensor), ETD(tk+1)}
53    - for an EventDriven, with one actuator, an non-smooth event detected at time tns: \n
54    {currentEvent(tk), EActuator(tact), ENonSmooth(tns), ETD(tk+1)}.
55 
56    After each process, the time values of each event are updated and nextEvent points to the first event after currentEvent.
57 
58    \section EMMfunc Main functions
59    - initialize(): process all events which have the same time as currentEvent
60    - processEvents(): process all events simultaneous to nextEvent, increment them to next step, update index sets,
61    increment currentEvent.
62 
63 
64 */
65 class EventsManager
66 {
67 protected:
68   /** serialization hooks
69   */
70   ACCEPT_SERIALIZATION(EventsManager);
71 
72   /** list of events
73    * The first element is the last processed event. All the others
74    * are unprocessed events.
75    * This list is not fixed and can be updated at any time
76    * depending on the simulation, user add ...
77    */
78   EventsContainer _events;
79 
80   /** Placeholder for the non smooth event */
81   SP::Event _eNonSmooth;
82 
83   /** Current index (for time instants) */
84   unsigned int _k;
85 
86   /** TimeDiscretisation for the time integration*/
87   SP::TimeDiscretisation _td;
88 
89   /** End of the Simulation */
90   double _T;
91 
92   /** unsigned long int variable to check if two events are too close */
93   static unsigned long int _GapLimit2Events;
94 
95   /** boolean to remember that a TD_EVENT has been deleted since a
96    * NS_EVENT was too close */
97   bool _NSeventInsteadOfTD;
98 
99   /** Insert an event in the event stack
100    * \param e the event to insert
101    * \return the position of the inserted event in the stack
102    */
103   unsigned int insertEv(SP::Event e);
104 
105   /** Update the set of events
106    * \param sim the Simulation using this EventsManager
107    */
108   void update(Simulation& sim);
109 
110   /** default constructor */
EventsManager()111   EventsManager() {};
112 
113 public:
114 
115   /**  default constructor
116    * \param td the TimeDiscretisation used in the Simulation
117    */
118   EventsManager(SP::TimeDiscretisation td);
119 
120   /** destructor
121    */
~EventsManager()122   virtual ~EventsManager() {};
123 
124   /** Initialize: just set the final time
125    * \param T the final time of the Simulation
126    */
127   void initialize(double T);
128 
129   /** Set the gap limit between two events
130    * \param var the new _GapLimit2Events
131    */
setGapLimitEvents(unsigned long int var)132   inline void setGapLimitEvents(unsigned long int var)
133   {
134     _GapLimit2Events = var;
135   };
136 
137   /** Get the gap limit between two events
138    * \return the gap limit
139    */
getGapLimitEvents() const140   inline unsigned long int getGapLimitEvents() const
141   {
142     return _GapLimit2Events;
143   };
144 
145   /** Change TimeDiscretisationEvent to TimeDiscretisationEventNoSaveInMemory
146    * \warning use this at your own risk, many integrators needs previous values
147    * to integrate properly
148    * \param sim the Simulation that owns this EventsManager
149    */
150   void noSaveInMemory(const Simulation& sim);
151 
152   /** get the current event
153    *  \return a pointer to Event
154    */
currentEvent() const155   inline SP::Event currentEvent() const
156   {
157     return _events[0];
158   };
159 
160   /** get the next event to be processed.
161    *  \return a pointer to Event
162    */
nextEvent() const163   inline SP::Event nextEvent() const
164   {
165     return _events[1];
166   };
167 
168   /** return all the events
169    * \return a reference to the events set
170    */
events()171   inline EventsContainer& events()
172   {
173     return _events;
174   };
175 
176   /** check if there are some unprocessed events
177    *  \return true if there are unprocessed events
178    */
hasNextEvent() const179   inline bool hasNextEvent() const
180   {
181     return _events.size() > 1;
182   };
183 
184   /** get the time of current event, in double format
185    *  \return the time of the last processed events
186    */
187   double startingTime() const ;
188 
189   /** get the time of next event, in double format
190    *  \return the time of the next events
191    */
192   double nextTime() const ;
193 
194   /** is an integration step required ? The current event and the next one may have
195    * the same time instant in which case no integration as to be performed
196    * \return true if the simulation needs to be integrate, no otherwise
197    */
198   bool needsIntegration() const;
199 
200   /** display EventsManager data
201    */
202   void display() const ;
203 
204   /** add a new Event in the allEvents list and update nextEvent value
205    * \param sim the simulation that owns this EventsManager
206    * \param time the time (double format) of occurence of the event
207    * \param yes_update indicator to update or not the next event (default value is true)
208    */
209   void scheduleNonSmoothEvent(Simulation& sim, double time, bool yes_update = true);
210 
211   /** Process the next event, update the indexSets if necessary
212    * \param sim the simulation that owns this EventsManager
213    */
214   void processEvents(Simulation& sim);
215 
216   /** Function to be called once after initialization.
217    * It is used to process NonSmoothEvents at the beginning of
218    * the Simulation, if there is any.
219    * \param sim the simulation that owns this EventsManager
220    */
221   void preUpdate(Simulation& sim);
222 
223   /** insert an event of a certain type. The event is created on the fly.
224    * \param type the type of the event
225    * \param time the time of the event
226    * \return a reference to the Event
227    */
228   Event& insertEvent(int type, double time);
229 
230   /** insert an event of a certain type. The event is created on the fly,
231    * and the SP::TimeDiscretisation given in argument is stored inside
232    * \param type the type of the event
233    * \param td a TimeDiscretisation for the Event
234    * \return a reference to the Event
235    */
236   Event& insertEvent(int type, SP::TimeDiscretisation td);
237 
getTk()238   double getTk()
239   {
240     return _td->getTk(_k);
241   }
242 
243   /** get time instant k+1 of the time discretisation
244    * \return a double. If the simulation is near the end (t_{k+1} >= T), it returns NaN.
245    */
getTkp1() const246   inline double getTkp1() const
247   {
248     double tkp1 = _td->getTk(_k+1);
249     if (tkp1 <= _T + 100.0*std::numeric_limits<double>::epsilon())
250       return tkp1;
251     else
252       return std::numeric_limits<double>::quiet_NaN();
253   };
254 
255   /** get time instant k+2 of the time discretisation
256       \return a double. If the simulation is near the end (t_{k+2} >= T), it returns NaN.
257   */
getTkp2() const258   inline double getTkp2() const
259   {
260     double tkp2 = _td->getTk(_k+2);
261     if (tkp2 <= _T + 100.0*std::numeric_limits<double>::epsilon())
262       return tkp2;
263     else
264       return std::numeric_limits<double>::quiet_NaN();
265   };
266 
267   /** get time instant k+3 of the time discretisation.
268    *  It is used when we have to reschedule a TD Event in scheduleNonSmoothEvent
269    *  \return a double. If the simulation is near the end (t_{k+3} >= T), it returns NaN.
270   */
getTkp3() const271   inline double getTkp3() const
272   {
273     double tkp3 = _td->getTk(_k+3);
274     if (tkp3 <= _T + 100.0*std::numeric_limits<double>::epsilon())
275       return tkp3;
276     else
277       return std::numeric_limits<double>::quiet_NaN();
278   };
279 
280   /** Get current timestep
281    * \return the current timestep
282    */
currentTimeStep()283   inline double currentTimeStep()
284   {
285     return _td->currentTimeStep(_k);
286   }
287 
288   /** get TimeDiscretisation
289    * \return the TimeDiscretisation in use for the time integration
290    */
timeDiscretisation() const291   inline const TimeDiscretisation& timeDiscretisation() const { return *_td;};
292 
293   /** update final time
294    * \param T the new final time
295    * */
updateT(double T)296   inline void updateT(double T) { _T = T; };
297 };
298 
299 #endif // EventsManager_H
300