Parse a PSS/E .raw file.
60 {
61 std::ifstream file(filename);
62 if (!file.is_open()) {
63 LOG_ERROR(
"Cannot open input file: {}", filename);
64 return;
65 }
66
67 LOG_DEBUG(
"Reading PSS/E Raw Format: {}", filename);
68
69 std::string line;
70
71 std::getline(file, line);
73
74 double sbase = 100.0;
75 int version = 33;
76
77 if (hdr.size() >= 2) sbase = std::stod(hdr[1]);
78 if (hdr.size() >= 3) version = std::stoi(hdr[2]);
79
80 LOG_DEBUG(
"PSS/E RAW format version {} detected (SBASE = {:.2f} MVA)", version, sbase);
81
82 if (version != 32 && version != 33) {
83 LOG_WARN(
"PSS/E version {} is not explicitly supported. Attempting to parse as v{}.",
84 version, (version >= 33 ? 33 : 32));
85 }
86
87
88 std::string title1, title2;
89 std::getline(file, title1);
90 std::getline(file, title2);
92
93
94
95
96 std::vector<int> busID;
97 std::vector<std::string> busName;
98 std::vector<int> busType;
99 std::vector<double> V, delta_vec;
100
101 std::map<int, int> busIndex;
102 int busCount = 0;
103
104 while (std::getline(file, line)) {
106
108 if (f.size() < 9) continue;
109
110 busCount++;
111 int origID = std::stoi(f[0]);
112 busIndex[origID] = busCount;
113
114 busID.push_back(busCount);
116
117 int ide = std::stoi(f[3]);
118 int type;
119 switch (ide) {
120 case 3: type = 1; break;
121 case 2: type = 2; break;
122 default: type = 3; break;
123 }
124 busType.push_back(type);
125
126 double vmag = std::stod(f[7]);
127 V.push_back(vmag > 0.0 ? vmag : 1.0);
128 delta_vec.push_back(0.0);
129 }
130
131 int nBus = busCount;
133
134
135 std::vector<double> Pl(nBus, 0.0), Ql(nBus, 0.0);
136 std::vector<double> Pg(nBus, 0.0), Qg(nBus, 0.0);
137 std::vector<double> Qgmax(nBus, 0.0), Qgmin(nBus, 0.0);
138 std::vector<double> Gs(nBus, 0.0), Bs(nBus, 0.0);
139
140
141
142 while (std::getline(file, line)) {
144
146 if (f.size() < 8) continue;
147
148 int origBus = std::stoi(f[0]);
149 int status = std::stoi(f[2]);
150 if (status == 0) continue;
151
152 int idx = busIndex[origBus] - 1;
153 Pl[idx] += std::stod(f[5]) / sbase;
154 Ql[idx] += std::stod(f[6]) / sbase;
155 }
156
157
158 while (std::getline(file, line)) {
160
162 if (f.size() < 4) continue;
163
164 int origBus = std::stoi(f[0]);
165 int status = std::stoi(f[1]);
166 if (status == 0) continue;
167
168 int idx = busIndex[origBus] - 1;
169 Gs[idx] += std::stod(f[2]) / sbase;
170 Bs[idx] += std::stod(f[3]) / sbase;
171 }
172
173
174
175 while (std::getline(file, line)) {
177
179 if (f.size() < 10) continue;
180
181 int origBus = std::stoi(f[0]);
182 int idx = busIndex[origBus] - 1;
183
184 Pg[idx] += std::stod(f[2]) / sbase;
185 Qg[idx] += std::stod(f[3]) / sbase;
186 Qgmax[idx] += std::stod(f[4]) / sbase;
187 Qgmin[idx] += std::stod(f[5]) / sbase;
188
189
190 double vs = std::stod(f[6]);
191 if (busType[idx] == 1 || busType[idx] == 2) {
192 V[idx] = vs;
193 }
194 }
195
196
197
198 std::vector<int> fromBus, toBus;
199 std::vector<double> R_vec, X_vec, G_vec, B_vec, tap_vec;
200
201 while (std::getline(file, line)) {
203
205 if (f.size() < 6) continue;
206
207 int from = std::stoi(f[0]);
208 int to = std::abs(std::stoi(f[1]));
209
210 fromBus.push_back(busIndex[from]);
211 toBus.push_back(busIndex[to]);
212 R_vec.push_back(std::stod(f[3]));
213 X_vec.push_back(std::stod(f[4]));
214 G_vec.push_back(0.0);
215 B_vec.push_back(std::stod(f[5]));
216 tap_vec.push_back(1.0);
217 }
218
219
220
221
222
223
224
225
226 while (std::getline(file, line)) {
228
230 if (f1.size() < 5) continue;
231
232 int I = std::stoi(f1[0]);
233 int J = std::stoi(f1[1]);
234 int K = std::stoi(f1[2]);
235
236 int cz = (f1.size() >= 6) ? std::stoi(f1[5]) : 1;
237
238
239 std::getline(file, line);
241
242 double r12 = (f2.size() >= 1) ? std::stod(f2[0]) : 0.0;
243 double x12 = (f2.size() >= 2) ? std::stod(f2[1]) : 0.0;
244 double sbase12 = (f2.size() >= 3) ? std::stod(f2[2]) : sbase;
245
246
247 if (cz == 2 && sbase12 > 0.0) {
248 r12 *= sbase / sbase12;
249 x12 *= sbase / sbase12;
250 }
251
252
253 std::getline(file, line);
255 double windv1 = (f3.size() >= 1) ? std::stod(f3[0]) : 1.0;
256
257
258 std::getline(file, line);
259
260 if (K != 0) {
261
262 std::getline(file, line);
263 LOG_WARN(
"3-winding transformer ({}-{}-{}) encountered, skipping.", I, J, K);
264 continue;
265 }
266
267 fromBus.push_back(busIndex[I]);
268 toBus.push_back(busIndex[J]);
269 R_vec.push_back(r12);
270 X_vec.push_back(x12);
271 G_vec.push_back(0.0);
272 B_vec.push_back(0.0);
273 double tapVal = (windv1 == 0.0) ? 1.0 : windv1;
274 tap_vec.push_back(tapVal);
275 }
276
277 busData.
ID = Eigen::Map<Eigen::VectorXi>(busID.data(), nBus);
278 busData.
Type = Eigen::Map<Eigen::VectorXi>(busType.data(), nBus);
279 busData.
V = Eigen::Map<Eigen::VectorXd>(V.data(), nBus);
280 busData.
delta = Eigen::Map<Eigen::VectorXd>(delta_vec.data(), nBus);
281 busData.
Pg = Eigen::Map<Eigen::VectorXd>(Pg.data(), nBus);
282 busData.
Qg = Eigen::Map<Eigen::VectorXd>(Qg.data(), nBus);
283 busData.
Pl = Eigen::Map<Eigen::VectorXd>(Pl.data(), nBus);
284 busData.
Ql = Eigen::Map<Eigen::VectorXd>(Ql.data(), nBus);
285 busData.
Qgmax = Eigen::Map<Eigen::VectorXd>(Qgmax.data(), nBus);
286 busData.
Qgmin = Eigen::Map<Eigen::VectorXd>(Qgmin.data(), nBus);
287 busData.
Gs = Eigen::Map<Eigen::VectorXd>(Gs.data(), nBus);
288 busData.
Bs = Eigen::Map<Eigen::VectorXd>(Bs.data(), nBus);
290
291 int nBranch = static_cast<int>(fromBus.size());
292 branchData.
From = Eigen::Map<Eigen::VectorXi>(fromBus.data(), nBranch);
293 branchData.
To = Eigen::Map<Eigen::VectorXi>(toBus.data(), nBranch);
294 branchData.
R = Eigen::Map<Eigen::VectorXd>(R_vec.data(), nBranch);
295 branchData.
X = Eigen::Map<Eigen::VectorXd>(X_vec.data(), nBranch);
296 branchData.
G = Eigen::Map<Eigen::VectorXd>(G_vec.data(), nBranch);
297 branchData.
B = Eigen::Map<Eigen::VectorXd>(B_vec.data(), nBranch);
299
300 LOG_DEBUG(
"PSS/E v{} file parsed: {} buses, {} branches (incl. transformers)",
301 version, nBus, nBranch);
302}
#define LOG_WARN(msg,...)
Macro for logging a warning-level message.
#define LOG_DEBUG(msg,...)
Macro for logging a debug-level message.
#define LOG_ERROR(msg,...)
Macro for logging an error-level message.
static std::vector< std::string > splitFields(const std::string &line)
static bool isSectionEnd(const std::string &line)
BranchData branchData
Parsed branch data.
BusData busData
Parsed bus data.
std::string stripQuotes(const std::string &s)
Strip surrounding single quotes and whitespace from a string.
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)