44#include <fmt/chrono.h>
62 char buf[MAX_COMPUTERNAME_LENGTH + 1];
63 DWORD bufLen =
sizeof(buf);
64 if (GetComputerNameA(buf, &bufLen))
return std::string(buf);
67 if (gethostname(buf,
sizeof(buf)) == 0)
return std::string(buf);
76 auto now = std::time(
nullptr);
77 return fmt::format(
"{:%d-%b-%Y %H:%M:%S}", fmt::localtime(now));
84 auto now = std::time(
nullptr);
85 return fmt::format(
"{:%d-%b-%Y}", fmt::localtime(now));
92 auto now = std::time(
nullptr);
93 return fmt::format(
"{:%H:%M:%S}", fmt::localtime(now));
113 const std::string& jobName,
114 const std::string& inputFile,
115 const std::string& solverName,
116 const std::string& formatName,
119 const Eigen::MatrixXcd& Y,
124 double basemva = 100.0
126 std::string outFile = jobName +
".out";
127 std::ofstream out(outFile);
128 if (!out.is_open())
return false;
130 int nBus = busData.
V.size();
131 int nBranch = branchData.
From.size();
136 out << fmt::format(
"\n deltaFlow v{:<32s}Date {:>14s} Time {:>8s}\n",
141 out << fmt::format(
" Hostname : {}\n",
hostname());
142 out << fmt::format(
" CMake Version : {}\n", CMake_VERSION);
143 out << fmt::format(
" Compiler Version : GCC {}\n", gcc_VERSION);
144 out << fmt::format(
" deltaFlow Version : {}\n", deltaFlow_VERSION);
148 out << fmt::format(
" Job Name : {}\n", jobName);
149 out << fmt::format(
" Input File : {}\n", inputFile);
150 out << fmt::format(
" Input Format : {}\n", formatName);
151 out << fmt::format(
" Solver Method : {}\n", solverName);
152 out << fmt::format(
" Convergence Tol. : {:.6e}\n", tolerance);
157 int nSlack = 0, nPV = 0, nPQ = 0;
158 for (
int i = 0; i < nBus; ++i) {
159 if (busData.
Type(i) == 1) nSlack++;
160 else if (busData.
Type(i) == 2) nPV++;
164 out << fmt::format(
" Number of Buses : {:>6d}\n", nBus);
165 out << fmt::format(
" Slack Buses : {:>6d}\n", nSlack);
166 out << fmt::format(
" PV Buses : {:>6d}\n", nPV);
167 out << fmt::format(
" PQ Buses : {:>6d}\n", nPQ);
168 out << fmt::format(
" Number of Branches : {:>6d}\n", nBranch);
169 out << fmt::format(
" Base MVA : {:>10.1f}\n", basemva);
173 out << fmt::format(
" Method : {}\n", solverName);
174 out << fmt::format(
" Iterations : {:>6d}\n", iterations);
175 out << fmt::format(
" Final Error : {:.6e}\n", finalError);
176 out << fmt::format(
" Tolerance : {:.6e}\n", tolerance);
177 out << fmt::format(
" Status : CONVERGED\n");
178 out << fmt::format(
" Elapsed Time (sec) : {:.3f}\n", elapsedSec);
182 out << fmt::format(
" {:>4s} {:>9s} {:>9s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s}\n",
183 "Bus",
"Voltage",
"Angle",
"Load",
"Load",
"Gen",
"Gen",
"Injected");
184 out << fmt::format(
" {:>4s} {:>9s} {:>9s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s}\n",
185 "No.",
"Mag.",
"Degree",
"MW",
"Mvar",
"MW",
"Mvar",
"Mvar");
186 out <<
" " << std::string(W - 4,
'=') <<
"\n";
188 for (
int i = 0; i < nBus; ++i) {
189 double injectedMvar = busData.
Qg(i) - busData.
Ql(i);
190 out << fmt::format(
" {:>4d} {:>9.4f} {:>9.4f} {:>10.4f} {:>10.4f} {:>10.4f} {:>10.4f} {:>10.4f}\n",
191 i + 1, busData.
V(i), busData.
delta(i),
192 busData.
Pl(i), busData.
Ql(i), busData.
Pg(i), busData.
Qg(i), injectedMvar);
195 double totalPl = busData.
Pl.sum();
196 double totalQl = busData.
Ql.sum();
197 double totalPg = busData.
Pg.sum();
198 double totalQg = busData.
Qg.sum();
199 double totalInjected = totalQg - totalQl;
201 out <<
" " << std::string(W - 4,
'=') <<
"\n";
202 out << fmt::format(
" Total{:>27.4f} {:>10.4f} {:>10.4f} {:>10.4f} {:>10.4f}\n",
203 totalPl, totalQl, totalPg, totalQg, totalInjected);
207 out << fmt::format(
" {:>4s} {:>4s} {:>9s} {:>9s} {:>9s} {:>9s} {:>9s} {:>9s}\n",
208 "From",
"To",
"MW",
"Mvar",
"MVA",
"Loss MW",
"Loss Mvar",
"Tap");
209 out <<
" " << std::string(W - 4,
'=') <<
"\n";
211 auto Bc = branchData.
B;
214 Eigen::VectorXcd Vc(nBus);
215 Eigen::VectorXcd S(nBus);
216 for (
int i = 0; i < nBus; ++i) {
217 double mag = busData.
V(i);
218 double ang_rad = busData.
delta(i) * M_PI / 180.0;
219 Vc(i) = std::polar(mag, ang_rad);
220 double P = busData.
Pg(i) - busData.
Pl(i);
221 double Q = busData.
Qg(i) - busData.
Ql(i);
222 S(i) = std::complex<double>(P, Q);
225 std::complex<double> SLT = 0.0;
227 for (
int n = 1; n <= nBus; ++n) {
231 for (
int L = 0; L < nLine; ++L) {
233 double P_inj = busData.
Pg(n_idx) - busData.
Pl(n_idx);
234 double Q_inj = busData.
Qg(n_idx) - busData.
Ql(n_idx);
235 double S_mag = std::abs(S(n_idx)) * basemva;
236 out << fmt::format(
" {:>4d} {:>9.3f} {:>9.3f} {:>9.3f}\n",
237 n, P_inj, Q_inj, S_mag);
241 auto writeLineFlow = [&](
int from,
int to,
int L) {
242 int f_idx = from - 1;
246 std::complex<double> In, Ik;
247 if (branchData.
From(L) == from) {
248 In = (Vc(f_idx) - aL * Vc(t_idx)) * Y(L) / (aL * aL) + Bc(L) / (aL * aL) * Vc(f_idx);
249 Ik = (Vc(t_idx) - Vc(f_idx) / aL) * Y(L) + Bc(L) * Vc(t_idx);
251 In = (Vc(f_idx) - Vc(t_idx) / aL) * Y(L) + Bc(L) * Vc(f_idx);
252 Ik = (Vc(t_idx) - aL * Vc(f_idx)) * Y(L) / (aL * aL) + Bc(L) / (aL * aL) * Vc(t_idx);
254 std::complex<double> Snk = Vc(f_idx) * std::conj(In) * basemva;
255 std::complex<double> Skn = Vc(t_idx) * std::conj(Ik) * basemva;
256 std::complex<double> SL = Snk + Skn;
260 out << fmt::format(
" {:>4d} {:>9.3f} {:>9.3f} {:>9.3f} {:>9.3f} {:>9.3f} {:>9.3f}\n",
261 to, std::real(Snk), std::imag(Snk), std::abs(Snk),
262 std::real(SL), std::imag(SL), aL);
264 out << fmt::format(
" {:>4d} {:>9.3f} {:>9.3f} {:>9.3f} {:>9.3f} {:>9.3f}\n",
265 to, std::real(Snk), std::imag(Snk), std::abs(Snk),
266 std::real(SL), std::imag(SL));
270 if (branchData.
From(L) == n) {
271 writeLineFlow(n, branchData.
To(L), L);
272 }
else if (branchData.
To(L) == n) {
273 writeLineFlow(n, branchData.
From(L), L);
280 out << fmt::format(
" Total loss {:>9.3f} {:>9.3f}\n",
281 std::real(SLT), std::imag(SLT));
286 out <<
" JOB TIME SUMMARY\n";
287 out << fmt::format(
" TOTAL CPU TIME (SEC) = {:>12.5f}\n", elapsedSec);
288 out << fmt::format(
" WALLCLOCK TIME (SEC) = {:>12d}\n",
static_cast<int>(std::round(elapsedSec)));
292 out <<
Display::center(
"THE ANALYSIS HAS BEEN COMPLETED SUCCESSFULLY") <<
"\n";
315 const std::string& jobName,
316 const std::string& inputFile,
317 const std::string& solverName,
318 const std::string& formatName,
327 std::string staFile = jobName +
".sta";
328 std::ofstream out(staFile);
329 if (!out.is_open())
return false;
331 out << fmt::format(
"deltaFlow v{:<36s}Date {:>14s} Time {:>8s}\n",
334 out <<
" SUMMARY OF JOB INFORMATION:\n";
335 out << fmt::format(
" {:>6s} {:>6s} {:>10s} {:>12s} {:>12s} {:>8s}\n",
336 "ITER",
"STATUS",
"ERROR",
"TOLERANCE",
"ELAPSED",
"RESULT");
338 out << fmt::format(
" {:>6d} {:>6s} {:>10.3e} {:>12.3e} {:>12.3f} {:>8s}\n",
340 converged ?
"CONV" :
"FAIL",
344 converged ?
"OK" :
"FAILED");
348 out <<
" THE ANALYSIS HAS COMPLETED SUCCESSFULLY\n";
350 out <<
" THE ANALYSIS HAS FAILED TO CONVERGE\n";
354 out <<
"Jobinfo File:\n";
355 out << fmt::format(
"Inputfile: {}\n", inputFile);
356 out << fmt::format(
"Solver: {}\n", solverName);
357 out << fmt::format(
"Format: {}\n", formatName);
358 out << fmt::format(
"Hostname: {}\n",
hostname());
361 out <<
"solver and hardware info\n";
362 out <<
"------------------------\n";
363 out << fmt::format(
"version : {}\n", deltaFlow_VERSION);
364 out << fmt::format(
"compiler : GCC {}\n", gcc_VERSION);
365 out << fmt::format(
"cmake : {}\n", CMake_VERSION);
366 out << fmt::format(
"hostname : {}\n",
hostname());
369 out <<
"model info\n";
370 out <<
"----------\n";
371 out << fmt::format(
" # of buses : {}\n", nBus);
372 out << fmt::format(
" # of branches : {}\n", nBranch);
375 out <<
"run and timing info\n";
376 out <<
"-------------------\n";
377 out << fmt::format(
"simulation end : {}\n",
timestamp());
378 out << fmt::format(
"elapsed time : {:.3f} seconds\n", elapsedSec);
379 out << fmt::format(
"iterations : {}\n", iterations);
380 out << fmt::format(
"final error : {:.6e}\n", finalError);
381 out << fmt::format(
"termination status: {}\n", converged ?
"normal" :
"failed");
398 const std::string& jobName,
399 const std::string& solverName,
400 const std::vector<std::pair<int, double>>& iterationHistory,
404 std::string msgFile = jobName +
".msg";
405 std::ofstream out(msgFile);
406 if (!out.is_open())
return false;
410 out << fmt::format(
"\n deltaFlow v{:<32s}Date {:>14s} Time {:>8s}\n",
416 out << fmt::format(
" {:>6s} {:>16s} {:>12s} {:>8s}\n",
417 "Iter",
"Max Mismatch",
"Tolerance",
"Status");
420 for (
const auto& [iter, error] : iterationHistory) {
421 std::string status = (error < tolerance) ?
"CONV" :
"";
422 out << fmt::format(
" {:>6d} {:>16.6e} {:>12.6e} {:>8s}\n",
423 iter, error, tolerance, status);
430 out <<
" " << solverName <<
" CONVERGED\n";
432 out <<
" *** WARNING: " << solverName <<
" DID NOT CONVERGE\n";
458 const std::string& jobName,
459 const std::string& inputFile,
460 const std::string& solverName,
461 const std::string& formatName,
464 const std::vector<std::pair<int, double>>& iterationHistory,
470 double basemva = 100.0
472 std::string datFile = jobName +
".dat";
473 std::ofstream out(datFile);
474 if (!out.is_open())
return false;
476 int nBus = busData.
V.size();
477 int nBranch = branchData.
From.size();
481 out << fmt::format(
"\n deltaFlow v{:<32s}Date {:>14s} Time {:>8s}\n",
485 out << fmt::format(
" Input File : {}\n", inputFile);
486 out << fmt::format(
" Input Format : {}\n", formatName);
488 int nSlack = 0, nPV = 0, nPQ = 0;
489 for (
int i = 0; i < nBus; ++i) {
490 if (busData.
Type(i) == 1) nSlack++;
491 else if (busData.
Type(i) == 2) nPV++;
495 out << fmt::format(
" Number of Buses : {:>6d}\n", nBus);
496 out << fmt::format(
" Slack Buses : {:>6d}\n", nSlack);
497 out << fmt::format(
" PV Buses : {:>6d}\n", nPV);
498 out << fmt::format(
" PQ Buses : {:>6d}\n", nPQ);
499 out << fmt::format(
" Number of Branches : {:>6d}\n", nBranch);
500 out << fmt::format(
" Base MVA : {:>10.1f}\n", basemva);
502 std::string solverBanner;
503 for (
const char &c : solverName) {
504 solverBanner += std::toupper(c);
508 out << fmt::format(
" Method : {}\n", solverName);
509 out << fmt::format(
" Max Iterations : {:>6d}\n",
static_cast<int>(iterationHistory.size()) > 0 ?
510 static_cast<int>(iterationHistory.back().first) : totalIterations);
511 out << fmt::format(
" Convergence Tol. : {:.6e}\n", tolerance);
514 out << fmt::format(
" {:>6s} {:>16s} {:>12s} {:>8s}\n",
515 "Iter",
"Max Mismatch",
"Tolerance",
"Status");
516 out <<
" " << std::string(W - 4,
'-') <<
"\n";
518 for (
const auto& [iter, error] : iterationHistory) {
520 if (error < tolerance)
524 out << fmt::format(
" {:>6d} {:>16.6e} {:>12.6e} {:>8s}\n",
525 iter, error, tolerance, status);
528 out <<
" " << std::string(W - 4,
'-') <<
"\n";
532 out << fmt::format(
" {} CONVERGED after {} iterations.\n", solverName, totalIterations);
533 out << fmt::format(
" Final max mismatch = {:.6e}\n", finalError);
535 out << fmt::format(
" *** WARNING: {} DID NOT CONVERGE after {} iterations.\n", solverName, totalIterations);
536 out << fmt::format(
" Final max mismatch = {:.6e}\n", finalError);
540 out << fmt::format(
" {:>4s} {:>9s} {:>9s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s}\n",
541 "Bus",
"Voltage",
"Angle",
"Load",
"Load",
"Gen",
"Gen",
"Injected");
542 out << fmt::format(
" {:>4s} {:>9s} {:>9s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s}\n",
543 "No.",
"Mag.",
"Degree",
"MW",
"Mvar",
"MW",
"Mvar",
"Mvar");
544 out <<
" " << std::string(W - 4,
'=') <<
"\n";
546 for (
int i = 0; i < nBus; ++i) {
547 double injectedMvar = busData.
Qg(i) - busData.
Ql(i);
548 out << fmt::format(
" {:>4d} {:>9.4f} {:>9.4f} {:>10.4f} {:>10.4f} {:>10.4f} {:>10.4f} {:>10.4f}\n",
549 i + 1, busData.
V(i), busData.
delta(i),
550 busData.
Pl(i), busData.
Ql(i), busData.
Pg(i), busData.
Qg(i), injectedMvar);
553 out <<
" " << std::string(W - 4,
'=') <<
"\n";
555 double totalPl = busData.
Pl.sum();
556 double totalQl = busData.
Ql.sum();
557 double totalPg = busData.
Pg.sum();
558 double totalQg = busData.
Qg.sum();
559 double totalInjected = totalQg - totalQl;
561 out << fmt::format(
" Total{:>27.4f} {:>10.4f} {:>10.4f} {:>10.4f} {:>10.4f}\n",
562 totalPl, totalQl, totalPg, totalQg, totalInjected);
565 out <<
" JOB TIME SUMMARY\n";
566 out << fmt::format(
" TOTAL CPU TIME (SEC) = {:>12.5f}\n", elapsedSec);
567 out << fmt::format(
" WALLCLOCK TIME (SEC) = {:>12d}\n",
static_cast<int>(std::round(elapsedSec)));
572 out <<
Display::center(
"THE ANALYSIS HAS BEEN COMPLETED SUCCESSFULLY") <<
"\n";
574 out <<
Display::center(
"*** THE ANALYSIS HAS NOT CONVERGED ***") <<
"\n";
Data structures and utility functions for reading and displaying bus and branch data in power system ...
Display and formatting utilities for terminal and file output.
std::string center(const std::string &text)
Returns a centered string within the page width.
constexpr int pageWidth
Standard output page width.
std::string sectionHeader(const std::string &title)
Returns a section header for output files.
std::string fileBanner()
Returns a full plain-text banner for output/log files.
Functions for writing solver output, status, message, and data files.
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.
std::string hostname()
Returns the current hostname.
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.
std::string timestamp()
Returns the current timestamp string.
std::string timeStr()
Returns the current time string.
std::string dateStr()
Returns the current date string.
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.
Contains all relevant data for each transmission line or transformer branch.
Eigen::VectorXd tapRatio
Transformer tap ratio ($$ a $$)
Eigen::VectorXd B
Line susceptance ($$ B $$) [p.u.].
Eigen::VectorXi From
From bus indices.
Eigen::VectorXi To
To bus indices.
Contains all relevant data for each bus in the power system.
Eigen::VectorXd Ql
Reactive power load [MVAr or p.u.].
Eigen::VectorXd V
Voltage magnitude [p.u.].
Eigen::VectorXd Pg
Active power generation [MW or p.u.].
Eigen::VectorXd delta
Voltage angle [rad or deg].
Eigen::VectorXd Pl
Active power load [MW or p.u.].
Eigen::VectorXd Qg
Reactive power generation [MVAr or p.u.].
Eigen::VectorXi Type
Bus type (1=Slack, 2=PV, 3=PQ)