0001 function [results, success, raw] = ktropf_solver(om, mpopt)
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 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0051 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0052 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0053 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0054 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0055 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0056 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0057 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0058 [PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;
0059
0060
0061 use_ktropts_file = 1;
0062 create_ktropts_file = 0;
0063
0064
0065 mpc = om.get_mpc();
0066 [baseMVA, bus, gen, branch, gencost] = ...
0067 deal(mpc.baseMVA, mpc.bus, mpc.gen, mpc.branch, mpc.gencost);
0068 [vv, ll, nne, nni] = om.get_idx();
0069
0070
0071 nb = size(bus, 1);
0072 ng = size(gen, 1);
0073 nl = size(branch, 1);
0074 ny = om.getN('var', 'y');
0075
0076
0077 [A, l, u] = om.params_lin_constraint();
0078
0079
0080 [x0, xmin, xmax] = om.params_var();
0081
0082
0083
0084 ieq = find( abs(u-l) <= eps );
0085 igt = find( u >= 1e10 & l > -1e10 );
0086 ilt = find( l <= -1e10 & u < 1e10 );
0087 ibx = find( (abs(u-l) > eps) & (u < 1e10) & (l > -1e10) );
0088 Af = [ A(ilt, :); -A(igt, :); A(ibx, :); -A(ibx, :) ];
0089 bf = [ u(ilt); -l(igt); u(ibx); -l(ibx)];
0090 Afeq = A(ieq, :);
0091 bfeq = u(ieq);
0092
0093
0094 [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch);
0095
0096
0097 if mpopt.opf.start < 2
0098 s = 1;
0099 lb = xmin; ub = xmax;
0100 lb(xmin == -Inf) = -1e10;
0101 ub(xmax == Inf) = 1e10;
0102 x0 = (lb + ub) / 2;
0103 k = find(xmin == -Inf & xmax < Inf);
0104 x0(k) = xmax(k) - s;
0105 k = find(xmin > -Inf & xmax == Inf);
0106 x0(k) = xmin(k) + s;
0107 Varefs = bus(bus(:, BUS_TYPE) == REF, VA) * (pi/180);
0108 Vmax = min(bus(:, VMAX), 1.5);
0109 Vmin = max(bus(:, VMIN), 0.5);
0110 Vm = (Vmax + Vmin) / 2;
0111 if mpopt.opf.v_cartesian
0112 V = Vm * exp(1j*Varefs(1));
0113 x0(vv.i1.Vr:vv.iN.Vr) = real(V);
0114 x0(vv.i1.Vi:vv.iN.Vi) = imag(V);
0115 else
0116 x0(vv.i1.Va:vv.iN.Va) = Varefs(1);
0117 x0(vv.i1.Vm:vv.iN.Vm) = Vm;
0118 if ny > 0
0119 ipwl = find(gencost(:, MODEL) == PW_LINEAR);
0120 c = gencost(sub2ind(size(gencost), ipwl, NCOST+2*gencost(ipwl, NCOST)));
0121 x0(vv.i1.y:vv.iN.y) = max(c) + 0.1 * abs(max(c));
0122 end
0123 end
0124 end
0125
0126
0127 il = find(branch(:, RATE_A) ~= 0 & branch(:, RATE_A) < 1e10);
0128 nl2 = length(il);
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 randx = rand(size(x0));
0160 [h, g, dh, dg] = opf_consfcn(randx, om, Ybus, Yf(il,:), Yt(il,:), mpopt, il);
0161 Js = [dh'; dg'];
0162 lam = struct('eqnonlin', rand(size(dg,2),1), 'ineqnonlin', rand(size(dh,2),1) );
0163 Hs = opf_hessfcn(randx, lam, 1, om, Ybus, Yf(il,:), Yt(il,:), mpopt, il);
0164 neq = length(g);
0165 niq = length(h);
0166
0167
0168 hess_fcn = @(x, lambda)opf_hessfcn(x, lambda, 1, om, Ybus, Yf(il,:), Yt(il,:), mpopt, il);
0169 fmoptions = optimset('GradObj', 'on', 'GradConstr', 'on', ...
0170 'Hessian', 'user-supplied', 'HessFcn', hess_fcn, ...
0171 'JacobPattern', Js, 'HessPattern', Hs );
0172 if use_ktropts_file
0173 if ~isempty(mpopt.knitro.opt_fname)
0174 opt_fname = mpopt.knitro.opt_fname;
0175 elseif mpopt.knitro.opt
0176 opt_fname = sprintf('knitro_user_options_%d.txt', mpopt.knitro.opt);
0177 else
0178
0179 ktropts.algorithm = 1;
0180 ktropts.outlev = mpopt.verbose;
0181 ktropts.feastol = mpopt.opf.violation;
0182 ktropts.xtol = mpopt.knitro.tol_x;
0183 ktropts.opttol = mpopt.knitro.tol_f;
0184 if mpopt.knitro.maxit ~= 0
0185 ktropts.maxit = mpopt.knitro.maxit;
0186 end
0187 ktropts.bar_directinterval = 0;
0188 opt_fname = write_ktropts(ktropts);
0189 create_ktropts_file = 1;
0190 end
0191 else
0192 fmoptions = optimset(fmoptions, 'Algorithm', 'interior-point', ...
0193 'TolCon', mpopt.opf.violation, 'TolX', mpopt.knitro.tol_x, ...
0194 'TolFun', mpopt.knitro.tol_f );
0195 if mpopt.fmincon.max_it ~= 0
0196 fmoptions = optimset(fmoptions, 'MaxIter', mpopt.fmincon.max_it, ...
0197 'MaxFunEvals', 4 * mpopt.fmincon.max_it);
0198 end
0199 if mpopt.verbose == 0,
0200 fmoptions.Display = 'off';
0201 elseif mpopt.verbose == 1
0202 fmoptions.Display = 'iter';
0203 else
0204 fmoptions.Display = 'testing';
0205 end
0206 opt_fname = [];
0207 end
0208
0209
0210 f_fcn = @(x)opf_costfcn(x, om);
0211 gh_fcn = @(x)opf_consfcn(x, om, Ybus, Yf(il,:), Yt(il,:), mpopt, il);
0212 if have_fcn('knitromatlab')
0213 [x, f, info, Output, Lambda] = knitromatlab(f_fcn, x0, Af, bf, Afeq, bfeq, ...
0214 xmin, xmax, gh_fcn, [], fmoptions, opt_fname);
0215 else
0216 [x, f, info, Output, Lambda] = ktrlink(f_fcn, x0, Af, bf, Afeq, bfeq, ...
0217 xmin, xmax, gh_fcn, fmoptions, opt_fname);
0218 end
0219 success = (info == 0);
0220
0221
0222 if create_ktropts_file
0223 delete(opt_fname);
0224 end
0225
0226
0227 if mpopt.opf.v_cartesian
0228 Vi = x(vv.i1.Vi:vv.iN.Vi);
0229 Vr = x(vv.i1.Vr:vv.iN.Vr);
0230 V = Vr + 1j*Vi;
0231 Va = angle(V);
0232 Vm = abs(V);
0233 else
0234 Va = x(vv.i1.Va:vv.iN.Va);
0235 Vm = x(vv.i1.Vm:vv.iN.Vm);
0236 V = Vm .* exp(1j*Va);
0237 end
0238 Pg = x(vv.i1.Pg:vv.iN.Pg);
0239 Qg = x(vv.i1.Qg:vv.iN.Qg);
0240
0241
0242
0243 bus(:, VA) = Va * 180/pi;
0244 bus(:, VM) = Vm;
0245 gen(:, PG) = Pg * baseMVA;
0246 gen(:, QG) = Qg * baseMVA;
0247 gen(:, VG) = Vm(gen(:, GEN_BUS));
0248
0249
0250 Sf = V(branch(:, F_BUS)) .* conj(Yf * V);
0251 St = V(branch(:, T_BUS)) .* conj(Yt * V);
0252 branch(:, PF) = real(Sf) * baseMVA;
0253 branch(:, QF) = imag(Sf) * baseMVA;
0254 branch(:, PT) = real(St) * baseMVA;
0255 branch(:, QT) = imag(St) * baseMVA;
0256
0257
0258
0259 muSf = zeros(nl, 1);
0260 muSt = zeros(nl, 1);
0261 if ~isempty(il)
0262 if upper(mpopt.opf.flow_lim(1)) == 'P'
0263 muSf(il) = Lambda.ineqnonlin(nni.i1.Sf:nni.iN.Sf);
0264 muSt(il) = Lambda.ineqnonlin(nni.i1.St:nni.iN.St);
0265 else
0266 muSf(il) = 2 * Lambda.ineqnonlin(nni.i1.Sf:nni.iN.Sf) .* branch(il, RATE_A) / baseMVA;
0267 muSt(il) = 2 * Lambda.ineqnonlin(nni.i1.St:nni.iN.St) .* branch(il, RATE_A) / baseMVA;
0268 end
0269 end
0270
0271
0272
0273 kl = find(Lambda.lower > 0 & Lambda.upper == 0);
0274 Lambda.upper(kl) = Lambda.lower(kl);
0275 Lambda.lower(kl) = 0;
0276 ku = find(Lambda.upper < 0 & Lambda.lower == 0);
0277 Lambda.lower(ku) = Lambda.upper(ku);
0278 Lambda.upper(ku) = 0;
0279
0280
0281 if mpopt.opf.v_cartesian
0282 if om.userdata.veq
0283 lam = Lambda.eqnonlin(nne.i1.Veq:nne.iN.Veq);
0284 mu_Vmax = zeros(size(lam));
0285 mu_Vmin = zeros(size(lam));
0286 mu_Vmax(lam > 0) = lam(lam > 0);
0287 mu_Vmin(lam < 0) = -lam(lam < 0);
0288 bus(om.userdata.veq, MU_VMAX) = mu_Vmax;
0289 bus(om.userdata.veq, MU_VMIN) = mu_Vmin;
0290 end
0291 bus(om.userdata.viq, MU_VMAX) = Lambda.ineqnonlin(nni.i1.Vmax:nni.iN.Vmax);
0292 bus(om.userdata.viq, MU_VMIN) = Lambda.ineqnonlin(nni.i1.Vmin:nni.iN.Vmin);
0293 else
0294 bus(:, MU_VMAX) = Lambda.upper(vv.i1.Vm:vv.iN.Vm);
0295 bus(:, MU_VMIN) = -Lambda.lower(vv.i1.Vm:vv.iN.Vm);
0296 end
0297 gen(:, MU_PMAX) = Lambda.upper(vv.i1.Pg:vv.iN.Pg) / baseMVA;
0298 gen(:, MU_PMIN) = -Lambda.lower(vv.i1.Pg:vv.iN.Pg) / baseMVA;
0299 gen(:, MU_QMAX) = Lambda.upper(vv.i1.Qg:vv.iN.Qg) / baseMVA;
0300 gen(:, MU_QMIN) = -Lambda.lower(vv.i1.Qg:vv.iN.Qg) / baseMVA;
0301 if mpopt.opf.current_balance
0302
0303
0304
0305
0306
0307
0308 VV = V ./ (V .* conj(V));
0309 VVr = real(VV);
0310 VVi = imag(VV);
0311 lamM = Lambda.eqnonlin(nne.i1.rImis:nne.iN.rImis);
0312 lamN = Lambda.eqnonlin(nne.i1.iImis:nne.iN.iImis);
0313 bus(:, LAM_P) = (VVr.*lamM + VVi.*lamN) / baseMVA;
0314 bus(:, LAM_Q) = (VVi.*lamM - VVr.*lamN) / baseMVA;
0315 else
0316 bus(:, LAM_P) = Lambda.eqnonlin(nne.i1.Pmis:nne.iN.Pmis) / baseMVA;
0317 bus(:, LAM_Q) = Lambda.eqnonlin(nne.i1.Qmis:nne.iN.Qmis) / baseMVA;
0318 end
0319 branch(:, MU_SF) = muSf / baseMVA;
0320 branch(:, MU_ST) = muSt / baseMVA;
0321
0322
0323 nlnN = 2*nb + 2*nl;
0324 nlt = length(ilt);
0325 ngt = length(igt);
0326 nbx = length(ibx);
0327
0328
0329 kl = find(Lambda.eqnonlin < 0);
0330 ku = find(Lambda.eqnonlin > 0);
0331 nl_mu_l = zeros(nlnN, 1);
0332 nl_mu_u = [zeros(2*nb, 1); muSf; muSt];
0333 nl_mu_l(kl) = -Lambda.eqnonlin(kl);
0334 nl_mu_u(ku) = Lambda.eqnonlin(ku);
0335
0336
0337 kl = find(Lambda.eqlin < 0);
0338 ku = find(Lambda.eqlin > 0);
0339
0340 mu_l = zeros(size(u));
0341 mu_l(ieq(kl)) = -Lambda.eqlin(kl);
0342 mu_l(igt) = Lambda.ineqlin(nlt+(1:ngt));
0343 mu_l(ibx) = Lambda.ineqlin(nlt+ngt+nbx+(1:nbx));
0344
0345 mu_u = zeros(size(u));
0346 mu_u(ieq(ku)) = Lambda.eqlin(ku);
0347 mu_u(ilt) = Lambda.ineqlin(1:nlt);
0348 mu_u(ibx) = Lambda.ineqlin(nlt+ngt+(1:nbx));
0349
0350 mu = struct( ...
0351 'var', struct('l', -Lambda.lower, 'u', Lambda.upper), ...
0352 'nln', struct('l', nl_mu_l, 'u', nl_mu_u), ...
0353 'nle', Lambda.eqnonlin, ...
0354 'nli', Lambda.ineqnonlin, ...
0355 'lin', struct('l', mu_l, 'u', mu_u) );
0356
0357 results = mpc;
0358 [results.bus, results.branch, results.gen, ...
0359 results.om, results.x, results.mu, results.f] = ...
0360 deal(bus, branch, gen, om, x, mu, f);
0361
0362 pimul = [ ...
0363 results.mu.nln.l - results.mu.nln.u;
0364 results.mu.lin.l - results.mu.lin.u;
0365 -ones(ny>0, 1);
0366 results.mu.var.l - results.mu.var.u;
0367 ];
0368 raw = struct('xr', x, 'pimul', pimul, 'info', info, 'output', Output);
0369
0370
0371
0372 function fname = write_ktropts(ktropts)
0373
0374
0375 fname = sprintf('ktropts_%06d.txt', fix(1e6*rand));
0376
0377
0378 [fd, msg] = fopen(fname, 'wt');
0379 if fd == -1
0380 error('could not create %d : %s', fname, msg);
0381 end
0382
0383
0384 fields = fieldnames(ktropts);
0385 for k = 1:length(fields)
0386 fprintf(fd, '%s %g\n', fields{k}, ktropts.(fields{k}));
0387 end
0388
0389
0390 if fd ~= 1
0391 fclose(fd);
0392 end