46 {
48
49 auto startTime = std::chrono::high_resolution_clock::now();
50
52
53 std::string jobName = args.getJobName();
54 std::string inputFile = args.getInputFile();
57 int maxIter = args.getMaxIterations();
58 double tolerance = args.getTolerance();
59
61 std::string formatName = (format ==
InputFormat::IEEE) ?
"IEEE Common Data Format" :
"PSS/E Raw Format";
62
65 LOG_DEBUG(
"Input format :: {}", formatName);
67 LOG_DEBUG(
"Tolerance :: {:.6e}", tolerance);
69
70 std::unique_ptr<Reader> reader;
71
72 switch (format) {
74 reader = std::make_unique<IEEECommonDataFormat>();
75 LOG_INFO(
"Reading IEEE Common Data Format file: {}", inputFile);
76 break;
78 reader = std::make_unique<PSSERawFormat>();
79 LOG_INFO(
"Reading PSS/E Raw Format file: {}", inputFile);
80 break;
81 default:
82 break;
83 }
84
85 reader->read(inputFile);
86
87 auto busData = reader->getBusData();
88 auto branchData = reader->getBranchData();
89
90 if (busData.ID.size() == 0 || branchData.From.size() == 0) {
91 LOG_ERROR(
"No bus or branch data found in '{}'. Check the file exists and is valid.", inputFile);
92 std::exit(1);
93 }
94
95 int N = busData.ID.size();
96 int nBranch = branchData.From.size();
97
98 LOG_INFO(
"Model: {} buses, {} branches", N, nBranch);
99
100 int nSlack = 0, nPV = 0, nPQ = 0;
101 for (int i = 0; i < N; ++i) {
102 if (busData.Type(i) == 1) nSlack++;
103 else if (busData.Type(i) == 2) nPV++;
104 else nPQ++;
105 }
106 LOG_DEBUG(
"Bus types: {} Slack, {} PV, {} PQ", nSlack, nPV, nPQ);
107
109 LOG_DEBUG(
"Admittance matrix computed ({}x{})", N, N);
110
111 Eigen::MatrixXd G = Y.array().real().matrix();
112 Eigen::MatrixXd B = Y.array().imag().matrix();
113
114
115 Eigen::VectorXd V(N);
116 Eigen::VectorXd delta = Eigen::VectorXd::Zero(N);
117
118 for (int i = 0; i < N; ++i) {
119 if (busData.Type(i) == 3) {
120 V(i) = 1.0;
121 } else {
122 V(i) = busData.V(i);
123 }
124 }
125
126 Eigen::VectorXi type_bus = busData.Type;
127
128 bool finalConverged = false;
129 int totalIterations = 0;
130 double finalError = 0.0;
131 std::vector<std::pair<int, double>> iterationHistory;
132
133 LOG_INFO(
"Starting {} solver ...", solverName);
134
135 switch (solver) {
137 double relaxation_coeff = args.getRelaxationCoefficient();
138
139 bool Q_lim_status = true;
140
141 while (Q_lim_status) {
142 Eigen::VectorXd Ps = busData.Pg - busData.Pl;
143 Eigen::VectorXd Qs = busData.Qg - busData.Ql;
144
145 std::vector<int> pv_indices;
146 for (int i = 0; i < N; ++i)
147 if (type_bus(i) == 2) pv_indices.push_back(i);
148
149 bool converged =
GaussSeidel(Y, V, delta, type_bus, Ps, Qs, N,
150 maxIter, tolerance, relaxation_coeff,
151 &iterationHistory);
152
153 finalConverged = converged;
154
155 if (!converged) {
156 LOG_ERROR(
"Gauss-Seidel solver failed to converge.");
157 break;
158 }
159
161 busData, pv_indices, N);
162
163 if (Q_lim_status)
164 LOG_DEBUG(
"Re-running Gauss-Seidel with updated bus types ...");
165 }
166 break;
167 }
168
170 default: {
171 bool Q_lim_status = true;
172
173 while (Q_lim_status) {
174 Eigen::VectorXd Ps = busData.Pg - busData.Pl;
175 Eigen::VectorXd Qs = busData.Qg - busData.Ql;
176
177 std::vector<int> pq_indices;
178 std::vector<int> pv_indices;
179
180 for (int i = 0; i < N; ++i) {
181 if (type_bus(i) == 3) pq_indices.push_back(i);
182 else if (type_bus(i) == 2) pv_indices.push_back(i);
183 }
184
185 int n_pq = static_cast<int>(pq_indices.size());
186
188 N, n_pq, pq_indices, maxIter, tolerance, &iterationHistory);
189
190 finalConverged = converged;
191
192 if (!converged) {
193 LOG_ERROR(
"Newton-Raphson solver failed to converge.");
194 break;
195 }
196
198 busData, pv_indices, N);
199
200 if (Q_lim_status) {
201 LOG_DEBUG(
"Re-running Newton-Raphson with updated bus types ...");
202 }
203 }
204 break;
205 }
206 }
207
208 if (!iterationHistory.empty()) {
209 totalIterations = iterationHistory.back().first;
210 finalError = iterationHistory.back().second;
211 }
212
213 if (!finalConverged) {
214 auto endTime = std::chrono::high_resolution_clock::now();
215 double elapsedSec = std::chrono::duration<double>(endTime - startTime).count();
217 N, nBranch, maxIter, 0.0, tolerance, false, elapsedSec);
218 std::exit(1);
219 }
220
221 Eigen::VectorXcd Vc(N);
222 for (int i = 0; i < N; ++i)
223 Vc(i) = std::polar(V(i), delta(i));
224
225 Eigen::VectorXd P_net = busData.Pg - busData.Pl;
226 Eigen::VectorXd Q_net = busData.Qg - busData.Ql;
227
228
229 for (int i = 0; i < N; ++i) {
230 if (busData.Type(i) == 1) {
231 std::complex<double> Ii = Y.row(i) * Vc;
232 std::complex<double> Si = Vc(i) * std::conj(Ii);
233 P_net(i) = Si.real();
234 Q_net(i) = Si.imag();
235 }
236 }
237
238
239 for (int i = 0; i < N; ++i) {
240 if (busData.Type(i) == 2) {
241 std::complex<double> Ii = Y.row(i) * Vc;
242 Q_net(i) = -std::imag(std::conj(Vc(i)) * Ii);
243 }
244 }
245
246 for (int i = 0; i < N; ++i) {
247 busData.V(i) = std::abs(Vc(i));
248 busData.delta(i) = std::arg(Vc(i)) * 180.0 / M_PI;
249 busData.Pg(i) = P_net(i) + busData.Pl(i);
250 busData.Qg(i) = Q_net(i) + busData.Ql(i);
251 }
252
253 double PLoss = busData.Pg.sum() - busData.Pl.sum();
254 double QLoss = busData.Qg.sum() - busData.Ql.sum();
255 LOG_DEBUG(
"Total real power loss: {:.6f} p.u.", PLoss);
256 LOG_DEBUG(
"Total reactive power loss: {:.6f} p.u.", QLoss);
257
260
261 auto endTime = std::chrono::high_resolution_clock::now();
262 double elapsedSec = std::chrono::duration<double>(endTime - startTime).count();
263
265
267 busData, branchData, Y, totalIterations, finalError, tolerance, elapsedSec);
268
270 N, nBranch, totalIterations, finalError, tolerance, finalConverged, elapsedSec);
271
273 busData, branchData, iterationHistory, totalIterations, finalError,
274 tolerance, finalConverged, elapsedSec);
275
277
278 fmt::print("\n");
280 " THE ANALYSIS HAS BEEN COMPLETED SUCCESSFULLY\n");
281 fmt::print("\n");
282 fmt::print(" Elapsed time : {:.3f} sec\n", elapsedSec);
283 fmt::print("\n");
284
285 return 0;
286}
Eigen::MatrixXcd computeAdmittanceMatrix(const BusData &busData, const BranchData &branchData)
Computes the complex bus admittance matrix ($$ Y_{bus} $$).
InputFormat
Supported input file formats.
@ IEEE
IEEE Common Data Format (.cdf, .txt)
@ PSSE
PSS/E Raw Data Format (.raw)
SolverType
Types of solvers supported by deltaFlow.
@ NewtonRaphson
Newton-Raphson iterative method.
@ GaussSeidel
Gauss-Seidel iterative method.
#define LOG_INFO(msg,...)
Macro for logging an info-level message.
#define LOG_DEBUG(msg,...)
Macro for logging a debug-level message.
#define LOG_ERROR(msg,...)
Macro for logging an error-level message.
bool checkQlimits(const Eigen::VectorXd &V, const Eigen::VectorXd &delta, Eigen::VectorXi &type_bus, const Eigen::MatrixXd &G, const Eigen::MatrixXd &B, BusData &busData, const std::vector< int > &pv_bus_id, int n_bus)
Checks reactive power limits on PV buses after solver convergence.
void dispBusData(const BusData &busData)
Displays bus data in a human-readable format.
void dispLineFlow(const BusData &busData, const BranchData &branchData, const Eigen::MatrixXcd &Y, double basemva)
Displays the line flow results, including power flow and losses.
bool writeOutputCSV(const BusData &busData)
Writes bus data results to a CSV file.
Parses and stores command-line arguments for deltaFlow.
constexpr fmt::rgb LOGO_COLOR
deltaFlow logo color
void printTerminalBanner()
Prints the full colored banner to terminal.
bool writeOutputFile(const std::string &jobName, const std::string &inputFile, const std::string &solverName, const std::string &formatName, const BusData &busData, const BranchData &branchData, const Eigen::MatrixXcd &Y, int iterations, double finalError, double tolerance, double elapsedSec, double basemva=100.0)
Writes the main output file (.out) with full analysis results.
bool writeDatFile(const std::string &jobName, const std::string &inputFile, const std::string &solverName, const std::string &formatName, const BusData &busData, const BranchData &branchData, const std::vector< std::pair< int, double > > &iterationHistory, int totalIterations, double finalError, double tolerance, bool converged, double elapsedSec, double basemva=100.0)
Writes the detailed data file (.dat) with full input/output records.
bool writeStatusFile(const std::string &jobName, const std::string &inputFile, const std::string &solverName, const std::string &formatName, int nBus, int nBranch, int iterations, double finalError, double tolerance, bool converged, double elapsedSec)
Writes the status file (.sta) with a compact solver summary.
bool writeMessageFile(const std::string &jobName, const std::string &solverName, const std::vector< std::pair< int, double > > &iterationHistory, double tolerance, bool converged)
Writes the message file (.msg) with iteration history.