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