Parse an IEEE CDF file (.cdf or .txt).
36 {
37 std::ifstream file(filename);
38 if (!file.is_open()) {
39 LOG_ERROR(
"Cannot open input file: {}", filename);
40 return;
41 }
42
43 LOG_DEBUG(
"Reading IEEE Common Data Format: {}", filename);
44
45 std::string line;
46 std::string section;
47 int busCount = 0;
48 int branchCount = 0;
49
50 std::vector<int> busID;
51 std::vector<std::string> busName;
52 std::vector<int> busType;
53 std::vector<double> V, delta, Pl, Ql, Pg, Qg, Qgmax, Qgmin, Gs, Bs;
54
55 std::vector<int> fromBus, toBus;
56 std::vector<double> R, X, G, B, tap;
57
58 std::map<std::string, std::string> busTypes;
59 busTypes["0"] = "3";
60 busTypes["1"] = "3";
61 busTypes["2"] = "2";
62 busTypes["3"] = "1";
63
64 std::map<std::string, int> busIndex;
65
66 while (std::getline(file, line)) {
67 std::string firstToken =
strip(line.substr(0, 4));
68
69 if (line.find(
"BUS DATA") != std::string::npos) { section =
"bus";
LOG_DEBUG(
"Parsing BUS DATA section ...");
continue; }
70 if (line.find(
"BRANCH DATA") != std::string::npos) { section =
"branch";
LOG_DEBUG(
"Parsing BRANCH DATA section ...");
continue; }
71 if (line.find("-999") != std::string::npos) { section = ""; continue; }
72
73 if (section == "bus" && !firstToken.empty() && std::all_of(firstToken.begin(), firstToken.end(), ::isdigit)) {
74 busCount++;
75 std::string
id =
strip(line.substr(0, 4));
76 busIndex[id] = busCount;
77 busID.push_back(busCount);
78 busName.push_back(
strip(line.substr(4, 11)));
79 std::string typeStr =
strip(line.substr(24, 2));
80 busType.push_back(std::stoi(busTypes[typeStr]));
81
82 double vmag = std::stod(
strip(line.substr(27, 6)));
83 V.push_back(vmag > 0.0 ? vmag : 1.0);
84 delta.push_back(0.0);
85 Pl.push_back(std::stod(
strip(line.substr(40, 9))) / 100.0);
86 Ql.push_back(std::stod(
strip(line.substr(49, 10))) / 100.0);
87 Pg.push_back(std::stod(
strip(line.substr(59, 8))) / 100.0);
88 Qg.push_back(std::stod(
strip(line.substr(67, 8))) / 100.0);
89 Qgmax.push_back(std::stod(
strip(line.substr(90, 8))) / 100.0);
90 Qgmin.push_back(std::stod(
strip(line.substr(98, 8))) / 100.0);
91 Gs.push_back(std::stod(
strip(line.substr(106, 8))));
92 Bs.push_back(std::stod(
strip(line.substr(114, 8))));
93 }
94
95 if (section == "branch" && !firstToken.empty() && std::all_of(firstToken.begin(), firstToken.end(), ::isdigit)) {
96 branchCount++;
97 std::string from =
strip(line.substr(0, 4));
98 std::string to =
strip(line.substr(5, 4));
99 fromBus.push_back(busIndex[from]);
100 toBus.push_back(busIndex[to]);
101 R.push_back(std::stod(
strip(line.substr(19, 10))));
102 X.push_back(std::stod(
strip(line.substr(29, 10))));
103 G.push_back(0.0);
104 B.push_back(std::stod(
strip(line.substr(40, 10))));
105 std::string aStr =
strip(line.substr(76, 6));
106 double aVal = aStr.empty() ? 0.0 : std::stod(aStr);
107 tap.push_back(aVal == 0.0 ? 1.0 : aVal);
108 }
109 }
110
111 int nBus = busID.size();
112 busData.
ID = Eigen::Map<Eigen::VectorXi>(busID.data(), nBus);
113 busData.
Type = Eigen::Map<Eigen::VectorXi>(busType.data(), nBus);
114 busData.
V = Eigen::Map<Eigen::VectorXd>(V.data(), nBus);
115 busData.
delta = Eigen::Map<Eigen::VectorXd>(delta.data(), nBus);
116 busData.
Pg = Eigen::Map<Eigen::VectorXd>(Pg.data(), nBus);
117 busData.
Qg = Eigen::Map<Eigen::VectorXd>(Qg.data(), nBus);
118 busData.
Pl = Eigen::Map<Eigen::VectorXd>(Pl.data(), nBus);
119 busData.
Ql = Eigen::Map<Eigen::VectorXd>(Ql.data(), nBus);
120 busData.
Qgmax = Eigen::Map<Eigen::VectorXd>(Qgmax.data(), nBus);
121 busData.
Qgmin = Eigen::Map<Eigen::VectorXd>(Qgmin.data(), nBus);
122 busData.
Gs = Eigen::Map<Eigen::VectorXd>(Gs.data(), nBus);
123 busData.
Bs = Eigen::Map<Eigen::VectorXd>(Bs.data(), nBus);
125
126 int nBranch = fromBus.size();
127 branchData.
From = Eigen::Map<Eigen::VectorXi>(fromBus.data(), nBranch);
128 branchData.
To = Eigen::Map<Eigen::VectorXi>(toBus.data(), nBranch);
129 branchData.
R = Eigen::Map<Eigen::VectorXd>(R.data(), nBranch);
130 branchData.
X = Eigen::Map<Eigen::VectorXd>(X.data(), nBranch);
131 branchData.
G = Eigen::Map<Eigen::VectorXd>(G.data(), nBranch);
132 branchData.
B = Eigen::Map<Eigen::VectorXd>(B.data(), nBranch);
134
135 LOG_DEBUG(
"IEEE CDF parsing complete: {} bus cards, {} branch cards", nBus, nBranch);
136}
#define LOG_DEBUG(msg,...)
Macro for logging a debug-level message.
#define LOG_ERROR(msg,...)
Macro for logging an error-level message.
BranchData branchData
Parsed branch data.
BusData busData
Parsed bus data.
std::string strip(const std::string &s)
Strip leading and trailing whitespace from a string.
Eigen::VectorXd tapRatio
Transformer tap ratio ($$ a $$)
Eigen::VectorXd B
Line susceptance ($$ B $$) [p.u.].
Eigen::VectorXd X
Reactance ($$ X $$) [p.u.].
Eigen::VectorXi From
From bus indices.
Eigen::VectorXd R
Resistance ($$ R $$) [p.u.].
Eigen::VectorXi To
To bus indices.
Eigen::VectorXd G
Line conductance ($$ G $$) [p.u.].
Eigen::VectorXd Ql
Reactive power load [MVAr or p.u.].
Eigen::VectorXd Qgmax
Max reactive power generation [MVAr or p.u.].
Eigen::VectorXi ID
Bus numbers.
Eigen::VectorXd V
Voltage magnitude [p.u.].
Eigen::VectorXd Pg
Active power generation [MW or p.u.].
std::vector< std::string > Name
Bus names.
Eigen::VectorXd Qgmin
Min reactive power generation [MVAr or p.u.].
Eigen::VectorXd Gs
Shunt conductance ($$ G_{sh} $$) [p.u.].
Eigen::VectorXd delta
Voltage angle [rad or deg].
Eigen::VectorXd Bs
Shunt susceptance ($$ B_{sh} $$) [p.u.].
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)