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