1
2 /* Siconos is a program dedicated to modeling, simulation and control
3 * of non smooth dynamical systems.
4 *
5 * Copyright 2021 INRIA.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #include "LsodarOSI.hpp"
21 #include "SiconosAlgebraProd.hpp"
22 #include "EventDriven.hpp"
23 #include "LagrangianLinearTIDS.hpp"
24 #include "BlockVector.hpp"
25 #include "NonSmoothDynamicalSystem.hpp"
26 #include "Topology.hpp"
27 #include "LagrangianRheonomousR.hpp"
28 #include "LagrangianScleronomousR.hpp"
29 #include "NewtonImpactNSL.hpp"
30 #include "MultipleImpactNSL.hpp"
31 #include "NewtonImpactFrictionNSL.hpp"
32 #include "FirstOrderNonLinearDS.hpp"
33 #include "ExtraAdditionalTerms.hpp"
34 #include "OneStepNSProblem.hpp"
35 #include "TypeName.hpp"
36 #include <odepack.h>
37
38 using namespace RELATION;
39
40 // #define DEBUG_NOCOLOR
41 // #define DEBUG_STDOUT
42 // #define DEBUG_MESSAGES
43 #include "siconos_debug.h"
44
45 int LsodarOSI::count_NST = 0;
46 int LsodarOSI::count_NFE = 0;
47
48 // ===== Out of class objects and functions =====
49
50 // global object and wrapping functions -> required for function plug-in and call in fortran routine.
51 SP::LsodarOSI global_object;
52
53 // This first function must have the same signature as argument F (arg 1) in DLSODAR (see opkdmain.f in Numerics)
54 extern "C" void LsodarOSI_f_wrapper(integer* sizeOfX, doublereal* time, doublereal* x, doublereal* xdot);
LsodarOSI_f_wrapper(integer * sizeOfX,doublereal * time,doublereal * x,doublereal * xdot)55 extern "C" void LsodarOSI_f_wrapper(integer* sizeOfX, doublereal* time, doublereal* x, doublereal* xdot)
56 {
57 return global_object->f(sizeOfX, time, x, xdot);
58 }
59
60 // Function to wrap g: same signature as argument G (arg 18) in DLSODAR (see opkdmain.f in Numerics)
61 extern "C" void LsodarOSI_g_wrapper(integer* nEq, doublereal* time, doublereal* x, integer* ng, doublereal* gOut);
LsodarOSI_g_wrapper(integer * nEq,doublereal * time,doublereal * x,integer * ng,doublereal * gOut)62 extern "C" void LsodarOSI_g_wrapper(integer* nEq, doublereal* time, doublereal* x, integer* ng, doublereal* gOut)
63 {
64 return global_object->g(nEq, time, x, ng, gOut);
65 }
66
67 // Function to wrap jacobianf: same signature as argument JAC (arg 16) in DLSODAR (see opkdmain.f in Numerics)
68 extern "C" void LsodarOSI_jacobianf_wrapper(integer* sizeOfX, doublereal* time, doublereal* x, integer* ml, integer* mu, doublereal* jacob, integer* nrowpd);
LsodarOSI_jacobianf_wrapper(integer * sizeOfX,doublereal * time,doublereal * x,integer * ml,integer * mu,doublereal * jacob,integer * nrowpd)69 extern "C" void LsodarOSI_jacobianf_wrapper(integer* sizeOfX, doublereal* time, doublereal* x, integer* ml, integer* mu, doublereal* jacob, integer* nrowpd)
70 {
71 return global_object->jacobianfx(sizeOfX, time, x, ml, mu, jacob, nrowpd);
72 }
73
LsodarOSI()74 LsodarOSI::LsodarOSI():
75 OneStepIntegrator(OSI::LSODAROSI)
76 {
77
78 _sizeTol =1;
79 _itol=1;
80 _intData.resize(9);
81 for(int i = 0; i < 9; i++) _intData[i] = 0;
82 _sizeMem = 2;
83 _steps=1;
84
85 // Set levels. This may depend on the nonsmooth law and will be updated during initializeWorkVectorsForInteraction(...) call.
86 _levelMinForOutput=0;
87 _levelMaxForOutput=2;
88 _levelMinForInput=1;
89 _levelMaxForInput=2;
90
91 rtol.reset(new doublereal[_sizeTol]) ; // rtol, relative tolerance
92 atol.reset(new doublereal[_sizeTol]) ; // atol, absolute tolerance
93 // Set atol and rtol values ...
94 rtol[0] = RTOL_DEFAULT ; // rtol
95 atol[0] = ATOL_DEFAULT ; // atol
96 }
97
setTol(integer newItol,SA::doublereal newRtol,SA::doublereal newAtol)98 void LsodarOSI::setTol(integer newItol, SA::doublereal newRtol, SA::doublereal newAtol)
99 {
100 // The input parameters ITOL, RTOL, and ATOL determine
101 // the error control performed by the solver. The solver will
102 // control the vector E = (E(i)) of estimated local errors
103 // in y, according to an inequality of the form
104 // max-norm of ( E(i)/EWT(i) ) .le. 1,
105 // where EWT = (EWT(i)) is a vector of positive error weights.
106 // The values of RTOL and ATOL should all be non-negative.
107 // The following table gives the types (scalar/array) of
108 // RTOL and ATOL, and the corresponding form of EWT(i).
109 //
110 // ITOL RTOL ATOL EWT(i)
111 // 1 scalar scalar RTOL*ABS(Y(i)) + ATOL
112 // 2 scalar array RTOL*ABS(Y(i)) + ATOL(i)
113 // 3 array scalar RTOL(i)*ABS(Y(i)) + ATOL
114 // 4 array array RTOL(i)*ABS(Y(i)) + ATOL(i)
115
116 _itol = newItol; // itol
117 rtol = newRtol;
118 atol = newAtol;
119 }
120
setMinMaxStepSizes(doublereal minStep,doublereal maxStep)121 void LsodarOSI::setMinMaxStepSizes(doublereal minStep, doublereal maxStep)
122 {
123 _intData[5] = 1; // set IOPT = 1
124 rwork[5] = minStep;
125 rwork[6] = maxStep;
126 }
127
setMaxNstep(integer maxNumberSteps)128 void LsodarOSI::setMaxNstep(integer maxNumberSteps)
129 {
130 _intData[5] = 1; // set IOPT = 1
131 iwork[5] = maxNumberSteps;
132 }
133
setTol(integer newItol,doublereal newRtol,doublereal newAtol)134 void LsodarOSI::setTol(integer newItol, doublereal newRtol, doublereal newAtol)
135 {
136 _itol = newItol; // itol
137 rtol[0] = newRtol; // rtol
138 atol[0] = newRtol; // atol
139 }
140
setMaxOrder(integer maxorderNonStiff,integer maxorderStiff)141 void LsodarOSI::setMaxOrder(integer maxorderNonStiff, integer maxorderStiff)
142 {
143 _intData[5] = 1; // set IOPT = 1
144 iwork[7] = maxorderNonStiff;
145 iwork[8] = maxorderStiff;
146 }
147
updateData()148 void LsodarOSI::updateData()
149 {
150 // Used to update some data (iwork ...) when _intData is modified.
151 // Warning: it only checks sizes and possibly reallocate memory, but no values are set.
152
153 iwork.reset(new integer[_intData[7]]);
154 for(int i = 0; i < _intData[7]; i++) iwork[i] = 0;
155
156 // This is for documentation purposes only
157 // Set the flag to generate extra printing at method switches.
158 //iwork[4] = 0;
159 // Set the maximal number of steps for one call
160 //iwork[5] = 0;
161 // set the maximum number of messages printed (per problem)
162 //iwork[6] = 0;
163 // Set the maximum order to be allowed for the nonstiff (Adams) method
164 //iwork[7] = 0;
165 // Set the maximum order to be allowed for the stiff (BDF) method.
166 //iwork[8] = 0;
167
168 rwork.reset(new doublereal[_intData[6]]);
169 for(int i = 0; i < _intData[6]; i++) rwork[i] = 0.0;
170
171 jroot.reset(new integer[_intData[1]]);
172 for(int i = 0; i < _intData[1]; i++) jroot[i] = 0;
173
174 }
175
fillXWork(integer * sizeOfX,doublereal * x)176 void LsodarOSI::fillXWork(integer* sizeOfX, doublereal* x)
177 {
178 assert((unsigned int)(*sizeOfX) == _xWork->size() && "LsodarOSI::fillXWork xWork and sizeOfX have different sizes");
179 (*_xWork) = x;
180 }
181
computeRhs(double t)182 void LsodarOSI::computeRhs(double t)
183 {
184 DEBUG_BEGIN("LsodarOSI::computeRhs(double t, DynamicalSystemsGraph& DSG0)\n")
185 DynamicalSystemsGraph::VIterator dsi, dsend;
186 for(std::tie(dsi, dsend) = _dynamicalSystemsGraph->vertices(); dsi != dsend; ++dsi)
187 {
188 if(!checkOSI(dsi)) continue;
189 SP::DynamicalSystem ds = _dynamicalSystemsGraph->bundle(*dsi);
190 // compute standard rhs stored in the dynamical system
191 ds->computeRhs(t);
192 DEBUG_EXPR(ds->getRhs().display(););
193 /* This next line is a good protection */
194 assert(_dynamicalSystemsGraph->properties(*dsi).workVectors);
195 VectorOfVectors& workVectors = *_dynamicalSystemsGraph->properties(*dsi).workVectors;
196 Type::Siconos dsType = Type::value(*ds);
197 if(dsType == Type::LagrangianLinearTIDS || dsType == Type::LagrangianDS)
198 {
199 SP::LagrangianDS lds = std::static_pointer_cast<LagrangianDS> (ds);
200 SiconosVector &free=*workVectors[LsodarOSI::FREE];
201 // we assume that inverseMass and forces are updated after call of ds->computeRhs(t);
202 free = *lds->forces();
203 if(lds->inverseMass())
204 lds->inverseMass()->Solve(free);
205 DEBUG_EXPR(free.display(););
206 }
207 if(_extraAdditionalTerms)
208 {
209 DynamicalSystemsGraph::VDescriptor dsgVD = _dynamicalSystemsGraph->descriptor(ds);
210 _extraAdditionalTerms->addSmoothTerms(*_dynamicalSystemsGraph, dsgVD, t, ds->getRhs());
211 }
212 }
213 DEBUG_END("LsodarOSI::computeRhs(double t, DynamicalSystemsGraph& DSG0)\n")
214
215 }
216
computeJacobianRhs(double t,DynamicalSystemsGraph & DSG0)217 void LsodarOSI::computeJacobianRhs(double t, DynamicalSystemsGraph& DSG0)
218 {
219
220 DynamicalSystemsGraph::VIterator dsi, dsend;
221 for(std::tie(dsi, dsend) = _dynamicalSystemsGraph->vertices(); dsi != dsend; ++dsi)
222 {
223 if(!checkOSI(dsi)) continue;
224 SP::DynamicalSystem ds = _dynamicalSystemsGraph->bundle(*dsi);
225 ds->computeJacobianRhsx(t);
226 if(_extraAdditionalTerms)
227 {
228 DynamicalSystemsGraph::VDescriptor dsgVD = DSG0.descriptor(ds);
229 _extraAdditionalTerms->addJacobianRhsContribution(DSG0, dsgVD, t, *(ds->jacobianRhsx()));
230 }
231 }
232 }
233
f(integer * sizeOfX,doublereal * time,doublereal * x,doublereal * xdot)234 void LsodarOSI::f(integer* sizeOfX, doublereal* time, doublereal* x, doublereal* xdot)
235 {
236 std::static_pointer_cast<EventDriven>(_simulation)->computef(*this, sizeOfX, time, x, xdot);
237 }
238
g(integer * nEq,doublereal * time,doublereal * x,integer * ng,doublereal * gOut)239 void LsodarOSI::g(integer* nEq, doublereal* time, doublereal* x, integer* ng, doublereal* gOut)
240 {
241 std::static_pointer_cast<EventDriven>(_simulation)->computeg(shared_from_this(), nEq, time, x, ng, gOut);
242 }
243
jacobianfx(integer * sizeOfX,doublereal * time,doublereal * x,integer * ml,integer * mu,doublereal * jacob,integer * nrowpd)244 void LsodarOSI::jacobianfx(integer* sizeOfX, doublereal* time, doublereal* x, integer* ml, integer* mu, doublereal* jacob, integer* nrowpd)
245 {
246 std::static_pointer_cast<EventDriven>(_simulation)->computeJacobianfx(*this, sizeOfX, time, x, jacob);
247 }
248
249
initializeWorkVectorsForDS(double t,SP::DynamicalSystem ds)250 void LsodarOSI::initializeWorkVectorsForDS(double t, SP::DynamicalSystem ds)
251 {
252 DEBUG_BEGIN("LsodarOSI::initializeWorkVectorsForDS( double t, SP::DynamicalSystem ds)\n");
253 // Get work buffers from the graph
254 VectorOfVectors& ds_work_vectors = *_initializeDSWorkVectors(ds);
255
256 Type::Siconos dsType = Type::value(*ds);
257
258 ds->initRhs(t); // This will create p[2] and other required vectors/buffers
259
260 if(dsType == Type::LagrangianDS || dsType == Type::LagrangianLinearTIDS)
261 {
262 LagrangianDS& lds = *std::static_pointer_cast<LagrangianDS>(ds);
263 // TODO FP: use buffer in graph for xWork?
264 if(!_xWork)
265 _xWork.reset(new BlockVector());
266 _xWork->insertPtr(lds.q());
267 _xWork->insertPtr(lds.velocity());
268 ds_work_vectors.resize(LsodarOSI::WORK_LENGTH);
269 ds_work_vectors[LsodarOSI::FREE].reset(new SiconosVector(lds.dimension()));
270 }
271 else
272 {
273 if(!_xWork)
274 _xWork.reset(new BlockVector());
275 _xWork->insertPtr(ds->x());
276 }
277 ds->swapInMemory();
278
279 // Update necessary data
280
281 // 1 - Neq; x vector size.
282 _intData[0] = _xWork->size();
283 // 5 - lrw, size of rwork
284 _intData[6] = 22 + _intData[0] * std::max(16, (int)_intData[0] + 9) + 3 * _intData[1];
285 // 6 - liw, size of iwork
286 _intData[7] = 20 + _intData[0];
287
288 // memory allocation for doublereal*, according to _intData values
289 updateData();
290
291 _xtmp.reset(new SiconosVector(_xWork->size()));
292
293 computeRhs(t);
294
295 DEBUG_END("LsodarOSI::initializeWorkVectorsForDS( double t, SP::DynamicalSystem ds)\n");
296 }
297
initializeWorkVectorsForInteraction(Interaction & inter,InteractionProperties & interProp,DynamicalSystemsGraph & DSG)298 void LsodarOSI::initializeWorkVectorsForInteraction(Interaction &inter,
299 InteractionProperties& interProp,
300 DynamicalSystemsGraph & DSG)
301 {
302 SP::DynamicalSystem ds1= interProp.source;
303 SP::DynamicalSystem ds2= interProp.target;
304 assert(ds1);
305 assert(ds2);
306
307
308 VectorOfBlockVectors& DSlink = inter.linkToDSVariables();
309 if(!interProp.workVectors)
310 {
311 interProp.workVectors.reset(new VectorOfVectors);
312 interProp.workVectors->resize(LsodarOSI::WORK_INTERACTION_LENGTH);
313 }
314
315 if(!interProp.workBlockVectors)
316 {
317 interProp.workBlockVectors.reset(new VectorOfBlockVectors);
318 interProp.workBlockVectors->resize(LsodarOSI::BLOCK_WORK_LENGTH);
319 }
320
321 VectorOfVectors& inter_work = *interProp.workVectors;
322 VectorOfBlockVectors& inter_work_block = *interProp.workBlockVectors;
323
324 Relation &relation = *inter.relation();
325 RELATION::TYPES relationType = relation.getType();
326
327 inter_work[LsodarOSI::OSNSP_RHS].reset(new SiconosVector(inter.dimension()));
328
329 NonSmoothLaw & nslaw = *inter.nonSmoothLaw();
330
331 Type::Siconos nslType = Type::value(nslaw);
332
333 if(nslType == Type::NewtonImpactNSL || nslType == Type::MultipleImpactNSL)
334 {
335 _levelMinForOutput = 0;
336 _levelMaxForOutput = 2 ;
337 _levelMinForInput = 1;
338 _levelMaxForInput = 2;
339 }
340 else if(nslType == Type::NewtonImpactFrictionNSL)
341 {
342 _levelMinForOutput = 0;
343 _levelMaxForOutput = 4;
344 _levelMinForInput = 1;
345 _levelMaxForInput = 2;
346 THROW_EXCEPTION("LsodarOSI::initializeWorkVectorsForInteraction not yet implemented for nonsmooth law of type NewtonImpactFrictionNSL");
347 }
348 else
349 THROW_EXCEPTION("LsodarOSI::initializeWorkVectorsForInteraction not yet implemented for nonsmooth of type");
350
351 // Check if interations levels (i.e. y and lambda sizes) are compliant with the current osi.
352 _check_and_update_interaction_levels(inter);
353 // Initialize/allocate memory buffers in interaction.
354 inter.initializeMemory(_steps);
355
356 /* allocate and set work vectors for the osi */
357
358 if(!(checkOSI(DSG.descriptor(ds1)) && checkOSI(DSG.descriptor(ds2))))
359 {
360 THROW_EXCEPTION("LsodarOSI::initializeWorkVectorsForInteraction. The implementation is not correct for two different OSI for one interaction");
361 }
362
363
364
365 VectorOfVectors &workVds1 = *DSG.properties(DSG.descriptor(ds1)).workVectors;
366 if(relationType == Lagrangian)
367 {
368 LagrangianDS& lds = *std::static_pointer_cast<LagrangianDS> (ds1);
369 inter_work_block[LsodarOSI::xfree].reset(new BlockVector());
370 inter_work_block[LsodarOSI::xfree]->insertPtr(workVds1[LsodarOSI::FREE]);
371 DSlink[LagrangianR::p2].reset(new BlockVector());
372 DSlink[LagrangianR::p2]->insertPtr(lds.p(2));
373 DSlink[LagrangianR::q2].reset(new BlockVector());
374 DSlink[LagrangianR::q2]->insertPtr(lds.acceleration());
375 }
376 // else if (relationType == NewtonEuler)
377 // {
378 // inter_work_block[::xfree].reset(new BlockVector());
379 // inter_work_block[::xfree]->insertPtr(workVds1[LsodarOSI::FREE]);
380 // }
381
382
383
384 if(ds1 != ds2)
385 {
386 VectorOfVectors &workVds2 = *DSG.properties(DSG.descriptor(ds2)).workVectors;
387 if(relationType == Lagrangian)
388 {
389 LagrangianDS& lds = *std::static_pointer_cast<LagrangianDS> (ds2);
390 inter_work_block[LsodarOSI::xfree]->insertPtr(workVds2[LsodarOSI::FREE]);
391 DSlink[LagrangianR::p2]->insertPtr(lds.p(2));
392 DSlink[LagrangianR::q2]->insertPtr(lds.acceleration());
393 }
394 // else if (relationType == NewtonEuler)
395 // {
396 // inter_work_block[NewtonEulerR::xfree]->insertPtr(workVds2[LsodarOSI::FREE]);
397 // }
398 }
399 }
400
initialize()401 void LsodarOSI::initialize()
402 {
403 DEBUG_BEGIN("LsodarOSI::initialize()\n");
404 OneStepIntegrator::initialize();
405 //std::string type;
406 // initialize xWork with x values of the dynamical systems present in the set.
407
408 // DynamicalSystemsGraph::VIterator dsi, dsend;
409 // for(std::tie(dsi, dsend) = _dynamicalSystemsGraph->vertices(); dsi != dsend; ++dsi)
410 // {
411 // if(!checkOSI(dsi)) continue;
412 // SP::DynamicalSystem ds = _dynamicalSystemsGraph->bundle(*dsi);
413 // initializeWorkVectorsForDS(m, m.t0(),ds);
414 // //ds->resetToInitialState();
415 // //ds->swapInMemory();
416 // }
417
418 // SP::InteractionsGraph indexSet0 = m.nonSmoothDynamicalSystem()->topology()->indexSet0();
419 // InteractionsGraph::VIterator ui, uiend;
420 // for (std::tie(ui, uiend) = indexSet0->vertices(); ui != uiend; ++ui)
421 // {
422 // Interaction& inter = *indexSet0->bundle(*ui);
423 // initializeWorkVectorsForInteraction(m.t0(), inter, indexSet0->properties(*ui), *_dynamicalSystemsGraph);
424 // }
425
426
427 // Integer parameters for LSODAROSI are saved in vector intParam.
428 // The link with variable names in opkdmain.f is indicated in comments
429
430 // 2 - Ng, number of constraints:
431 _intData[1] = std::static_pointer_cast<EventDriven>(_simulation)->computeSizeOfg();
432 // 3 - Itol, itask, iopt
433 _intData[2] = _itol; // itol, 1 if ATOL is a scalar, else 2 (ATOL array)
434 _intData[3] = 1; // itask, an index specifying the task to be performed. 1: normal computation.
435 _intData[5] = 0; // iopt: 0 if no optional input else 1.
436
437 // 4 - Istate
438 _intData[4] = 1; // istate, an index used for input and output to specify the state of the calculation.
439 // On input:
440 // 1: first call for the problem (initializations will be done).
441 // 2: means this is not the first call, and the calculation is to continue normally, with no change in any input
442 // parameters except possibly TOUT and ITASK.
443 // 3: means this is not the first call, and the calculation is to continue normally, but with
444 // a change in input parameters other than TOUT and ITASK.
445 // On output:
446 // 1: means nothing was done; TOUT = t and ISTATE = 1 on input.
447 // 2: means the integration was performed successfully, and no roots were found.
448 // 3: means the integration was successful, and one or more roots were found before satisfying the stop condition specified by ITASK. See JROOT.
449 // <0: error. See table below, in integrate function output message.
450
451
452
453 // 7 - JT, Jacobian type indicator
454 _intData[8] = 2; // jt, Jacobian type indicator.
455 // 1 means a user-supplied full (NEQ by NEQ) Jacobian.
456 // 2 means an internally generated (difference quotient) full Jacobian (using NEQ extra calls to f per df/dx value).
457 // 4 means a user-supplied banded Jacobian.
458 // 5 means an internally generated banded Jacobian (using ML+MU+1 extra calls to f per df/dx evaluation).
459
460 // set the optional input flags of LSODAROSI to 0
461 // LSODAROSI will take the default values
462
463
464 // === Error handling in LSODAROSI===
465
466 // parameters: itol, rtol, atol.
467 // Control vector E = (E(i)) of estimated local errors in y:
468 // max-norm of ( E(i)/EWT(i) )< 1
469 // EWT = (EWT(i)) vector of positive error weights.
470 // The values of RTOL and ATOL should all be non-negative.
471 //
472 // ITOL RTOL ATOL EWT(i)
473 // 1 scalar scalar RTOL*ABS(Y(i)) + ATOL
474 // 2 scalar array RTOL*ABS(Y(i)) + ATOL(i)
475 // 3 array scalar RTOL(i)*ABS(Y(i)) + ATOL
476 // 4 array array RTOL(i)*ABS(Y(i)) + ATOL(i)
477 DEBUG_END("LsodarOSI::initialize()\n");
478 }
479
integrate(double & tinit,double & tend,double & tout,int & istate)480 void LsodarOSI::integrate(double& tinit, double& tend, double& tout, int& istate)
481 {
482
483 DEBUG_BEGIN("LsodarOSI::integrate(double& tinit, double& tend, double& tout, int& istate) with \n");
484 DEBUG_PRINTF("tinit = %f, tend= %f, tout = %f, istate = %i\n", tinit, tend, tout, istate);
485
486 // For details on DLSODAR parameters, see opkdmain.f in externals/odepack
487 doublereal tend_DR = tend ; // next point where output is desired (different from t!)
488 doublereal tinit_DR = tinit; // current (starting) time
489
490 // === Pointers to function ===
491 // --> definition and initialisation thanks to wrapper:
492 global_object = std::static_pointer_cast<LsodarOSI>(shared_from_this()); // Warning: global object must be initialized to current one before pointers to function initialisation.
493
494 #ifdef HAS_FORTRAN
495 // function to compute the righ-hand side of xdot = f(x,t) + Tu
496 fpointer pointerToF = LsodarOSI_f_wrapper;
497
498 // function to compute the Jacobian/x of the rhs.
499 jacopointer pointerToJacobianF = LsodarOSI_jacobianf_wrapper; // function to compute the Jacobian/x of the rhs.
500
501 // function to compute the constraints
502 gpointer pointerToG;
503 pointerToG = LsodarOSI_g_wrapper; // function to compute the constraints
504 #endif
505
506 // === LSODAR CALL ===
507 DEBUG_EXPR(_xWork->display(););
508 *_xtmp = *_xWork;
509 if(istate == 3)
510 {
511 istate = 1; // restart TEMPORARY
512 }
513
514 _intData[4] = istate;
515
516 #ifdef HAS_FORTRAN
517 // call LSODAR to integrate dynamical equation
518 CNAME(dlsodar)(pointerToF,
519 &(_intData[0]),
520 _xtmp->getArray(),
521 &tinit_DR,
522 &tend_DR,
523 &(_intData[2]),
524 rtol.get(),
525 atol.get(),
526 &(_intData[3]),
527 &(_intData[4]),
528 &(_intData[5]),
529 rwork.get(),
530 &(_intData[6]),
531 iwork.get(),
532 &(_intData[7]),
533 pointerToJacobianF,
534 &(_intData[8]),
535 pointerToG, &
536 (_intData[1]),
537 jroot.get());
538 #else
539 THROW_EXCEPTION("LsodarOSI, Fortran Language is not enabled in siconos kernel. Compile with fortran if you need Lsodar");
540 #endif
541 // jroot: jroot[i] = 1 if g(i) has a root at t, else jroot[i] = 0.
542
543 // === Post ===
544 if(_intData[4] < 0) // if istate < 0 => LSODAROSI failed
545 {
546 std::cout << "LSodar::integrate(...) failed - Istate = " << _intData[4] <<std::endl;
547 std::cout << " -1 means excess work done on this call (perhaps wrong JT, or so small tolerance (ATOL and RTOL), or small maximum number of steps for one call (MXSTEP)). You should increase ATOL or RTOL or increase the MXSTEP" <<std::endl;
548 std::cout << " -2 means excess accuracy requested (tolerances too small)." <<std::endl;
549 std::cout << " -3 means illegal input detected (see printed message)." <<std::endl;
550 std::cout << " -4 means repeated error test failures (check all inputs)." <<std::endl;
551 std::cout << " -5 means repeated convergence failures (perhaps bad Jacobian supplied or wrong choice of JT or tolerances)." <<std::endl;
552 std::cout << " -6 means error weight became zero during problem. (Solution component i vanished, and ATOL or ATOL(i) = 0.)" <<std::endl;
553 std::cout << " -7 means work space insufficient to finish (see messages)." <<std::endl;
554 THROW_EXCEPTION("LsodarOSI, integration failed");
555 }
556
557 *_xWork = *_xtmp;
558 istate = _intData[4];
559 tout = tinit_DR; // real ouput time
560 tend = tend_DR; // necessary for next start of DLSODAR
561 DEBUG_PRINTF("tout = %g, tinit = %g, tend = %g ", tout, tinit, tend);
562 DEBUG_EXPR(_xtmp->display(););
563 DEBUG_EXPR(_xWork->display(););
564 if(istate == 3)
565 {
566 // std:: std::cout << "ok\n";
567 assert(true);
568 }
569 // Update counters
570 count_NST = iwork[10];
571 count_NFE = iwork[11];
572 // tinit = tinit_DR;
573 DEBUG_END("LsodarOSI::integrate(double& tinit, double& tend, double& tout, int& istate)\n");
574 }
575
576
updateState(const unsigned int level)577 void LsodarOSI::updateState(const unsigned int level)
578 {
579 // Compute all required (ie time-dependent) data for the DS of the OSI.
580 DynamicalSystemsGraph::VIterator dsi, dsend;
581 if(level == 1) // ie impact case: compute velocity
582 {
583 for(std::tie(dsi, dsend) = _dynamicalSystemsGraph->vertices(); dsi != dsend; ++dsi)
584 {
585 if(!checkOSI(dsi)) continue;
586 SP::LagrangianDS lds = std::static_pointer_cast<LagrangianDS>(_dynamicalSystemsGraph->bundle(*dsi));
587 lds->computePostImpactVelocity();
588 }
589 }
590 else if(level == 2)
591 {
592 double time = _simulation->nextTime();
593 for(std::tie(dsi, dsend) = _dynamicalSystemsGraph->vertices(); dsi != dsend; ++dsi)
594 {
595 if(!checkOSI(dsi)) continue;
596 {
597 SP::DynamicalSystem ds = _dynamicalSystemsGraph->bundle(*dsi);
598 ds->update(time);
599 }
600 }
601 }
602 else THROW_EXCEPTION("LsodarOSI::updateState(index), index is out of range. Index = " + std::to_string(level));
603 }
604
605 struct LsodarOSI::_NSLEffectOnFreeOutput : public SiconosVisitor
606 {
607 using SiconosVisitor::visit;
608
609 OneStepNSProblem * _osnsp;
610 SP::Interaction _inter;
611 InteractionProperties& _interProp;
_NSLEffectOnFreeOutputLsodarOSI::_NSLEffectOnFreeOutput612 _NSLEffectOnFreeOutput(OneStepNSProblem *p, SP::Interaction inter, InteractionProperties& interProp) :
613 _osnsp(p), _inter(inter), _interProp(interProp) {};
614
visitLsodarOSI::_NSLEffectOnFreeOutput615 void visit(const NewtonImpactNSL& nslaw)
616 {
617 double e;
618 e = nslaw.e();
619 Index subCoord(4);
620 subCoord[0] = 0;
621 subCoord[1] = _inter->nonSmoothLaw()->size();
622 subCoord[2] = 0;
623 subCoord[3] = subCoord[1];
624 SiconosVector & osnsp_rhs = *(*_interProp.workVectors)[LsodarOSI::OSNSP_RHS];
625 subscal(e, *_inter->yOld(_osnsp->inputOutputLevel()), osnsp_rhs, subCoord, false); // q = q + e * q
626 }
627
628 // visit function added by Son (9/11/2010)
visitLsodarOSI::_NSLEffectOnFreeOutput629 void visit(const MultipleImpactNSL& nslaw)
630 {
631 ;
632 }
633 // note : no NewtonImpactFrictionNSL
634 };
635
636
computeFreeOutput(InteractionsGraph::VDescriptor & vertex_inter,OneStepNSProblem * osnsp)637 void LsodarOSI::computeFreeOutput(InteractionsGraph::VDescriptor& vertex_inter, OneStepNSProblem* osnsp)
638 {
639 SP::OneStepNSProblems allOSNS = _simulation->oneStepNSProblems();
640 SP::InteractionsGraph indexSet = osnsp->simulation()->indexSet(osnsp->indexSetLevel());
641 SP::Interaction inter = indexSet->bundle(vertex_inter);
642 VectorOfBlockVectors& DSlink = inter->linkToDSVariables();
643 VectorOfBlockVectors& inter_work_block = *indexSet->properties(vertex_inter).workBlockVectors;
644
645 // Get relation and non smooth law types
646 RELATION::TYPES relationType = inter->relation()->getType();
647 RELATION::SUBTYPES relationSubType = inter->relation()->getSubType();
648 unsigned int sizeY = inter->nonSmoothLaw()->size();
649
650 unsigned int relativePosition = 0;
651 SP::Interaction mainInteraction = inter;
652 Index coord(8);
653 coord[0] = relativePosition;
654 coord[1] = relativePosition + sizeY;
655 coord[2] = 0;
656 coord[4] = 0;
657 coord[6] = 0;
658 coord[7] = sizeY;
659 SP::SiconosMatrix C;
660 // SP::SiconosMatrix D;
661 // SP::SiconosMatrix F;
662 SiconosVector& osnsp_rhs = *(*indexSet->properties(vertex_inter).workVectors)[LsodarOSI::OSNSP_RHS];
663
664 SP::BlockVector Xfree;
665
666
667 // All of these values should be stored in the node corrseponding to the Interactionwhen a LsodarOSI scheme is used.
668
669 /* V.A. 10/10/2010
670 * Following the type of OSNS we need to retrieve the velocity or the acceleration
671 * This tricks is not very nice but for the moment the OSNS do not known if
672 * it is in accelaration of not
673 */
674
675 //SP::OneStepNSProblems allOSNS = _simulation->oneStepNSProblems();
676 if(((*allOSNS)[SICONOS_OSNSP_ED_SMOOTH_ACC]).get() == osnsp)
677 {
678 if(relationType == Lagrangian)
679 {
680 Xfree = inter_work_block[LsodarOSI::xfree];
681 DEBUG_EXPR(Xfree->display(););
682 }
683 // else if (relationType == NewtonEuler)
684 // {
685 // Xfree = inter->data(::FREE);
686 // }
687 assert(Xfree);
688 // std::cout << "Computeqblock Xfree (Gamma)========" << std::endl;
689 // Xfree->display();
690 }
691 else if(((*allOSNS)[SICONOS_OSNSP_ED_IMPACT]).get() == osnsp)
692 {
693 Xfree = DSlink[LagrangianR::q1];
694 // std::cout << "Computeqblock Xfree (Velocity)========" << std::endl;
695 // Xfree->display();
696
697 }
698 else
699 THROW_EXCEPTION(" computeqBlock for Event Event-driven is wrong ");
700
701 if(relationType == Lagrangian)
702 {
703 C = mainInteraction->relation()->C();
704 if(C)
705 {
706 assert(Xfree);
707
708 coord[3] = C->size(1);
709 coord[5] = C->size(1);
710
711 subprod(*C, *Xfree, osnsp_rhs, coord, true);
712 }
713
714 SP::SiconosMatrix ID(new SimpleMatrix(sizeY, sizeY));
715 ID->eye();
716
717 Index xcoord(8);
718 xcoord[0] = 0;
719 xcoord[1] = sizeY;
720 xcoord[2] = 0;
721 xcoord[3] = sizeY;
722 xcoord[4] = 0;
723 xcoord[5] = sizeY;
724 xcoord[6] = 0;
725 xcoord[7] = sizeY;
726 // For the relation of type LagrangianRheonomousR
727 if(relationSubType == RheonomousR)
728 {
729 if(((*allOSNS)[SICONOS_OSNSP_ED_SMOOTH_ACC]).get() == osnsp)
730 {
731 THROW_EXCEPTION("LsodarOSI::computeFreeOutput not yet implemented for LCP at acceleration level with LagrangianRheonomousR");
732 }
733 else if(((*allOSNS)[SICONOS_OSNSP_TS_VELOCITY]).get() == osnsp)
734 {
735 std::static_pointer_cast<LagrangianRheonomousR>(inter->relation())->computehDot(simulation()->getTkp1(), *DSlink[LagrangianR::q0], *DSlink[LagrangianR::z]);
736 subprod(*ID, *(std::static_pointer_cast<LagrangianRheonomousR>(inter->relation())->hDot()), osnsp_rhs, xcoord, false); // y += hDot
737 }
738 else
739 THROW_EXCEPTION("LsodarOSI::computeFreeOutput not implemented for SICONOS_OSNSP ");
740 }
741 // For the relation of type LagrangianScleronomousR
742 if(relationSubType == ScleronomousR)
743 {
744 if(((*allOSNS)[SICONOS_OSNSP_ED_SMOOTH_ACC]).get() == osnsp)
745 {
746 std::static_pointer_cast<LagrangianScleronomousR>(inter->relation())->computedotjacqhXqdot(simulation()->getTkp1(), *inter, DSlink);
747 subprod(*ID, *(std::static_pointer_cast<LagrangianScleronomousR>(inter->relation())->dotjacqhXqdot()), osnsp_rhs, xcoord, false); // y += NonLinearPart
748 }
749 }
750 }
751 else
752 THROW_EXCEPTION("LsodarOSI::computeFreeOutput not yet implemented for Relation of type " + std::to_string(relationType));
753 if(((*allOSNS)[SICONOS_OSNSP_ED_IMPACT]).get() == osnsp)
754 {
755 if(inter->relation()->getType() == Lagrangian || inter->relation()->getType() == NewtonEuler)
756 {
757 SP::SiconosVisitor nslEffectOnFreeOutput(new _NSLEffectOnFreeOutput(osnsp, inter, indexSet->properties(vertex_inter)));
758 inter->nonSmoothLaw()->accept(*nslEffectOnFreeOutput);
759 }
760 }
761
762 }
display()763 void LsodarOSI::display()
764 {
765 OneStepIntegrator::display();
766 std::cout << " --- > LsodarOSI specific values: " <<std::endl;
767 std::cout << "Number of equations: " << _intData[0] <<std::endl;
768 std::cout << "Number of constraints: " << _intData[1] <<std::endl;
769 std::cout << "itol, itask, istate, iopt, lrw, liw, jt: (for details on what are these variables see opkdmain.f)" <<std::endl;
770 std::cout << _intData[2] << ", " << _intData[3] << ", " << _intData[4] << ", " << _intData[5] << ", " << _intData[6] << ", " << _intData[7] << ", " << _intData[8] <<std::endl;
771 std::cout << "====================================" <<std::endl;
772 }
773