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 matrices
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, decreases 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 decreaseLastId() {
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 : };
|