46int main(
int argc,
char* argv[]) {
49 auto startTime = std::chrono::high_resolution_clock::now();
61 std::string formatName = (format ==
InputFormat::IEEE) ?
"IEEE Common Data Format" :
"PSS/E Raw Format";
65 LOG_DEBUG(
"Input format :: {}", formatName);
67 LOG_DEBUG(
"Tolerance :: {:.6e}", tolerance);
70 std::unique_ptr<Reader> reader;
74 reader = std::make_unique<IEEECommonDataFormat>();
75 LOG_INFO(
"Reading IEEE Common Data Format file: {}", inputFile);
78 reader = std::make_unique<PSSERawFormat>();
79 LOG_INFO(
"Reading PSS/E Raw Format file: {}", inputFile);
85 reader->read(inputFile);
87 auto busData = reader->getBusData();
88 auto branchData = reader->getBranchData();
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);
95 int N = busData.ID.size();
96 int nBranch = branchData.From.size();
98 LOG_INFO(
"Model: {} buses, {} branches", N, nBranch);
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++;
106 LOG_DEBUG(
"Bus types: {} Slack, {} PV, {} PQ", nSlack, nPV, nPQ);
109 LOG_DEBUG(
"Admittance matrix computed ({}x{})", N, N);
111 Eigen::MatrixXd G = Y.array().real().matrix();
112 Eigen::MatrixXd B = Y.array().imag().matrix();
115 Eigen::VectorXd V(N);
116 Eigen::VectorXd delta = Eigen::VectorXd::Zero(N);
118 for (
int i = 0; i < N; ++i) {
119 if (busData.Type(i) == 3) {
126 Eigen::VectorXi type_bus = busData.Type;
128 bool finalConverged =
false;
129 int totalIterations = 0;
130 double finalError = 0.0;
131 std::vector<std::pair<int, double>> iterationHistory;
133 LOG_INFO(
"Starting {} solver ...", solverName);
139 bool Q_lim_status =
true;
141 while (Q_lim_status) {
142 Eigen::VectorXd Ps = busData.Pg - busData.Pl;
143 Eigen::VectorXd Qs = busData.Qg - busData.Ql;
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);
149 bool converged =
GaussSeidel(Y, V, delta, type_bus, Ps, Qs, N,
150 maxIter, tolerance, relaxation_coeff,
153 finalConverged = converged;
156 LOG_ERROR(
"Gauss-Seidel solver failed to converge.");
161 busData, pv_indices, N);
164 LOG_DEBUG(
"Re-running Gauss-Seidel with updated bus types ...");
171 bool Q_lim_status =
true;
173 while (Q_lim_status) {
174 Eigen::VectorXd Ps = busData.Pg - busData.Pl;
175 Eigen::VectorXd Qs = busData.Qg - busData.Ql;
177 std::vector<int> pq_indices;
178 std::vector<int> pv_indices;
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);
185 int n_pq =
static_cast<int>(pq_indices.size());
188 N, n_pq, pq_indices, maxIter, tolerance, &iterationHistory);
190 finalConverged = converged;
193 LOG_ERROR(
"Newton-Raphson solver failed to converge.");
198 busData, pv_indices, N);
201 LOG_DEBUG(
"Re-running Newton-Raphson with updated bus types ...");
208 if (!iterationHistory.empty()) {
209 totalIterations = iterationHistory.back().first;
210 finalError = iterationHistory.back().second;
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);
221 Eigen::VectorXcd Vc(N);
222 for (
int i = 0; i < N; ++i)
223 Vc(i) = std::polar(V(i), delta(i));
225 Eigen::VectorXd P_net = busData.Pg - busData.Pl;
226 Eigen::VectorXd Q_net = busData.Qg - busData.Ql;
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();
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);
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);
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);
261 auto endTime = std::chrono::high_resolution_clock::now();
262 double elapsedSec = std::chrono::duration<double>(endTime - startTime).count();
267 busData, branchData, Y, totalIterations, finalError, tolerance, elapsedSec);
270 N, nBranch, totalIterations, finalError, tolerance, finalConverged, elapsedSec);
273 busData, branchData, iterationHistory, totalIterations, finalError,
274 tolerance, finalConverged, elapsedSec);
280 " THE ANALYSIS HAS BEEN COMPLETED SUCCESSFULLY\n");
282 fmt::print(
" Elapsed time : {:.3f} sec\n", elapsedSec);
int main(int argc, char *argv[])
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.