Home > matpower5.0 > toggle_softlims.m

toggle_softlims

PURPOSE ^

TOGGLE_SOFTLIMS Relax DC optimal power flow branch limits.

SYNOPSIS ^

function mpc = toggle_softlims(mpc, on_off)

DESCRIPTION ^

TOGGLE_SOFTLIMS Relax DC optimal power flow branch limits.
   MPC = TOGGLE_SOFTLIMS(MPC, 'on')
   MPC = TOGGLE_SOFTLIMS(MPC, 'off')
   T_F = TOGGLE_SOFTLIMS(MPC, 'status')

   Enables, disables or checks the status of a set of OPF userfcn
   callbacks to implement relaxed branch flow limits a DC optimal flow model.

   These callbacks expect to find a 'softlims' field in the input MPC,
   where MPC.softlims is a struct with the following fields:
       idx     (optional) n x 1, index vector for branches whos flow
               limits are to be relaxed, default is to use all on-line
               branches with non-zero limits specified in RATE_A
       cost    (optional) n x 1, linear marginal cost per MW of exceeding
               RATE_A. Can optionally be a scalar, in which case it is
               applied to all soft limits. Default if not specified is
               $1000/MW.

   The 'int2ext' callback also packages up results and stores them in
   the following output fields of results.softlims:
       overload - nl x 1, amount of overload of each line in MW
       ovl_cost - nl x 1, total cost of overload in $/hr

   The shadow prices on the soft limit constraints are also returned in the
   MU_SF and MU_ST columns of the branch matrix.
   Note: These shadow prices are equal to the corresponding hard limit
       shadow prices when the soft limits are not violated. When violated,
       the shadow price on a soft limit constraint is equal to the
       user-specified soft limit violation cost.

   See also ADD_USERFCN, REMOVE_USERFCN, RUN_USERFCN, T_CASE30_USERFCNS.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function mpc = toggle_softlims(mpc, on_off)
0002 %TOGGLE_SOFTLIMS Relax DC optimal power flow branch limits.
0003 %   MPC = TOGGLE_SOFTLIMS(MPC, 'on')
0004 %   MPC = TOGGLE_SOFTLIMS(MPC, 'off')
0005 %   T_F = TOGGLE_SOFTLIMS(MPC, 'status')
0006 %
0007 %   Enables, disables or checks the status of a set of OPF userfcn
0008 %   callbacks to implement relaxed branch flow limits a DC optimal flow model.
0009 %
0010 %   These callbacks expect to find a 'softlims' field in the input MPC,
0011 %   where MPC.softlims is a struct with the following fields:
0012 %       idx     (optional) n x 1, index vector for branches whos flow
0013 %               limits are to be relaxed, default is to use all on-line
0014 %               branches with non-zero limits specified in RATE_A
0015 %       cost    (optional) n x 1, linear marginal cost per MW of exceeding
0016 %               RATE_A. Can optionally be a scalar, in which case it is
0017 %               applied to all soft limits. Default if not specified is
0018 %               $1000/MW.
0019 %
0020 %   The 'int2ext' callback also packages up results and stores them in
0021 %   the following output fields of results.softlims:
0022 %       overload - nl x 1, amount of overload of each line in MW
0023 %       ovl_cost - nl x 1, total cost of overload in $/hr
0024 %
0025 %   The shadow prices on the soft limit constraints are also returned in the
0026 %   MU_SF and MU_ST columns of the branch matrix.
0027 %   Note: These shadow prices are equal to the corresponding hard limit
0028 %       shadow prices when the soft limits are not violated. When violated,
0029 %       the shadow price on a soft limit constraint is equal to the
0030 %       user-specified soft limit violation cost.
0031 %
0032 %   See also ADD_USERFCN, REMOVE_USERFCN, RUN_USERFCN, T_CASE30_USERFCNS.
0033 
0034 %   To do for future versions:
0035 %       - make softlims input field optional, convert all lines if missing
0036 %       Inputs:
0037 %       cost    n x 3, linear marginal cost per MW of exceeding each of
0038 %               RATE_A, RATE_B and RATE_C. Columns 2 and 3 are optional.
0039 %       brkpts  n x npts, allow to specify arbitrary breakpoints at which
0040 %               cost increases, defined as percentages above RATE_A.
0041 %       base_flow   n x 1, arbitrary baseline (other than RATE_A)
0042 
0043 %   MATPOWER
0044 %   $Id: toggle_softlims.m 2433 2014-12-03 14:45:50Z ray $
0045 %   by Ray Zimmerman, PSERC Cornell
0046 %   Copyright (c) 2009-2014 by Power System Engineering Research Center (PSERC)
0047 %
0048 %   This file is part of MATPOWER.
0049 %   See http://www.pserc.cornell.edu/matpower/ for more info.
0050 %
0051 %   MATPOWER is free software: you can redistribute it and/or modify
0052 %   it under the terms of the GNU General Public License as published
0053 %   by the Free Software Foundation, either version 3 of the License,
0054 %   or (at your option) any later version.
0055 %
0056 %   MATPOWER is distributed in the hope that it will be useful,
0057 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
0058 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0059 %   GNU General Public License for more details.
0060 %
0061 %   You should have received a copy of the GNU General Public License
0062 %   along with MATPOWER. If not, see <http://www.gnu.org/licenses/>.
0063 %
0064 %   Additional permission under GNU GPL version 3 section 7
0065 %
0066 %   If you modify MATPOWER, or any covered work, to interface with
0067 %   other modules (such as MATLAB code and MEX-files) available in a
0068 %   MATLAB(R) or comparable environment containing parts covered
0069 %   under other licensing terms, the licensors of MATPOWER grant
0070 %   you additional permission to convey the resulting work.
0071 
0072 if strcmp(upper(on_off), 'ON')
0073     %% check for proper softlims inputs
0074     %% (inputs are optional, defaults handled in ext2int callback)
0075     
0076     %% add callback functions
0077     %% note: assumes all necessary data included in 1st arg (mpc, om, results)
0078     %%       so, no additional explicit args are needed
0079     mpc = add_userfcn(mpc, 'ext2int', @userfcn_softlims_ext2int);
0080     mpc = add_userfcn(mpc, 'formulation', @userfcn_softlims_formulation);
0081     mpc = add_userfcn(mpc, 'int2ext', @userfcn_softlims_int2ext);
0082     mpc = add_userfcn(mpc, 'printpf', @userfcn_softlims_printpf);
0083     mpc = add_userfcn(mpc, 'savecase', @userfcn_softlims_savecase);
0084     mpc.userfcn.status.softlims = 1;
0085 elseif strcmp(upper(on_off), 'OFF')
0086     mpc = remove_userfcn(mpc, 'savecase', @userfcn_softlims_savecase);
0087     mpc = remove_userfcn(mpc, 'printpf', @userfcn_softlims_printpf);
0088     mpc = remove_userfcn(mpc, 'int2ext', @userfcn_softlims_int2ext);
0089     mpc = remove_userfcn(mpc, 'formulation', @userfcn_softlims_formulation);
0090     mpc = remove_userfcn(mpc, 'ext2int', @userfcn_softlims_ext2int);
0091     mpc.userfcn.status.softlims = 0;
0092 elseif strcmp(upper(on_off), 'STATUS')
0093     if isfield(mpc, 'userfcn') && isfield(mpc.userfcn, 'status') && ...
0094             isfield(mpc.userfcn.status, 'softlims')
0095         mpc = mpc.userfcn.status.softlims;
0096     else
0097         mpc = 0;
0098     end
0099 else
0100     error('toggle_softlims: 2nd argument must be ''on'', ''off'' or ''status''');
0101 end
0102 
0103 
0104 %%-----  ext2int  ------------------------------------------------------
0105 function mpc = userfcn_softlims_ext2int(mpc, args)
0106 %
0107 %   mpc = userfcn_softlims_ext2int(mpc, args)
0108 %
0109 %   This is the 'ext2int' stage userfcn callback that prepares the input
0110 %   data for the formulation stage. It expects to find a 'softlims' field in
0111 %   mpc as described above. The optional args are not currently used.
0112 
0113 %% define named indices into data matrices
0114 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0115     TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0116     ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0117 
0118 %% check for proper softlims inputs
0119 default_cost = 1000;    %% used if cost is not specified
0120 if isfield(mpc, 'softlims')
0121     if ~isfield(mpc.softlims, 'idx')
0122         mpc.softlims.idx = [];
0123     end
0124     if ~isfield(mpc.softlims, 'cost')
0125         mpc.softlims.cost = default_cost;
0126     end
0127 else
0128     mpc.softlims.idx = [];
0129     mpc.softlims.cost = default_cost;
0130 end
0131 
0132 %% initialize some things
0133 s = mpc.softlims;
0134 o = mpc.order;
0135 nl0 = size(o.ext.branch, 1);    %% original number of branches
0136 nl = size(mpc.branch, 1);       %% number of on-line branches
0137 
0138 %% save softlims struct for external indexing
0139 mpc.order.ext.softlims = s;
0140 
0141 %%-----  convert stuff to internal indexing  -----
0142 s = softlims_defaults(s, o.ext.branch);     %% get defaults
0143 e2i = zeros(nl0, 1);
0144 e2i(o.branch.status.on) = (1:nl)';  %% ext->int branch index mapping
0145 s.idx = e2i(s.idx);
0146 k = find(s.idx == 0);   %% find idxes corresponding to off-line branches
0147 s.idx(k) = [];          %% delete them
0148 s.cost(k, :) = [];
0149 k = find(mpc.branch(s.idx, RATE_A) <= 0);   %% find branches w/o limits
0150 s.idx(k) = [];          %% delete them
0151 s.cost(k, :) = [];
0152 
0153 %%-----  remove hard limits on branches with soft limits  -----
0154 s.Pfmax = mpc.branch(s.idx, RATE_A) / mpc.baseMVA;  %% save limit first
0155 mpc.branch(s.idx, RATE_A) = 0;                      %% then remove it
0156 
0157 mpc.softlims = s;
0158 mpc.order.int.softlims = s;
0159 
0160 
0161 %%-----  formulation  --------------------------------------------------
0162 function om = userfcn_softlims_formulation(om, args)
0163 %
0164 %   om = userfcn_softlims_formulation(om, args)
0165 %
0166 %   This is the 'formulation' stage userfcn callback that defines the
0167 %   user costs and constraints for interface flow limits. It expects to
0168 %   find a 'softlims' field in the mpc stored in om, as described above. The
0169 %   optional args are not currently used.
0170 
0171 %% define named indices into data matrices
0172 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0173     TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0174     ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0175 
0176 %% initialize some things
0177 mpc = get_mpc(om);
0178 [baseMVA, bus, branch] = deal(mpc.baseMVA, mpc.bus, mpc.branch);
0179 s = mpc.softlims;
0180 
0181 %% form B matrices for DC model
0182 [B, Bf, Pbusinj, Pfinj] = makeBdc(baseMVA, bus, branch);
0183 n = size(Bf, 2);        %% dim of theta
0184 
0185 %% form constraints (flv is flow limit violation variable)
0186 %%   -Bf * Va - flv <=  Pfinj + Pfmax
0187 %%    Bf * Va - flv <= -Pfinj + Pfmax
0188 ns = length(s.idx);     %% number of soft limits
0189 I = speye(ns, ns);
0190 As = [-Bf(s.idx, :) -I; Bf(s.idx, :) -I];
0191 ls = -Inf(2*ns, 1);
0192 us = [   Pfinj(s.idx) + s.Pfmax;
0193         -Pfinj(s.idx) + s.Pfmax ];
0194 
0195 %% costs on flv variable
0196 Cw = s.cost(:, 1) * mpc.baseMVA;
0197 
0198 %% add vars, costs, constraints
0199 om = add_vars(om, 'flv', ns, zeros(ns, 1), zeros(ns, 1), Inf(ns, 1));
0200 om = add_costs(om, 'vc', struct('N', I, 'Cw', Cw), {'flv'});
0201 om = add_constraints(om, 'softlims',  As, ls, us, {'Va', 'flv'});   %% 2*ns
0202 
0203 
0204 %%-----  int2ext  ------------------------------------------------------
0205 function results = userfcn_softlims_int2ext(results, args)
0206 %
0207 %   results = userfcn_softlims_int2ext(results, args)
0208 %
0209 %   This is the 'int2ext' stage userfcn callback that converts everything
0210 %   back to external indexing and packages up the results. It expects to
0211 %   find a 'softlims' field in the results struct as described for mpc above.
0212 %   It also expects the results to contain solved branch flows and linear
0213 %   constraints named 'softlims' which are used to populate output fields
0214 %   in results.softlims. The optional args are not currently used.
0215 
0216 %% define named indices into data matrices
0217 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0218     TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0219     ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0220 
0221 %% get internal softlims struct
0222 s = results.softlims;
0223 
0224 %%-----  convert stuff back to external indexing  -----
0225 o = results.order;
0226 nl0 = size(o.ext.branch, 1);    %% original number of branches
0227 nl = size(results.branch, 1);   %% number of on-line branches
0228 o.branch.status.on;
0229 results.softlims = results.order.ext.softlims;
0230 
0231 %%-----  restore hard limits  -----
0232 results.branch(s.idx, RATE_A) = s.Pfmax * results.baseMVA;
0233 
0234 %%-----  results post-processing  -----
0235 %% get shadow prices
0236 n = size(results.lin.mu.u.softlims, 1) / 2;
0237 results.branch(s.idx, MU_ST) = results.lin.mu.u.softlims(1:n) / results.baseMVA;
0238 results.branch(s.idx, MU_SF) = results.lin.mu.u.softlims(n+1:end) / results.baseMVA;
0239 %% get overloads and overload costs
0240 results.softlims.overload = zeros(nl0, 1);
0241 k = find(results.branch(:, RATE_A) & ...
0242          abs(results.branch(:, PF)) > results.branch(:, RATE_A) );
0243 results.softlims.overload(o.branch.status.on(k)) = ...
0244         abs(results.branch(k, PF)) - results.branch(k, RATE_A);
0245 results.softlims.ovl_cost = zeros(size(results.softlims.overload));
0246 results.softlims.ovl_cost(o.branch.status.on(s.idx)) = ...
0247     results.softlims.overload(o.branch.status.on(s.idx)) .* s.cost(:, 1);
0248 
0249 
0250 %%-----  printpf  ------------------------------------------------------
0251 function results = userfcn_softlims_printpf(results, fd, mpopt, args)
0252 %
0253 %   results = userfcn_softlims_printpf(results, fd, mpopt, args)
0254 %
0255 %   This is the 'printpf' stage userfcn callback that pretty-prints the
0256 %   results. It expects a results struct, a file descriptor and a MATPOWER
0257 %   options struct. The optional args are not currently used.
0258 
0259 %% define named indices into data matrices
0260 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0261     TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0262     ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0263 
0264 %%-----  print results  -----
0265 ptol = 1e-6;        %% tolerance for displaying shadow prices
0266 isOPF           = isfield(results, 'f') && ~isempty(results.f);
0267 SUPPRESS        = mpopt.out.suppress_detail;
0268 if SUPPRESS == -1
0269     if size(results.bus, 1) > 500
0270         SUPPRESS = 1;
0271     else
0272         SUPPRESS = 0;
0273     end
0274 end
0275 OUT_ALL         = mpopt.out.all;
0276 OUT_FORCE       = mpopt.out.force;
0277 OUT_BRANCH      = OUT_ALL == 1 || (OUT_ALL == -1 && ~SUPPRESS && mpopt.out.branch);
0278 
0279 if isOPF && OUT_BRANCH && (results.success || OUT_FORCE)
0280     s = softlims_defaults(results.softlims, results.branch);   %% get defaults
0281     k = find(s.overload(s.idx) | sum(results.branch(s.idx, MU_SF:MU_ST), 2) > ptol);
0282 
0283     fprintf(fd, '\n================================================================================');
0284     fprintf(fd, '\n|     Soft Flow Limits                                                         |');
0285     fprintf(fd, '\n================================================================================');
0286     fprintf(fd, '\nBrnch   From   To     Flow      Limit    Overload     mu');
0287     fprintf(fd, '\n  #     Bus    Bus    (MW)      (MW)       (MW)     ($/MW)');
0288     fprintf(fd, '\n-----  -----  -----  --------  --------  --------  ---------');
0289     fprintf(fd, '\n%4d%7d%7d%10.2f%10.2f%10.2f%11.3f', ...
0290             [   s.idx(k), results.branch(s.idx(k), [F_BUS, T_BUS]), ...
0291                 results.branch(s.idx(k), [PF, RATE_A]), ...
0292                 s.overload(s.idx(k)), ...
0293                 sum(results.branch(s.idx(k), [MU_SF:MU_ST]), 2) ...
0294             ]');
0295     fprintf(fd, '\n                                         --------');
0296     fprintf(fd, '\n                                Total:%10.2f', ...
0297             sum(s.overload(s.idx(k))));
0298     fprintf(fd, '\n');
0299 end
0300 
0301 
0302 %%-----  savecase  -----------------------------------------------------
0303 function mpc = userfcn_softlims_savecase(mpc, fd, prefix, args)
0304 %
0305 %   mpc = userfcn_softlims_savecase(mpc, fd, mpopt, args)
0306 %
0307 %   This is the 'savecase' stage userfcn callback that prints the M-file
0308 %   code to save the 'softlims' field in the case file. It expects a
0309 %   MATPOWER case struct (mpc), a file descriptor and variable prefix
0310 %   (usually 'mpc.'). The optional args are not currently used.
0311 
0312 if isfield(mpc, 'softlims')
0313     s = mpc.softlims;
0314 
0315     fprintf(fd, '\n%%%%-----  Soft Flow Limit Data  -----%%%%\n');
0316 
0317     if isfield(s, 'idx')
0318         fprintf(fd, '%%%% branch indexes\n');
0319         fprintf(fd, '%%\tbranchidx\n');
0320         if isempty(s.idx)
0321             fprintf(fd, '%ssoftlims.idx = [];\n\n', prefix);
0322         else
0323             fprintf(fd, '%ssoftlims.idx = [\n', prefix);
0324             fprintf(fd, '\t%d;\n', s.idx);
0325             fprintf(fd, '];\n\n');
0326         end
0327     end
0328 
0329     fprintf(fd, '%%%% violation cost coefficients\n');
0330     fprintf(fd, '%%\trate_a_cost\n');
0331     fprintf(fd, '%ssoftlims.cost = [\n', prefix);
0332     fprintf(fd, '\t%g;\n', s.cost);
0333     fprintf(fd, '];\n');
0334 
0335     %% save output fields for solved case
0336     if isfield(mpc.softlims, 'overload')
0337         fprintf(fd, '\n%%%% overloads\n');
0338         fprintf(fd, '%%\toverload\n');
0339         fprintf(fd, '%ssoftlims.overload = [\n', prefix);
0340         fprintf(fd, '\t%g;\n', s.overload);
0341         fprintf(fd, '];\n');
0342 
0343         fprintf(fd, '\n%%%% overload costs\n');
0344         fprintf(fd, '%%\toverload_costs\n');
0345         fprintf(fd, '%ssoftlims.ovl_cost = [\n', prefix);
0346         fprintf(fd, '\t%g;\n', s.ovl_cost);
0347         fprintf(fd, '];\n');
0348     end
0349 end
0350 
0351 %%-----  softlims_defaults  --------------------------------------------
0352 function s = softlims_defaults(s, branch)
0353 %
0354 %   s = softlims_defaults(s, branch)
0355 %
0356 %   Takes a softlims struct that could have an empty 'idx' field or a
0357 %   scalar 'cost' field and fills them out with the defaults, where the
0358 %   default for 'idx' includes all on-line branches with non-zero RATE_A,
0359 %   and the default for the cost is to apply the scalar to each soft limit
0360 %   violation.
0361 
0362 %% define named indices into data matrices
0363 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0364     TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0365     ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0366 
0367 if isempty(s.idx)
0368     s.idx = find(branch(:, BR_STATUS) > 0 & branch(:, RATE_A) > 0);
0369 end
0370 if length(s.cost) == 1 && length(s.idx) > 1
0371     s.cost = s.cost * ones(size(s.idx));
0372 end

Generated on Mon 26-Jan-2015 15:21:31 by m2html © 2005