deltaFlow
PowerFlowApplication.C
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Saud Zahir
3 *
4 * This file is part of deltaFlow.
5 *
6 * deltaFlow is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * deltaFlow is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with deltaFlow. If not, see
18 * <https://www.gnu.org/licenses/>.
19 */
20
22
23#include <chrono>
24#include <cmath>
25#include <complex>
26#include <cstdlib>
27#include <utility>
28
29#include "Admittance.H"
30#include "Argparse.H"
31#include "DatFileWriter.H"
32#include "Display.H"
33#include "Logger.H"
35#include "MsgFileWriter.H"
36#include "OutFileWriter.H"
37#include "Qlim.H"
38#include "ReaderFactory.H"
39#include "SolverFactory.H"
40#include "StaFileWriter.H"
41#include "Writer.H"
42
44 : options_(std::move(options)) {}
45
47 std::string inputFile = options_.inputFile;
49
51 formatName_ = reader_->name();
52
53 LOG_INFO("Reading {} file: {}", formatName_, inputFile);
54
55 reader_->read(inputFile);
56
57 busData_ = reader_->getBusData();
58 branchData_ = reader_->getBranchData();
59
60 if (busData_.ID.size() == 0 || branchData_.From.size() == 0) {
61 LOG_ERROR("No bus or branch data found in '{}'. Check the file exists and is valid.", inputFile);
62 std::exit(1);
63 }
64
65 N_ = busData_.ID.size();
66 nBranch_ = branchData_.From.size();
67
68 LOG_INFO("Model: {} buses, {} branches", N_, nBranch_);
69
70 int nSlack = 0, nPV = 0, nPQ = 0;
71 for (int i = 0; i < N_; ++i) {
72 if (busData_.Type(i) == 1) nSlack++;
73 else if (busData_.Type(i) == 2) nPV++;
74 else nPQ++;
75 }
76 LOG_DEBUG("Bus types: {} Slack, {} PV, {} PQ", nSlack, nPV, nPQ);
77}
78
80 LoggingSolverObserver observer;
82 LOG_DEBUG("Admittance matrix computed ({}x{})", N_, N_);
83
84 V_.resize(N_);
85 delta_ = Eigen::VectorXd::Zero(N_);
86
87 // Flat start: PQ buses -> V=1.0, delta=0 for all; PV/Slack keep file voltage
88 for (int i = 0; i < N_; ++i) {
89 if (busData_.Type(i) == 3) { // PQ bus
90 V_(i) = 1.0;
91 } else {
92 V_(i) = busData_.V(i); // PV/Slack keep specified voltage
93 }
94 }
95
97}
98
100 SolverType solverType = options_.solverType;
101
102 auto solverImpl = SolverFactory::create(solverType);
103 solverName_ = solverImpl->name();
104
105 Eigen::MatrixXd G = Y_.array().real().matrix();
106 Eigen::MatrixXd B = Y_.array().imag().matrix();
107
108 int maxIter = options_.maxIterations;
109 double tolerance = options_.tolerance;
110
111 LOG_INFO("Starting {} solver ...", solverName_);
112
113 LoggingSolverObserver observer;
114 bool Q_lim_status = true;
115
116 while (Q_lim_status) {
117 Eigen::VectorXd Ps = busData_.Pg - busData_.Pl;
118 Eigen::VectorXd Qs = busData_.Qg - busData_.Ql;
119
120 std::vector<int> pq_indices;
121 std::vector<int> pv_indices;
122
123 for (int i = 0; i < N_; ++i) {
124 if (typeBus_(i) == 3) pq_indices.push_back(i);
125 else if (typeBus_(i) == 2) pv_indices.push_back(i);
126 }
127
128 SolverContext ctx;
129 ctx.Y = &Y_;
130 ctx.G = &G;
131 ctx.B = &B;
132 ctx.V = &V_;
133 ctx.delta = &delta_;
134 ctx.type_bus = &typeBus_;
135 ctx.pq_bus_id = &pq_indices;
136 ctx.P = &Ps;
137 ctx.Q = &Qs;
138 ctx.N = N_;
139 ctx.n_pq = static_cast<int>(pq_indices.size());
140 ctx.maxIter = maxIter;
141 ctx.tolerance = tolerance;
144 ctx.observer = &observer;
145
146 bool converged = solverImpl->solve(ctx);
147 finalConverged_ = converged;
148
149 if (!converged) {
150 LOG_ERROR("{} solver failed to converge.", solverName_);
151 break;
152 }
153
154 Q_lim_status = Qlim::check(V_, delta_, typeBus_, G, B, busData_, pv_indices, N_, &observer);
155
156 if (Q_lim_status) {
157 LOG_DEBUG("Re-running {} with updated bus types ...", solverName_);
158 }
159 }
160
161 if (!iterationHistory_.empty()) {
162 totalIterations_ = iterationHistory_.back().first;
163 finalError_ = iterationHistory_.back().second;
164 }
165}
166
168 Eigen::VectorXcd Vc(N_);
169 for (int i = 0; i < N_; ++i)
170 Vc(i) = std::polar(V_(i), delta_(i));
171
172 Eigen::VectorXd P_net = busData_.Pg - busData_.Pl;
173 Eigen::VectorXd Q_net = busData_.Qg - busData_.Ql;
174
175 // Recalculate slack bus power injection
176 for (int i = 0; i < N_; ++i) {
177 if (busData_.Type(i) == 1) { // Slack
178 std::complex<double> Ii = Y_.row(i) * Vc;
179 std::complex<double> Si = Vc(i) * std::conj(Ii);
180 P_net(i) = Si.real();
181 Q_net(i) = Si.imag();
182 }
183 }
184
185 // Recalculate reactive power for PV buses
186 for (int i = 0; i < N_; ++i) {
187 if (busData_.Type(i) == 2) { // PV
188 std::complex<double> Ii = Y_.row(i) * Vc;
189 Q_net(i) = -std::imag(std::conj(Vc(i)) * Ii);
190 }
191 }
192
193 for (int i = 0; i < N_; ++i) {
194 busData_.V(i) = std::abs(Vc(i));
195 busData_.delta(i) = std::arg(Vc(i)) * 180.0 / M_PI;
196 busData_.Pg(i) = P_net(i) + busData_.Pl(i);
197 busData_.Qg(i) = Q_net(i) + busData_.Ql(i);
198 }
199
200 double PLoss = busData_.Pg.sum() - busData_.Pl.sum();
201 double QLoss = busData_.Qg.sum() - busData_.Ql.sum();
202 LOG_DEBUG("Total real power loss: {:.6f} p.u.", PLoss);
203 LOG_DEBUG("Total reactive power loss: {:.6f} p.u.", QLoss);
204}
205
206void PowerFlowApplication::writeFailureStatus(double elapsedSec) const {
207 StaFileWriter staWriter;
209 N_, nBranch_, options_.maxIterations, 0.0, options_.tolerance, false, elapsedSec);
210}
211
212void PowerFlowApplication::writeOutputs(double elapsedSec) const {
215
217
218 std::string jobName = options_.jobName;
219 std::string inputFile = options_.inputFile;
220 double tolerance = options_.tolerance;
221
222 OutFileWriter outWriter;
223 outWriter.write(jobName, inputFile, solverName_, formatName_,
224 busData_, branchData_, Y_, totalIterations_, finalError_, tolerance, elapsedSec);
225
226 StaFileWriter staWriter;
227 staWriter.write(jobName, inputFile, solverName_, formatName_,
228 N_, nBranch_, totalIterations_, finalError_, tolerance, finalConverged_, elapsedSec);
229
230 DatFileWriter datWriter;
231 datWriter.write(jobName, inputFile, solverName_, formatName_,
233 tolerance, finalConverged_, elapsedSec);
234
235 MsgFileWriter msgWriter;
236 msgWriter.write(jobName, solverName_, iterationHistory_, tolerance, finalConverged_);
237}
238
240 auto startTime = std::chrono::high_resolution_clock::now();
241
242 LOG_DEBUG("Job name :: {}", options_.jobName);
243 LOG_DEBUG("Input file :: {}", options_.inputFile);
244 LOG_DEBUG("Tolerance :: {:.6e}", options_.tolerance);
245 LOG_DEBUG("Max iter :: {}", options_.maxIterations);
246
247 loadInput();
248 prepareModel();
249 solve();
250
251 if (!finalConverged_) {
252 auto endTime = std::chrono::high_resolution_clock::now();
253 double elapsedSec = std::chrono::duration<double>(endTime - startTime).count();
254 writeFailureStatus(elapsedSec);
255 return 1;
256 }
257
259
260 auto endTime = std::chrono::high_resolution_clock::now();
261 double elapsedSec = std::chrono::duration<double>(endTime - startTime).count();
262
263 writeOutputs(elapsedSec);
264
265 fmt::print("\n");
266 fmt::print(fg(Display::LOGO_COLOR) | fmt::emphasis::bold,
267 " THE ANALYSIS HAS BEEN COMPLETED SUCCESSFULLY\n");
268 fmt::print("\n");
269 fmt::print(" Elapsed time : {:.3f} sec\n", elapsedSec);
270 fmt::print("\n");
271
272 return 0;
273}
Declaration of a class for constructing the bus admittance matrix ($$ Y_{bus} $$) in power system ana...
Command-line argument parsing utilities for deltaFlow.
InputFormat
Supported input file formats.
Definition Argparse.H:52
SolverType
Types of solvers supported by deltaFlow.
Definition Argparse.H:43
Writer for the detailed data output file (.dat).
Display and formatting utilities for terminal and file output.
Logger utilities for deltaFlow, providing logging macros and a singleton Logger class.
#define LOG_INFO(msg,...)
Macro for logging an info-level message.
Definition Logger.H:86
#define LOG_DEBUG(msg,...)
Macro for logging a debug-level message.
Definition Logger.H:85
#define LOG_ERROR(msg,...)
Macro for logging an error-level message.
Definition Logger.H:88
Concrete ISolverObserver that reports to the Logger singleton and the terminal progress bar (Dependen...
Writer for the iteration-history message file (.msg).
Writer for the main analysis output file (.out).
Orchestrates a full deltaFlow power-flow analysis run (SRP).
Reactive power limit (Q-limit) checking for PV buses.
Factory for constructing Reader instances from InputFormat, so callers (e.g.
Factory for constructing ISolver instances from SolverType, so callers (e.g.
Writer for the compact status output file (.sta).
void dispBusData(const BusData &busData)
Displays bus data in a human-readable format.
Definition Writer.C:36
void dispLineFlow(const BusData &busData, const BranchData &branchData, const Eigen::MatrixXcd &Y, double basemva)
Displays the line flow results, including power flow and losses.
Definition Writer.C:76
bool writeOutputCSV(const BusData &busData)
Writes bus data results to a CSV file.
Definition Writer.C:192
Output utilities for writing power system analysis results to CSV files.
static Eigen::MatrixXcd build(const BusData &busData, const BranchData &branchData, ISolverObserver *observer=nullptr)
Computes the complex bus admittance matrix ($$ Y_{bus} $$).
Definition Admittance.C:34
Writes the detailed data file (.dat) with full input/output records.
bool write(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) const
Writes the detailed data file (.dat) with full input/output records.
Reports solver progress to the Logger singleton and terminal progress bar.
Writes the message file (.msg) with iteration history.
bool write(const std::string &jobName, const std::string &solverName, const std::vector< std::pair< int, double > > &iterationHistory, double tolerance, bool converged) const
Writes the message file (.msg) with iteration history.
Writes the main output file (.out) with full analysis results.
bool write(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) const
Writes the main output file (.out) with full analysis results.
std::unique_ptr< Reader > reader_
PowerFlowApplication(PowerFlowOptions options)
Construct the application from already-parsed command-line options.
void loadInput()
Reads and validates the input file via ReaderFactory.
void writeFailureStatus(double elapsedSec) const
Writes only the status file, used on the non-convergence early-exit path.
void finalizeResults()
Recomputes slack/PV bus power injections and updates busData_ post-solve.
void writeOutputs(double elapsedSec) const
Writes all output files (.out, .sta, .dat, .msg) and CSV/terminal display.
int run()
Runs the full analysis pipeline: load input, solve, apply Q-limits, recompute results,...
void solve()
Runs the selected solver, re-running on Q-limit violations.
std::vector< std::pair< int, double > > iterationHistory_
void prepareModel()
Computes Y_bus and sets up the flat-start voltage/angle vectors.
static bool check(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, ISolverObserver *observer=nullptr)
Checks reactive power limits on PV buses after solver convergence.
Definition Qlim.C:36
static std::unique_ptr< Reader > create(InputFormat format)
Construct a concrete reader for the given input format.
static std::unique_ptr< ISolver > create(SolverType type)
Construct a concrete solver for the given solver type.
Writes the status file (.sta) with a compact solver summary.
bool write(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) const
Writes the status file (.sta) with a compact solver summary.
constexpr fmt::rgb LOGO_COLOR
deltaFlow logo color
Definition Display.H:50
Eigen::VectorXi From
From bus indices.
Definition Data.H:84
Eigen::VectorXd Ql
Reactive power load [MVAr or p.u.].
Definition Data.H:65
Eigen::VectorXi ID
Bus numbers.
Definition Data.H:56
Eigen::VectorXd V
Voltage magnitude [p.u.].
Definition Data.H:60
Eigen::VectorXd Pg
Active power generation [MW or p.u.].
Definition Data.H:62
Eigen::VectorXd delta
Voltage angle [rad or deg].
Definition Data.H:61
Eigen::VectorXd Pl
Active power load [MW or p.u.].
Definition Data.H:64
Eigen::VectorXd Qg
Reactive power generation [MVAr or p.u.].
Definition Data.H:63
Eigen::VectorXi Type
Bus type (1=Slack, 2=PV, 3=PQ)
Definition Data.H:58
Plain data holder for parsed command-line options.
std::string inputFile
Path to input file.
std::string jobName
Job name (defaults to input filename)
int maxIterations
Maximum number of iterations ($$ N_{max} $$)
double tolerance
Convergence tolerance ($$ \epsilon $$)
SolverType solverType
Solver type.
InputFormat inputFormat
Input file format.
double relaxation
Relaxation coefficient ($$ \omega $$)
Shared input/output parameters for power-flow solvers.
Definition ISolver.H:49
const Eigen::VectorXd * Q
Scheduled reactive power injections (Qg - Ql).
Definition ISolver.H:65
double tolerance
Convergence tolerance.
Definition ISolver.H:73
Eigen::VectorXd * V
Voltage magnitudes [p.u.].
Definition ISolver.H:56
const Eigen::MatrixXcd * Y
Bus admittance matrix (used by Gauss-Seidel).
Definition ISolver.H:51
const Eigen::VectorXd * P
Scheduled active power injections (Pg - Pl).
Definition ISolver.H:64
int maxIter
Maximum number of iterations.
Definition ISolver.H:72
int N
Total number of buses.
Definition ISolver.H:68
Eigen::VectorXd * delta
Voltage angles [rad].
Definition ISolver.H:57
const Eigen::MatrixXd * G
Conductance matrix (used by Newton-Raphson).
Definition ISolver.H:52
Eigen::VectorXi * type_bus
Bus type vector (1=Slack, 2=PV, 3=PQ).
Definition ISolver.H:60
class ISolverObserver * observer
Optional injected progress/log observer (DIP); nullptr = silent.
Definition ISolver.H:78
const Eigen::MatrixXd * B
Susceptance matrix (used by Newton-Raphson).
Definition ISolver.H:53
std::vector< std::pair< int, double > > * iterHistory
Optional iteration history sink.
Definition ISolver.H:77
int n_pq
Number of PQ buses (Newton-Raphson).
Definition ISolver.H:69
double omega
Relaxation coefficient (Gauss-Seidel only).
Definition ISolver.H:74
const std::vector< int > * pq_bus_id
0-based PQ bus indices (Newton-Raphson).
Definition ISolver.H:61