48 if (
nodes->size() == 0) {
57 this->
nodes->push_back(tNode);
64 this->
nodes->erase(std::remove(this->
nodes->begin(), this->nodes->end(), node), this->nodes->end());
70 if (tElement ==
nullptr) {
78 if (tElement ==
nullptr) {
80 if (node !=
nullptr) {
92 if (tElement ==
nullptr) {
100 if (node->getName() == name) {
109 if (node->getId() == id) {
118 if (el->getName() == name) {
123 if (voltageSource->getName() == name) {
124 return voltageSource;
132 if (el->getId() == id) {
141 if (voltageSource->getId() == id) {
142 return voltageSource;
159 current += voltageSource->getCurrent();
169 currents +=
toString(voltageSource->getCurrent(), 4) +
" ";
171 if (!currents.empty()) {
179 std::vector<Element*>* vsources =
new std::vector<Element*>(0);
183 vsources->push_back(el);
198void Circuit::removeColumn(Eigen::MatrixXd& matrix,
int colToRemove) {
199 const int numRows = (int)matrix.rows();
200 const int numCols = (int)matrix.cols() - 1;
202 if (colToRemove < numCols) {
203 matrix.block(0, colToRemove, numRows, numCols - colToRemove) = matrix.rightCols(numCols - colToRemove);
206 matrix.conservativeResize(numRows, numCols);
209bool Circuit::solveEquationsNRmethod(
double* eqn,
double* vals, std::vector<int>* removable_ids) {
212 int numofeqs = numofcolumn - (int)removable_ids->size();
215 Eigen::MatrixXd A = Eigen::Map < Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >(eqn, numofeqs, numofcolumn);
220 for (std::vector<int>::reverse_iterator it = removable_ids->rbegin(); it != removable_ids->rend(); ++it) {
221 id = (*it >= 0 ? *it : -(*it));
230 Node* tNode =
nullptr;
231 for (
int i = 0; i < numofcolumn; i++) {
233 if (tNode !=
nullptr) {
239 WRITE_ERROR(
TL(
"Index of renumbered node exceeded the reduced number of equations."));
248 if (tElem !=
nullptr) {
250 WRITE_ERROR(
TL(
"Index of renumbered element exceeded the reduced number of equations."));
257 WRITE_ERROR(
TL(
"Structural error in reduced circuit matrix."));
261 Eigen::Map<Eigen::VectorXd> b(vals, numofeqs);
262 Eigen::VectorXd x = A.colPivHouseholderQr().solve(b);
265 Eigen::MatrixXd J = A;
268 int max_iter_of_NR = 10;
276 std::vector<double> alpha_notSolution;
278 double alpha_res = 1e-2;
280 double currentSumActual = 0.0;
282 Eigen::VectorXd x_best = x;
283 bool x_best_exist =
true;
285 if (x.maxCoeff() > 10e6 || x.minCoeff() < -10e6) {
286 WRITE_ERROR(
TL(
"Initial solution x used during solving DC circuit is out of bounds.\n"));
298 for (
int i = 0; i < numofeqs - (int)
voltageSources->size(); i++) {
304 for (
auto& node : *
nodes) {
305 if (node->isGround() || node->isRemovable() || node->getNumMatrixRow() == -2) {
308 if (node->getNumMatrixRow() != i) {
309 WRITE_ERROR(
TL(
"wrongly assigned row of matrix A during solving the circuit"));
313 for (
auto it_element = node->getElements()->begin(); it_element != node->getElements()->end(); it_element++) {
316 if ((*it_element)->isEnabled()) {
318 int PosNode_NumACol = (*it_element)->getPosNode()->getNumMatrixCol();
319 int NegNode_NumACol = (*it_element)->getNegNode()->getNumMatrixCol();
321 if (PosNode_NumACol == -1) {
323 diff_voltage = -x[NegNode_NumACol];
324 }
else if (NegNode_NumACol == -1) {
326 diff_voltage = x[PosNode_NumACol];
329 diff_voltage = (x[PosNode_NumACol] - x[NegNode_NumACol]);
332 if ((*it_element)->getPosNode() == node) {
334 vals[i] -= alpha * (*it_element)->getPowerWanted() / diff_voltage;
335 (*it_element)->setCurrent(-alpha * (*it_element)->getPowerWanted() / diff_voltage);
336 if (PosNode_NumACol != -1) {
338 J(i, PosNode_NumACol) -= alpha * (*it_element)->getPowerWanted() / diff_voltage / diff_voltage;
340 if (NegNode_NumACol != -1) {
342 J(i, NegNode_NumACol) += alpha * (*it_element)->getPowerWanted() / diff_voltage / diff_voltage;
346 vals[i] += alpha * (*it_element)->getPowerWanted() / diff_voltage;
351 WRITE_WARNING(
TL(
"The negative node of current source is not the ground."))
352 if (PosNode_NumACol != -1) {
354 J(i, PosNode_NumACol) += alpha * (*it_element)->getPowerWanted() / diff_voltage / diff_voltage;
356 if (NegNode_NumACol != -1) {
358 J(i, NegNode_NumACol) -= alpha * (*it_element)->getPowerWanted() / diff_voltage / diff_voltage;
372 currentSumActual = 0;
374 currentSumActual -= vals[i];
377 if ((A * x - b).norm() < 1e-6) {
381 alpha_notSolution.push_back(alpha);
391 alpha_notSolution.push_back(alpha);
402 }
else if (iterNR == max_iter_of_NR) {
404 alpha_notSolution.push_back(alpha);
412 dx = -J.colPivHouseholderQr().solve(A * x - b);
417 if (alpha_notSolution.empty()) {
422 if ((alpha_notSolution.back() -
alphaBest) < alpha_res) {
423 max_iter_of_NR = 2 * max_iter_of_NR;
427 alpha_res = alpha_res / 10;
429 if (alpha_res < 5e-5) {
432 alpha = alpha_notSolution.back();
433 alpha_notSolution.pop_back();
441 for (
int i = 0; i < numofeqs; i++) {
448 for (
auto& node : *
nodes) {
449 if (node->isGround() || node->isRemovable() || node->getNumMatrixRow() == -2) {
452 if (node->getNumMatrixRow() != i) {
453 WRITE_ERROR(
TL(
"wrongly assigned row of matrix A during solving the circuit"));
455 for (
auto it_element = node->getElements()->begin(); it_element != node->getElements()->end(); it_element++) {
457 if ((*it_element)->isEnabled()) {
459 int PosNode_NumACol = (*it_element)->getPosNode()->getNumMatrixCol();
460 int NegNode_NumACol = (*it_element)->getNegNode()->getNumMatrixCol();
461 if (PosNode_NumACol == -1) {
462 diff_voltage = -x_best[NegNode_NumACol];
463 }
else if (NegNode_NumACol == -1) {
464 diff_voltage = x_best[PosNode_NumACol];
466 diff_voltage = (x_best[PosNode_NumACol] - x_best[NegNode_NumACol]);
469 if ((*it_element)->getPosNode() == node) {
470 (*it_element)->setCurrent(-
alphaBest * (*it_element)->getPowerWanted() / diff_voltage);
476 WRITE_WARNING(
TL(
"The negative node of current source is not the ground."))
492 int numofeqs = numofcolumn - (int)removable_ids->size();
497 Node* tNode =
nullptr;
498 for (
int i = 0; i < numofcolumn; i++) {
500 if (tNode !=
nullptr)
505 WRITE_ERROR(
TL(
"Results deployment during circuit evaluation was unsuccessful."));
513 if (tElem !=
nullptr) {
515 WRITE_ERROR(
TL(
"Results deployment during circuit evaluation was unsuccessful."));
523 WRITE_ERROR(
TL(
"Results deployment during circuit evaluation was unsuccessful."));
528 Node* nextNONremovableNode1 =
nullptr;
529 Node* nextNONremovableNode2 =
nullptr;
532 if (!node->isRemovable()) {
535 if (node->getElements()->size() != 2) {
539 el1 = node->getElements()->front();
540 el2 = node->getElements()->back();
559 y = ((1 - x) * nextNONremovableNode1->
getVoltage()) + (x * nextNONremovableNode2->
getVoltage());
561 node->setRemovability(
false);
566 double currentSum = 0;
567 for (
Element*
const el : *voltageSource->getPosNode()->getElements()) {
569 if (el != voltageSource) {
571 currentSum += (voltageSource->getPosNode()->getVoltage() - el->getTheOtherNode(voltageSource->getPosNode())->
getVoltage()) / el->getResistance();
573 WRITE_WARNING(
TL(
"Cannot assign unambigous electric current value to two voltage sources connected in parallel at the same node."));
577 voltageSource->setCurrent(currentSum);
582 nodes =
new std::vector<Node*>(0);
583 elements =
new std::vector<Element*>(0);
591 nodes =
new std::vector<Node*>(0);
592 elements =
new std::vector<Element*>(0);
600bool Circuit::_solveNRmethod() {
601 double* eqn =
nullptr;
602 double* vals =
nullptr;
603 std::vector<int> removable_ids;
606 createEquationsNRmethod(eqn, vals, &removable_ids);
607 if (!solveEquationsNRmethod(eqn, vals, &removable_ids)) {
618bool Circuit::solve() {
622 return this->_solveNRmethod();
625bool Circuit::createEquationsNRmethod(
double*& eqs,
double*& vals, std::vector<int>* removable_ids) {
633 int m = n - (int)(removable_ids->size() +
voltageSources->size());
636 eqs =
new double[m * n];
637 vals =
new double[m];
639 for (
int i = 0; i < m; i++) {
641 for (
int j = 0; j < n; j++) {
648 for (std::vector<Node*>::iterator it =
nodes->begin(); it !=
nodes->end(); it++) {
649 if ((*it)->isGround() || (*it)->isRemovable()) {
651 (*it)->setNumMatrixRow(-1);
656 bool noVoltageSource = createEquationNRmethod((*it), (eqs + n * i), vals[i], removable_ids);
658 if (noVoltageSource) {
659 (*it)->setNumMatrixRow(i);
662 (*it)->setNumMatrixRow(-2);
664 for (
int j = 0; j < n; j++) {
671 std::sort(removable_ids->begin(), removable_ids->end(), std::less<int>());
676 createEquation((*it), (eqs + n * i), vals[i]);
683bool Circuit::createEquation(
Element* vsource,
double* eqn,
double& val) {
698bool Circuit::createEquationNRmethod(
Node* node,
double* eqn,
double& val, std::vector<int>* removable_ids) {
700 for (std::vector<Element*>::iterator it = node->
getElements()->begin(); it != node->
getElements()->end(); it++) {
702 switch ((*it)->getType()) {
704 if ((*it)->isEnabled()) {
705 x = (*it)->getResistance();
707 Node* nextNONremovableNode = (*it)->getTheOtherNode(node);
708 Element* nextSerialResistor = *it;
710 nextSerialResistor = nextNONremovableNode->
getAnOtherElement(nextSerialResistor);
712 nextNONremovableNode = nextSerialResistor->
getTheOtherNode(nextNONremovableNode);
716 eqn[node->
getId()] += x;
718 if (!nextNONremovableNode->
isGround()) {
719 eqn[nextNONremovableNode->
getId()] -= x;
724 if ((*it)->isEnabled()) {
726 if ((*it)->getPosNode() == node) {
729 x = (*it)->getPowerWanted() /
voltageSources->front()->getVoltage();
737 if ((*it)->getPosNode() == node) {
742 eqn[(*it)->getId()] += x;
744 removable_ids->push_back((*it)->getId());
763 for (std::vector<Node*>::iterator it =
nodes->begin(); it !=
nodes->end(); it++) {
765 if ((*it)->getElements()->size() == 2 && !(*it)->isGround()) {
767 (*it)->setRemovability(
true);
768 for (std::vector<Element*>::iterator it2 = (*it)->getElements()->begin(); it2 != (*it)->getElements()->end(); it2++) {
770 (*it)->setRemovability(
false);
774 if ((*it)->isRemovable()) {
776 removable_ids->push_back((*it)->getId());
779 (*it)->setRemovability(
false);
783 std::sort(removable_ids->begin(), removable_ids->end(), std::less<int>());
795 WRITE_WARNING(
TL(
"Trying to add resistor element into the overhead wire circuit with resistance < 1e-6. "))
797 WRITE_ERROR(
TL(
"Trying to add resistor element into the overhead wire circuit with resistance < 0. "))
806 std::cout <<
"The element: '" + name +
"' already exists.";
810 e =
new Element(name, et, value);
835 this->
elements->erase(std::remove(this->
elements->begin(), this->elements->end(), element), this->elements->end());
842 if (voltageSource->getNegNode() == unusedNode) {
843 voltageSource->setNegNode(newNode);
847 if (voltageSource->getPosNode() == unusedNode) {
848 voltageSource->setPosNode(newNode);
854 if (element->getNegNode() == unusedNode) {
855 element->setNegNode(newNode);
859 if (element->getPosNode() == unusedNode) {
860 element->setPosNode(newNode);
871 if (unusedNode->
getId() != modLastId) {
873 if (node_last !=
nullptr) {
877 if (elem_last !=
nullptr) {
880 WRITE_ERROR(
TL(
"The element or node with the last Id was not found in the circuit!"));
890 for (std::vector<Element*>::iterator it =
elements->begin(); it !=
elements->end(); it++) {
892 (*it)->setEnabled(
true);
897 (*it)->setEnabled(
true);
904 for (std::vector<Node*>::iterator it =
nodes->begin(); it !=
nodes->end(); it++) {
905 if ((*it)->getNumOfElements() < 2) {
907 if ((*it)->getNumOfElements() < 1) {
914 if ((*it)->getPosNode() ==
nullptr || (*it)->getNegNode() ==
nullptr) {
916 WRITE_ERRORF(
TL(
"Circuit Voltage Source '%' is connected to less than two nodes, please adjust the definition of the section (with substation '%')."), (*it)->getName(), substationId);
921 for (std::vector<Element*>::iterator it =
elements->begin(); it !=
elements->end(); it++) {
922 if ((*it)->getPosNode() ==
nullptr || (*it)->getNegNode() ==
nullptr) {
924 WRITE_ERRORF(
TL(
"Circuit Element '%' is connected to less than two nodes, please adjust the definition of the section (with substation '%')."), (*it)->getName(), substationId);
931 bool* nodesVisited =
new bool[num];
932 for (
int i = 0; i < num; i++) {
933 nodesVisited[i] =
false;
937 if (!
getNode(-1)->isGround()) {
939 WRITE_ERRORF(
TL(
"Circuit Node with id '-1' is not the grounded, please adjust the definition of the section (with substation '%')."), substationId);
941 std::vector<Node*>* queue =
new std::vector<Node*>(0);
942 Node* node =
nullptr;
943 Node* neigboringNode =
nullptr;
947 queue->push_back(node);
949 while (!queue->empty()) {
950 node = queue->back();
952 if (!nodesVisited[node->
getId()]) {
953 nodesVisited[node->
getId()] =
true;
955 neigboringNode = (*it)->getTheOtherNode(node);
957 queue->push_back(neigboringNode);
960 nodesVisited[(*it)->getId()] = 1;
963 WRITE_ERRORF(
TL(
"A Circuit Resistor Element connects the ground, please adjust the definition of the section (with substation '%')."), substationId);
969 for (
int i = 0; i < num; i++) {
970 if (nodesVisited[i] == 0) {
972 WRITE_WARNINGF(
TL(
"Circuit Node or Voltage Source with internal id '%' has been not visited during checking of the circuit. The circuit is disconnected, please adjust the definition of the section (with substation '%')."),
toString(i), substationId);
static std::mutex circuit_lock
#define WRITE_WARNINGF(...)
#define WRITE_ERRORF(...)
#define WRITE_WARNING(msg)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
std::vector< Node * > * nodes
std::vector< Element * > * getCurrentSources()
Node * addNode(std::string name)
double getVoltage(std::string name)
int getNumVoltageSources()
Element * addElement(std::string name, double value, Node *pNode, Node *nNode, Element::ElementType et)
void eraseNode(Node *node)
double getCurrent(std::string name)
Element * getElement(std::string name)
double circuitCurrentLimit
The electric current limit of the voltage sources.
double getTotalCurrentOfCircuitSources()
The sum of voltage source currents in the circuit.
void detectRemovableNodes(std::vector< int > *removable_ids)
double getCurrentLimit()
@ brief Get the electric current limit of this circuit.
std::vector< Element * > * elements
void replaceAndDeleteNode(Node *unusedNode, Node *newNode)
Element * getVoltageSource(int id)
double getTotalPowerOfCircuitSources()
The sum of voltage source powers in the circuit.
void deployResults(double *vals, std::vector< int > *removable_ids)
double getResistance(std::string name)
double alphaBest
Best alpha scaling value.
bool checkCircuit(std::string substationId="")
std::vector< Element * > * voltageSources
@ ALPHA_VOLTAGE_LIMITS
The scaling alpha is applied (is not one] due to voltage limits.
@ ALPHA_NOT_APPLIED
The scaling alpha is not applied (is one)
@ ALPHA_CURRENT_LIMITS
The scaling alpha is applied (is not one) due to current limits.
@ ALPHA_NOT_CONVERGING
The Newton-Rhapson method has reached maximum iterations and no solution of circuit has been found wi...
Node * getNode(std::string name)
std::string & getCurrentsOfCircuitSource(std::string ¤ts)
List of currents of voltage sources as a string.
void eraseElement(Element *element)
void setNegNode(Node *node)
void setPosNode(Node *node)
Node * getTheOtherNode(Node *node)
@ CURRENT_SOURCE_traction_wire
@ VOLTAGE_SOURCE_traction_wire
static bool gOverheadWireCurrentLimits
void setVoltage(double volt)
void setGround(bool isground)
void setNumMatrixCol(int num)
Element * getAnOtherElement(Element *element)
void addElement(Element *element)
void eraseElement(Element *element)
std::vector< Element * > * getElements()