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 Simulation.hpp 19 \brief Global interface for simulation process description. 20 */ 21 22 #ifndef SIMULATION_H 23 #define SIMULATION_H 24 25 #include "SiconosConst.hpp" 26 #include "SimulationTypeDef.hpp" 27 #include "SiconosFwd.hpp" 28 #include <fstream> 29 #include "NonSmoothDynamicalSystem.hpp" 30 #include "InteractionManager.hpp" 31 32 /** Description of the simulation process (integrators, time 33 discretisation and so on). 34 35 !!! This is an abstract class !!! 36 37 The available simulations are TimeStepping, EventDriven and TimeSteppingD1Minus. 38 */ 39 40 class Simulation : public std::enable_shared_from_this<Simulation> 41 { 42 protected: 43 /** serialization hooks 44 */ 45 ACCEPT_SERIALIZATION(Simulation); 46 47 /** name or id of the Simulation */ 48 std::string _name; 49 50 /** tool to manage all events */ 51 SP::EventsManager _eventsManager; 52 53 /** current starting time for integration */ 54 double _tinit; 55 56 /** current ending time for integration */ 57 double _tend; 58 59 /** real ending time for integration (different from tend in case of 60 stop during integrate, for example when a root is found in 61 an EventDriven strategy) 62 */ 63 double _tout; 64 65 double _T; 66 67 /** the dynamical systems integrators */ 68 SP::OSISet _allOSI; 69 70 /** the non smooth problems (each problem is identified thanks to 71 its id) */ 72 SP::OneStepNSProblems _allNSProblems; 73 74 /** A pointer to the simulated nonsmooth dynamical system 75 */ 76 SP::NonSmoothDynamicalSystem _nsds; 77 78 /** An interaction manager 79 */ 80 SP::InteractionManager _interman; 81 82 /** _numberOfIndexSets is the number of index sets that we need for 83 * simulation. It corresponds for most of the simulations to levelMaxForOutput + 1. 84 * Nevertheless, some simulations need more sets of indices that the number 85 * of outputs that we considered. 86 */ 87 unsigned int _numberOfIndexSets; 88 89 /** tolerance value used to compute the index sets. 90 Default: equal to 10 x machine double precision (std::numeric_limits<double>::epsilon) 91 */ 92 double _tolerance; 93 94 /** Output setup: if true, display solver stats */ 95 bool _printStat; 96 97 /** _staticLevels : do not recompute levels once they have been 98 * initialized */ 99 bool _staticLevels; 100 101 /** File id for stats outputs.*/ 102 std::ofstream statOut; 103 104 /** 105 * bool, option specifying if a critere of relative convergence is 106 * used. Default value is false. 107 */ 108 bool _useRelativeConvergenceCriterion; 109 /** 110 * bool used to remind if the relative convergence held(useful for 111 * the newton-check-convergence). Modified only if 112 * _useRelativeConvergenceCriterion is true. 113 */ 114 bool _relativeConvergenceCriterionHeld; 115 /** 116 *double, relative tolerance. Used only if 117 *_useRelativeConvergenceCriterion is true. 118 */ 119 double _relativeConvergenceTol; 120 121 bool _isInitialized; 122 123 /** current NSDS changelog position */ 124 NonSmoothDynamicalSystem::ChangeLogIter _nsdsChangeLogPosition; 125 126 /** map of not-yet-initialized DS variables for each OSI */ 127 std::map< SP::OneStepIntegrator, std::list<SP::DynamicalSystem> > _OSIDSmap; 128 129 /** Call the interaction manager one if is registered, otherwise do nothing. */ 130 void updateInteractions(); 131 132 /*TS set the ds->q memory, the world (CAD model for example) must be updated. 133 Overload this method to update user model.*/ updateWorldFromDS()134 virtual void updateWorldFromDS() 135 { 136 ; 137 }; 138 139 /** initialize OSI-DS links in the NSDS graph. */ 140 void initializeOSIAssociations(); 141 142 /** initialize objects (DSs and Interations) found in the NSDS 143 * Changelog and update the changelog iterator. 144 */ 145 void initializeNSDSChangelog(); 146 147 /** initialize index sets for OSIs */ 148 void initializeIndexSets(); 149 150 private: 151 152 /** copy constructor. Private => no copy nor pass-by value. 153 */ 154 Simulation(const Simulation&); 155 156 /* assignment of simulation. Private => no copy nor pass-by value. 157 */ 158 Simulation& operator=(const Simulation&); 159 160 public: 161 162 /** default constructor, for serialization 163 */ Simulation()164 Simulation() {}; 165 166 /** default constructor 167 * \param nsds current nonsmooth dynamical system 168 * \param td the timeDiscretisation for this Simulation 169 */ 170 Simulation(SP::NonSmoothDynamicalSystem nsds, SP::TimeDiscretisation td); 171 172 /** constructor with only a TimeDiscretisation 173 * \param td the timeDiscretisation for this Simulation 174 */ 175 Simulation(SP::TimeDiscretisation td); 176 177 /** destructor 178 */ 179 virtual ~Simulation(); 180 181 /** clear all maps. This function should not exist, but there is a cycle 182 * with the shared_ptr: the OneStepIntegrator and OneStepNSProblem have 183 * both a link to the Simulation, and here we have all the OneStepIntegrator 184 * and OneStepNSProblem in maps. Then the memory is never freed. The clumsy 185 * way to deal with it is to call this function from the Model destructor 186 * to free the maps and then the cycle is broken 187 * \warning do not call this yourself, it is meant to be called from 188 * the desctructor of the Model 189 */ 190 void clear(); 191 192 // GETTERS/SETTERS 193 194 /** get the name of the Simulation 195 * \return std::string : the name of the Simulation 196 */ name() const197 inline const std::string name() const 198 { 199 return _name; 200 } 201 202 /** set the name of the Simulation 203 \param newName the new name 204 */ setName(const std::string & newName)205 inline void setName(const std::string& newName) 206 { 207 _name = newName; 208 } 209 210 /** returns time instant k of the time discretisation */ 211 double getTk() const; 212 213 /** get time instant k+1 of the time discretisation 214 * \warning: this instant may be different from nextTime(), if for example some 215 non-smooth events or some sensor events are present 216 \return a double. If the simulation is near the end (t_{k+1} > T), it returns NaN. 217 */ 218 double getTkp1() const; 219 220 /** get time instant k+2 of the time discretisation 221 * \warning: this instant may be different from nextTime(), if for example some 222 non-smooth events or some sensor events are present 223 * \return a double. If the simulation is near the end (t_{k+2} > T), it returns NaN. 224 */ 225 double getTkp2() const; 226 227 /** returns current timestep */ 228 double currentTimeStep() const; 229 230 /** returns a pointer to the EventsManager 231 */ eventsManager() const232 inline SP::EventsManager eventsManager() const 233 { 234 return _eventsManager; 235 }; 236 237 /** get "current time" (ie starting point for current integration, 238 time of currentEvent of eventsManager.) 239 \return a double. 240 */ 241 double startingTime() const; 242 243 /** get "next time" (ie ending point for current integration, time 244 of nextEvent of eventsManager.) 245 \return a double. 246 */ 247 double nextTime() const; 248 249 /** get the current time step size ("next time"-"current time") 250 * \return a double. 251 */ timeStep() const252 inline double timeStep() const 253 { 254 return (nextTime() - startingTime()); 255 }; 256 257 /** true if a future event is to be treated or not (ie if some 258 events remain in the eventsManager). 259 */ 260 bool hasNextEvent() const; 261 262 /** get all the Integrators of the Simulation 263 * \return an OSISset 264 */ oneStepIntegrators() const265 inline const SP::OSISet oneStepIntegrators() const 266 { 267 return _allOSI; 268 }; 269 270 /** get the number of OSIs in the Simulation (ie the size of allOSI) 271 * \return an unsigned int 272 */ numberOfOSI() const273 inline size_t numberOfOSI() const 274 { 275 return _allOSI->size(); 276 } 277 278 /** insert an Integrator into the simulation list of integrators 279 * \param osi the OneStepIntegrator to add 280 */ 281 virtual void insertIntegrator(SP::OneStepIntegrator osi); 282 283 /** associate an OSI with a DS */ 284 void associate(SP::OneStepIntegrator osi, SP::DynamicalSystem ds); 285 286 /** get a pointer to indexSets[i] 287 \param i number of the required index set 288 \return a graph of interactions 289 */ 290 SP::InteractionsGraph indexSet(unsigned int i); 291 292 /** get allNSProblems 293 * \return a pointer to OneStepNSProblems object (container of 294 * SP::OneStepNSProblem) 295 */ oneStepNSProblems() const296 inline const SP::OneStepNSProblems oneStepNSProblems() const 297 { 298 return _allNSProblems; 299 }; 300 301 /** get the number of OSNSP in the Simulation (ie the size of allNSProblems) 302 * \return an unsigned int 303 */ numberOfOSNSProblems() const304 inline size_t numberOfOSNSProblems() const 305 { 306 return _allNSProblems->size(); 307 } 308 309 /** get a OneStep nonsmooth problem of the simulation, identify with its number. 310 \param id number of the required osnspb 311 \return a pointer to OneStepNSProblem 312 */ 313 SP::OneStepNSProblem oneStepNSProblem(int id); 314 315 /** add a OneStepNSProblem in the Simulation 316 \param osns the OneStepNSProblem to insert 317 \param Id its id: default is SICONOS_OSNSP_DEFAULT, 318 at impact level SICONOS_OSNSP_ED_IMPACT, at acceleration level 319 SICONOS_OSNSP_ED_ACCELERATION 320 */ 321 virtual void insertNonSmoothProblem(SP::OneStepNSProblem osns, int Id = SICONOS_OSNSP_DEFAULT); 322 323 324 /** get the NonSmoothDynamicalSystem 325 * \return NonSmoothDynamicalSystem 326 */ nonSmoothDynamicalSystem() const327 inline SP::NonSmoothDynamicalSystem nonSmoothDynamicalSystem() const 328 { 329 return _nsds; 330 } 331 /** set the NonSmoothDynamicalSystem of the Simulation 332 * \param newPtr a pointer on NonSmoothDynamicalSystem 333 */ setNonSmoothDynamicalSystemPtr(SP::NonSmoothDynamicalSystem newPtr)334 void setNonSmoothDynamicalSystemPtr(SP::NonSmoothDynamicalSystem newPtr) 335 { 336 _nsdsChangeLogPosition = _nsds->changeLogBegin(); 337 _nsds = newPtr; 338 } 339 340 /** get tolerance 341 * \return a double 342 */ tolerance() const343 double tolerance() const 344 { 345 return _tolerance; 346 }; 347 348 /** set the value of offset for q dof vector in dynamical systems 349 (to avoid events accumulation) 350 \param inputVal new tolerance 351 */ setTolerance(double inputVal)352 void setTolerance(double inputVal) 353 { 354 _tolerance = inputVal; 355 }; 356 357 /** set printStat value: if true, print solver stats. 358 \param newVal true to activate stats 359 */ setPrintStat(const bool & newVal)360 inline void setPrintStat(const bool& newVal) 361 { 362 _printStat = newVal; 363 }; 364 365 /** get printStat value 366 \return true if stats are activated 367 */ getPrintStat() const368 inline bool getPrintStat() const 369 { 370 return _printStat; 371 }; 372 373 /** update all index sets of the topology, using current y and 374 lambda values of Interactions. 375 */ 376 void updateIndexSets(); 377 378 /** update indexSets[i] of the topology, using current y and lambda 379 values of Interactions. 380 \param level the number of the set to be updated 381 */ 382 virtual void updateIndexSet(unsigned int level) = 0; 383 384 /** Complete initialisation of the Simulation (OneStepIntegrators, 385 OneStepNSProblem, TImediscretisation). 386 */ 387 virtual void initialize(); 388 389 /** Initialize a single Interaction for this Simulation, used for dynamic 390 * topology updates. */ 391 virtual void initializeInteraction(double time, SP::Interaction inter); 392 393 /** Set an object to automatically manage interactions during the simulation 394 * \param manager 395 */ insertInteractionManager(SP::InteractionManager manager)396 void insertInteractionManager(SP::InteractionManager manager) 397 { _interman = manager; } 398 399 /** computes a one step NS problem 400 * \param nb the id of the OneStepNSProblem to be computed 401 * \return information about the solver convergence. 402 */ 403 int computeOneStepNSProblem(int nb); 404 405 /** update input 406 * \param level lambda order used to compute input 407 * level is set to 0 by default since in all time-stepping schemes we update all the state 408 */ 409 virtual void updateInput(unsigned int level=0); 410 411 /** update state of each dynamical system 412 */ 413 virtual void updateState(unsigned int level=0); 414 415 /** update output 416 * \param level lambda order used to compute output 417 * level is set to 0 by default since in all time-stepping schemes we update all the state 418 */ 419 virtual void updateOutput(unsigned int level=0); 420 421 /** update output, state, and input 422 * \param level lambda order used to compute input 423 * level is set to 0 by default since in all time-stepping schemes we update all the state 424 */ update(unsigned int level=0)425 void update(unsigned int level=0) 426 { updateInput(level); updateState(level); updateOutput(level); } 427 428 /** run the simulation, from t0 to T 429 * with default parameters if any particular settings has been done 430 */ 431 virtual void run(); 432 433 /** initialisation for OneStepNSProblem. 434 */ 435 virtual void initOSNS() = 0; 436 437 438 /** step from current event to next event of EventsManager 439 */ 440 virtual void advanceToEvent() = 0; 441 442 443 /** clear the NSDS changelog up to current position. If you have a 444 * particularly dynamic simulation (DS and Interactions created and 445 * destroyed frequently), then it is important to call this 446 * periodically. 447 */ 448 void clearNSDSChangeLog(); 449 450 451 /* Set the option to specify if a relative convergence criterion must 452 be used to stop the Newton iterations. 453 \param use true if relative critarion activated 454 */ setUseRelativeConvergenceCriteron(bool use)455 inline void setUseRelativeConvergenceCriteron(bool use) 456 { 457 _useRelativeConvergenceCriterion = use; 458 }; 459 /** 460 \return true if the relative convergence criterion is activated. 461 */ useRelativeConvergenceCriteron()462 inline bool useRelativeConvergenceCriteron() 463 { 464 return _useRelativeConvergenceCriterion; 465 }; 466 467 /** Set the relative convergence tolerance 468 \param v tolerance value 469 */ setRelativeConvergenceTol(double v)470 inline void setRelativeConvergenceTol(double v) 471 { 472 _relativeConvergenceTol = v; 473 }; 474 475 /** 476 \return the relative convergence tolerence. 477 * 478 */ relativeConvergenceTol()479 inline double relativeConvergenceTol() 480 { 481 return _relativeConvergenceTol; 482 }; 483 484 /** 485 \param newVal a new relative convergence criterion 486 * 487 */ setRelativeConvergenceCriterionHeld(bool newVal)488 inline void setRelativeConvergenceCriterionHeld(bool newVal) 489 { 490 _relativeConvergenceCriterionHeld = newVal; 491 }; 492 /** 493 \return true if the relative convergence criterion held. 494 * 495 */ relativeConvergenceCriterionHeld()496 inline bool relativeConvergenceCriterionHeld() 497 { 498 return _relativeConvergenceCriterionHeld; 499 }; 500 501 /** return input lambda[level](coor) for all the interactions 502 \param level lambda min order to be computed 503 \param coor the coordinate of interest 504 \return a SP::SiconosVector that contains the concatenated value 505 */ 506 SP::SiconosVector lambda(unsigned int level = 0, unsigned int coor=0 ); 507 508 /** return output y[level](coor) for all the interactions 509 \param level y min order to be computed 510 \param coor the coordinate of interest 511 \return a SP::SiconosVector that contains the concatenated value 512 */ 513 SP::SiconosVector y(unsigned int level = 0, unsigned int coor=0 ); 514 515 /** call eventsManager processEvents. 516 */ 517 void processEvents(); 518 519 520 /** set staticLevels 521 * \param b decides whether levels should be computed at each iteration 522 */ setStaticLevels(bool b)523 void setStaticLevels(bool b) 524 { 525 _staticLevels = b; 526 } 527 528 /** This updates the end of the Simulation. 529 * \warning this should be called only from the Model, to synchronise the 2 values 530 * \param T the new final time 531 */ 532 void updateT(double T); 533 computeResiduY()534 virtual bool computeResiduY() { return false; }; 535 computeResiduR()536 virtual bool computeResiduR() { return false; }; 537 538 /** Add a new Interaction between one or a pair of DSs. 539 * \param inter the SP::Interaction to add 540 * \param ds1 the first SP::DynamicalSystem in the Interaction 541 * \param ds2 the second SP::DynamicalSystem in the Interaction, if any 542 */ 543 void link(SP::Interaction inter, 544 SP::DynamicalSystem ds1, 545 SP::DynamicalSystem ds2 = SP::DynamicalSystem()); 546 547 /** Remove an Interaction from the simulation. 548 * \param inter the SP::Interaction to remove 549 */ 550 void unlink(SP::Interaction inter); 551 552 /** visitors hook 553 */ 554 VIRTUAL_ACCEPT_VISITORS(Simulation); 555 }; 556 557 #endif // SIMULATION_H 558