Home > matpower4.0 > ipoptopf_solver.m

ipoptopf_solver

PURPOSE ^

IPOPTOPF_SOLVER Solves AC optimal power flow using MIPS.

SYNOPSIS ^

function [results, success, raw] = ipoptopf_solver(om, mpopt)

DESCRIPTION ^

IPOPTOPF_SOLVER  Solves AC optimal power flow using MIPS.

   [RESULTS, SUCCESS, RAW] = IPOPTOPF_SOLVER(OM, MPOPT)

   Inputs are an OPF model object and a MATPOWER options vector.

   Outputs are a RESULTS struct, SUCCESS flag and RAW output struct.

   RESULTS is a MATPOWER case struct (mpc) with the usual baseMVA, bus
   branch, gen, gencost fields, along with the following additional
   fields:
       .order      see 'help ext2int' for details of this field
       .x          final value of optimization variables (internal order)
       .f          final objective function value
       .mu         shadow prices on ...
           .var
               .l  lower bounds on variables
               .u  upper bounds on variables
           .nln
               .l  lower bounds on nonlinear constraints
               .u  upper bounds on nonlinear constraints
           .lin
               .l  lower bounds on linear constraints
               .u  upper bounds on linear constraints

   SUCCESS     1 if solver converged successfully, 0 otherwise

   RAW         raw output in form returned by MINOS
       .xr     final value of optimization variables
       .pimul  constraint multipliers
       .info   solver specific termination code
       .output solver specific output information

   See also OPF, MIPS.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [results, success, raw] = ipoptopf_solver(om, mpopt)
0002 %IPOPTOPF_SOLVER  Solves AC optimal power flow using MIPS.
0003 %
0004 %   [RESULTS, SUCCESS, RAW] = IPOPTOPF_SOLVER(OM, MPOPT)
0005 %
0006 %   Inputs are an OPF model object and a MATPOWER options vector.
0007 %
0008 %   Outputs are a RESULTS struct, SUCCESS flag and RAW output struct.
0009 %
0010 %   RESULTS is a MATPOWER case struct (mpc) with the usual baseMVA, bus
0011 %   branch, gen, gencost fields, along with the following additional
0012 %   fields:
0013 %       .order      see 'help ext2int' for details of this field
0014 %       .x          final value of optimization variables (internal order)
0015 %       .f          final objective function value
0016 %       .mu         shadow prices on ...
0017 %           .var
0018 %               .l  lower bounds on variables
0019 %               .u  upper bounds on variables
0020 %           .nln
0021 %               .l  lower bounds on nonlinear constraints
0022 %               .u  upper bounds on nonlinear constraints
0023 %           .lin
0024 %               .l  lower bounds on linear constraints
0025 %               .u  upper bounds on linear constraints
0026 %
0027 %   SUCCESS     1 if solver converged successfully, 0 otherwise
0028 %
0029 %   RAW         raw output in form returned by MINOS
0030 %       .xr     final value of optimization variables
0031 %       .pimul  constraint multipliers
0032 %       .info   solver specific termination code
0033 %       .output solver specific output information
0034 %
0035 %   See also OPF, MIPS.
0036 
0037 %   MATPOWER
0038 %   $Id: ipoptopf_solver.m,v 1.4 2010/06/09 14:56:58 ray Exp $
0039 %   by Ray Zimmerman, PSERC Cornell
0040 %   and Carlos E. Murillo-Sanchez, PSERC Cornell & Universidad Autonoma de Manizales
0041 %   Copyright (c) 2000-2010 by Power System Engineering Research Center (PSERC)
0042 %
0043 %   This file is part of MATPOWER.
0044 %   See http://www.pserc.cornell.edu/matpower/ for more info.
0045 %
0046 %   MATPOWER is free software: you can redistribute it and/or modify
0047 %   it under the terms of the GNU General Public License as published
0048 %   by the Free Software Foundation, either version 3 of the License,
0049 %   or (at your option) any later version.
0050 %
0051 %   MATPOWER is distributed in the hope that it will be useful,
0052 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
0053 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0054 %   GNU General Public License for more details.
0055 %
0056 %   You should have received a copy of the GNU General Public License
0057 %   along with MATPOWER. If not, see <http://www.gnu.org/licenses/>.
0058 %
0059 %   Additional permission under GNU GPL version 3 section 7
0060 %
0061 %   If you modify MATPOWER, or any covered work, to interface with
0062 %   other modules (such as MATLAB code and MEX-files) available in a
0063 %   MATLAB(R) or comparable environment containing parts covered
0064 %   under other licensing terms, the licensors of MATPOWER grant
0065 %   you additional permission to convey the resulting work.
0066 
0067 %%----- initialization -----
0068 %% define named indices into data matrices
0069 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0070     VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0071 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0072     MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0073     QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0074 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0075     TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0076     ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0077 [PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;
0078 
0079 %% options
0080 verbose = mpopt(31);    %% VERBOSE
0081 feastol = mpopt(81);    %% PDIPM_FEASTOL
0082 gradtol = mpopt(82);    %% PDIPM_GRADTOL
0083 comptol = mpopt(83);    %% PDIPM_COMPTOL
0084 costtol = mpopt(84);    %% PDIPM_COSTTOL
0085 max_it  = mpopt(85);    %% PDIPM_MAX_IT
0086 max_red = mpopt(86);    %% SCPDIPM_RED_IT
0087 step_control = (mpopt(11) == 565);  %% OPF_ALG == 565, MIPS-sc
0088 if feastol == 0
0089     feastol = mpopt(16);    %% = OPF_VIOLATION by default
0090 end
0091 opt = struct(   'feastol', feastol, ...
0092                 'gradtol', gradtol, ...
0093                 'comptol', comptol, ...
0094                 'costtol', costtol, ...
0095                 'max_it', max_it, ...
0096                 'max_red', max_red, ...
0097                 'step_control', step_control, ...
0098                 'cost_mult', 1e-4, ...
0099                 'verbose', verbose  );
0100 
0101 %% unpack data
0102 mpc = get_mpc(om);
0103 [baseMVA, bus, gen, branch, gencost] = ...
0104     deal(mpc.baseMVA, mpc.bus, mpc.gen, mpc.branch, mpc.gencost);
0105 [vv, ll, nn] = get_idx(om);
0106 
0107 %% problem dimensions
0108 nb = size(bus, 1);          %% number of buses
0109 ng = size(gen, 1);          %% number of buses
0110 nl = size(branch, 1);       %% number of branches
0111 ny = getN(om, 'var', 'y');  %% number of piece-wise linear costs
0112 
0113 %% linear constraints
0114 [A, l, u] = linear_constraints(om);
0115 
0116 %% bounds on optimization vars
0117 [x0, xmin, xmax] = getv(om);
0118 
0119 %% build admittance matrices
0120 [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch);
0121 
0122 %% try to select an interior initial point
0123 ll = xmin; uu = xmax;
0124 ll(xmin == -Inf) = -1e10;   %% replace Inf with numerical proxies
0125 uu(xmax ==  Inf) =  1e10;
0126 x0 = (ll + uu) / 2;
0127 Varefs = bus(bus(:, BUS_TYPE) == REF, VA) * (pi/180);
0128 x0(vv.i1.Va:vv.iN.Va) = Varefs(1);  %% angles set to first reference angle
0129 if ny > 0
0130     ipwl = find(gencost(:, MODEL) == PW_LINEAR);
0131 %     PQ = [gen(:, PMAX); gen(:, QMAX)];
0132 %     c = totcost(gencost(ipwl, :), PQ(ipwl));
0133     c = gencost(sub2ind(size(gencost), ipwl, NCOST+2*gencost(ipwl, NCOST)));    %% largest y-value in CCV data
0134     x0(vv.i1.y:vv.iN.y) = max(c) + 0.1 * abs(max(c));
0135 %     x0(vv.i1.y:vv.iN.y) = c + 0.1 * abs(c);
0136 end
0137 
0138 %% find branches with flow limits
0139 il = find(branch(:, RATE_A) ~= 0 & branch(:, RATE_A) < 1e10);
0140 nl2 = length(il);           %% number of constrained lines
0141 
0142 %%-----  run opf  -----
0143 %% build Jacobian and Hessian structure
0144 nA = size(A, 1);                %% number of original linear constraints
0145 nx = length(x0);
0146 f = branch(:, F_BUS);                           %% list of "from" buses
0147 t = branch(:, T_BUS);                           %% list of "to" buses
0148 Cf = sparse(1:nl, f, ones(nl, 1), nl, nb);      %% connection matrix for line & from buses
0149 Ct = sparse(1:nl, t, ones(nl, 1), nl, nb);      %% connection matrix for line & to buses
0150 Cl = Cf + Ct;
0151 Cb = Cl' * Cl + speye(nb);
0152 Cl2 = Cl(il, :);
0153 Cg = sparse(gen(:, GEN_BUS), (1:ng)', 1, nb, ng);
0154 nz = nx - 2*(nb+ng);
0155 nxtra = nx - 2*nb;
0156 Js = [
0157     Cb      Cb      Cg              sparse(nb,ng)   sparse(nb,nz);
0158     Cb      Cb      sparse(nb,ng)   Cg              sparse(nb,nz);
0159     Cl2     Cl2     sparse(nl2, 2*ng)               sparse(nl2,nz);
0160     Cl2     Cl2     sparse(nl2, 2*ng)               sparse(nl2,nz);
0161     A;
0162 ];
0163 [f, df, d2f] = opf_costfcn(x0, om);
0164 Hs = tril(d2f + [
0165     Cb  Cb  sparse(nb,nxtra);
0166     Cb  Cb  sparse(nb,nxtra);
0167     sparse(nxtra,nx);
0168 ]);
0169 
0170 %% set options struct for IPOPT
0171 options.ipopt = ipopt_options([], mpopt);
0172 
0173 %% extra data to pass to functions
0174 options.auxdata = struct( ...
0175     'om',       om, ...
0176     'Ybus',     Ybus, ...
0177     'Yf',       Yf(il,:), ...
0178     'Yt',       Yt(il,:), ...
0179     'mpopt',    mpopt, ...
0180     'il',       il, ...
0181     'A',        A, ...
0182     'nA',       nA, ...
0183     'neqnln',   2*nb, ...
0184     'niqnln',   2*nl2, ...
0185     'Js',       Js, ...
0186     'Hs',       Hs    );
0187 
0188 % %% check Jacobian and Hessian structure
0189 % xr                  = rand(size(x0));
0190 % lambda              = rand(2*nb+2*nl2, 1);
0191 % options.auxdata.Js  = jacobian(xr, options.auxdata);
0192 % options.auxdata.Hs  = tril(hessian(xr, 1, lambda, options.auxdata));
0193 % Js1 = options.auxdata.Js;
0194 % options.auxdata.Js = Js;
0195 % Hs1 = options.auxdata.Hs;
0196 % [i1, j1, s] = find(Js);
0197 % [i2, j2, s] = find(Js1);
0198 % if length(i1) ~= length(i2) || norm(i1-i2) ~= 0 || norm(j1-j2) ~= 0
0199 %     error('something''s wrong with the Jacobian structure');
0200 % end
0201 % [i1, j1, s] = find(Hs);
0202 % [i2, j2, s] = find(Hs1);
0203 % if length(i1) ~= length(i2) || norm(i1-i2) ~= 0 || norm(j1-j2) ~= 0
0204 %     error('something''s wrong with the Hessian structure');
0205 % end
0206 
0207 %% define variable and constraint bounds
0208 options.lb = xmin;
0209 options.ub = xmax;
0210 options.cl = [zeros(2*nb, 1); -Inf*ones(2*nl2, 1); l];
0211 options.cu = [zeros(2*nb, 1);     zeros(2*nl2, 1); u];
0212 
0213 %% assign function handles
0214 funcs.objective         = @objective;
0215 funcs.gradient          = @gradient;
0216 funcs.constraints       = @constraints;
0217 funcs.jacobian          = @jacobian;
0218 funcs.hessian           = @hessian;
0219 funcs.jacobianstructure = @(d) Js;
0220 funcs.hessianstructure  = @(d) Hs;
0221 %funcs.jacobianstructure = @jacobianstructure;
0222 %funcs.hessianstructure  = @hessianstructure;
0223 
0224 %% run the optimization
0225 [x, info] = ipopt(x0,funcs,options);
0226 
0227 if info.status == 0 || info.status == 1
0228     success = 1;
0229 else
0230     success = 0;
0231 end
0232 if isfield(info, 'iter')
0233     output.iterations = info.iter;
0234 else
0235     output.iterations = [];
0236 end
0237 f = opf_costfcn(x, om);
0238 
0239 %% update solution data
0240 Va = x(vv.i1.Va:vv.iN.Va);
0241 Vm = x(vv.i1.Vm:vv.iN.Vm);
0242 Pg = x(vv.i1.Pg:vv.iN.Pg);
0243 Qg = x(vv.i1.Qg:vv.iN.Qg);
0244 V = Vm .* exp(1j*Va);
0245 
0246 %%-----  calculate return values  -----
0247 %% update voltages & generator outputs
0248 bus(:, VA) = Va * 180/pi;
0249 bus(:, VM) = Vm;
0250 gen(:, PG) = Pg * baseMVA;
0251 gen(:, QG) = Qg * baseMVA;
0252 gen(:, VG) = Vm(gen(:, GEN_BUS));
0253 
0254 %% compute branch flows
0255 Sf = V(branch(:, F_BUS)) .* conj(Yf * V);  %% cplx pwr at "from" bus, p.u.
0256 St = V(branch(:, T_BUS)) .* conj(Yt * V);  %% cplx pwr at "to" bus, p.u.
0257 branch(:, PF) = real(Sf) * baseMVA;
0258 branch(:, QF) = imag(Sf) * baseMVA;
0259 branch(:, PT) = real(St) * baseMVA;
0260 branch(:, QT) = imag(St) * baseMVA;
0261 
0262 %% line constraint is actually on square of limit
0263 %% so we must fix multipliers
0264 muSf = zeros(nl, 1);
0265 muSt = zeros(nl, 1);
0266 if ~isempty(il)
0267     muSf(il) = 2 * info.lambda(2*nb+    (1:nl2)) .* branch(il, RATE_A) / baseMVA;
0268     muSt(il) = 2 * info.lambda(2*nb+nl2+(1:nl2)) .* branch(il, RATE_A) / baseMVA;
0269 end
0270 
0271 %% update Lagrange multipliers
0272 bus(:, MU_VMAX)  = info.zu(vv.i1.Vm:vv.iN.Vm);
0273 bus(:, MU_VMIN)  = info.zl(vv.i1.Vm:vv.iN.Vm);
0274 gen(:, MU_PMAX)  = info.zu(vv.i1.Pg:vv.iN.Pg) / baseMVA;
0275 gen(:, MU_PMIN)  = info.zl(vv.i1.Pg:vv.iN.Pg) / baseMVA;
0276 gen(:, MU_QMAX)  = info.zu(vv.i1.Qg:vv.iN.Qg) / baseMVA;
0277 gen(:, MU_QMIN)  = info.zl(vv.i1.Qg:vv.iN.Qg) / baseMVA;
0278 bus(:, LAM_P)    = info.lambda(nn.i1.Pmis:nn.iN.Pmis) / baseMVA;
0279 bus(:, LAM_Q)    = info.lambda(nn.i1.Qmis:nn.iN.Qmis) / baseMVA;
0280 branch(:, MU_SF) = muSf / baseMVA;
0281 branch(:, MU_ST) = muSt / baseMVA;
0282 
0283 %% package up results
0284 nlnN = getN(om, 'nln');
0285 
0286 %% extract multipliers for nonlinear constraints
0287 kl = find(info.lambda(1:2*nb) < 0);
0288 ku = find(info.lambda(1:2*nb) > 0);
0289 nl_mu_l = zeros(nlnN, 1);
0290 nl_mu_u = [zeros(2*nb, 1); muSf; muSt];
0291 nl_mu_l(kl) = -info.lambda(kl);
0292 nl_mu_u(ku) =  info.lambda(ku);
0293 
0294 %% extract multipliers for linear constraints
0295 lam_lin = info.lambda(2*nb+2*nl2+(1:nA));   %% lambda for linear constraints
0296 kl = find(lam_lin < 0);                     %% lower bound binding
0297 ku = find(lam_lin > 0);                     %% upper bound binding
0298 mu_l = zeros(nA, 1);
0299 mu_l(kl) = -lam_lin(kl);
0300 mu_u = zeros(nA, 1);
0301 mu_u(ku) = lam_lin(ku);
0302 
0303 mu = struct( ...
0304   'var', struct('l', info.zl, 'u', info.zu), ...
0305   'nln', struct('l', nl_mu_l, 'u', nl_mu_u), ...
0306   'lin', struct('l', mu_l, 'u', mu_u) );
0307 
0308 results = mpc;
0309 [results.bus, results.branch, results.gen, ...
0310     results.om, results.x, results.mu, results.f] = ...
0311         deal(bus, branch, gen, om, x, mu, f);
0312 
0313 pimul = [ ...
0314   results.mu.nln.l - results.mu.nln.u;
0315   results.mu.lin.l - results.mu.lin.u;
0316   -ones(ny>0, 1);
0317   results.mu.var.l - results.mu.var.u;
0318 ];
0319 raw = struct('xr', x, 'pimul', pimul, 'info', info.status, 'output', output);
0320 
0321 
0322 %-----  callback functions  -----
0323 function f = objective(x, d)
0324 f = opf_costfcn(x, d.om);
0325 
0326 function df = gradient(x, d)
0327 [f, df] = opf_costfcn(x, d.om);
0328 
0329 function c = constraints(x, d)
0330 [hn, gn] = opf_consfcn(x, d.om, d.Ybus, d.Yf, d.Yt, d.mpopt, d.il);
0331 if isempty(d.A)
0332     c = [gn; hn];
0333 else
0334     c = [gn; hn; d.A*x];
0335 end
0336 
0337 function J = jacobian(x, d)
0338 [hn, gn, dhn, dgn] = opf_consfcn(x, d.om, d.Ybus, d.Yf, d.Yt, d.mpopt, d.il);
0339 J = [dgn'; dhn'; d.A];
0340 
0341 function H = hessian(x, sigma, lambda, d)
0342 lam.eqnonlin   = lambda(1:d.neqnln);
0343 lam.ineqnonlin = lambda(d.neqnln+(1:d.niqnln));
0344 H = tril(opf_hessfcn(x, lam, sigma, d.om, d.Ybus, d.Yf, d.Yt, d.mpopt, d.il));
0345 
0346 % function Js = jacobianstructure(d)
0347 % Js = d.Js;
0348 %
0349 % function Hs = hessianstructure(d)
0350 % Hs = d.Hs;

Generated on Mon 26-Jan-2015 14:56:45 by m2html © 2005