Line data Source code
1 : /****************************************************************************/ 2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo 3 : // Copyright (C) 2001-2024 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 : /****************************************************************************/ 14 : /// @file Circuit.h 15 : /// @author Jakub Sevcik (RICE) 16 : /// @author Jan Prikryl (RICE) 17 : /// @date 2019-12-15 18 : /// 19 : /// @note based on console-based C++ DC circuits simulator, 20 : /// https://github.com/rka97/Circuits-Solver by 21 : /// Ahmad Khaled, Ahmad Essam, Omnia Zakaria, Mary Nader 22 : /// and available under MIT license, see https://github.com/rka97/Circuits-Solver/blob/master/LICENSE 23 : /// 24 : // Representation of electric circuit of overhead wires 25 : /****************************************************************************/ 26 : #pragma once 27 : #include <config.h> 28 : 29 : #include <vector> 30 : #ifdef HAVE_EIGEN 31 : #ifdef _MSC_VER 32 : #pragma warning(push) 33 : #pragma warning(disable: 4464 5031) 34 : #endif 35 : // avoid warnings in clang 36 : #ifdef __clang__ 37 : #pragma clang system_header 38 : #endif 39 : #include <Eigen/Dense> 40 : #include <Eigen/Geometry> 41 : #include <Eigen/Sparse> 42 : #ifdef _MSC_VER 43 : #pragma warning(pop) 44 : #endif 45 : #endif 46 : 47 : #include "Element.h" 48 : 49 : // =========================================================================== 50 : // class declarations 51 : // =========================================================================== 52 : class Node; 53 : 54 : 55 : // =========================================================================== 56 : // class definitions 57 : // =========================================================================== 58 : /** 59 : * All interactions will be through this class, the user will know nothing about the other classes, 60 : * and will interact only through the names of the elements/nodes. 61 : */ 62 : class Circuit { 63 : 64 : private: 65 : 66 : std::vector<Node*>* nodes; 67 : std::vector<Element*>* elements; 68 : std::vector<Element*>* voltageSources; 69 : 70 : int lastId; 71 : bool iscleaned; 72 : 73 : /// @brief The electric current limit of the voltage sources. 74 : double circuitCurrentLimit; 75 : 76 : /** 77 : * @brief Best alpha scaling value. 78 : * 79 : * This parameter is used to scale down the power demands of current sources (vehicles 80 : * that draw power from the circuit) so that a solution of the system can be found. 81 : * Note: the system is nonlinear (quadratic), hence in some cases (typically too high 82 : * power demands) a solution cannot be found. In that moment we decrease all power 83 : * requirements by `alpha` and try to solve again, until we find alpha that ensures 84 : * stable solution. This is then reported as alphaBest. 85 : */ 86 : double alphaBest; 87 : public: 88 : /** 89 : * @brief Flag of alpha scaling parameter 90 : * 91 : * returns ALPHA_NOT_APPLIED => alpha should be 1 92 : * returns ALPHA_CURRENT_LIMITS => alpha is lower than one due to electric current limits of the substation 93 : * returns ALPHA_VOLTAGE_LIMITS => alpha is not one due to inability of network to transfer requested power due to overhead wire resistance 94 : * returns ALPHA_NOT_CONVERGING => number of allowed iterations exceeded 95 : */ 96 : enum alphaFlag { 97 : /// @brief The scaling alpha is not applied (is one) 98 : ALPHA_NOT_APPLIED = 0, 99 : /// @brief The scaling alpha is applied (is not one) due to current limits 100 : ALPHA_CURRENT_LIMITS, 101 : /// @brief The scaling alpha is applied (is not one] due to voltage limits 102 : ALPHA_VOLTAGE_LIMITS, 103 : /// @brief The Newton-Rhapson method has reached maximum iterations and no solution of circuit has been found with actual value of alpha 104 : ALPHA_NOT_CONVERGING 105 : }; 106 : private: 107 : alphaFlag alphaReason; 108 : 109 : public: 110 : Node* getNode(std::string name); 111 : Element* getElement(std::string name); 112 : Node* getNode(int id); 113 : Element* getVoltageSource(int id); 114 : std::vector<Element*>* getCurrentSources(); 115 : 116 : /// @brief The sum of voltage source powers in the circuit 117 : double getTotalPowerOfCircuitSources(); 118 : /// @brief The sum of voltage source currents in the circuit 119 : double getTotalCurrentOfCircuitSources(); 120 : /// @brief List of currents of voltage sources as a string 121 : std::string& getCurrentsOfCircuitSource(std::string& currents); 122 : 123 : void lock(); 124 : void unlock(); 125 : 126 : /// @brief return alphaBest variable, the best alpha scaling value 127 : double getAlphaBest() { 128 360 : return alphaBest; 129 : }; 130 : 131 : /// @brief return the reason why `alpha` scaling value has been used 132 : alphaFlag getAlphaReason() { 133 180 : return alphaReason; 134 : }; 135 : 136 : private: 137 : 138 : Element* getElement(int id); 139 : /* 140 : * detects removable nodes = sets node variable "isremovable" to true if node is removable and adds id of such node to "removable_ids" vector 141 : * node is denoted as removable if it is connected just to 2 elements and both of them are resistor 142 : * the reason is that in such case there are two serial resistor and we can only sum their resistance value 143 : * 144 : * "removable_ids" vector is sort from the least to the greatest 145 : */ 146 : void detectRemovableNodes(std::vector<int>* removable_ids); 147 : 148 : void deployResults(double* vals, std::vector<int>* removable_ids); 149 : 150 : #ifdef HAVE_EIGEN 151 : /* 152 : * creates all of the equations that represent the circuit 153 : * in the form Ax = B(1/x) where A and B are matricies 154 : * @param eqn : A 155 : * @param vals : B 156 : */ 157 : bool createEquationsNRmethod(double*& eqs, double*& vals, std::vector<int>* removable_ids); 158 : 159 : /* 160 : * creates the nodal equation of the node 'node' GV = I 161 : * in the form Ax = B(1/x) where A is a matrix with one row 162 : * @param node : the node to be analyzed 163 : * @param eqn : A 164 : * @param val : B 165 : */ 166 : bool createEquationNRmethod(Node* node, double* eqn, double& val, std::vector<int>* removable_ids); 167 : 168 : /** 169 : * @brief Create the equation of the voltage source. 170 : * Create the equation V2 - V1 = E of the voltage source in the form Ax = B, 171 : * where A is a matrix with one row, B a value 172 : * @param[in] vsource The voltage source 173 : * @param[in] eqn : A 174 : * @param[in] val : B 175 : * @return ??? 176 : */ 177 : bool createEquation(Element* vsource, double* eqn, double& val); 178 : 179 : /* 180 : * removes the "colToRemove"-th column from matrix "matrix" 181 : */ 182 : void removeColumn(Eigen::MatrixXd& matrix, const int colToRemove); 183 : 184 : /* 185 : * solves the system of nonlinear equations Ax = B(1/x) 186 : * @param eqn : A 187 : * @param vals : B 188 : */ 189 : bool solveEquationsNRmethod(double* eqn, double* vals, std::vector<int>*); 190 : 191 : bool _solveNRmethod(); 192 : 193 : #endif 194 : public: 195 : 196 : // a Constructor, same functionality as "init" functions 197 : Circuit(); 198 : // RICE_CHECK: Is this a traction substation current limit, global for all substations? 199 : /// @brief Constructor with user-specified current limit parameter. 200 : Circuit(double currentLimit); 201 : 202 : // adds an element with name "name", type "type" and value "value" to positive node "pNode" and negative node "nNode"" 203 : Element* addElement(std::string name, double value, Node* pNode, Node* nNode, Element::ElementType et); 204 : 205 : void eraseElement(Element* element); 206 : 207 : // adds a node with name "name" 208 : Node* addNode(std::string name); 209 : 210 : // erases a node with name "name" 211 : void eraseNode(Node* node); 212 : 213 : // gets current through element "name" 214 : double getCurrent(std::string name); 215 : 216 : // gets voltage across element or node "name" 217 : double getVoltage(std::string name); 218 : 219 : // gets the resistance of an element. 220 : double getResistance(std::string name); 221 : 222 : // gets the number of voltage sources in the circuit. 223 : int getNumVoltageSources(); 224 : 225 : // checks if the circuit's connections are correct. 226 : bool checkCircuit(std::string substationId = ""); 227 : 228 : #ifdef HAVE_EIGEN 229 : // solves the circuit and deploys the results 230 : bool solve(); 231 : #endif 232 : 233 : // cleans up after superposition. 234 : void cleanUpSP(); 235 : 236 : //replaces unusedNode with newNode everywhere in the circuit, modifies the ids of other nodes and elements, descreases the id by one and deletes unusedNode 237 : void replaceAndDeleteNode(Node* unusedNode, Node* newNode); 238 : 239 : // returns lastId 240 : int getLastId() { 241 203 : return lastId; 242 : }; 243 : 244 : // decreases lastId by one 245 : void descreaseLastId() { 246 195 : lastId--; 247 : }; 248 : 249 : /// RICE_CHECK: Is this identical to the current limit of a traction substation? 250 : /// @brief Set the electric current limit of this circuit. 251 : void setCurrentLimit(double myCurrentLimit) { 252 : circuitCurrentLimit = myCurrentLimit; 253 : }; 254 : 255 : /// @ brief Get the electric current limit of this circuit. 256 : double getCurrentLimit() { 257 180 : return circuitCurrentLimit; 258 : }; 259 : };