0001 function [data, warns] = psse_parse(records, sections, verbose, rev)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 if nargin < 4
0059 rev = 0;
0060 if nargin < 3
0061 verbose = 0;
0062 end
0063 end
0064 defaultrev = 23;
0065
0066
0067 s = 1;
0068 warns = {};
0069
0070
0071
0072
0073
0074 if verbose
0075 if rev
0076 fprintf('Forcing interpretation as PSS/E revision %d\n', rev);
0077 else
0078 fprintf('Attempting to determine PSS/E revision from content.\n');
0079 end
0080 fprintf('Parsing case identification data ...');
0081 end
0082 if rev
0083 warns{end+1} = sprintf('Conversion explicitly using PSS/E revision %d', rev);
0084 end
0085 [d, c] = psse_parse_line(records{1}, 'dfdfff');
0086 nn = length(d);
0087 data.id.IC = d{1};
0088 if isempty(d{2}) || d{2} <= 0
0089 error('ERROR: Probable corrupt file, unable to read a valid SBASE value from the first line.');
0090 else
0091 data.id.SBASE = d{2};
0092 end
0093 if ~isempty(d{3})
0094 data.id.REV = d{3};
0095 else
0096 tmp = regexp(c, 'PSS(/|\(tm\))E-(?<rev>\d+)', 'tokens');
0097 if ~isempty(tmp) && size(tmp{1}, 2) == 2
0098 data.id.REV = str2num(tmp{1}{2});
0099 else
0100 data.id.REV = 0;
0101 end
0102 end
0103 if ~isempty(d{4})
0104 data.id.XFRRAT = d{4};
0105 else
0106 data.id.XFRRAT = 0;
0107 end
0108 if ~isempty(d{5})
0109 data.id.NXFRAT = d{5};
0110 else
0111 data.id.NXFRAT = 0;
0112 end
0113 if ~isempty(d{6})
0114 data.id.BASFRQ = d{6};
0115 else
0116 data.id.BASFRQ = 0;
0117 end
0118 data.id.comment0 = c;
0119 data.id.comment1 = records{2};
0120 data.id.comment2 = records{3};
0121 if verbose
0122 if rev
0123 if data.id.REV
0124 fprintf('.. override detected rev %2d w/%2d ... done.\n', data.id.REV, rev);
0125 else
0126 fprintf('...... unknown rev, using rev %2d ... done.\n', rev);
0127 end
0128 else
0129 if data.id.REV
0130 fprintf('......... rev %2d format detected ... done.\n', data.id.REV);
0131 else
0132 fprintf('...... unknown rev, using rev %2d ... done.\n', defaultrev);
0133 end
0134 end
0135 end
0136 if ~rev
0137 if data.id.REV
0138 rev = data.id.REV;
0139 else
0140 rev = defaultrev;
0141 data.id.REV = defaultrev;
0142 warns{end+1} = sprintf('Unknown REV, using REV %2d format.', defaultrev);
0143 end
0144 else
0145 data.id.REV = rev;
0146 end
0147 if isempty(data.id.IC) || data.id.IC ~= 0
0148 warns{end+1} = sprintf('IC = %d indicates that this may be a change case, rather than base case\n PSSE2MPC is NOT designed to handle change cases.', data.id.IC);
0149 if verbose
0150 fprintf('WARNING : %s\n', warns{end});
0151 end
0152 end
0153 s = s + 1;
0154
0155
0156 if rev < 24
0157 [data.bus, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0158 'bus', 'ddffffdffsfd');
0159 elseif rev < 31
0160 [data.bus, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0161 'bus', 'dsfdffddffd');
0162 else
0163 [data.bus, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0164 'bus', 'dsfddddffff..');
0165
0166 end
0167 s = s + 1;
0168
0169
0170 if rev >= 24
0171 [data.load, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0172 'load', 'd.d..ffffff...');
0173
0174 s = s + 1;
0175 end
0176
0177
0178 if rev > 30
0179 [data.shunt, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0180 'fixed shunt', 'd.dff');
0181
0182 s = s + 1;
0183 end
0184
0185
0186 [data.gen, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0187 'generator', 'd.fffff.f.....d.ff...........');
0188
0189 s = s + 1;
0190
0191
0192 if rev <= 27
0193 [data.branch, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0194 'branch', 'dd.ffffffffffffd');
0195
0196 elseif rev < 31
0197 [data.branch, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0198 'branch', 'dd.ffffffffffd');
0199
0200 else
0201 [data.branch, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0202 'branch', 'dd.ffffffffffd');
0203
0204 end
0205 s = s + 1;
0206
0207
0208 if rev <= 27
0209 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'transformer adjustment');
0210 end
0211
0212
0213 if rev > 27
0214
0215
0216
0217 label = 'transformer';
0218 if ~isempty(sections(s).name) && ~strcmpi(label, sections(s).name)
0219 if verbose > 1
0220 fprintf('----- WARNING: Expected section labeled: ''%s''\n', upper(label));
0221 fprintf('----- Found section labeled: ''%s''\n', sections(s).name);
0222 end
0223 end
0224
0225
0226 if verbose
0227 fprintf('Analyzing transformer types ...');
0228 end
0229
0230
0231 nt2 = round((sections(s).last - sections(s).first + 1) / 4);
0232 nt3 = round((sections(s).last - sections(s).first + 1) / 5);
0233
0234
0235 idx2 = zeros(nt2, 1);
0236 idx3 = zeros(nt3, 1);
0237
0238
0239 i = sections(s).first;
0240 i2 = 0;
0241 i3 = 0;
0242
0243 while i <= sections(s).last
0244
0245 pat = '[^''",\s/]+\s*(,|\s)\s*[^''",\s/]+\s*(,|\s)\s*([^''",\s/]+)';
0246 m = regexp(records{i}, pat, 'tokens', 'once');
0247 if length(m) ~= 3
0248 disp(m);
0249 error('m should be length 3');
0250 end
0251 if length(m{3}) == 1 && m{3}(1) == '0'
0252 i2 = i2 + 1;
0253 idx2(i2) = i;
0254 i = i + 4;
0255 else
0256 i3 = i3 + 1;
0257 idx3(i3) = i;
0258 i = i + 5;
0259 end
0260 end
0261 nt2 = i2;
0262 nt3 = i3;
0263
0264 if verbose
0265 str = sprintf(' %d(%d) two(three)-winding.', nt2, nt3);
0266 spacers = repmat('.', 1, 36-length(str));
0267 fprintf('%s %s ... done.\n', spacers, str);
0268 end
0269
0270
0271 idx2 = idx2(1:nt2);
0272 idx3 = idx3(1:nt3);
0273
0274
0275 [t2_1, warns] = psse_parse_section(warns, records(idx2), verbose, ...
0276 '2-winding transformers (1)', 'dd..ddd....d........');
0277
0278 [t3_1, warns] = psse_parse_section(warns, records(idx3), verbose, ...
0279 '3-winding transformers (1)', 'ddd.ddd....d........');
0280
0281
0282
0283
0284 [t2_2, warns] = psse_parse_section(warns, records(idx2+1), verbose, ...
0285 '2-winding transformers (2)', 'fff');
0286
0287
0288
0289 [t2_3, warns] = psse_parse_section(warns, records(idx2+2), verbose, ...
0290 '2-winding transformers (3)', 'ffffff..........');
0291
0292
0293
0294 [t2_4, warns] = psse_parse_section(warns, records(idx2+3), verbose, ...
0295 '2-winding transformers (4)', 'ff');
0296
0297
0298
0299 [t3_2, warns] = psse_parse_section(warns, records(idx3+1), verbose, ...
0300 '3-winding transformers (2)', 'fffffffffff');
0301
0302
0303
0304
0305 [t3_3, warns] = psse_parse_section(warns, records(idx3+2), verbose, ...
0306 '3-winding transformers (3)', 'ffffff..........');
0307
0308
0309
0310
0311 [t3_4, warns] = psse_parse_section(warns, records(idx3+3), verbose, ...
0312 '3-winding transformers (4)', 'ffffff..........');
0313
0314
0315
0316
0317 [t3_5, warns] = psse_parse_section(warns, records(idx3+4), verbose, ...
0318 '3-winding transformers (5)', 'ffffff..........');
0319
0320
0321
0322 data.trans2.num = [t2_1.num(:, 1:20) t2_2.num(:, 1:3) t2_3.num(:, 1:16) t2_4.num(:, 1:2)];
0323 data.trans2.txt = [t2_1.txt(:, 1:20) t2_2.txt(:, 1:3) t2_3.txt(:, 1:16) t2_4.txt(:, 1:2)];
0324
0325
0326 data.trans3.num = [t3_1.num(:, 1:20) t3_2.num(:, 1:11) t3_3.num(:, 1:16) t3_4.num(:, 1:16) t3_5.num(:, 1:16)];
0327 data.trans3.txt = [t3_1.txt(:, 1:20) t3_2.txt(:, 1:11) t3_3.txt(:, 1:16) t3_4.txt(:, 1:16) t3_5.txt(:, 1:16)];
0328
0329
0330
0331
0332
0333 s = s + 1;
0334 end
0335
0336
0337 [data.area, warns] = psse_parse_section(warns, records, sections, s, verbose, 'area', 'ddffs');
0338 s = s + 1;
0339
0340
0341 label = 'two-terminal DC';
0342 if ~isempty(sections(s).name) && ~strcmpi(label, sections(s).name)
0343 if verbose > 1
0344 fprintf('----- WARNING: Expected section labeled: ''%s''\n', upper(label));
0345 fprintf('----- Found section labeled: ''%s''\n', sections(s).name);
0346 end
0347 end
0348 idx = sections(s).first:3:sections(s).last;
0349 if rev < 31
0350 [dc1, warns] = psse_parse_section(warns, records(idx), verbose, ...
0351 'two-terminal DC (1)', '.d.ff.......');
0352
0353 [dc2, warns] = psse_parse_section(warns, records(idx+1), verbose, ...
0354 'two-terminal DC (2)', 'd.ff.............');
0355
0356 [dc3, warns] = psse_parse_section(warns, records(idx+2), verbose, ...
0357 'two-terminal DC (3)', 'd.ff.............');
0358
0359 else
0360 [dc1, warns] = psse_parse_section(warns, records(idx), verbose, ...
0361 'two-terminal DC (1)', '.d.ff.......');
0362
0363 [dc2, warns] = psse_parse_section(warns, records(idx+1), verbose, ...
0364 'two-terminal DC (2)', 'd.ff.............');
0365
0366 [dc3, warns] = psse_parse_section(warns, records(idx+2), verbose, ...
0367 'two-terminal DC (3)', 'd.ff.............');
0368
0369 end
0370
0371
0372 data.twodc.num = [dc1.num dc2.num dc3.num];
0373 data.twodc.txt = [dc1.txt dc2.txt dc3.txt];
0374
0375
0376
0377
0378 s = s + 1;
0379
0380
0381 if rev > 28
0382 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'voltage source converter');
0383 end
0384
0385
0386 if rev < 31
0387
0388 if rev <= 27
0389 [data.swshunt, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0390 'switched shunt', 'd....f');
0391
0392 elseif rev <= 29
0393 [data.swshunt, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0394 'switched shunt', 'd.....f');
0395
0396 else
0397 [data.swshunt, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0398 'switched shunt', 'd......f');
0399
0400 end
0401 s = s + 1;
0402 end
0403
0404
0405 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'impedance correction');
0406
0407
0408 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'multi-terminal DC');
0409
0410
0411 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'multi-section line');
0412
0413
0414 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'zone');
0415
0416
0417 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'inter-area transfer');
0418
0419
0420 if rev > 24
0421 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'owner');
0422 end
0423
0424
0425 if rev > 25
0426 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'FACTS control device');
0427 end
0428
0429
0430 if rev > 30
0431
0432 if rev < 32
0433 [data.swshunt, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0434 'switched shunt', 'd......f');
0435
0436 else
0437 [data.swshunt, warns] = psse_parse_section(warns, records, sections, s, verbose, ...
0438 'switched shunt', 'd........f');
0439
0440 end
0441 s = s + 1;
0442 end
0443
0444
0445 if rev > 31
0446 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'GNE device');
0447 end
0448
0449
0450 if rev > 32
0451 [s, warns] = psse_skip_section(warns, sections, s, verbose, 'induction machine');
0452 end
0453
0454
0455 if s <= length(sections)
0456 warns{end+1} = sprintf('Found %d additional section(s)', length(sections)-s+1);
0457 if verbose > 1
0458 fprintf('----- WARNING: Found %d additional section(s):\n', length(sections)-s+1);
0459 end
0460 end
0461 while s <= length(sections)
0462 n = sections(s).last - sections(s).first + 1;
0463 if n
0464 str = sprintf('with %d line(s)', n);
0465 else
0466 str = sprintf('(empty)');
0467 end
0468 if isempty(sections(s).name)
0469 warns{end+1} = sprintf(' unlabeled section %s', str);
0470 if verbose > 1
0471 fprintf('----- unlabeled section %s\n', str);
0472 end
0473 else
0474 warns{end+1} = sprintf(' ''%s DATA'' %s', sections(s).name, str);
0475 if verbose > 1
0476 fprintf('----- ''%s DATA'' %s\n', sections(s).name, str);
0477 end
0478 end
0479 s = s + 1;
0480 end
0481
0482
0483
0484
0485 function [s, warns] = psse_skip_section(warns, sections, s, verbose, label)
0486
0487
0488
0489 if s > length(sections)
0490 if verbose
0491 spacers = repmat('.', 1, 58-length(label));
0492 fprintf('No %s data read %s done.\n', label, spacers);
0493 end
0494 else
0495 nr = sections(s).last - sections(s).first + 1;
0496 if nr > 1
0497 ss = 'lines';
0498 else
0499 ss = 'line';
0500 end
0501 if nr
0502 warns{end+1} = sprintf('Skipped %d %s of %s data.', nr, ss, label);
0503 end
0504 if ~isempty(sections(s).name) && ~strcmp(upper(label), sections(s).name)
0505 warns{end+1} = sprintf('Section label mismatch, found ''%s'', expected ''%s''', ...
0506 sections(s).name, upper(label));
0507 if verbose
0508 fprintf('----- WARNING: Found section labeled: ''%s''\n', sections(s).name);
0509 fprintf('----- Expected section labeled: ''%s''\n', upper(label));
0510 end
0511 end
0512 if verbose && nr
0513 spacers = repmat('.', 1, 47-length(ss)-length(label));
0514 fprintf('Skipping%6d %s of %s data %s done.\n', nr, ss, label, spacers);
0515 end
0516 s = s + 1;
0517 end