0001 function [MVAbase, bus, gen, branch, success, et] = ...
0002 runpf(casedata, mpopt, fname, solvedcase)
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 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0074 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0075 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0076 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0077 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0078 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0079 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0080 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0081
0082
0083 if nargin < 4
0084 solvedcase = '';
0085 if nargin < 3
0086 fname = '';
0087 if nargin < 2
0088 mpopt = mpoption;
0089 if nargin < 1
0090 casedata = 'case9';
0091 end
0092 end
0093 end
0094 end
0095
0096
0097 qlim = mpopt.pf.enforce_q_lims;
0098 dc = strcmp(upper(mpopt.model), 'DC');
0099
0100
0101 mpc = loadcase(casedata);
0102
0103
0104 if size(mpc.branch,2) < QT
0105 mpc.branch = [ mpc.branch zeros(size(mpc.branch, 1), QT-size(mpc.branch,2)) ];
0106 end
0107
0108
0109 mpc = ext2int(mpc, mpopt);
0110 [baseMVA, bus, gen, branch] = deal(mpc.baseMVA, mpc.bus, mpc.gen, mpc.branch);
0111
0112 if ~isempty(mpc.bus)
0113
0114 [ref, pv, pq] = bustypes(bus, gen);
0115
0116
0117 on = find(gen(:, GEN_STATUS) > 0);
0118 gbus = gen(on, GEN_BUS);
0119
0120
0121 t0 = tic;
0122 its = 0;
0123 if mpopt.verbose > 0
0124 v = mpver('all');
0125 fprintf('\nMATPOWER Version %s, %s', v.Version, v.Date);
0126 end
0127 if dc
0128 if mpopt.verbose > 0
0129 fprintf(' -- DC Power Flow\n');
0130 end
0131
0132 Va0 = bus(:, VA) * (pi/180);
0133
0134
0135 [B, Bf, Pbusinj, Pfinj] = makeBdc(baseMVA, bus, branch);
0136
0137
0138
0139 Pbus = real(makeSbus(baseMVA, bus, gen)) - Pbusinj - bus(:, GS) / baseMVA;
0140
0141
0142 [Va, success] = dcpf(B, Pbus, Va0, ref, pv, pq);
0143 its = 1;
0144
0145
0146 branch(:, [QF, QT]) = zeros(size(branch, 1), 2);
0147 branch(:, PF) = (Bf * Va + Pfinj) * baseMVA;
0148 branch(:, PT) = -branch(:, PF);
0149 bus(:, VM) = ones(size(bus, 1), 1);
0150 bus(:, VA) = Va * (180/pi);
0151
0152
0153
0154
0155 refgen = zeros(size(ref));
0156 for k = 1:length(ref)
0157 temp = find(gbus == ref(k));
0158 refgen(k) = on(temp(1));
0159 end
0160 gen(refgen, PG) = gen(refgen, PG) + (B(ref, :) * Va - Pbus(ref)) * baseMVA;
0161 else
0162 alg = upper(mpopt.pf.alg);
0163 switch alg
0164 case 'NR-SP'
0165 mpopt = mpoption(mpopt, 'pf.current_balance', 0, 'pf.v_cartesian', 0);
0166 case 'NR-SC'
0167 mpopt = mpoption(mpopt, 'pf.current_balance', 0, 'pf.v_cartesian', 1);
0168 case 'NR-SH'
0169 mpopt = mpoption(mpopt, 'pf.current_balance', 0, 'pf.v_cartesian', 2);
0170 case 'NR-IP'
0171 mpopt = mpoption(mpopt, 'pf.current_balance', 1, 'pf.v_cartesian', 0);
0172 case 'NR-IC'
0173 mpopt = mpoption(mpopt, 'pf.current_balance', 1, 'pf.v_cartesian', 1);
0174 case 'NR-IH'
0175 mpopt = mpoption(mpopt, 'pf.current_balance', 1, 'pf.v_cartesian', 2);
0176 end
0177 if mpopt.verbose > 0
0178 switch alg
0179 case {'NR', 'NR-SP'}
0180 solver = 'Newton';
0181 case 'NR-SC'
0182 solver = 'Newton-SC';
0183 case 'NR-SH'
0184 solver = 'Newton-SH';
0185 case 'NR-IP'
0186 solver = 'Newton-IP';
0187 case 'NR-IC'
0188 solver = 'Newton-IC';
0189 case 'NR-IH'
0190 solver = 'Newton-IH';
0191 case 'FDXB'
0192 solver = 'fast-decoupled, XB';
0193 case 'FDBX'
0194 solver = 'fast-decoupled, BX';
0195 case 'GS'
0196 solver = 'Gauss-Seidel';
0197 case 'PQSUM'
0198 solver = 'Power Summation';
0199 case 'ISUM'
0200 solver = 'Current Summation';
0201 case 'YSUM'
0202 solver = 'Admittance Summation';
0203 otherwise
0204 solver = 'unknown';
0205 end
0206 fprintf(' -- AC Power Flow (%s)\n', solver);
0207 end
0208 switch alg
0209 case {'NR', 'NR-SP', 'NR-SC', 'NR-SH', 'NR-IP', 'NR-IC', 'NR-IH'}
0210 otherwise
0211 if mpopt.pf.current_balance || mpopt.pf.v_cartesian
0212 error('runpf: power flow algorithm ''%s'' only supports power balance, polar version\nI.e. both ''pf.current_balance'' and ''pf.v_cartesian'' must be set to 0.');
0213 end
0214 end
0215 if have_zip_loads(mpopt)
0216 if mpopt.pf.current_balance || mpopt.pf.v_cartesian
0217 warnstr = 'Newton algorithm (current or cartesian/hybrid versions) do';
0218 elseif strcmp(alg, 'GS')
0219 warnstr = 'Gauss-Seidel algorithm does';
0220 else
0221 warnstr = '';
0222 end
0223 if warnstr
0224 warning('runpf: %s not support ZIP load model. Converting to constant power loads.', warnstr);
0225 mpopt = mpoption(mpopt, 'exp.sys_wide_zip_loads', ...
0226 struct('pw', [], 'qw', []));
0227 end
0228 end
0229
0230
0231
0232 V0 = bus(:, VM) .* exp(1j * pi/180 * bus(:, VA));
0233 vcb = ones(size(V0));
0234 vcb(pq) = 0;
0235 k = find(vcb(gbus));
0236 V0(gbus(k)) = gen(on(k), VG) ./ abs(V0(gbus(k))).* V0(gbus(k));
0237
0238 if qlim
0239 ref0 = ref;
0240 Varef0 = bus(ref0, VA);
0241 limited = [];
0242 fixedQg = zeros(size(gen, 1), 1);
0243 end
0244
0245
0246 [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch);
0247
0248 repeat = 1;
0249 while (repeat)
0250
0251
0252 Sbus = @(Vm)makeSbus(baseMVA, bus, gen, mpopt, Vm);
0253
0254
0255 switch alg
0256 case {'NR', 'NR-SP', 'NR-SC', 'NR-SH', 'NR-IP', 'NR-IC', 'NR-IH'}
0257 if mpopt.pf.current_balance
0258 switch mpopt.pf.v_cartesian
0259 case 0
0260 newtonpf_fcn = @newtonpf_I_polar;
0261 case 1
0262 newtonpf_fcn = @newtonpf_I_cart;
0263 case 2
0264 newtonpf_fcn = @newtonpf_I_hybrid;
0265 end
0266 else
0267 switch mpopt.pf.v_cartesian
0268 case 0
0269 newtonpf_fcn = @newtonpf;
0270 case 1
0271 newtonpf_fcn = @newtonpf_S_cart;
0272 case 2
0273 newtonpf_fcn = @newtonpf_S_hybrid;
0274 end
0275 end
0276 [V, success, iterations] = newtonpf_fcn(Ybus, Sbus, V0, ref, pv, pq, mpopt);
0277 case {'FDXB', 'FDBX'}
0278 [Bp, Bpp] = makeB(baseMVA, bus, branch, alg);
0279 [V, success, iterations] = fdpf(Ybus, Sbus, V0, Bp, Bpp, ref, pv, pq, mpopt);
0280 case 'GS'
0281 [V, success, iterations] = gausspf(Ybus, Sbus([]), V0, ref, pv, pq, mpopt);
0282 case {'PQSUM', 'ISUM', 'YSUM'}
0283 [mpc, success, iterations] = radial_pf(mpc, mpopt);
0284 otherwise
0285 error('runpf: ''%s'' is not a valid power flow algorithm. See ''pf.alg'' details in MPOPTION help.', alg);
0286 end
0287 its = its + iterations;
0288
0289
0290 switch alg
0291 case {'NR', 'NR-SP', 'NR-SC', 'NR-SH', 'NR-IP', 'NR-IC', 'NR-IH', 'FDXB', 'FDBX', 'GS'}
0292 [bus, gen, branch] = pfsoln(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V, ref, pv, pq, mpopt);
0293 case {'PQSUM', 'ISUM', 'YSUM'}
0294 bus = mpc.bus;
0295 gen = mpc.gen;
0296 branch = mpc.branch;
0297 end
0298
0299 if success && qlim
0300
0301 mx = find( gen(:, GEN_STATUS) > 0 ...
0302 & gen(:, QG) > gen(:, QMAX) + mpopt.opf.violation );
0303 mn = find( gen(:, GEN_STATUS) > 0 ...
0304 & gen(:, QG) < gen(:, QMIN) - mpopt.opf.violation );
0305
0306 if ~isempty(mx) || ~isempty(mn)
0307
0308 infeas = union(mx', mn')';
0309
0310 remaining = find( gen(:, GEN_STATUS) > 0 & ...
0311 ( bus(gen(:, GEN_BUS), BUS_TYPE) == PV | ...
0312 bus(gen(:, GEN_BUS), BUS_TYPE) == REF ));
0313 if length(infeas) == length(remaining) && all(infeas == remaining) && ...
0314 (isempty(mx) || isempty(mn))
0315
0316
0317 if mpopt.verbose
0318 fprintf('All %d remaining gens exceed their Q limits : INFEASIBLE PROBLEM\n', length(infeas));
0319 end
0320 success = 0;
0321 break;
0322 end
0323
0324
0325 if qlim == 2
0326 [junk, k] = max([gen(mx, QG) - gen(mx, QMAX);
0327 gen(mn, QMIN) - gen(mn, QG)]);
0328 if k > length(mx)
0329 mn = mn(k-length(mx));
0330 mx = [];
0331 else
0332 mx = mx(k);
0333 mn = [];
0334 end
0335 end
0336
0337 if mpopt.verbose && ~isempty(mx)
0338 fprintf('Gen %d at upper Q limit, converting to PQ bus\n', mx);
0339 end
0340 if mpopt.verbose && ~isempty(mn)
0341 fprintf('Gen %d at lower Q limit, converting to PQ bus\n', mn);
0342 end
0343
0344
0345 fixedQg(mx) = gen(mx, QMAX);
0346 fixedQg(mn) = gen(mn, QMIN);
0347 mx = [mx;mn];
0348
0349
0350 gen(mx, QG) = fixedQg(mx);
0351 if length(ref) > 1 && any(bus(gen(mx, GEN_BUS), BUS_TYPE) == REF)
0352 error('runpf: Sorry, MATPOWER cannot enforce Q limits for slack buses in systems with multiple slacks.');
0353 end
0354 bus(gen(mx, GEN_BUS), BUS_TYPE) = PQ;
0355
0356
0357 ref_temp = ref;
0358 [ref, pv, pq] = bustypes(bus, gen);
0359
0360
0361
0362 if ref ~= ref_temp
0363 bus(ref, BUS_TYPE) = REF;
0364 bus( pv, BUS_TYPE) = PV;
0365 if mpopt.verbose
0366 fprintf('Bus %d is new slack bus\n', ref);
0367 end
0368 end
0369 limited = [limited; mx];
0370 else
0371 repeat = 0;
0372 end
0373 else
0374 repeat = 0;
0375 end
0376 end
0377 if qlim && ~isempty(limited)
0378 if ref ~= ref0
0379
0380 bus(:, VA) = bus(:, VA) - bus(ref0, VA) + Varef0;
0381 end
0382 end
0383 end
0384 else
0385 t0 = tic;
0386 success = 0;
0387 its = 0;
0388 if mpopt.verbose
0389 fprintf('Power flow not valid : MATPOWER case contains no connected buses\n');
0390 end
0391 end
0392 mpc.et = toc(t0);
0393 mpc.success = success;
0394 mpc.iterations = its;
0395
0396
0397
0398 [mpc.bus, mpc.gen, mpc.branch] = deal(bus, gen, branch);
0399 results = int2ext(mpc);
0400
0401
0402 if ~isempty(results.order.gen.status.off)
0403 results.gen(results.order.gen.status.off, [PG QG]) = 0;
0404 end
0405 if ~isempty(results.order.branch.status.off)
0406 results.branch(results.order.branch.status.off, [PF QF PT QT]) = 0;
0407 end
0408
0409 if fname
0410 [fd, msg] = fopen(fname, 'at');
0411 if fd == -1
0412 error(msg);
0413 else
0414 if mpopt.out.all == 0
0415 printpf(results, fd, mpoption(mpopt, 'out.all', -1));
0416 else
0417 printpf(results, fd, mpopt);
0418 end
0419 fclose(fd);
0420 end
0421 end
0422 printpf(results, 1, mpopt);
0423
0424
0425 if solvedcase
0426 savecase(solvedcase, results);
0427 end
0428
0429 if nargout == 1 || nargout == 2
0430 MVAbase = results;
0431 bus = success;
0432 elseif nargout > 2
0433 [MVAbase, bus, gen, branch, et] = ...
0434 deal(results.baseMVA, results.bus, results.gen, results.branch, results.et);
0435
0436 end
0437
0438 function TorF = have_zip_loads(mpopt)
0439 if (~isempty(mpopt.exp.sys_wide_zip_loads.pw) && ...
0440 any(mpopt.exp.sys_wide_zip_loads.pw(2:3))) || ...
0441 (~isempty(mpopt.exp.sys_wide_zip_loads.qw) && ...
0442 any(mpopt.exp.sys_wide_zip_loads.qw(2:3)))
0443 TorF = 1;
0444 else
0445 TorF = 0;
0446 end