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