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