Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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: 4127 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 : public:
65 : /// @brief whether per-substation overhead-wire current limits should be enforced
66 : static void enforceCurrentLimits(const bool val) {
67 42780 : myCurrentLimits = val;
68 : }
69 :
70 : private:
71 :
72 : std::vector<Node*>* nodes;
73 : std::vector<Element*>* elements;
74 : std::vector<Element*>* voltageSources;
75 :
76 : int lastId;
77 : bool iscleaned;
78 :
79 : /// @brief The electric current limit of the voltage sources.
80 : double circuitCurrentLimit;
81 :
82 : /**
83 : * @brief Best alpha scaling value.
84 : *
85 : * This parameter is used to scale down the power demands of current sources (vehicles
86 : * that draw power from the circuit) so that a solution of the system can be found.
87 : * Note: the system is nonlinear (quadratic), hence in some cases (typically too high
88 : * power demands) a solution cannot be found. In that moment we decrease all power
89 : * requirements by `alpha` and try to solve again, until we find alpha that ensures
90 : * stable solution. This is then reported as alphaBest.
91 : */
92 : double alphaBest;
93 :
94 : /// @brief whether per-substation overhead-wire current limits should be enforced
95 : static bool myCurrentLimits;
96 : public:
97 : /**
98 : * @brief Flag of alpha scaling parameter
99 : *
100 : * returns ALPHA_NOT_APPLIED => alpha should be 1
101 : * returns ALPHA_CURRENT_LIMITS => alpha is lower than one due to electric current limits of the substation
102 : * returns ALPHA_VOLTAGE_LIMITS => alpha is not one due to inability of network to transfer requested power due to overhead wire resistance
103 : * returns ALPHA_NOT_CONVERGING => number of allowed iterations exceeded
104 : */
105 : enum alphaFlag {
106 : /// @brief The scaling alpha is not applied (is one)
107 : ALPHA_NOT_APPLIED = 0,
108 : /// @brief The scaling alpha is applied (is not one) due to current limits
109 : ALPHA_CURRENT_LIMITS,
110 : /// @brief The scaling alpha is applied (is not one] due to voltage limits
111 : ALPHA_VOLTAGE_LIMITS,
112 : /// @brief The Newton-Rhapson method has reached maximum iterations and no solution of circuit has been found with actual value of alpha
113 : ALPHA_NOT_CONVERGING
114 : };
115 : private:
116 : alphaFlag alphaReason;
117 :
118 : public:
119 : Node* getNode(std::string name);
120 : Element* getElement(std::string name);
121 : Node* getNode(int id);
122 : Element* getVoltageSource(int id);
123 : std::vector<Element*>* getCurrentSources();
124 :
125 : /// @brief The sum of voltage source powers in the circuit
126 : double getTotalPowerOfCircuitSources();
127 : /// @brief The sum of voltage source currents in the circuit
128 : double getTotalCurrentOfCircuitSources();
129 : /// @brief List of currents of voltage sources as a string
130 : std::string& getCurrentsOfCircuitSource(std::string& currents);
131 :
132 : void lock();
133 : void unlock();
134 :
135 : /// @brief return alphaBest variable, the best alpha scaling value
136 : double getAlphaBest() {
137 360 : return alphaBest;
138 : }
139 :
140 : /// @brief return the reason why `alpha` scaling value has been used
141 : alphaFlag getAlphaReason() {
142 180 : return alphaReason;
143 : }
144 :
145 : private:
146 :
147 : Element* getElement(int id);
148 : /*
149 : * detects removable nodes = sets node variable "isremovable" to true if node is removable and adds id of such node to "removable_ids" vector
150 : * node is denoted as removable if it is connected just to 2 elements and both of them are resistor
151 : * the reason is that in such case there are two serial resistor and we can only sum their resistance value
152 : *
153 : * "removable_ids" vector is sort from the least to the greatest
154 : */
155 : void detectRemovableNodes(std::vector<int>* removable_ids);
156 :
157 : void deployResults(double* vals, std::vector<int>* removable_ids);
158 :
159 : #ifdef HAVE_EIGEN
160 : /*
161 : * creates all of the equations that represent the circuit
162 : * in the form Ax = B(1/x) where A and B are matrices
163 : * @param eqn : A
164 : * @param vals : B
165 : */
166 : bool createEquationsNRmethod(double*& eqs, double*& vals, std::vector<int>* removable_ids);
167 :
168 : /*
169 : * creates the nodal equation of the node 'node' GV = I
170 : * in the form Ax = B(1/x) where A is a matrix with one row
171 : * @param node : the node to be analyzed
172 : * @param eqn : A
173 : * @param val : B
174 : */
175 : bool createEquationNRmethod(Node* node, double* eqn, double& val, std::vector<int>* removable_ids);
176 :
177 : /**
178 : * @brief Create the equation of the voltage source.
179 : * Create the equation V2 - V1 = E of the voltage source in the form Ax = B,
180 : * where A is a matrix with one row, B a value
181 : * @param[in] vsource The voltage source
182 : * @param[in] eqn : A
183 : * @param[in] val : B
184 : * @return ???
185 : */
186 : bool createEquation(Element* vsource, double* eqn, double& val);
187 :
188 : /*
189 : * removes the "colToRemove"-th column from matrix "matrix"
190 : */
191 : void removeColumn(Eigen::MatrixXd& matrix, const int colToRemove);
192 :
193 : /*
194 : * solves the system of nonlinear equations Ax = B(1/x)
195 : * @param eqn : A
196 : * @param vals : B
197 : */
198 : bool solveEquationsNRmethod(double* eqn, double* vals, std::vector<int>*);
199 :
200 : bool _solveNRmethod();
201 :
202 : #endif
203 : public:
204 :
205 : // a Constructor, same functionality as "init" functions
206 : Circuit();
207 : // RICE_CHECK: Is this a traction substation current limit, global for all substations?
208 : /// @brief Constructor with user-specified current limit parameter.
209 : Circuit(double currentLimit);
210 :
211 : // adds an element with name "name", type "type" and value "value" to positive node "pNode" and negative node "nNode""
212 : Element* addElement(std::string name, double value, Node* pNode, Node* nNode, Element::ElementType et);
213 :
214 : void eraseElement(Element* element);
215 :
216 : // adds a node with name "name"
217 : Node* addNode(std::string name);
218 :
219 : // erases a node with name "name"
220 : void eraseNode(Node* node);
221 :
222 : // gets current through element "name"
223 : double getCurrent(std::string name);
224 :
225 : // gets voltage across element or node "name"
226 : double getVoltage(std::string name);
227 :
228 : // gets the resistance of an element.
229 : double getResistance(std::string name);
230 :
231 : // gets the number of voltage sources in the circuit.
232 : int getNumVoltageSources();
233 :
234 : // checks if the circuit's connections are correct.
235 : bool checkCircuit(std::string substationId = "");
236 :
237 : #ifdef HAVE_EIGEN
238 : // solves the circuit and deploys the results
239 : bool solve();
240 : #endif
241 :
242 : // cleans up after superposition.
243 : void cleanUpSP();
244 :
245 : //replaces unusedNode with newNode everywhere in the circuit, modifies the ids of other nodes and elements, decreases the id by one and deletes unusedNode
246 : void replaceAndDeleteNode(Node* unusedNode, Node* newNode);
247 :
248 : // returns lastId
249 : int getLastId() {
250 203 : return lastId;
251 : };
252 :
253 : // decreases lastId by one
254 : void decreaseLastId() {
255 195 : lastId--;
256 : };
257 :
258 : /// RICE_CHECK: Is this identical to the current limit of a traction substation?
259 : /// @brief Set the electric current limit of this circuit.
260 : void setCurrentLimit(double myCurrentLimit) {
261 : circuitCurrentLimit = myCurrentLimit;
262 : };
263 :
264 : /// @ brief Get the electric current limit of this circuit.
265 : double getCurrentLimit() {
266 180 : return circuitCurrentLimit;
267 : };
268 : };
|