Home > matpower6.0 > extras > misc > make_opf_feasible.m

make_opf_feasible

PURPOSE ^

MAKE_OPF_FEASIBLE Attempts to relax constraints to make an OPF feasible.

SYNOPSIS ^

function [r, chgs] = make_opf_feasible(mpc, mpopt)

DESCRIPTION ^

MAKE_OPF_FEASIBLE Attempts to relax constraints to make an OPF feasible.
   [RESULTS, CHGS] = MAKE_OPF_FEASIBLE(MPC, MPOPT) 

   Attempts to automate the process of finding a feasible OPF solution when
   starting with an infeasible case.

   MPC - initial (possibly infeasible) MATPOWER case struct
   MPOPT - (optional) MATPOWER options struct.

   Work-in-progress:   CHGS are currently not returned.
                       At this point, the code *is* the documentation.

   See also RUNOPF.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [r, chgs] = make_opf_feasible(mpc, mpopt)
0002 %MAKE_OPF_FEASIBLE Attempts to relax constraints to make an OPF feasible.
0003 %   [RESULTS, CHGS] = MAKE_OPF_FEASIBLE(MPC, MPOPT)
0004 %
0005 %   Attempts to automate the process of finding a feasible OPF solution when
0006 %   starting with an infeasible case.
0007 %
0008 %   MPC - initial (possibly infeasible) MATPOWER case struct
0009 %   MPOPT - (optional) MATPOWER options struct.
0010 %
0011 %   Work-in-progress:   CHGS are currently not returned.
0012 %                       At this point, the code *is* the documentation.
0013 %
0014 %   See also RUNOPF.
0015 
0016 %   MATPOWER
0017 %   Copyright (c) 2014-2016, Power Systems Engineering Research Center (PSERC)
0018 %   by Ray Zimmerman, PSERC Cornell
0019 %
0020 %   This file is part of MATPOWER.
0021 %   Covered by the 3-clause BSD License (see LICENSE file for details).
0022 %   See http://www.pserc.cornell.edu/matpower/ for more info.
0023 
0024 %% define constants
0025 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0026     VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0027 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0028     TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0029     ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0030 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0031     MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0032     QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0033 
0034 %%-----  process inputs  -----
0035 if nargin < 2
0036     mpopt = mpoption();
0037 end
0038 
0039 %% initialize
0040 msg = '';
0041 done = 0;
0042 rc = 0;     %% return code
0043 
0044 %%-----  on-line generation capacity <= fixed load  -----
0045 ig = find(~isload(mpc.gen) & mpc.gen(:, GEN_STATUS) > 0);
0046 total_Pmax = sum(mpc.gen(ig, PMAX));
0047 total_Pd   = total_load(mpc.bus, [], 'all');
0048 if total_Pmax <= total_Pd
0049     msg = sprintf('%stotal fixed load (%g MW) > total on-line generation capacity (%g MW)\n', ...
0050         msg, total_Pd, total_Pmax);
0051     r = mpc;
0052     r.success = 0;
0053     r.f = NaN;
0054     rc = -2;        %% inadequate on-line generation capacity
0055     done = 1;
0056 end
0057 
0058 %%-----  check for infeasible limits  -----
0059 if ~done
0060     %% generator P limits
0061     g = find(mpc.gen(:, PMIN) > mpc.gen(:, PMAX) & mpc.gen(:, GEN_STATUS) > 0);
0062     if ~isempty(g)
0063         for k = 1:length(g)
0064             msg = sprintf('%sPmax (%g) < Pmin (%g) for generator %d at bus %d, ', ...
0065                 msg, mpc.gen(g(k), PMAX), mpc.gen(g(k), PMIN), g(k), mpc.gen(g(k), GEN_BUS));
0066             %% decide which limit to move based on where Pg is
0067             if mpc.gen(g(k), PG) >= mpc.gen(g(k), PMIN)
0068                 mpc.gen(g(k), PMAX) = mpc.gen(g(k), PMIN);      %% move Pmax
0069                 msg = sprintf('%smove Pmax\n', msg);
0070             elseif mpc.gen(g(k), PG) <= mpc.gen(g(k), PMAX)
0071                 mpc.gen(g(k), PMAX) = mpc.gen(g(k), PMIN);      %% move Pmin
0072                 msg = sprintf('%smove Pmax\n', msg);
0073             else
0074                 tmp = mpc.gen(g(k), PMAX);                      %% swap 'em
0075                 mpc.gen(g(k), PMAX) = mpc.gen(g(k), PMIN);
0076                 mpc.gen(g(k), PMIN) = tmp;
0077                 msg = sprintf('%sswap Pmin and Pmax\n', msg);
0078             end
0079         end
0080         rc = 2;         %% fixed generation capacity limits
0081     end
0082     
0083     %% generator Q limits
0084 %     rc = 3;         %% fixed reactive generation capacity limits
0085 
0086     %% voltage angle limits
0087 %     rc = 4;         %% fixed voltage angle limits
0088 
0089     %% voltage magnitude limits
0090 %     rc = 5;         %% fixed voltage magnitude limits
0091 
0092     %% negative branch flow limits
0093 %     rc = 6;         %% fixed negative branch flow limits
0094 
0095     %% run initial (infeasible?) case
0096     r = runopf(mpc, mpopt);
0097     if r.success
0098         done = 1;
0099     end
0100 end
0101 
0102 %%-----  attempt with short term branch ratings  -----
0103 if ~done
0104     %% get branch limits
0105     rate_a = mpc.branch(:, RATE_A);
0106     rate_b = mpc.branch(:, RATE_B);
0107     rate_c = mpc.branch(:, RATE_C);
0108     rate_a(rate_a == 0) = Inf;
0109     rate_b(rate_b == 0) = Inf;
0110     rate_c(rate_c == 0) = Inf;
0111 
0112     %% set short term limits
0113     rating = max([rate_a rate_b], [], 2);
0114     rating(isinf(rating)) = 0;
0115     mpc.branch(:, RATE_A) = rating;
0116     r = runopf(mpc, mpopt);
0117     if r.success
0118         done = 1;
0119         rc = 7;         %% using short-term branch ratings
0120         msg = sprintf('%susing short-term branch ratings\n', msg);
0121     end
0122 end
0123 
0124 %%-----  attempt with emergency branch ratings  -----
0125 if ~done
0126     %% set emergency limits
0127     rating = max([rate_a rate_b rate_c], [], 2);
0128     rating(isinf(rating)) = 0;
0129     mpc.branch(:, RATE_A) = rating;
0130     r = runopf(mpc, mpopt);
0131 
0132     if r.success
0133         done = 1;
0134         rc = 8;         %% using emergency branch ratings
0135         msg = sprintf('%susing emergency branch ratings\n', msg);
0136     end
0137 end
0138 
0139 %%-----  attempt without branch flow limits  -----
0140 if ~done
0141     %% try with no line limits
0142     mpc.branch(:, RATE_A) = 0;
0143     r = runopf(mpc, mpopt);
0144                 
0145     if ~r.success
0146         done = 1;
0147         msg = sprintf('%sstill infeasible without line limits\n', msg);
0148     else
0149         %% the following lines should be eliminated when I do further
0150         %% relaxations
0151         msg = sprintf('%susing no branch limits\n', msg);
0152         rc = 9;         %% using no branch ratings
0153     end
0154 end
0155 
0156 %%-----  try again, relaxing only violated limits  -----
0157 if ~done
0158 
0159 end
0160 
0161 %% include msg in output
0162 r.msg = msg;
0163 r.rc  = rc;
0164 if mpopt.verbose
0165     fprintf('%s', r.msg);
0166 end

Generated on Fri 16-Dec-2016 12:45:37 by m2html © 2005