Eclipse SUMO - Simulation of Urban MObility
Circuit.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2020 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
19 // Representation of electric circuit of overhead wires
21 /****************************************************************************/
22 #include <cfloat>
23 #include <cstdlib>
24 #include <iostream>
25 #include <ctime>
26 #include <mutex>
28 #include <utils/common/ToString.h>
29 #ifdef HAVE_EIGEN
30 #include "Eigen/Dense"
31 #include "Eigen/Sparse"
32 #include "Eigen/Geometry"
33 #endif
34 #include "Element.h"
35 #include "Circuit.h"
36 
37 using namespace std;
38 
39 std::mutex circuit_lock;
40 
41 Node* Circuit::addNode(string name) {
42  if (getNode(name) != nullptr) {
43  //WRITE_ERROR("The node: '" + name + "' already exists.");
44  std::cout << "The node '" + name + "' already exists." << std::endl;
45  return nullptr;
46  }
47 
48  if (nodes->size() == 0) {
49  lastId = -1;
50  }
51  Node* tNode = new Node(name, this->lastId);
52  if (lastId == -1) {
53  tNode->setGround(true);
54  }
55  this->lastId++;
56  circuit_lock.lock();
57  this->nodes->push_back(tNode);
58  circuit_lock.unlock();
59  return tNode;
60 }
61 
62 void Circuit::eraseNode(Node* node) {
63  circuit_lock.lock();
64  this->nodes->erase(std::remove(this->nodes->begin(), this->nodes->end(), node), this->nodes->end());
65  circuit_lock.unlock();
66 }
67 
68 double Circuit::getCurrent(string name) {
69  Element* tElement = getElement(name);
70  if (tElement == nullptr) {
71  return DBL_MAX;
72  }
73  return tElement->getCurrent();
74 }
75 
76 double Circuit::getVoltage(string name) {
77  Element* tElement = getElement(name);
78  if (tElement == nullptr) {
79  Node* node = getNode(name);
80  if (node != nullptr) {
81  return node->getVoltage();
82  } else {
83  return DBL_MAX;
84  }
85  } else {
86  return tElement->getVoltage();
87  }
88 }
89 
90 double Circuit::getResistance(string name) {
91  Element* tElement = getElement(name);
92  if (tElement == nullptr) {
93  return -1;
94  }
95  return tElement->getResistance();
96 }
97 
98 Node* Circuit::getNode(string name) {
99  // for (vector<Node*>::iterator it = this->nodes->begin(); it != nodes->end(); it++) {
100  for (auto&& it : *this->nodes) {
101  if (it->getName() == name) {
102  return it;
103  }
104  }
105  return nullptr;
106 }
107 
109  for (vector<Node*>::iterator it = this->nodes->begin(); it != nodes->end(); it++) {
110  if ((*it)->getId() == id) {
111  return (*it);
112  }
113  }
114  return nullptr;
115 }
116 
118  for (vector<Element*>::iterator it = this->elements->begin(); it != elements->end(); it++) {
119  if ((*it)->getName() == name) {
120  return (*it);
121  }
122  }
123  for (vector<Element*>::iterator it = this->voltageSources->begin(); it != voltageSources->end(); it++) {
124  if ((*it)->getName() == name) {
125  return (*it);
126  }
127  }
128  return nullptr;
129 }
130 
132  for (vector<Element*>::iterator it = this->elements->begin(); it != elements->end(); it++) {
133  if ((*it)->getId() == id) {
134  return (*it);
135  }
136  }
137  for (vector<Element*>::iterator it = this->voltageSources->begin(); it != voltageSources->end(); it++) {
138  if ((*it)->getId() == id) {
139  return (*it);
140  }
141  }
142  return nullptr;
143 }
144 
146  for (vector<Element*>::iterator it = this->voltageSources->begin(); it != voltageSources->end(); it++) {
147  if ((*it)->getId() == id) {
148  return (*it);
149  }
150  }
151  return nullptr;
152 }
153 
154 vector<Element*>* Circuit::getCurrentSources() {
155  vector<Element*>* vsources = new vector<Element*>(0);
156  for (vector<Element*>::iterator it = this->elements->begin(); it != elements->end(); it++) {
157  if ((*it)->getType() == Element::ElementType::CURRENT_SOURCE_traction_wire) {
158  //if ((*it)->getType() == Element::ElementType::CURRENT_SOURCE_traction_wire && !isnan((*it)->getPowerWanted())) {
159  vsources->push_back(*it);
160  }
161  }
162  return vsources;
163 }
164 
166  circuit_lock.lock();
167 }
168 
170  circuit_lock.unlock();
171 }
172 
173 #ifdef HAVE_EIGEN
174 void Circuit::removeColumn(Eigen::MatrixXd& matrix, int colToRemove) {
175  const int numRows = (int)matrix.rows();
176  const int numCols = (int)matrix.cols() - 1;
177 
178  if (colToRemove < numCols) {
179  matrix.block(0, colToRemove, numRows, numCols - colToRemove) = matrix.rightCols(numCols - colToRemove);
180  }
181 
182  matrix.conservativeResize(numRows, numCols);
183 }
184 
185 bool Circuit::solveEquationsNRmethod(double* eqn, double* vals, std::vector<int>* removable_ids) {
186  // removable_ids includes nodes with voltage source already
187  int numofcolumn = (int)voltageSources->size() + (int)nodes->size() - 1;
188  int numofeqs = numofcolumn - (int)removable_ids->size();
189 
190  Eigen::MatrixXd A = Eigen::Map < Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >(eqn, numofeqs, numofcolumn);
191 
192  int id;
193  // removing removable columns
194  for (std::vector<int>::reverse_iterator it = removable_ids->rbegin(); it != removable_ids->rend(); ++it) {
195  id = (*it >= 0 ? *it : -(*it));
196  removeColumn(A, id);
197  }
198 
199  // detecting number of column for each node
200  // in other words: detecting elements of x to certain node
201  int j = 0;
202  Element* tElem = nullptr;
203  Node* tNode = nullptr;
204  for (int i = 0; i < numofcolumn; i++) {
205  tNode = getNode(i);
206  if (tNode != nullptr)
207  if (tNode->isRemovable()) {
208  tNode->setNumMatrixCol(-1);
209  continue;
210  } else {
211  // TODO: is the numofeqs (defined above) still the same as the part below?
212  if (j > numofcolumn - (int) removable_ids->size()) {
213  WRITE_ERROR("Number of column deployment during circuit evaluation was unsuccessfull.");
214  break;
215  }
216  tNode->setNumMatrixCol(j);
217  j++;
218  continue;
219  } else {
220  tElem = getElement(i);
221  if (tElem != nullptr) {
222  // TODO: is the numofeqs (defined above) still the same as the part below?
223  if (j > numofcolumn - (int) removable_ids->size()) {
224  WRITE_ERROR("Number of column deployment deployment during circuit evaluation was unsuccessfull.");
225  break;
226  }
227  continue;
228  }
229  }
230  WRITE_ERROR("Number of column deployment during circuit evaluation was unsuccessfull.");
231  }
232 
233  Eigen::Map<Eigen::VectorXd> b(vals, numofeqs);
234  Eigen::VectorXd x = A.colPivHouseholderQr().solve(b);
235  // probably unused
236  // double relative_error = (A*x - b).norm() / b.norm();
237 
238  Eigen::MatrixXd J = A;
239  Eigen::VectorXd dx;
240  int max_iter_of_NR = 10;
241  int attemps = 0;
242  double alpha = 1;
243  alphaBest = 0;
244  //TODORICE alphaBest private and function get and setAlphaBest
245  std::vector<double> alpha_notSolution;
246  double alpha_res = 1e-2;
247  double* x_best = new double[numofeqs];
248  //init x_best
249  for (int i = 0; i < numofeqs; i++) {
250  x_best[i] = x[i];
251  }
252  if (x.maxCoeff() > 10e6 || x.minCoeff() < -10e6) {
253 
254  WRITE_ERROR("Here is the matrix A:\n" + toString(A));
255  WRITE_ERROR("Here is the vector b:\n" + toString(b));
256  WRITE_ERROR("Here is the vector x:\n" + toString(x));
257  for (int i = 0; i < numofeqs; i++) {
258  x_best[i] = 600;
259  }
260  }
261  //search alpha
262  while (true) {
263 
264  ++attemps;
265  int iterNR = 0;
266  // run Newton-Raphson methods
267  while (true) {
268 
269  for (int i = 0; i < numofeqs - (int) voltageSources->size(); i++) {
270  vals[i] = 0;
271  }
272  J = A;
273 
274  int i = 0;
275  for (auto& node : *nodes) {
276  if (node->isGround() || node->isRemovable() || node->getNumMatrixRow() == -2) {
277  continue;
278  }
279  if (node->getNumMatrixRow() != i) {
280  WRITE_ERROR("wrongly assigned row of matrix A during solving the circuit");
281  }
282  // TODO: Range-based loop
283  for (auto it_element = node->getElements()->begin(); it_element != node->getElements()->end(); it_element++) {
284  if ((*it_element)->getType() == Element::ElementType::CURRENT_SOURCE_traction_wire) {
285  if ((*it_element)->isEnabled()) {
286  double diff_voltage;
287  if ((*it_element)->getPosNode()->getNumMatrixCol() == -1) {
288  diff_voltage = -x[(*it_element)->getNegNode()->getNumMatrixCol()];
289  } else if ((*it_element)->getNegNode()->getNumMatrixCol() == -1) {
290  diff_voltage = x[(*it_element)->getPosNode()->getNumMatrixCol()];
291  } else {
292  diff_voltage = (x[(*it_element)->getPosNode()->getNumMatrixCol()] - x[(*it_element)->getNegNode()->getNumMatrixCol()]);
293  }
294 
295  if ((*it_element)->getPosNode() == node) {
296  vals[i] -= alpha * (*it_element)->getPowerWanted() / diff_voltage;
297  (*it_element)->setCurrent(-alpha * (*it_element)->getPowerWanted() / diff_voltage);
298  if ((*it_element)->getPosNode()->getNumMatrixCol() != -1) {
299  J(i, (*it_element)->getPosNode()->getNumMatrixCol()) -= alpha * (*it_element)->getPowerWanted() / diff_voltage / diff_voltage;
300  }
301  if ((*it_element)->getNegNode()->getNumMatrixCol() != -1) {
302  J(i, (*it_element)->getNegNode()->getNumMatrixCol()) += alpha * (*it_element)->getPowerWanted() / diff_voltage / diff_voltage;
303  }
304  } else {
305  vals[i] += alpha * (*it_element)->getPowerWanted() / diff_voltage;
306  //sign before alpha - or + during setting current?
307  //(*it_element)->setCurrent(alpha * (*it_element)->getPowerWanted() / diff_voltage);
308  if ((*it_element)->getPosNode()->getNumMatrixCol() != -1) {
309  J(i, (*it_element)->getPosNode()->getNumMatrixCol()) += alpha * (*it_element)->getPowerWanted() / diff_voltage / diff_voltage;
310  }
311  if ((*it_element)->getNegNode()->getNumMatrixCol() != -1) {
312  J(i, (*it_element)->getNegNode()->getNumMatrixCol()) -= alpha * (*it_element)->getPowerWanted() / diff_voltage / diff_voltage;
313  }
314  }
315  }
316  }
317  }
318  i++;
319  }
320 
321  // TODO: The variable below was declared as `b`, renamed to `bb`, check if the rename was consistent.
322  Eigen::Map<Eigen::VectorXd> bb(vals, numofeqs);
323 
324  if ((A * x - bb).norm() < 1e-6) {
325  alphaBest = alpha;
326  for (int ii = 0; ii < numofeqs; ii++) {
327  x_best[ii] = x[ii];
328  }
329  break;
330  } else if (iterNR == max_iter_of_NR) {
331  alpha_notSolution.push_back(alpha);
332  for (int ii = 0; ii < numofeqs; ii++) {
333  x[ii] = x_best[ii];
334  }
335  break;
336  }
337 
338  dx = -J.colPivHouseholderQr().solve(A * x - bb);
339  x = x + dx;
340  ++iterNR;
341  }
342 
343  if (alpha_notSolution.empty()) {
344  break;
345  }
346 
347  if ((alpha_notSolution.back() - alphaBest) < alpha_res) {
348  max_iter_of_NR = 2 * max_iter_of_NR;
349  alpha_res = alpha_res / 10;
350  if (alpha_res < 5e-5) {
351  break;
352  }
353  alpha = alpha_notSolution.back();
354  alpha_notSolution.pop_back();
355  continue;
356  }
357 
358  alpha = alphaBest + 0.5 * (alpha_notSolution.back() - alphaBest);
359  }
360 
361  for (int i = 0; i < numofeqs; i++) {
362  vals[i] = x_best[i];
363  }
364 
365  int i = 0;
366  for (auto& node : *nodes) {
367  if (node->isGround() || node->isRemovable() || node->getNumMatrixRow() == -2) {
368  continue;
369  }
370  if (node->getNumMatrixRow() != i) {
371  WRITE_ERROR("wrongly assigned row of matrix A during solving the circuit");
372  }
373  for (auto it_element = node->getElements()->begin(); it_element != node->getElements()->end(); it_element++) {
374  if ((*it_element)->getType() == Element::ElementType::CURRENT_SOURCE_traction_wire) {
375  if ((*it_element)->isEnabled()) {
376  double diff_voltage;
377  if ((*it_element)->getPosNode()->getNumMatrixCol() == -1) {
378  diff_voltage = -x_best[(*it_element)->getNegNode()->getNumMatrixCol()];
379  } else if ((*it_element)->getNegNode()->getNumMatrixCol() == -1) {
380  diff_voltage = x_best[(*it_element)->getPosNode()->getNumMatrixCol()];
381  } else {
382  diff_voltage = (x_best[(*it_element)->getPosNode()->getNumMatrixCol()] - x_best[(*it_element)->getNegNode()->getNumMatrixCol()]);
383  }
384 
385  if ((*it_element)->getPosNode() == node) {
386  (*it_element)->setCurrent(-alphaBest * (*it_element)->getPowerWanted() / diff_voltage);
387  } else {
388  //sign before alpha - or + during setting current?
389  //(*it_element)->setCurrent(alpha * (*it_element)->getPowerWanted() / diff_voltage);
390  }
391  }
392  }
393  }
394  i++;
395  }
396 
397  return true;
398 }
399 #endif
400 
401 void Circuit::deployResults(double* vals, std::vector<int>* removable_ids) {
402  int n = (int)(voltageSources->size() + nodes->size() - 1);
403  int j = 0;
404  Element* tElem = nullptr;
405  Node* tNode = nullptr;
406  for (int i = 0; i < n; i++) {
407  tNode = getNode(i);
408  if (tNode != nullptr)
409  if (tNode->isRemovable()) {
410  continue;
411  } else {
412  // TODO: Is the n - (int) removable_ids->size() constant?
413  if (j > n - (int) removable_ids->size()) {
414  WRITE_ERROR("Results deployment during circuit evaluation was unsuccessfull.");
415  break;
416  }
417  tNode->setVoltage(vals[j]);
418  j++;
419  continue;
420  } else {
421  tElem = getElement(i);
422  if (tElem != nullptr) {
423  // TODO: Is the n - (int) removable_ids->size() constant?
424  if (j > n - (int) removable_ids->size()) {
425  WRITE_ERROR("Results deployment during circuit evaluation was unsuccessfull.");
426  break;
427  }
428  //tElem->setCurrent(vals[j]);
429  //TODORICE dodelat vypocet proudu na zdroji z Kirchhofova zakona: proudy dovnitr = proudy ven
430  //tElem->setCurrent(-1000);
431  //j++;
432  continue;
433  }
434  }
435  WRITE_ERROR("Results deployment during circuit evaluation was unsuccessfull.");
436  }
437 
438  Element* el1 = nullptr;
439  Element* el2 = nullptr;
440  Node* nextNONremovableNode1 = nullptr;
441  Node* nextNONremovableNode2 = nullptr;
442  // interpolate result of voltage to removable nodes
443  for (vector<Node*>::iterator it = nodes->begin(); it != nodes->end(); it++) {
444  if (!(*it)->isRemovable()) {
445  continue;
446  }
447  if ((*it)->getElements()->size() != 2) {
448  continue;
449  }
450 
451  el1 = (*it)->getElements()->front();
452  el2 = (*it)->getElements()->back();
453  nextNONremovableNode1 = el1->getTheOtherNode(*it);
454  nextNONremovableNode2 = el2->getTheOtherNode(*it);
455  double x = el1->getResistance();
456  double y = el2->getResistance();
457 
458  while (nextNONremovableNode1->isRemovable()) {
459  el1 = nextNONremovableNode1->getAnOtherElement(el1);
460  x += el1->getResistance();
461  nextNONremovableNode1 = el1->getTheOtherNode(nextNONremovableNode1);
462  }
463 
464  while (nextNONremovableNode2->isRemovable()) {
465  el2 = nextNONremovableNode2->getAnOtherElement(el2);
466  y += el2->getResistance();
467  nextNONremovableNode2 = el2->getTheOtherNode(nextNONremovableNode2);
468  }
469 
470  x = x / (x + y);
471  y = ((1 - x) * nextNONremovableNode1->getVoltage()) + (x * nextNONremovableNode2->getVoltage());
472  (*it)->setVoltage(((1 - x)*nextNONremovableNode1->getVoltage()) + (x * nextNONremovableNode2->getVoltage()));
473  (*it)->setRemovability(false);
474  }
475 
476  /*
477  for (int i = 0; i < n; i++) {
478  Node* tNode = getNode(i);
479  if (tNode != nullptr)
480  tNode->setVoltage(vals[i]);
481  else
482  {
483  Element* tElem = getElement(i);
484  if (tElem != nullptr) {
485  tElem->setCurrent(vals[i]);
486  }
487  }
488  }
489  */
490 }
491 
493  nodes = new vector<Node*>(0);
494  elements = new vector<Element*>(0);
495  voltageSources = new vector<Element*>(0);
496  lastId = 0;
497  iscleaned = true;
498 }
499 
500 #ifdef HAVE_EIGEN
501 bool Circuit::_solveNRmethod() {
502  double* eqn = nullptr;
503  double* vals = nullptr;
504  std::vector<int> removable_ids;
505 
506  detectRemovableNodes(&removable_ids);
507  createEquationsNRmethod(eqn, vals, &removable_ids);
508  if (!solveEquationsNRmethod(eqn, vals, &removable_ids)) {
509  return false;
510  }
511  deployResults(vals, &removable_ids);
512 
513  return true;
514 }
515 
516 bool Circuit::solve() {
517  if (!iscleaned) {
518  cleanUpSP();
519  }
520  return this->_solveNRmethod();
521 }
522 
523 bool Circuit::createEquationsNRmethod(double*& eqs, double*& vals, std::vector<int>* removable_ids) {
524  // removable_ids does not include nodes with voltage source
525  int n = (int)(voltageSources->size() + nodes->size() - 1);
526  int m = n - (int)(removable_ids->size() - voltageSources->size());
527  //cout << endl << endl << n << endl << endl;
528  eqs = new double[m * n];
529  vals = new double[m];
530 
531  for (int i = 0; i < m; i++) {
532  vals[i] = 0;
533  for (int j = 0; j < n; j++) {
534  eqs[i * n + j] = 0;
535  }
536  }
537 
538  int i = 0;
539  for (vector<Node*>::iterator it = nodes->begin(); it != nodes->end(); it++) {
540  if ((*it)->isGround() || (*it)->isRemovable()) {
541  (*it)->setNumMatrixRow(-1);
542  continue;
543  }
544  bool noVoltageSource = createEquationNRmethod((*it), (eqs + n * i), vals[i], removable_ids);
545  // if the node it has element of type "voltage source" we do not use the equation, because some value of current throw the voltage source can be always find
546  if (noVoltageSource) {
547  (*it)->setNumMatrixRow(i);
548  i++;
549  } else {
550  (*it)->setNumMatrixRow(-2);
551  vals[i] = 0;
552  for (int j = 0; j < n; j++) {
553  eqs[n * i + j] = 0;
554  }
555  }
556  }
557  // removable_ids includes nodes with voltage source already
558  std::sort(removable_ids->begin(), removable_ids->end(), std::less<int>());
559 
560  for (vector<Element*>::iterator it = voltageSources->begin(); it != voltageSources->end(); it++) {
561  createEquation((*it), (eqs + n * i), vals[i]);
562  i++;
563  }
564 
565  return true;
566 }
567 
568 bool Circuit::createEquation(Element* vsource, double* eqn, double& val) {
569  if (!vsource->getPosNode()->isGround()) {
570  eqn[vsource->getPosNode()->getId()] = 1;
571  }
572  if (!vsource->getNegNode()->isGround()) {
573  eqn[vsource->getNegNode()->getId()] = -1;
574  }
575  if (vsource->isEnabled()) {
576  val = vsource->getVoltage();
577  } else {
578  val = 0;
579  }
580  return true;
581 }
582 
583 bool Circuit::createEquationNRmethod(Node* node, double* eqn, double& val, std::vector<int>* removable_ids) {
584  for (vector<Element*>::iterator it = node->getElements()->begin(); it != node->getElements()->end(); it++) {
585  double x;
586  switch ((*it)->getType()) {
587  case Element::ElementType::RESISTOR_traction_wire:
588  if ((*it)->isEnabled()) {
589  x = (*it)->getResistance();
590  Node* nextNONremovableNode = (*it)->getTheOtherNode(node);
591  Element* nextSerialResistor = *it;
592  while (nextNONremovableNode->isRemovable()) {
593  nextSerialResistor = nextNONremovableNode->getAnOtherElement(nextSerialResistor);
594  x += nextSerialResistor->getResistance();
595  nextNONremovableNode = nextSerialResistor->getTheOtherNode(nextNONremovableNode);
596  }
597  x = 1 / x;
598  eqn[node->getId()] += x;
599  if (!nextNONremovableNode->isGround()) {
600  eqn[nextNONremovableNode->getId()] -= x;
601  }
602  //if (!(*it)->getTheOtherNode(node)->isGround())
603  // eqn[(*it)->getTheOtherNode(node)->getId()] -= x;
604  }
605  break;
606  case Element::ElementType::CURRENT_SOURCE_traction_wire:
607  if ((*it)->isEnabled()) {
608  if ((*it)->getPosNode() == node) {
609  x = (*it)->getCurrent();
610  } else {
611  x = -(*it)->getCurrent();
612  }
613  } else {
614  x = 0;
615  }
616  val += x;
617  break;
618  case Element::ElementType::VOLTAGE_SOURCE_traction_wire:
619  if ((*it)->getPosNode() == node) {
620  x = -1;
621  } else {
622  x = 1;
623  }
624  eqn[(*it)->getId()] += x;
625  // equations with voltage source can be igored, because some value of current throw the voltage source can be always find
626  removable_ids->push_back((*it)->getId());
627  return false;
628  break;
629  case Element::ElementType::ERROR_traction_wire:
630  return false;
631  break;
632  }
633  }
634  return true;
635 }
636 #endif
637 
638 void Circuit::detectRemovableNodes(std::vector<int>* removable_ids) {
639  for (vector<Node*>::iterator it = nodes->begin(); it != nodes->end(); it++) {
640  if ((*it)->getElements()->size() == 2 && !(*it)->isGround()) {
641  (*it)->setRemovability(true);
642  for (vector<Element*>::iterator it2 = (*it)->getElements()->begin(); it2 != (*it)->getElements()->end(); it2++) {
643  if ((*it2)->getType() != Element::ElementType::RESISTOR_traction_wire) {
644  (*it)->setRemovability(false);
645  break;
646  }
647  }
648  if ((*it)->isRemovable()) {
649  removable_ids->push_back((*it)->getId());
650  }
651  } else {
652  (*it)->setRemovability(false);
653  }
654  }
655  std::sort(removable_ids->begin(), removable_ids->end(), std::less<int>());
656  return;
657 }
658 
659 Element* Circuit::addElement(string name, double value, Node* pNode, Node* nNode, Element::ElementType et) {
660  if ((et == Element::ElementType::RESISTOR_traction_wire && value <= 0) || et == Element::ElementType::ERROR_traction_wire) {
661  return nullptr;
662  }
663 
664  Element* e = getElement(name);
665 
666  if (e != nullptr) {
667  //WRITE_ERROR("The element: '" + name + "' already exists.");
668  std::cout << "The element: '" + name + "' already exists.";
669  return nullptr;
670  }
671 
672  e = new Element(name, et, value);
673  if (e->getType() == Element::ElementType::VOLTAGE_SOURCE_traction_wire) {
674  e->setId(lastId);
675  lastId++;
676  circuit_lock.lock();
677  this->voltageSources->push_back(e);
678  circuit_lock.unlock();
679  } else {
680  circuit_lock.lock();
681  this->elements->push_back(e);
682  circuit_lock.unlock();
683  }
684 
685  e->setPosNode(pNode);
686  e->setNegNode(nNode);
687 
688  pNode->addElement(e);
689  nNode->addElement(e);
690  return e;
691 }
692 
694  //element->getPosNode()->eraseElement(element);
695  //element->getNegNode()->eraseElement(element);
696  circuit_lock.lock();
697  this->elements->erase(std::remove(this->elements->begin(), this->elements->end(), element), this->elements->end());
698  circuit_lock.unlock();
699 }
700 
701 void Circuit::replaceAndDeleteNode(Node* unusedNode, Node* newNode) {
702  //replace element node if it is unusedNode
703  for (auto& voltageSource : *voltageSources) {
704  if (voltageSource->getNegNode() == unusedNode) {
705  voltageSource->setNegNode(newNode);
706  newNode->eraseElement(voltageSource);
707  newNode->addElement(voltageSource);
708  }
709  if (voltageSource->getPosNode() == unusedNode) {
710  voltageSource->setPosNode(newNode);
711  newNode->eraseElement(voltageSource);
712  newNode->addElement(voltageSource);
713  }
714  }
715  for (auto& element : *elements) {
716  if (element->getNegNode() == unusedNode) {
717  element->setNegNode(newNode);
718  newNode->eraseElement(element);
719  newNode->addElement(element);
720  }
721  if (element->getPosNode() == unusedNode) {
722  element->setPosNode(newNode);
723  newNode->eraseElement(element);
724  newNode->addElement(element);
725  }
726  }
727 
728  //erase unusedNode from nodes vector
729  this->eraseNode(unusedNode);
730 
731  //modify id of other elements and nodes
732  int modLastId = this->getLastId() - 1;
733  if (unusedNode->getId() != modLastId) {
734  Node* node_last = this->getNode(modLastId);
735  if (node_last != nullptr) {
736  node_last->setId(unusedNode->getId());
737  } else {
738  Element* elem_last = this->getVoltageSource(modLastId);
739  if (elem_last != nullptr) {
740  elem_last->setId(unusedNode->getId());
741  } else {
742  WRITE_ERROR("The element or node with the last Id was not found in the circuit!");
743  }
744  }
745  }
746 
747  this->descreaseLastId();
748  delete unusedNode;
749 }
750 
752  for (vector<Element*>::iterator it = elements->begin(); it != elements->end(); it++) {
753  if ((*it)->getType() != Element::ElementType::RESISTOR_traction_wire) {
754  (*it)->setEnabled(true);
755  }
756  }
757 
758  for (vector<Element*>::iterator it = voltageSources->begin(); it != voltageSources->end(); it++) {
759  (*it)->setEnabled(true);
760  }
761  this->iscleaned = true;
762 }
763 
764 bool Circuit::checkCircuit(std::string substationId) {
765  // check empty nodes
766  for (vector<Node*>::iterator it = nodes->begin(); it != nodes->end(); it++) {
767  if ((*it)->getNumOfElements() < 2) {
768  //cout << "WARNING: Node [" << (*it)->getName() << "] is connected to less than two elements, please enter other elements.\n";
769  if ((*it)->getNumOfElements() < 1) {
770  return false;
771  }
772  }
773  }
774  // check voltage sources
775  for (vector<Element*>::iterator it = voltageSources->begin(); it != voltageSources->end(); it++) {
776  if ((*it)->getPosNode() == nullptr || (*it)->getNegNode() == nullptr) {
777  //cout << "ERROR: Voltage Source [" << (*it)->getName() << "] is connected to less than two nodes, please enter the other end.\n";
778  WRITE_ERROR("Circuit Voltage Source '" + (*it)->getName() + "' is connected to less than two nodes, please adjust the definition of the section (with substation '" + substationId + "').");
779  return false;
780  }
781  }
782  // check other elements
783  for (vector<Element*>::iterator it = elements->begin(); it != elements->end(); it++) {
784  if ((*it)->getPosNode() == nullptr || (*it)->getNegNode() == nullptr) {
785  //cout << "ERROR: Element [" << (*it)->getName() << "] is connected to less than two nodes, please enter the other end.\n";
786  WRITE_ERROR("Circuit Element '" + (*it)->getName() + "' is connected to less than two nodes, please adjust the definition of the section (with substation '" + substationId + "').");
787  return false;
788  }
789  }
790 
791  // check connectivity
792  int num = (int)nodes->size() + getNumVoltageSources() - 1;
793  bool* nodesVisited = new bool[num];
794  for (int i = 0; i < num; i++) {
795  nodesVisited[i] = false;
796  }
797  // TODO: Probably unused
798  // int id = -1;
799  if (!getNode(-1)->isGround()) {
800  //cout << "ERROR: Node id -1 is not the ground \n";
801  WRITE_ERROR("Circuit Node with id '-1' is not the grounded, please adjust the definition of the section (with substation '" + substationId + "').");
802  }
803  vector<Node*>* queue = new vector<Node*>(0);
804  Node* node = nullptr;
805  Node* neigboringNode = nullptr;
806  //start with (voltageSources->front()->getPosNode())
807  nodesVisited[voltageSources->front()->getId()] = 1;
808  node = voltageSources->front()->getPosNode();
809  queue->push_back(node);
810 
811  while (!queue->empty()) {
812  node = queue->back();
813  queue->pop_back();
814  if (!nodesVisited[node->getId()]) {
815  nodesVisited[node->getId()] = true;
816  for (auto it = node->getElements()->begin(); it != node->getElements()->end(); it++) {
817  neigboringNode = (*it)->getTheOtherNode(node);
818  if (!neigboringNode->isGround()) {
819  queue->push_back(neigboringNode);
820  } else if ((*it)->getType() == Element::ElementType::VOLTAGE_SOURCE_traction_wire) {
822  nodesVisited[(*it)->getId()] = 1;
823  } else if ((*it)->getType() == Element::ElementType::RESISTOR_traction_wire) {
824  //cout << "ERROR: The resistor type connects the ground \n";
825  WRITE_ERROR("A Circuit Resistor Element connects the ground, please adjust the definition of the section (with substation '" + substationId + "').");
826  }
827  }
828  }
829  }
830 
831  for (int i = 0; i < num; i++) {
832  if (nodesVisited[i] == 0) {
833  //cout << "ERROR: Node or voltage source with id " << (i) << " has been not visited during checking of the circuit => Disconnectivity of the circuit. \n";
834  WRITE_WARNING("Circuit Node or Voltage Source with internal id '" + toString(i) + "' has been not visited during checking of the circuit. The circuit is disconnected, please adjust the definition of the section (with substation '" + substationId + "').");
835  }
836  }
837 
838  return true;
839 }
840 
842  return (int) voltageSources->size();
843 }
std::mutex circuit_lock
Definition: Circuit.cpp:39
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
double getCurrent(string name)
Definition: Circuit.cpp:68
int getNumVoltageSources()
Definition: Circuit.cpp:841
vector< Element * > * getCurrentSources()
Definition: Circuit.cpp:154
Element * addElement(string name, double value, Node *pNode, Node *nNode, Element::ElementType et)
Definition: Circuit.cpp:659
void eraseNode(Node *node)
Definition: Circuit.cpp:62
void cleanUpSP()
Definition: Circuit.cpp:751
void unlock()
Definition: Circuit.cpp:169
Circuit()
Definition: Circuit.cpp:492
void lock()
Definition: Circuit.cpp:165
void detectRemovableNodes(std::vector< int > *removable_ids)
Definition: Circuit.cpp:638
void replaceAndDeleteNode(Node *unusedNode, Node *newNode)
Definition: Circuit.cpp:701
Node * getNode(string name)
Definition: Circuit.cpp:98
double getVoltage(string name)
Definition: Circuit.cpp:76
Element * getVoltageSource(int id)
Definition: Circuit.cpp:145
void deployResults(double *vals, std::vector< int > *removable_ids)
Definition: Circuit.cpp:401
Element * getElement(string name)
Definition: Circuit.cpp:117
bool checkCircuit(std::string substationId="")
Definition: Circuit.cpp:764
Node * addNode(string name)
Definition: Circuit.cpp:41
double getResistance(string name)
Definition: Circuit.cpp:90
void eraseElement(Element *element)
Definition: Circuit.cpp:693
void setId(int id)
Definition: Element.cpp:127
ElementType getType()
Definition: Element.cpp:113
double getResistance()
Definition: Element.cpp:93
void setNegNode(Node *node)
Definition: Element.cpp:124
Node * getNegNode()
Definition: Element.cpp:109
double getCurrent()
Definition: Element.cpp:79
void setPosNode(Node *node)
Definition: Element.cpp:120
Node * getPosNode()
Definition: Element.cpp:106
double getVoltage()
Definition: Element.cpp:70
bool isEnabled()
Definition: Element.cpp:142
Node * getTheOtherNode(Node *node)
Definition: Element.cpp:132
ElementType
Definition: Element.h:45
Definition: Node.h:31
vector< Element * > * getElements()
Definition: Node.cpp:99
void setVoltage(double voltage)
Definition: Node.cpp:55
void setGround(bool isground)
Definition: Node.cpp:71
void setNumMatrixCol(int num)
Definition: Node.cpp:91
int getId()
Definition: Node.cpp:75
bool isRemovable()
Definition: Node.h:60
Element * getAnOtherElement(Element *element)
Definition: Node.cpp:107
bool isGround()
Definition: Node.cpp:67
void addElement(Element *element)
Definition: Node.cpp:42
void eraseElement(Element *element)
Definition: Node.cpp:46
double getVoltage()
Definition: Node.cpp:51
void setId(int id)
Definition: Node.cpp:79