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 #include "Topology.hpp"
19 #include "SiconosException.hpp"
20 #include "NonSmoothLaw.hpp"
21 #include "NonSmoothDynamicalSystem.hpp"
22 #include "Interaction.hpp"
23 #include "EqualityConditionNSL.hpp"
24 #include "OneStepIntegrator.hpp"
25
26 #if (__cplusplus >= 201103L) && !defined(USE_BOOST_FOR_CXX11)
27 #include <functional>
28 #else
29 #include <boost/bind.hpp>
30 #endif
31
32
33 #include <algorithm>
34 #include <limits>
35
36 //#define DEBUG_STDOUT
37 //#define DEBUG_MESSAGES 1
38 #include "siconos_debug.h"
39
40 #define MAX_RELATIVE_DEGREE 999
41
42 // --- CONSTRUCTORS/DESTRUCTOR ---
43
44 // default
Topology()45 Topology::Topology()
46 {
47 _IG.resize(1);
48 _DSG.resize(1);
49
50 _IG[0].reset(new InteractionsGraph());
51 _DSG[0].reset(new DynamicalSystemsGraph());
52
53 _IG[0]->update_vertices_indices();
54 _IG[0]->update_edges_indices();
55 }
56
57 // destructor
~Topology()58 Topology::~Topology()
59 {
60 clear();
61 }
62
63 std::pair<DynamicalSystemsGraph::EDescriptor, InteractionsGraph::VDescriptor>
__addInteractionInIndexSet0(SP::Interaction inter,SP::DynamicalSystem ds1,SP::DynamicalSystem ds2)64 Topology::__addInteractionInIndexSet0(SP::Interaction inter, SP::DynamicalSystem ds1, SP::DynamicalSystem ds2)
65 {
66 // !! Private function !!
67 //
68 // This function must
69 // - insert interaction and ds into IG/DSG
70 // - update graph properties related to modeling (DSlink ...)
71 //
72 // Expected result : all interaction methods can be safely called after a call
73 // to this function (whatever the simulation is, if it exists or not).
74
75 // Update total number of constraints
76 _numberOfConstraints += inter->nonSmoothLaw()->size();
77
78 SP::DynamicalSystem ds2_ = ds2;
79 // _DSG is the hyper forest : (vertices : dynamical systems, edges :
80 // Interactions)
81 //
82 // _IG is the hyper graph : (vertices : Interactions, edges :
83 // dynamical systems)
84 assert(_DSG[0]->edges_number() == _IG[0]->size());
85
86 // _IG = L(_DSG), L is the line graph transformation
87 // vector of the Interaction
88 DynamicalSystemsGraph::VDescriptor dsgv1, dsgv2;
89 dsgv1 = _DSG[0]->add_vertex(ds1);
90
91 if(ds2)
92 {
93 dsgv2 = _DSG[0]->add_vertex(ds2);
94 }
95 else
96 {
97 dsgv2 = dsgv1;
98 ds2_ = ds1;
99 }
100
101 // this may be a multi edges graph
102 assert(!_DSG[0]->is_edge(dsgv1, dsgv2, inter));
103 assert(!_IG[0]->is_vertex(inter));
104 InteractionsGraph::VDescriptor ig_new_ve;
105 DynamicalSystemsGraph::EDescriptor new_ed;
106 std::tie(new_ed, ig_new_ve) = _DSG[0]->add_edge(dsgv1, dsgv2, inter, *_IG[0]);
107
108 inter->initializeLinkToDsVariables(*ds1, *ds2_);
109
110 // add self branches in vertex properties
111 // note : boost graph SEGFAULT on self branch removal
112 // see https://svn.boost.org/trac/boost/ticket/4622
113 _IG[0]->properties(ig_new_ve).source = ds1;
114 _IG[0]->properties(ig_new_ve).source_pos = 0;
115
116 if(!ds2) // self loop in ds graph, source=target in interaction graph
117 {
118 _IG[0]->properties(ig_new_ve).target = ds1;
119 _IG[0]->properties(ig_new_ve).target_pos = 0;
120 }
121 else
122 {
123 _IG[0]->properties(ig_new_ve).target = ds2;
124 _IG[0]->properties(ig_new_ve).target_pos = ds1->dimension();
125 }
126
127 assert(_IG[0]->bundle(ig_new_ve) == inter);
128 assert(_IG[0]->is_vertex(inter));
129 assert(_DSG[0]->is_edge(dsgv1, dsgv2, inter));
130 assert(_DSG[0]->edges_number() == _IG[0]->size());
131
132
133
134
135 return std::pair<DynamicalSystemsGraph::EDescriptor, InteractionsGraph::VDescriptor>(new_ed, ig_new_ve);
136 }
137
138 /* an edge is removed from _DSG graph if the corresponding vertex is
139 removed from the adjoint graph (_IG)
140 */
141 struct VertexIsRemoved
142 {
VertexIsRemovedVertexIsRemoved143 VertexIsRemoved(SP::Interaction I,
144 SP::DynamicalSystemsGraph sg, SP::InteractionsGraph asg) :
145 _I(I), __DSG(sg), __IG(asg) {};
operator ()VertexIsRemoved146 bool operator()(DynamicalSystemsGraph::EDescriptor ed)
147 {
148
149 if(__IG->is_vertex(__DSG->bundle(ed)))
150 {
151 InteractionsGraph::VDescriptor ivd = __IG->descriptor(__DSG->bundle(ed));
152
153 if(__IG->bundle(ivd) == _I)
154 {
155 __IG->remove_vertex(__DSG->bundle(ed));
156
157 assert(__IG->size() == __DSG->edges_number() - 1);
158
159 return true;
160 }
161 else
162 {
163 return false;
164 }
165 }
166 else
167 {
168 return true;
169 }
170 }
171 SP::Interaction _I;
172 SP::DynamicalSystemsGraph __DSG;
173 SP::InteractionsGraph __IG;
174 };
175
176 /* an edge is removed from _DSG graph if the corresponding vertex is
177 removed from the adjoint graph (_IG)
178 */
179 struct VertexIsRemovedDS
180 {
VertexIsRemovedDSVertexIsRemovedDS181 VertexIsRemovedDS(SP::DynamicalSystem ds,
182 SP::DynamicalSystemsGraph sg, SP::InteractionsGraph asg) :
183 _ds(ds), __DSG(sg), __IG(asg) {};
operator ()VertexIsRemovedDS184 bool operator()(DynamicalSystemsGraph::EDescriptor ed)
185 {
186 if(__IG->is_vertex(__DSG->bundle(ed)))
187 {
188 InteractionsGraph::VDescriptor ivd = __IG->descriptor(__DSG->bundle(ed));
189
190 if(__IG->properties(ivd).source == _ds
191 || __IG->properties(ivd).target == _ds)
192 {
193 __IG->remove_vertex(__DSG->bundle(ed));
194
195 assert(__IG->size() == __DSG->edges_number() - 1);
196
197 return true;
198 }
199 else
200 {
201 return false;
202 }
203 }
204 else
205 {
206 return true;
207 }
208 }
209 SP::DynamicalSystem _ds;
210 SP::DynamicalSystemsGraph __DSG;
211 SP::InteractionsGraph __IG;
212 };
213
214 /* remove an interaction : remove edges (Interaction) from _DSG if
215 corresponding vertices are removed from _IG */
__removeInteractionFromIndexSet(SP::Interaction inter)216 void Topology::__removeInteractionFromIndexSet(SP::Interaction inter)
217 {
218
219 SP::DynamicalSystem ds1 = _IG[0]->properties(_IG[0]->descriptor(inter)).source;
220 SP::DynamicalSystem ds2 = _IG[0]->properties(_IG[0]->descriptor(inter)).target;
221 _DSG[0]->remove_out_edge_if(_DSG[0]->descriptor(ds1), VertexIsRemoved(inter, _DSG[0], _IG[0]));
222 if(ds1 != ds2)
223 _DSG[0]->remove_out_edge_if(_DSG[0]->descriptor(ds2), VertexIsRemoved(inter, _DSG[0], _IG[0]));
224 }
225
226
insertDynamicalSystem(SP::DynamicalSystem ds)227 void Topology::insertDynamicalSystem(SP::DynamicalSystem ds)
228 {
229 _DSG[0]->add_vertex(ds);
230 setHasChanged(true);
231 }
232
233 /* remove a dynamical system : remove edges (DynamicalSystem) from _IG if
234 corresponding vertices are removed from _DSG */
__removeDynamicalSystemFromIndexSet(SP::DynamicalSystem ds)235 void Topology::__removeDynamicalSystemFromIndexSet(SP::DynamicalSystem ds)
236 {
237 _DSG[0]->remove_edge_if(_DSG[0]->descriptor(ds),
238 VertexIsRemovedDS(ds, _DSG[0], _IG[0]));
239
240 // note: remove_vertex also calls clear_vertex and removes all in/out edges
241 _DSG[0]->remove_vertex(ds);
242 }
243
244
setName(SP::DynamicalSystem ds,const std::string & name)245 void Topology::setName(SP::DynamicalSystem ds, const std::string& name)
246 {
247 DynamicalSystemsGraph::VDescriptor dsgv = _DSG[0]->descriptor(ds);
248 _DSG[0]->name.insert(dsgv, name);
249 }
250
name(SP::DynamicalSystem ds)251 std::string Topology::name(SP::DynamicalSystem ds)
252 {
253 DynamicalSystemsGraph::VDescriptor dsgv = _DSG[0]->descriptor(ds);
254 if(dsgv)
255 return _DSG[0]->name.at(dsgv);
256 else
257 return "";
258 }
259
setName(SP::Interaction inter,const std::string & name)260 void Topology::setName(SP::Interaction inter, const std::string& name)
261 {
262 InteractionsGraph::VDescriptor igv = _IG[0]->descriptor(inter);
263 _IG[0]->name.insert(igv, name);
264 }
265
name(SP::Interaction inter)266 std::string Topology::name(SP::Interaction inter)
267 {
268 InteractionsGraph::VDescriptor igv = _IG[0]->descriptor(inter);
269 if(igv)
270 return _IG[0]->name.at(igv);
271 else
272 return "";
273 }
274
setOSI(SP::DynamicalSystem ds,SP::OneStepIntegrator OSI)275 void Topology::setOSI(SP::DynamicalSystem ds, SP::OneStepIntegrator OSI)
276 {
277 _DSG[0]->properties(_DSG[0]->descriptor(ds)).osi = OSI;
278 }
279
setControlProperty(SP::Interaction inter,const bool isControlInteraction)280 void Topology::setControlProperty(SP::Interaction inter,
281 const bool isControlInteraction)
282 {
283 InteractionsGraph::VDescriptor ivd = _IG[0]->descriptor(inter);
284 DynamicalSystemsGraph::VDescriptor dvd = _DSG[0]->descriptor(_IG[0]->properties(ivd).target);
285 SP::Interaction interG;
286 DynamicalSystemsGraph::OEIterator oei, oeiend;
287 for(std::tie(oei, oeiend) = _DSG[0]->out_edges(dvd); oei != oeiend; ++oei)
288 {
289 interG = _DSG[0]->bundle(*oei);
290 if(inter == interG)
291 {
292 _DSG[0]->properties(*oei).forControl = isControlInteraction;
293 break;
294 }
295 }
296 _IG[0]->properties(ivd).forControl = isControlInteraction;
297 }
298
indexSet(unsigned int num) const299 SP::InteractionsGraph Topology::indexSet(unsigned int num) const
300 {
301 if(num >= _IG.size())
302 {
303 THROW_EXCEPTION("Topology::indexSet: indexSet does not exist");
304 }
305 assert(num < _IG.size()) ;
306 return _IG[num];
307 };
308
removeInteraction(SP::Interaction inter)309 void Topology::removeInteraction(SP::Interaction inter)
310 {
311 DEBUG_PRINTF("removeInteraction : %p\n", &*inter);
312
313 assert(_DSG[0]->edges_number() == _IG[0]->size());
314 __removeInteractionFromIndexSet(inter);
315 assert(_DSG[0]->edges_number() == _IG[0]->size());
316 setHasChanged(true);
317 }
318
removeDynamicalSystem(SP::DynamicalSystem ds)319 void Topology::removeDynamicalSystem(SP::DynamicalSystem ds)
320 {
321 DEBUG_PRINTF("removeDynamicalSystem : %p\n", &*ds);
322
323 assert(_DSG[0]->edges_number() == _IG[0]->size() && "1");
324 __removeDynamicalSystemFromIndexSet(ds);
325 assert(_DSG[0]->edges_number() == _IG[0]->size() && "2");
326 setHasChanged(true);
327 }
328
329
330 std::pair<DynamicalSystemsGraph::EDescriptor, InteractionsGraph::VDescriptor>
link(SP::Interaction inter,SP::DynamicalSystem ds,SP::DynamicalSystem ds2)331 Topology::link(SP::Interaction inter, SP::DynamicalSystem ds, SP::DynamicalSystem ds2)
332 {
333 DEBUG_PRINTF("Topology::link : inter %p, ds1 %p, ds2 %p\n", &*inter, &*ds,
334 &*ds2);
335
336 // If the interaction is already in the graph remove it
337 if(indexSet0()->is_vertex(inter))
338 {
339 __removeInteractionFromIndexSet(inter);
340 }
341
342 // Compute interaction dimension (sum of involved dynamical systems sizes)
343 unsigned int sumOfDSSizes = 0;
344 sumOfDSSizes += ds->dimension();
345 if(ds2)
346 {
347 sumOfDSSizes += ds2->dimension();
348 inter->setHas2Bodies(true);
349 }
350 inter->setDSSizes(sumOfDSSizes);
351
352 return __addInteractionInIndexSet0(inter, ds, ds2);
353 }
354
hasInteraction(SP::Interaction inter) const355 bool Topology::hasInteraction(SP::Interaction inter) const
356 {
357 return indexSet0()->is_vertex(inter);
358 }
359
hasDynamicalSystem(SP::DynamicalSystem ds) const360 bool Topology::hasDynamicalSystem(SP::DynamicalSystem ds) const
361 {
362 return _DSG[0]->is_vertex(ds);
363 }
364
setProperties()365 void Topology::setProperties()
366 {
367 _IG[0]->update_vertices_indices();
368 _IG[0]->update_edges_indices();
369
370 for(unsigned int i = 1; i < _IG.size(); ++i)
371 {
372 // .. global properties may be defined here with
373 // InteractionsSubGraphProperties(), see SiconosProperties.hpp
374 // VertexSubProperties or EdgeSubProperties and the macros
375 // INSTALL_GRAPH_PROPERTIES
376
377 _IG[i]->properties().symmetric = _symmetric;
378
379 _IG[i]->update_vertices_indices();
380 _IG[i]->update_edges_indices();
381 }
382
383 _DSG[0]->properties().symmetric = _symmetric;
384
385 _DSG[0]->update_vertices_indices();
386 _DSG[0]->update_edges_indices();
387
388 }
389
clear()390 void Topology::clear()
391 {
392 _IG.clear();
393 _DSG.clear();
394 }
395
getDynamicalSystem(unsigned int requiredNumber) const396 SP::DynamicalSystem Topology::getDynamicalSystem(unsigned int requiredNumber) const
397 {
398 DynamicalSystemsGraph::VIterator vi, vdend;
399 SP::DynamicalSystem ds;
400 unsigned int currentNumber;
401 for(std::tie(vi, vdend) = _DSG[0]->vertices(); vi != vdend; ++vi)
402 {
403 ds = _DSG[0]->bundle(*vi);
404 currentNumber = ds->number();
405 if(currentNumber == requiredNumber)
406 return ds;
407 }
408
409 THROW_EXCEPTION("Topology::getDynamicalSystem(n) ds not found.");
410
411 return ds;
412 }
413
414
displayDynamicalSystems() const415 void Topology::displayDynamicalSystems() const
416 {
417 DynamicalSystemsGraph::VIterator vi, vdend;
418 SP::DynamicalSystem ds;
419 unsigned int currentNumber;
420 for(std::tie(vi, vdend) = _DSG[0]->vertices(); vi != vdend; ++vi)
421 {
422 ds = _DSG[0]->bundle(*vi);
423 currentNumber = ds->number();
424 std::cout << "Dynamical system number : " << currentNumber << std::endl;
425 ds->display();
426 }
427 }
428
getDynamicalSystem(std::string name) const429 SP::DynamicalSystem Topology::getDynamicalSystem(std::string name) const
430 {
431 DynamicalSystemsGraph::VIterator vi, vdend;
432 for(std::tie(vi, vdend) = _DSG[0]->vertices(); vi != vdend; ++vi)
433 {
434 if(name == _DSG[0]->name.at(*vi))
435 return _DSG[0]->bundle(*vi);
436 }
437
438 THROW_EXCEPTION("Topology::getDynamicalSystem() ds not found.");
439
440 return SP::DynamicalSystem();
441 }
442
443
numberOfInvolvedDS(unsigned int inumber)444 unsigned int Topology::numberOfInvolvedDS(unsigned int inumber)
445 {
446 if(inumber >= _IG.size())
447 {
448 THROW_EXCEPTION("Topology::numberOfInvolvedDS :: index number must be smaller than the number of indexSets");
449 }
450
451 /* on an adjoint graph a dynamical system may be on several edges */
452 std::map<SP::DynamicalSystem, bool> flag;
453
454 unsigned int return_value = 0;
455
456 SP::InteractionsGraph indexSet = _IG[inumber];
457
458 InteractionsGraph::VIterator vi, viend;
459 for(std::tie(vi, viend) = indexSet->vertices();
460 vi != viend; ++vi)
461 {
462 if(indexSet->properties(*vi).source)
463 {
464 if(flag.find(indexSet->properties(*vi).source) == flag.end())
465 {
466 flag[indexSet->properties(*vi).source] = true;
467 return_value++;
468 }
469 }
470 if(indexSet->properties(*vi).target)
471 {
472 if(flag.find(indexSet->properties(*vi).target) == flag.end())
473 {
474 flag[indexSet->properties(*vi).target] = true;
475 return_value++;
476 }
477 }
478 }
479
480 InteractionsGraph::EIterator ei, eiend;
481
482 for(std::tie(ei, eiend) = indexSet->edges();
483 ei != eiend; ++ei)
484 {
485 if(flag.find(indexSet->bundle(*ei)) == flag.end())
486 {
487 flag[indexSet->bundle(*ei)] = true;
488 return_value++;
489 }
490 }
491
492 return return_value;
493 }
494
getInteraction(unsigned int requiredNumber) const495 SP::Interaction Topology::getInteraction(unsigned int requiredNumber) const
496 {
497 InteractionsGraph::VIterator vi, vdend;
498 SP::Interaction inter;
499 unsigned int currentNumber;
500 for(std::tie(vi, vdend) = _IG[0]->vertices(); vi != vdend; ++vi)
501 {
502 inter = _IG[0]->bundle(*vi);
503 currentNumber = inter->number();
504 if(currentNumber == requiredNumber)
505 return inter;
506 }
507
508 return inter;
509 }
510
getInteraction(std::string name) const511 SP::Interaction Topology::getInteraction(std::string name) const
512 {
513 DynamicalSystemsGraph::VIterator vi, vdend;
514 for(std::tie(vi, vdend) = _IG[0]->vertices(); vi != vdend; ++vi)
515 {
516 if(name == _IG[0]->name.at(*vi))
517 return _IG[0]->bundle(*vi);
518 }
519
520 return SP::Interaction();
521 }
522
interactionsForDS(SP::DynamicalSystem ds) const523 std::vector<SP::Interaction> Topology::interactionsForDS(
524 SP::DynamicalSystem ds) const
525 {
526 InteractionsGraph::VIterator ui, uiend;
527 SP::Interaction inter;
528 std::vector<SP::Interaction> result;
529 if(!ds) return result;
530 for(std::tie(ui, uiend) = _IG[0]->vertices(); ui != uiend; ++ui)
531 {
532 inter = _IG[0]->bundle(*ui);
533 SP::DynamicalSystem ds1 = _IG[0]->properties(_IG[0]->descriptor(inter)).source;
534 SP::DynamicalSystem ds2 = _IG[0]->properties(_IG[0]->descriptor(inter)).target;
535 if(ds == ds1 || ds == ds2)
536 result.push_back(inter);
537 }
538 return result;
539 }
540
interactionsForPairOfDS(SP::DynamicalSystem dsA,SP::DynamicalSystem dsB) const541 std::vector<SP::Interaction> Topology::interactionsForPairOfDS(
542 SP::DynamicalSystem dsA,
543 SP::DynamicalSystem dsB) const
544 {
545 InteractionsGraph::VIterator ui, uiend;
546 SP::Interaction inter;
547 std::vector<SP::Interaction> result;
548 if(!dsA && !dsB) return result;
549 for(std::tie(ui, uiend) = _IG[0]->vertices(); ui != uiend; ++ui)
550 {
551 inter = _IG[0]->bundle(*ui);
552 SP::DynamicalSystem ds1 = _IG[0]->properties(_IG[0]->descriptor(inter)).source;
553 SP::DynamicalSystem ds2 = _IG[0]->properties(_IG[0]->descriptor(inter)).target;
554 int found = 0;
555 if(dsA == ds1)
556 found = 1;
557 else if(dsA == ds2)
558 found = 2;
559 if(found==2 && dsB != ds1)
560 found = 0;
561 else if(found==1 && dsB == ds2)
562 found = 0;
563 if(found)
564 result.push_back(inter);
565 }
566 return result;
567 }
568
569 std::vector<SP::DynamicalSystem>
dynamicalSystemsForInteraction(SP::Interaction inter) const570 Topology::dynamicalSystemsForInteraction(
571 SP::Interaction inter) const
572 {
573 SP::DynamicalSystem ds1 = _IG[0]->properties(_IG[0]->descriptor(inter)).source;
574 SP::DynamicalSystem ds2 = _IG[0]->properties(_IG[0]->descriptor(inter)).target;
575 std::vector<SP::DynamicalSystem> result;
576 if(ds1) result.push_back(ds1);
577 if(ds2 && ds1 != ds2) result.push_back(ds2);
578 return result;
579 }
580