0001 function [results, success, raw] = opf_execute(om, mpopt)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0020 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0021 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0022 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0023 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0024 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0025 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0026 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0027
0028
0029
0030 dc = strcmp(upper(mpopt.model), 'DC');
0031 alg = upper(mpopt.opf.ac.solver);
0032 sdp = strcmp(alg, 'SDPOPF');
0033 vcart = ~dc && mpopt.opf.v_cartesian;
0034
0035
0036 [vv, ll, nne, nni] = om.get_idx();
0037
0038 if mpopt.verbose > 0
0039 v = mpver('all');
0040 fprintf('\nMATPOWER Version %s, %s', v.Version, v.Date);
0041 end
0042
0043
0044 if dc
0045 if mpopt.verbose > 0
0046 fprintf(' -- DC Optimal Power Flow\n');
0047 end
0048 [results, success, raw] = dcopf_solver(om, mpopt);
0049 else
0050
0051 if mpopt.verbose > 0
0052 fprintf(' -- AC Optimal Power Flow\n AC OPF formulation: ');
0053 if sdp
0054 fprintf('SDP relaxation\n');
0055 else
0056 if vcart
0057 v = 'cartesian';
0058 else
0059 v = 'polar';
0060 end
0061 if mpopt.opf.current_balance
0062 v2 = 'current';
0063 else
0064 v2 = 'power';
0065 end
0066 fprintf('%s voltages, %s balance eqns\n', v, v2);
0067 end
0068 end
0069
0070
0071 if (~isempty(mpopt.exp.sys_wide_zip_loads.pw) && ...
0072 any(mpopt.exp.sys_wide_zip_loads.pw(2:3))) || ...
0073 (~isempty(mpopt.exp.sys_wide_zip_loads.qw) && ...
0074 any(mpopt.exp.sys_wide_zip_loads.qw(2:3)))
0075 switch alg
0076 case {'PDIPM', 'TRALM', 'MINOPF', 'SDPOPF'}
0077 warning('opf_execute: ''%s'' solver does not support ZIP load model. Converting to constant power loads.', alg)
0078 mpopt = mpoption(mpopt, 'exp.sys_wide_zip_loads', ...
0079 struct('pw', [], 'qw', []));
0080 end
0081 end
0082
0083
0084 switch alg
0085 case 'MIPS'
0086 [results, success, raw] = mipsopf_solver(om, mpopt);
0087 case 'IPOPT'
0088 if ~have_fcn('ipopt')
0089 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' requires IPOPT (see https://github.com/coin-or/Ipopt)', alg);
0090 end
0091 [results, success, raw] = ipoptopf_solver(om, mpopt);
0092 case 'PDIPM'
0093 if mpopt.pdipm.step_control
0094 if ~have_fcn('scpdipmopf')
0095 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' requires SCPDIPMOPF (see http://www.pserc.cornell.edu/tspopf/)', alg);
0096 end
0097 else
0098 if ~have_fcn('pdipmopf')
0099 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' requires PDIPMOPF (see http://www.pserc.cornell.edu/tspopf/)', alg);
0100 end
0101 end
0102 [results, success, raw] = tspopf_solver(om, mpopt);
0103 case 'TRALM'
0104 if ~have_fcn('tralmopf')
0105 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' requires TRALM (see http://www.pserc.cornell.edu/tspopf/)', alg);
0106 end
0107 [results, success, raw] = tspopf_solver(om, mpopt);
0108 case 'MINOPF'
0109 if ~have_fcn('minopf')
0110 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' requires MINOPF (see http://www.pserc.cornell.edu/minopf/)', alg);
0111 end
0112 [results, success, raw] = mopf_solver(om, mpopt);
0113 case 'FMINCON'
0114 if ~have_fcn('fmincon')
0115 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' requires FMINCON (Optimization Toolbox 2.x or later)', alg);
0116 end
0117 [results, success, raw] = fmincopf_solver(om, mpopt);
0118 case 'KNITRO'
0119 if ~have_fcn('knitro')
0120 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' requires Artelys Knitro (see https://www.artelys.com/solvers/knitro/)', alg);
0121 end
0122 [results, success, raw] = ktropf_solver(om, mpopt);
0123 case 'SDPOPF'
0124 if ~have_fcn('yalmip')
0125 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' requires YALMIP (see https://yalmip.github.io)', alg);
0126 end
0127 [results, success, raw] = sdpopf_solver(om, mpopt);
0128 otherwise
0129 error('opf_execute: MPOPT.opf.ac.solver = ''%s'' is not a valid AC OPF solver selection', alg);
0130 end
0131 end
0132 if ~isfield(raw, 'output') || ~isfield(raw.output, 'alg') || isempty(raw.output.alg)
0133 raw.output.alg = alg;
0134 end
0135
0136 if success
0137 if ~dc && ~sdp
0138
0139 results.gen(:, VG) = results.bus(results.gen(:, GEN_BUS), VM);
0140
0141
0142 if ll.N.PQh > 0 || ll.N.PQl > 0
0143 mu_PQh = results.mu.lin.l(ll.i1.PQh:ll.iN.PQh) - results.mu.lin.u(ll.i1.PQh:ll.iN.PQh);
0144 mu_PQl = results.mu.lin.l(ll.i1.PQl:ll.iN.PQl) - results.mu.lin.u(ll.i1.PQl:ll.iN.PQl);
0145 Apqdata = om.get_userdata('Apqdata');
0146 results.gen = update_mupq(results.baseMVA, results.gen, mu_PQh, mu_PQl, Apqdata);
0147 end
0148
0149
0150 if mpopt.opf.return_raw_der
0151
0152 if isfield(results, 'dg')
0153 raw.dg = results.dg;
0154 raw.g = results.g;
0155 end
0156
0157 if ~isfield(raw, 'dg')
0158 mpc = om.get_mpc();
0159 [Ybus, Yf, Yt] = makeYbus(mpc.baseMVA, mpc.bus, mpc.branch);
0160 [g, geq, dg, dgeq] = opf_consfcn(results.x, om, Ybus, Yf, Yt, mpopt);
0161 raw.g = [ geq; g];
0162 raw.dg = [ dgeq'; dg'];
0163 end
0164
0165 [f, df, d2f] = opf_costfcn(results.x, om);
0166 raw.df = df;
0167 raw.d2f = d2f;
0168 end
0169 end
0170
0171
0172 if isfield(results, 'dg')
0173 rmfield(results, 'dg');
0174 rmfield(results, 'g');
0175 end
0176
0177
0178 iang = om.get_userdata('iang');
0179 if ~sdp && length(iang)
0180 if vcart
0181 iang = om.get_userdata('iang');
0182 results.branch(iang, MU_ANGMIN) = results.mu.nli(nni.i1.angL:nni.iN.angL) * pi/180;
0183 results.branch(iang, MU_ANGMAX) = results.mu.nli(nni.i1.angU:nni.iN.angU) * pi/180;
0184 else
0185 iang = om.get_userdata('iang');
0186 results.branch(iang, MU_ANGMIN) = results.mu.lin.l(ll.i1.ang:ll.iN.ang) * pi/180;
0187 results.branch(iang, MU_ANGMAX) = results.mu.lin.u(ll.i1.ang:ll.iN.ang) * pi/180;
0188 end
0189 end
0190 else
0191
0192 if ~dc && mpopt.opf.return_raw_der
0193 raw.dg = [];
0194 raw.g = [];
0195 raw.df = [];
0196 raw.d2f = [];
0197 end
0198 end
0199
0200 if ~sdp
0201
0202 om_var_order = om.get('var', 'order');
0203 for k = 1:length(om_var_order)
0204 name = om_var_order(k).name;
0205 if om.getN('var', name)
0206 idx = vv.i1.(name):vv.iN.(name);
0207 results.var.val.(name) = results.x(idx);
0208 results.var.mu.l.(name) = results.mu.var.l(idx);
0209 results.var.mu.u.(name) = results.mu.var.u(idx);
0210 end
0211 end
0212
0213
0214 om_lin_order = om.get('lin', 'order');
0215 for k = 1:length(om_lin_order)
0216 name = om_lin_order(k).name;
0217 if om.getN('lin', name)
0218 idx = ll.i1.(name):ll.iN.(name);
0219 results.lin.mu.l.(name) = results.mu.lin.l(idx);
0220 results.lin.mu.u.(name) = results.mu.lin.u(idx);
0221 end
0222 end
0223
0224
0225 if ~dc
0226 om_nle_order = om.get('nle', 'order');
0227 for k = 1:length(om_nle_order)
0228 name = om_nle_order(k).name;
0229 if om.getN('nle', name)
0230 results.nle.lambda.(name) = results.mu.nle(nne.i1.(name):nne.iN.(name));
0231 end
0232 end
0233
0234 om_nli_order = om.get('nli', 'order');
0235 for k = 1:length(om_nli_order)
0236 name = om_nli_order(k).name;
0237 if om.getN('nli', name)
0238 results.nli.mu.(name) = results.mu.nli(nni.i1.(name):nni.iN.(name));
0239 end
0240 end
0241 end
0242
0243
0244 om_qdc_order = om.get('qdc', 'order');
0245 for k = 1:length(om_qdc_order)
0246 name = om_qdc_order(k).name;
0247 if om.getN('qdc', name)
0248 results.qdc.(name) = om.eval_quad_cost(results.x, name);
0249 end
0250 end
0251
0252
0253 om_nlc_order = om.get('nlc', 'order');
0254 for k = 1:length(om_nlc_order)
0255 name = om_nlc_order(k).name;
0256 if om.getN('nlc', name)
0257 results.nlc.(name) = om.eval_nln_cost(results.x, name);
0258 end
0259 end
0260
0261
0262 om_cost_order = om.get('cost', 'order');
0263 for k = 1:length(om_cost_order)
0264 name = om_cost_order(k).name;
0265 if om.getN('cost', name)
0266 results.cost.(name) = om.eval_legacy_cost(results.x, name);
0267 end
0268 end
0269
0270
0271
0272
0273 pwl1 = om.get_userdata('pwl1');
0274 if ~isempty(pwl1) && ~strcmp(alg, 'TRALM') && ~(strcmp(alg, 'PDIPM') && mpopt.pdipm.step_control)
0275
0276 vv = om.get_idx();
0277 if dc
0278 nx = vv.iN.Pg;
0279 else
0280 nx = vv.iN.Qg;
0281 end
0282 y = zeros(length(pwl1), 1);
0283 raw.xr = [ raw.xr(1:nx); y; raw.xr(nx+1:end)];
0284 results.x = [ results.x(1:nx); y; results.x(nx+1:end)];
0285 end
0286 end