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 
19 #include "FirstOrderNonLinearDS.hpp"
20 #include "PluginTypes.hpp"
21 
22 // #define DEBUG_MESSAGES
23 // #define DEBUG_STDOUT
24 #include "siconos_debug.h"
25 #include <iostream>
26 
27 // ===== CONSTRUCTORS =====
28 
_init(SP::SiconosVector initial_state)29 void FirstOrderNonLinearDS::_init(SP::SiconosVector initial_state)
30 {
31   DEBUG_PRINT("internal _init from FirstOrderNonLinearDS\n");
32 
33   // Memory allocation only for required parts of the DS:
34   // state (initial and current). All other operators are optional and
35   // allocated with 'set'-like methods.
36   assert(_n > 0 && "dynamical system dimension should be greater than 0.");
37   // Set initial conditions
38   _x0 = initial_state;
39 
40   // == Current state ==
41   // x is composed of two blocks of size n, x[0] = \f$ x \f$ and x[1]=\f$ \dot x \f$.
42   // x[0] initialized with x0.
43   // _x.resize(2); done in base class constructor.
44   _x[0].reset(new SiconosVector(*_x0));
45   _x[1].reset(new SiconosVector(_n));
46   _r.reset(new SiconosVector(_n)); // FP: move this to initializeNonSmoothInput?
47   _zeroPlugin();
48 }
49 
50 // From a minimum set of data
FirstOrderNonLinearDS(SP::SiconosVector initial_state)51 FirstOrderNonLinearDS::FirstOrderNonLinearDS(SP::SiconosVector initial_state):
52   DynamicalSystem(initial_state->size())
53 {
54   _init(initial_state);
55   // dot x = r
56 }
57 
58 // From a minimum set of data
FirstOrderNonLinearDS(SP::SiconosVector initial_state,const std::string & fPlugin,const std::string & jacobianfxPlugin)59 FirstOrderNonLinearDS::FirstOrderNonLinearDS(SP::SiconosVector initial_state, const std::string& fPlugin, const std::string& jacobianfxPlugin):
60   DynamicalSystem(initial_state->size())
61 {
62   _init(initial_state);
63   // == f and its jacobian ==
64   // Allocation and link with the plug-in
65   setComputeFFunction(SSLH::getPluginName(fPlugin), SSLH::getPluginFunctionName(fPlugin));
66   setComputeJacobianfxFunction(SSLH::getPluginName(jacobianfxPlugin), SSLH::getPluginFunctionName(jacobianfxPlugin));
67   // dot x  = f(x, z , t) + r
68 }
69 
70 // Copy constructor
FirstOrderNonLinearDS(const FirstOrderNonLinearDS & FONLDS)71 FirstOrderNonLinearDS::FirstOrderNonLinearDS(const FirstOrderNonLinearDS & FONLDS): DynamicalSystem(FONLDS)
72 {
73   _zeroPlugin();
74 
75   if(FONLDS.M())
76     _M.reset(new SimpleMatrix(*(FONLDS.M())));
77   if(FONLDS.f())
78     _f.reset(new SiconosVector(*(FONLDS.f())));
79   if(FONLDS.jacobianfx())
80     _jacobianfx.reset(new SimpleMatrix(*(FONLDS.jacobianfx())));
81   if(FONLDS.getPluginF())
82     _pluginf.reset(new PluggedObject(*(FONLDS.getPluginF())));
83   if(FONLDS.getPluginJacxf())
84     _pluginJacxf.reset(new PluggedObject(*(FONLDS.getPluginJacxf())));
85   if(FONLDS.getPluginM())
86     _pluginM.reset(new PluggedObject(*(FONLDS.getPluginM())));
87   if(FONLDS.invM())
88     _invM.reset(new SimpleMatrix(*(FONLDS.invM())));
89 
90   // Memory stuff to me moved to graph/osi
91   if(FONLDS.fold())
92     _fold.reset(new SiconosVector(*(FONLDS.fold())));
93   _rMemory = FONLDS.rMemory();
94 }
95 
96 
_zeroPlugin()97 void FirstOrderNonLinearDS::_zeroPlugin()
98 {
99   _pluginf.reset(new PluggedObject());
100   _pluginJacxf.reset(new PluggedObject());
101   _pluginM.reset(new PluggedObject());
102 }
103 
initRhs(double time)104 void FirstOrderNonLinearDS::initRhs(double time)
105 {
106   computeRhs(time);
107 
108 
109   // !! jacxRhs must always be allocated (we must check this?)!!
110   if(! _jacxRhs)   // if not allocated with a set or anything else
111   {
112     if(_jacobianfx && ! _M)   // if M is not defined, then jacobianfx = jacobianRhsx, no memory allocation for that one.
113       _jacxRhs = _jacobianfx;
114     else//  if (_jacobianfx && _M) or if(!jacobianRhsx)
115       _jacxRhs.reset(new SimpleMatrix(_n, _n));
116 
117     // else no allocation, jacobian is equal to 0.
118   }
119   computeJacobianRhsx(time);
120 }
121 
updatePlugins(double time)122 void FirstOrderNonLinearDS::updatePlugins(double time)
123 {
124   if(_M)
125     computeM(time);
126   if(_f)
127   {
128     computef(time, _x[0]);
129     computeJacobianfx(time, _x[0]);
130   }
131 }
132 
initializeNonSmoothInput(unsigned int level)133 void FirstOrderNonLinearDS::initializeNonSmoothInput(unsigned int level)
134 {
135   /**\warning V.A. _r should be initialized here and not in  the constructor
136    * The level should also be used if we need more that one _r
137    */
138   if(!_r)
139     _r.reset(new SiconosVector(_n));
140 }
141 
142 
143 
144 // ===== MEMORY MANAGEMENT FUNCTIONS =====
145 
initMemory(unsigned int steps)146 void FirstOrderNonLinearDS::initMemory(unsigned int steps)
147 {
148   DynamicalSystem::initMemory(steps);
149 
150   if(_f && !_fold)
151     _fold.reset(new SiconosVector(_n));
152 
153   if(steps == 0)
154     std::cout << "Warning : FirstOrderNonLinearDS::initMemory with size equal to zero" <<std::endl;
155   else
156     _rMemory.setMemorySize(steps, _n);
157 }
158 
swapInMemory()159 void FirstOrderNonLinearDS::swapInMemory()
160 {
161   DEBUG_BEGIN("void FirstOrderNonLinearDS::swapInMemory()\n");
162   _xMemory.swap(*_x[0]);
163   _rMemory.swap(*_r);
164   if(_f)
165   {
166     assert(_fold);
167     *_fold = *_f;
168   }
169   DEBUG_EXPR(_xMemory.display());
170   DEBUG_END("void FirstOrderNonLinearDS::swapInMemory()\n");
171 }
172 
173 // ===== COMPUTE PLUGINS FUNCTIONS =====
174 
setComputeMFunction(const std::string & pluginPath,const std::string & functionName)175 void FirstOrderNonLinearDS::setComputeMFunction(const std::string& pluginPath, const std::string& functionName)
176 {
177   if(!_M)
178     _M.reset(new SimpleMatrix(_n, _n));
179 
180   _pluginM->setComputeFunction(pluginPath, functionName);
181 }
182 
setComputeMFunction(FPtr1 fct)183 void FirstOrderNonLinearDS::setComputeMFunction(FPtr1 fct)
184 {
185   if(!_M)
186     _M.reset(new SimpleMatrix(_n, _n));
187 
188   _pluginM->setComputeFunction((void *)fct);
189 }
190 
setComputeFFunction(const std::string & pluginPath,const std::string & functionName)191 void FirstOrderNonLinearDS::setComputeFFunction(const std::string& pluginPath, const std::string& functionName)
192 {
193   if(!_f)
194     _f.reset(new SiconosVector(_n));
195 
196   _pluginf->setComputeFunction(pluginPath, functionName);
197 }
198 
setComputeFFunction(FPtr1 fct)199 void FirstOrderNonLinearDS::setComputeFFunction(FPtr1 fct)
200 {
201   if(!_f)
202     _f.reset(new SiconosVector(_n));
203   _pluginf->setComputeFunction((void *)fct);
204 }
205 
setComputeJacobianfxFunction(const std::string & pluginPath,const std::string & functionName)206 void FirstOrderNonLinearDS::setComputeJacobianfxFunction(const std::string& pluginPath, const std::string& functionName)
207 {
208   if(!_jacobianfx)
209     _jacobianfx.reset(new SimpleMatrix(_n, _n));
210   _pluginJacxf->setComputeFunction(pluginPath, functionName);
211 }
212 
setComputeJacobianfxFunction(FPtr1 fct)213 void FirstOrderNonLinearDS::setComputeJacobianfxFunction(FPtr1 fct)
214 {
215   if(!_jacobianfx)
216     _jacobianfx.reset(new SimpleMatrix(_n, _n));
217   _pluginJacxf->setComputeFunction((void *)fct);
218 }
219 
computeM(double time)220 void FirstOrderNonLinearDS::computeM(double time)
221 {
222   if(_pluginM->fPtr && _M)
223   {
224     ((FNLDSPtrfct)_pluginM->fPtr)(time, _n, &((*(_x[0]))(0)), &(*_M)(0, 0), _z->size(), &(*_z)(0));
225   }
226 }
227 
computef(double time,SP::SiconosVector state)228 void FirstOrderNonLinearDS::computef(double time, SP::SiconosVector state)
229 {
230   if(_f && _pluginf->fPtr)
231     ((FNLDSPtrfct)_pluginf->fPtr)(time, _n, &(*state)(0), &(*_f)(0), _z->size(), &(*_z)(0));
232 }
233 
computeJacobianfx(double time,SP::SiconosVector state)234 void FirstOrderNonLinearDS::computeJacobianfx(double time, SP::SiconosVector state)
235 {
236   if(_jacobianfx && _pluginJacxf->fPtr)
237     ((FNLDSPtrfct)_pluginJacxf->fPtr)(time, _n, state->getArray(), &(*_jacobianfx)(0, 0), _z->size(), _z->getArray());
238 }
239 
computeRhs(double time)240 void FirstOrderNonLinearDS::computeRhs(double time)
241 {
242   // second argument is useless at the time - Used in derived classes
243 
244   // compute rhs = M-1*( f + r ).
245 
246   *_x[1] = *_r; // Warning: p update is done in Interactions/Relations
247 
248   if(_f)
249   {
250     computef(time, _x[0]);
251     *(_x[1]) += *_f;
252   }
253 
254   if(_M)
255   {
256     computeM(time);
257     // allocate invM at the first call of the present function
258     if(! _invM)
259       _invM.reset(new SimpleMatrix(*_M));
260     else if(_pluginM->fPtr) // if M is plugged, invM must be updated
261       *_invM = *_M;
262 
263     _invM->Solve(*_x[1]);
264   }
265 }
266 
computeJacobianRhsx(double time)267 void FirstOrderNonLinearDS::computeJacobianRhsx(double time)
268 {
269   // second argument is useless at the time - Used in derived classes
270 
271   // compute jacobian of rhs according to x, = M-1(jacobianfx + jacobianX(T.u))
272   // At the time, second term is set to zero.
273   //assert(!_pluginJacxf->fPtr && "FirstOrderNonLinearDS::computeJacobianRhsx: there is no plugin to compute the jacobian of f");
274 
275   computeJacobianfx(time, _x[0]);
276   // solve M*jacobianXRhS = jacobianfx
277   if(_M && _jacobianfx)
278   {
279     *_jacxRhs = *_jacobianfx;
280     // copy _M into _invM for LU-factorisation, at the first call of this function.
281 
282     computeM(time);
283 
284     if(! _invM)
285       _invM.reset(new SimpleMatrix(*_M));
286     else if(_pluginM->fPtr) // if M is plugged, invM must be updated
287       *_invM = *_M;
288     _invM->Solve(*_jacxRhs);
289   }
290   // else jacobianRhsx = jacobianfx, pointers equality set in initRhs
291 
292 }
293 
294 // ===== MISCELLANEOUS ====
295 
display(bool brief) const296 void FirstOrderNonLinearDS::display(bool brief) const
297 {
298   std::cout << " =====> First Order Non Linear DS (number: " << _number << ")." <<std::endl;
299   std::cout << "- n (size) : " << _n <<std::endl;
300   std::cout << "- x " <<std::endl;
301   if(_x[0]) _x[0]->display();
302   else std::cout << "-> nullptr" <<std::endl;
303   std::cout << "- x0 " <<std::endl;
304   if(_x0) _x0->display();
305   else std::cout << "-> nullptr" <<std::endl;
306   std::cout << "- M: " <<std::endl;
307   if(_M) _M->display();
308   else std::cout << "-> nullptr" <<std::endl;
309   std::cout << " ============================================" <<std::endl;
310 }
311 
resetAllNonSmoothParts()312 void FirstOrderNonLinearDS::resetAllNonSmoothParts()
313 {
314   _r->zero();
315 }
316 
resetNonSmoothPart(unsigned int level)317 void FirstOrderNonLinearDS::resetNonSmoothPart(unsigned int level)
318 {
319   // V.A. 28/05/2012:  for the moment various level are not used for First Order systems
320   //assert(0);
321   _r->zero();
322 }
323