Antares Simulator
Power System Simulator
Loading...
Searching...
No Matches
grid.hxx
1/*
2** Copyright 2007-2024, RTE (https://www.rte-france.com)
3** See AUTHORS.txt
4** SPDX-License-Identifier: MPL-2.0
5** This file is part of Antares-Simulator,
6** Adequacy and Performance assessment for interconnected energy networks.
7**
8** Antares_Simulator is free software: you can redistribute it and/or modify
9** it under the terms of the Mozilla Public Licence 2.0 as published by
10** the Mozilla Foundation, either version 2 of the License, or
11** (at your option) any later version.
12**
13** Antares_Simulator is distributed in the hope that it will be useful,
14** but WITHOUT ANY WARRANTY; without even the implied warranty of
15** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16** Mozilla Public Licence 2.0 for more details.
17**
18** You should have received a copy of the Mozilla Public Licence 2.0
19** along with Antares_Simulator. If not, see <https://opensource.org/license/mpl-2-0/>.
20*/
21#include <algorithm>
22#include <list>
23#include <numeric>
24#include <stack>
25#include <utility>
26
27#include "antares/solver/constraints-builder/cbuilder.h"
28#include "antares/solver/constraints-builder/grid.h"
29
30using namespace Yuni;
31
32namespace Antares
33{
34namespace Graph
35{
36template<class NodeT>
38 inf(0)
39{
40}
41
42template<class NodeT>
44{
45 for (auto i = pEdgesList.begin(); i != pEdgesList.end(); i++)
46 {
47 delete (*i);
48 }
49 for (auto i = pNodesList.begin(); i != pNodesList.end(); i++)
50 {
51 delete (*i);
52 }
53}
54
55template<class NodeT>
56typename Grid<NodeT>::NodeP Grid<NodeT>::addNode(NodeT& n, std::string id)
57{
58 auto nodeIT = std::find_if(pNodesList.begin(),
59 pNodesList.end(),
60 [&id](const NodeP& nodeP) -> bool
61 { return nodeP->getName() == id; });
62
63 if (nodeIT == pNodesList.end())
64 {
65 NodeP newNode = new Graph::Node<NodeT>(&n);
66 newNode->setName(id);
67 pNodesList.push_back(newNode);
68 return newNode;
69 }
70 else
71 {
72 return *nodeIT;
73 }
74}
75
76template<class NodeT>
78{
79 std::string s1(n1->getName());
80 std::string s2(n2->getName());
81 EdgeP edgePtr = findEdgeFromNodeNames(s1, s2);
82 if (edgePtr == nullptr)
83 {
84 EdgeP newEdge = new Edge<NodeT>(n1, n2);
85 inf += weight;
86 newEdge->setWeight(weight);
87
88 // add edge to the list
89 pEdgesList.push_back(newEdge);
90
91 // redefine inf
92 inf += weight;
93
94 // update adjency
95 adjency[newEdge->getOrigin()].insert(std::make_pair(newEdge->getDestination(), newEdge));
96 adjency[newEdge->getDestination()].insert(std::make_pair(newEdge->getOrigin(), newEdge));
97
98 return newEdge;
99 }
100 else
101 {
102 return edgePtr;
103 }
104}
105
106template<class NodeT>
108{
109 // create union-find set
110 MapNodes uf;
111
112 for (auto i = pNodesList.begin(); i != pNodesList.end(); i++)
113 {
114 uf.insert(std::make_pair(*i, *i));
115 }
116
117 // algorithm
118 for (auto i = pEdgesList.begin(); i != pEdgesList.end(); i++)
119 {
120 // if the two areas are not yet connected
121 if (uf[(*i)->getOrigin()] != uf[(*i)->getDestination()])
122 {
123 // update uf
124 NodeP cset(uf[(*i)->getDestination()]);
125 for (auto j = pNodesList.begin(); j != pNodesList.end(); j++)
126 {
127 if (uf[*j] == cset)
128 {
129 uf[*j] = uf[(*i)->getOrigin()];
130 }
131 }
132 }
133 }
134
135 std::unordered_map<NodeP, bool> cVec;
136 for (auto cIT = uf.begin(); cIT != uf.end(); cIT++)
137 {
138 cVec[cIT->second] = true;
139 }
140
141 return (uint)(cVec.size());
143
144template<class NodeT>
146{
147 // clear spanning tree
148 pMinSpanningTree.clear();
149
150 // create union-find set
151 MapNodes uf;
152
153 for (auto i = pNodesList.begin(); i != pNodesList.end(); i++)
154 {
155 uf.insert(std::make_pair(*i, *i));
156 }
157
158 // create temporary sorted vector of Link
159 VectorEdgeP tempEdgesList = pEdgesList;
160 std::stable_sort(tempEdgesList.begin(),
161 tempEdgesList.end(),
163
164 // algorithm
165 for (auto i = tempEdgesList.begin(); i != tempEdgesList.end(); i++)
166 {
167 // if the two areas are not yet connected
168 if (uf[(*i)->getOrigin()] != uf[(*i)->getDestination()])
169 {
170 pMinSpanningTree.push_back(*i);
171
172 // update uf
173 NodeP cset(uf[(*i)->getDestination()]);
174 for (auto j = pNodesList.begin(); j != pNodesList.end(); j++)
175 {
176 if (uf[*j] == cset)
177 {
178 uf[*j] = uf[(*i)->getOrigin()];
179 }
180 }
181 }
182 }
183}
184
185template<class NodeT>
187{
188 // build the minimum spanning tree
189 kruskal();
190
191 if (pMinSpanningTree.empty())
192 {
193 return false;
194 }
195
196 // clear the spanning cycle base
197 pMesh.clear();
198 meshIndexMatrix.clear();
199
200 // initialization
201 std::vector<EdgeP> linksToBeAdded;
202 for (auto i = pEdgesList.begin(); i != pEdgesList.end(); i++)
203 {
204 // check if the link already belong to the skeleton
205 if (std::find(pMinSpanningTree.begin(), pMinSpanningTree.end(), (*i))
206 == pMinSpanningTree.end())
207 {
208 linksToBeAdded.push_back(*i);
209 }
210 }
211
212 std::vector<EdgeIncidence> incidenceMatrix(linksToBeAdded.size());
213 for (uint i = 0; i < linksToBeAdded.size(); i++)
214 {
215 incidenceMatrix[i] = getIncidenceVector(linksToBeAdded[i]);
216 }
217
218 for (uint i = 0; i < linksToBeAdded.size(); i++)
219 {
220 logs.info() << "Searching basis (loop " << i + 1 << "/" << linksToBeAdded.size() << ")";
221 // build the graph with two copies (+/-) for each node and edge
222 Grid<NodeT> polarisedDuplicate;
223 getDuplicatedGrid(polarisedDuplicate);
224 VectorEdgeP v = getEdgeVectorFromIncidence(incidenceMatrix[i]);
225 VectorEdgeP Ci;
227 VectorNodeP adjacentNodes;
228 // retrait des arêtes (u,v) qui sont dans Ei et remplacement dans le graphe dupliqué
229 // par(u+,v-) et (u-,v+)
230 for (uint j = 0; j < v.size(); j++)
231 {
232 if (std::find(adjacentNodes.begin(), adjacentNodes.end(), v[j]->getOrigin())
233 == adjacentNodes.end())
234 {
235 adjacentNodes.push_back(v[j]->getOrigin());
236 }
237 if (std::find(adjacentNodes.begin(), adjacentNodes.end(), v[j]->getDestination())
238 == adjacentNodes.end())
239 {
240 adjacentNodes.push_back(v[j]->getDestination());
241 }
242
243 EdgeP ei = polarisedDuplicate.findEdgeFromNodeNames(v[j]->getOrigin()->getName() + "+",
244 v[j]->getDestination()->getName()
245 + "+");
246
247 NodeP ni1 = polarisedDuplicate.findNodeFromName(v[j]->getOrigin()->getName() + "+");
248 NodeP ni2 = polarisedDuplicate.findNodeFromName(v[j]->getDestination()->getName()
249 + "-");
250
251 polarisedDuplicate.addEdge(ni1, ni2, ei->getWeight());
252 polarisedDuplicate.removeEdge(ei);
253
254 ei = polarisedDuplicate.findEdgeFromNodeNames(v[j]->getOrigin()->getName() + "-",
255 v[j]->getDestination()->getName() + "-");
256
257 ni1 = polarisedDuplicate.findNodeFromName(v[j]->getOrigin()->getName() + "-");
258 ni2 = polarisedDuplicate.findNodeFromName(v[j]->getDestination()->getName() + "+");
259
260 polarisedDuplicate.addEdge(ni1, ni2, ei->getWeight());
261 polarisedDuplicate.removeEdge(ei);
262 }
263
265 v = polarisedDuplicate.twoLevelPath(adjacentNodes);
266
268 Ci.clear();
269 std::vector<int> edgeIndices;
270 for (typename VectorEdgeP::iterator e = v.begin(); e != v.end(); e++)
271 {
272 auto name1 = (*e)->getOrigin()->getName();
273 name1 = name1.substr(0, name1.length() - 1);
274 auto name2 = (*e)->getDestination()->getName();
275 name2 = name2.substr(0, name2.length() - 1);
276 EdgeP ei = findEdgeFromNodeNames(name1, name2);
277 Ci.push_back(ei);
278
279 auto eIT = std::find(pEdgesList.begin(), pEdgesList.end(), ei);
280 int pos = (int)std::distance(pEdgesList.begin(), eIT);
281 edgeIndices.push_back(pos);
282 }
283
284 pMesh.push_back(Ci);
285 EdgeIncidence I = getIncidenceVector(Ci);
286 meshIndexMatrix.push_back(edgeIndices);
287 // remplacement par la différence symétrique des des jeux d'arêtes
288 for (uint j = i + 1; j < linksToBeAdded.size(); j++)
289 {
290 if (incidenceInnerProduct(I, incidenceMatrix[j]) == 1)
291 {
292 incidenceMatrix[j] = incidenceXOR(incidenceMatrix[i], incidenceMatrix[j]);
293 }
295 }
296
297 return true;
298}
299
304template<class NodeT>
306{
307 // duplicate nodes
308 for (typename VectorNodeP::iterator node = pNodesList.begin(); node != pNodesList.end(); node++)
309 {
310 { //+
311 grid.addNode((*(*node)->nodeProperties), (*node)->getName() + "+");
312 }
313
314 { //-
315 grid.addNode((*(*node)->nodeProperties), (*node)->getName() + "-");
316 }
317 }
318
319 // Duplicate edges
320 for (typename VectorEdgeP::iterator e = pEdgesList.begin(); e != pEdgesList.end(); e++)
321 {
322 { //+
323 auto nodeOrigIT = std::find_if(grid.pNodesList.begin(),
324 grid.pNodesList.end(),
325 [&e](const NodeP& nodeP) -> bool {
326 return nodeP->getName()
327 == (*e)->getOrigin()->getName() + "+";
328 });
329
330 auto nodeDestIT = std::find_if(grid.pNodesList.begin(),
331 grid.pNodesList.end(),
332 [&e](const NodeP& nodeP) -> bool {
333 return nodeP->getName()
334 == (*e)->getDestination()->getName() + "+";
335 });
336
337 grid.addEdge(*nodeOrigIT, *nodeDestIT, (*e)->getWeight());
338 }
339
340 { //-
341 auto nodeOrigIT = std::find_if(grid.pNodesList.begin(),
342 grid.pNodesList.end(),
343 [&e](const NodeP& nodeP) -> bool {
344 return nodeP->getName()
345 == (*e)->getOrigin()->getName() + "-";
346 });
347
348 auto nodeDestIT = std::find_if(grid.pNodesList.begin(),
349 grid.pNodesList.end(),
350 [&e](const NodeP& nodeP) -> bool {
351 return nodeP->getName()
352 == (*e)->getDestination()->getName() + "-";
353 });
354
355 grid.addEdge(*nodeOrigIT, *nodeDestIT, (*e)->getWeight());
356 }
357 }
358 return true;
359}
360
365template<class NodeT>
367{
368 // duplicate nodes
369 for (typename VectorNodeP::iterator node = pNodesList.begin(); node != pNodesList.end(); node++)
370 {
371 {
372 grid.addNode((*(*node)->nodeProperties), (*node)->getName());
373 }
374 }
375
376 // duplicate edges
377 for (typename VectorEdgeP::iterator e = pEdgesList.begin(); e != pEdgesList.end(); e++)
378 {
379 { //+
380 auto nodeOrigIT = std::find_if(grid.pNodesList.begin(),
381 grid.pNodesList.end(),
382 [&e](const NodeP& nodeP) -> bool {
383 return nodeP->getName()
384 == (*e)->getOrigin()->getName();
385 });
386
387 auto nodeDestIT = std::find_if(grid.pNodesList.begin(),
388 grid.pNodesList.end(),
389 [&e](const NodeP& nodeP) -> bool {
390 return nodeP->getName()
391 == (*e)->getDestination()->getName();
392 });
393
394 grid.addEdge(*nodeOrigIT, *nodeDestIT, (*e)->getWeight());
395 }
396 }
397 return true;
398}
399
400template<class NodeT>
401typename Grid<NodeT>::VectorEdgeP Grid<NodeT>::twoLevelPath(VectorNodeP vN)
402{
403 VectorEdgeP SP, minSP;
404 double minLength = DBL_MAX, length;
405 for (typename VectorNodeP::iterator n = vN.begin(); n != vN.end(); n++)
406 {
407 SP = findShortestPath(findNodeFromName((*n)->getName() + "+"),
408 findNodeFromName((*n)->getName() + "-"));
409 length = std::accumulate(SP.begin(),
410 SP.end(),
411 (long)0,
413 if (length < minLength)
414 {
415 minLength = length;
416 minSP = SP;
417 }
418 }
419
420 return minSP;
421}
422
424template<class NodeT>
425typename Grid<NodeT>::VectorEdgeP Grid<NodeT>::findShortestPath(NodeP node1, NodeP node2) const
426{
427 assert(node1 != node2);
428
429 // Dijkstra (lots of computation which could be optimised)
430 // initialization
431 std::map<NodeP, double> dist;
432 std::map<NodeP, NodeP> prev;
433
434 // decorate to avoid warnings at compile
435 [[maybe_unused]] bool checkNode1(false), checkNode2(false);
436 VectorNodeP nodes = pNodesList;
437
438 for (auto i = nodes.begin(); i != nodes.end(); i++)
439 {
440 dist[(*i)] = inf;
441 prev[(*i)] = 0;
442 if ((*i) == node1)
443 {
444 checkNode1 = true;
445 }
446 else if ((*i) == node2)
447 {
448 checkNode2 = true;
449 }
450 }
451 assert(checkNode1 && checkNode2);
452 dist[node1] = 0;
453 // search for shortest path
454 bool targetFound(0);
455 while (!targetFound)
456 {
457 // look for closest element u belonging in nodes
458 std::pair<Grid::NodeP, double> u(nullptr, inf - 1);
459 typename Grid::VectorNodeP::iterator ui;
460 for (auto i = nodes.begin(); i != nodes.end(); i++)
461 {
462 if (dist[(*i)] < u.second)
463 {
464 u.first = (*i);
465 u.second = dist[(*i)];
466 ui = i;
467 }
468 }
469
470 // see if destination node has been f
471 if (u.first == node2)
472 {
473 targetFound = true;
474 break;
475 }
476
477 // remove u from the list of nodes
478 nodes.erase(ui);
479
480 // update the neighoubours of u
481 for (auto i = adjency.at(u.first).begin(); i != adjency.at(u.first).end(); i++)
482 {
483 if (i->second == nullptr)
484 {
485 assert(0);
486 }
487
488 if ((u.second + i->second->getWeight()) < dist[i->first])
489 {
490 dist[i->first] = u.second + i->second->getWeight();
491 prev[i->first] = u.first;
492 }
493 }
494 }
495
496 // rebuild path
497 Grid::VectorEdgeP path;
498 Grid::NodeP currentNode = node2;
499
500 while (prev[currentNode] != nullptr)
501 {
502 path.push_back(adjency.at(currentNode).at(prev[currentNode]));
503 currentNode = prev[currentNode];
504 }
505
506 return path;
507}
508
509} // namespace Graph
510} // namespace Antares
Definition grid.h:63
Antares Grid (graph)
Definition grid.h:129
EdgeP addEdge(NodeP, NodeP, long weight=0)
Add one edge to the graph.
Definition grid.hxx:77
VectorEdgeP findShortestPath(NodeP node1, NodeP node2) const
Find shortest path between the two nodes (Djikstra)
Definition grid.hxx:425
NodeP addNode(NodeT &, std::string)
Add one node to the graph.
Definition grid.hxx:56
bool cloneGrid(Grid &)
get a clone of the Grid
Definition grid.hxx:366
~Grid()
Destructor.
Definition grid.hxx:43
NodeP findNodeFromName(std::string name)
find a node from it's name
Definition grid.h:233
void kruskal()
Kruskal algorithm.
Definition grid.hxx:145
bool getDuplicatedGrid(Grid &)
get a Gid where edges and nodes are duplicated
Definition grid.hxx:305
EdgeP findEdgeFromNodeNames(std::string u, std::string v)
find an edge from node names
Definition grid.h:158
Grid()
Constructor.
Definition grid.hxx:37
bool buildMesh()
Get minimum spanning tree.
Definition grid.hxx:186
Definition grid.h:37