Home > matpower7.1 > lib > scale_load.m

scale_load

PURPOSE ^

SCALE_LOAD Scales fixed and/or dispatchable loads.

SYNOPSIS ^

function [bus, gen, gencost] = scale_load(dmd, bus, gen, load_zone, opt, gencost)

DESCRIPTION ^

SCALE_LOAD Scales fixed and/or dispatchable loads.
   MPC = SCALE_LOAD(LOAD, MPC);
   MPC = SCALE_LOAD(LOAD, MPC, LOAD_ZONE)
   MPC = SCALE_LOAD(LOAD, MPC, LOAD_ZONE, OPT)
   BUS = SCALE_LOAD(LOAD, BUS);
   [BUS, GEN] = SCALE_LOAD(LOAD, BUS, GEN, LOAD_ZONE, OPT)
   [BUS, GEN, GENCOST] = ...
       SCALE_LOAD(LOAD, BUS, GEN, LOAD_ZONE, OPT, GENCOST)

   Scales active (and optionally reactive) loads in each zone by a
   zone-specific ratio, i.e. R(k) for zone k. Inputs are ...

   LOAD - Each element specifies the amount of scaling for the
       corresponding load zone, either as a direct scale factor
       or as a target quantity. If there are nz load zones this
       vector has nz elements.

   MPC - standard MATPOWER case struct or case file name
       
   BUS - standard BUS matrix with nb rows, where the fixed active
       and reactive loads available for scaling are specified in
       columns PD and QD

   GEN - (optional) standard GEN matrix with ng rows, where the
       dispatchable loads available for scaling are specified by
       columns PG, QG, PMIN, QMIN and QMAX (in rows for which
       ISLOAD(GEN) returns true). If GEN is empty, it assumes
       there are no dispatchable loads.

   LOAD_ZONE - (optional) nb element vector where the value of
       each element is either zero or the index of the load zone
       to which the corresponding bus belongs. If LOAD_ZONE(b) = k
       then the loads at bus b will be scaled according to the
       value of LOAD(k). If LOAD_ZONE(b) = 0, the loads at bus b
       will not be modified. If LOAD_ZONE is empty, the default is
       determined by the dimensions of the LOAD vector. If LOAD is
       a scalar, a single system-wide zone including all buses is
       used, i.e. LOAD_ZONE = ONES(nb, 1). If LOAD is a vector, the
       default LOAD_ZONE is defined as the areas specified in the
       BUS matrix, i.e. LOAD_ZONE = BUS(:, BUS_AREA), and LOAD
       should have dimension = MAX(BUS(:, BUS_AREA)).

   OPT - (optional) struct with three possible fields, 'scale',
       'pq' and 'which' that determine the behavior as follows:

     OPT.scale (default is 'FACTOR')
       'FACTOR'   : LOAD consists of direct scale factors, where
                    LOAD(k) = scale factor R(k) for zone k
       'QUANTITY' : LOAD consists of target quantities, where
                    LOAD(k) = desired total active load in MW for
                    zone k after scaling by an appropriate R(k)

     OPT.pq    (default is 'PQ')
       'PQ' : scale both active and reactive loads
       'P'  : scale only active loads

     OPT.which (default is 'BOTH' if GEN is provided, else 'FIXED')
       'FIXED'        : scale only fixed loads
       'DISPATCHABLE' : scale only dispatchable loads
       'BOTH'         : scale both fixed and dispatchable loads

     OPT.cost : (default = -1) flag to include cost in scaling or not
       -1 : include cost if gencost is available
        0 : do not include cost
        1 : include cost (error if gencost not available)

   GENCOST - (optional) standard GENCOST matrix with ng (or 2*ng)
       rows, where the dispatchable load rows are determined by
       the GEN matrix. If included, the quantity axis of the marginal
       "cost" or benefit function of any dispatchable loads will be
       scaled with the size of the load itself (using MODCOST twice,
       once with MODTYPE equal to SCALE_F and once with SCALE_X).

   Examples:
       Scale all real and reactive fixed loads up by 10%.

       bus = scale_load(1.1, bus);

       Scale all active loads (fixed and dispatchable) at the first 10
       buses so their total equals 100 MW, and at next 10 buses so their
       total equals 50 MW.

       load_zone = zeros(nb, 1);
       load_zone(1:10) = 1;
       load_zone(11:20) = 2;
       opt = struct('pq', 'P', 'scale', 'QUANTITY');
       dmd = [100; 50];
       [bus, gen] = scale_load(dmd, bus, gen, load_zone, opt);

   See also TOTAL_LOAD.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [bus, gen, gencost] = scale_load(dmd, bus, gen, load_zone, opt, gencost)
0002 %SCALE_LOAD Scales fixed and/or dispatchable loads.
0003 %   MPC = SCALE_LOAD(LOAD, MPC);
0004 %   MPC = SCALE_LOAD(LOAD, MPC, LOAD_ZONE)
0005 %   MPC = SCALE_LOAD(LOAD, MPC, LOAD_ZONE, OPT)
0006 %   BUS = SCALE_LOAD(LOAD, BUS);
0007 %   [BUS, GEN] = SCALE_LOAD(LOAD, BUS, GEN, LOAD_ZONE, OPT)
0008 %   [BUS, GEN, GENCOST] = ...
0009 %       SCALE_LOAD(LOAD, BUS, GEN, LOAD_ZONE, OPT, GENCOST)
0010 %
0011 %   Scales active (and optionally reactive) loads in each zone by a
0012 %   zone-specific ratio, i.e. R(k) for zone k. Inputs are ...
0013 %
0014 %   LOAD - Each element specifies the amount of scaling for the
0015 %       corresponding load zone, either as a direct scale factor
0016 %       or as a target quantity. If there are nz load zones this
0017 %       vector has nz elements.
0018 %
0019 %   MPC - standard MATPOWER case struct or case file name
0020 %
0021 %   BUS - standard BUS matrix with nb rows, where the fixed active
0022 %       and reactive loads available for scaling are specified in
0023 %       columns PD and QD
0024 %
0025 %   GEN - (optional) standard GEN matrix with ng rows, where the
0026 %       dispatchable loads available for scaling are specified by
0027 %       columns PG, QG, PMIN, QMIN and QMAX (in rows for which
0028 %       ISLOAD(GEN) returns true). If GEN is empty, it assumes
0029 %       there are no dispatchable loads.
0030 %
0031 %   LOAD_ZONE - (optional) nb element vector where the value of
0032 %       each element is either zero or the index of the load zone
0033 %       to which the corresponding bus belongs. If LOAD_ZONE(b) = k
0034 %       then the loads at bus b will be scaled according to the
0035 %       value of LOAD(k). If LOAD_ZONE(b) = 0, the loads at bus b
0036 %       will not be modified. If LOAD_ZONE is empty, the default is
0037 %       determined by the dimensions of the LOAD vector. If LOAD is
0038 %       a scalar, a single system-wide zone including all buses is
0039 %       used, i.e. LOAD_ZONE = ONES(nb, 1). If LOAD is a vector, the
0040 %       default LOAD_ZONE is defined as the areas specified in the
0041 %       BUS matrix, i.e. LOAD_ZONE = BUS(:, BUS_AREA), and LOAD
0042 %       should have dimension = MAX(BUS(:, BUS_AREA)).
0043 %
0044 %   OPT - (optional) struct with three possible fields, 'scale',
0045 %       'pq' and 'which' that determine the behavior as follows:
0046 %
0047 %     OPT.scale (default is 'FACTOR')
0048 %       'FACTOR'   : LOAD consists of direct scale factors, where
0049 %                    LOAD(k) = scale factor R(k) for zone k
0050 %       'QUANTITY' : LOAD consists of target quantities, where
0051 %                    LOAD(k) = desired total active load in MW for
0052 %                    zone k after scaling by an appropriate R(k)
0053 %
0054 %     OPT.pq    (default is 'PQ')
0055 %       'PQ' : scale both active and reactive loads
0056 %       'P'  : scale only active loads
0057 %
0058 %     OPT.which (default is 'BOTH' if GEN is provided, else 'FIXED')
0059 %       'FIXED'        : scale only fixed loads
0060 %       'DISPATCHABLE' : scale only dispatchable loads
0061 %       'BOTH'         : scale both fixed and dispatchable loads
0062 %
0063 %     OPT.cost : (default = -1) flag to include cost in scaling or not
0064 %       -1 : include cost if gencost is available
0065 %        0 : do not include cost
0066 %        1 : include cost (error if gencost not available)
0067 %
0068 %   GENCOST - (optional) standard GENCOST matrix with ng (or 2*ng)
0069 %       rows, where the dispatchable load rows are determined by
0070 %       the GEN matrix. If included, the quantity axis of the marginal
0071 %       "cost" or benefit function of any dispatchable loads will be
0072 %       scaled with the size of the load itself (using MODCOST twice,
0073 %       once with MODTYPE equal to SCALE_F and once with SCALE_X).
0074 %
0075 %   Examples:
0076 %       Scale all real and reactive fixed loads up by 10%.
0077 %
0078 %       bus = scale_load(1.1, bus);
0079 %
0080 %       Scale all active loads (fixed and dispatchable) at the first 10
0081 %       buses so their total equals 100 MW, and at next 10 buses so their
0082 %       total equals 50 MW.
0083 %
0084 %       load_zone = zeros(nb, 1);
0085 %       load_zone(1:10) = 1;
0086 %       load_zone(11:20) = 2;
0087 %       opt = struct('pq', 'P', 'scale', 'QUANTITY');
0088 %       dmd = [100; 50];
0089 %       [bus, gen] = scale_load(dmd, bus, gen, load_zone, opt);
0090 %
0091 %   See also TOTAL_LOAD.
0092 
0093 %   MATPOWER
0094 %   Copyright (c) 2004-2016, Power Systems Engineering Research Center (PSERC)
0095 %   by Ray Zimmerman, PSERC Cornell
0096 %
0097 %   This file is part of MATPOWER.
0098 %   Covered by the 3-clause BSD License (see LICENSE file for details).
0099 %   See https://matpower.org for more info.
0100 
0101 %% define constants
0102 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0103     VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0104 %% purposely being backward compatible with older MATPOWER
0105 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, ...
0106     PMAX, PMIN, MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN] = idx_gen;
0107 
0108 %%-----  process inputs  -----
0109 if ischar(bus)      %% passing in case as file name string
0110     bus = loadcase(bus);
0111 end
0112 if isstruct(bus)
0113     use_mpc = 1;
0114     if nargin < 4
0115         load_zone = struct;
0116         if nargin < 3
0117             gen = [];
0118         end
0119     end
0120     %% shift and reassign inputs
0121     opt = load_zone;
0122     load_zone = gen;
0123     mpc = bus;
0124     gen = mpc.gen;
0125     bus = mpc.bus;
0126     if isfield(mpc, 'gencost')
0127         gencost = mpc.gencost;
0128     else
0129         gencost = [];
0130     end
0131     if nargout > 1
0132         error('scale_load: too many output arguments')
0133     end
0134 else
0135     use_mpc = 0;
0136     if nargin < 6
0137         gencost = [];
0138         if nargin < 5
0139             opt = struct;
0140             if nargin < 4
0141                 load_zone = [];
0142                 if nargin < 3
0143                     gen = [];
0144                 end
0145             end
0146         end
0147     end
0148 end
0149 
0150 %% fill out and check opt
0151 if isempty(gen)
0152     opt.which = 'FIXED';
0153 end
0154 if ~isfield(opt, 'pq')
0155     opt.pq = 'PQ';          %% 'PQ' or 'P'
0156 end
0157 if ~isfield(opt, 'which')
0158     opt.which = 'BOTH';     %% 'FIXED', 'DISPATCHABLE' or 'BOTH'
0159 end
0160 if ~isfield(opt, 'scale')
0161     opt.scale = 'FACTOR';   %% 'FACTOR' or 'QUANTITY'
0162 end
0163 if ~isfield(opt, 'cost')
0164     opt.cost = -1;          %% -1, 0, or 1
0165 end
0166 if ~strcmp(opt.pq, 'P') && ~strcmp(opt.pq, 'PQ')
0167     error('scale_load: opt.pq must equal ''PQ'' or ''P''');
0168 end
0169 if opt.which(1) ~= 'F' && opt.which(1) ~= 'D' && opt.which(1) ~= 'B'
0170     error('scale_load: opt.which should be ''FIXED'', ''DISPATCHABLE'' or ''BOTH''');
0171 end
0172 if opt.scale(1) ~= 'F' && opt.scale(1) ~= 'Q'
0173     error('scale_load: opt.scale should be ''FACTOR'' or ''QUANTITY''');
0174 end
0175 if isempty(gen) && opt.which(1) ~= 'F'
0176     error('scale_load: need gen matrix to scale dispatchable loads');
0177 end
0178 if opt.cost == -1
0179     if isempty(gencost)
0180         opt.cost = 0;
0181     else
0182         opt.cost = 1;
0183     end
0184 end
0185 if ~use_mpc && nargout < 3 && opt.cost
0186     error('scale_load: missing gencost as output argument');
0187 end
0188 if nargout > 2 && isempty(gencost)
0189     error('scale_load: missing gencost as input argument');
0190 end
0191 
0192 %% create dispatchable load connection matrix
0193 nb = size(bus, 1);          %% number of buses
0194 if ~isempty(gen)
0195     ng = size(gen, 1);
0196     is_ld = isload(gen) & gen(:, GEN_STATUS) > 0;
0197     ld = find(is_ld);
0198 
0199     %% create map of external bus numbers to bus indices
0200     i2e = bus(:, BUS_I);
0201     e2i = sparse(max(i2e), 1);
0202     e2i(i2e) = (1:nb)';
0203 
0204     Cld = sparse(e2i(gen(:, GEN_BUS)), (1:ng)', is_ld, nb, ng);
0205 else
0206     ng = [];
0207     ld = [];
0208 end
0209 
0210 if isempty(load_zone)
0211     if length(dmd) == 1         %% make a single zone of all load buses
0212         load_zone = zeros(nb, 1);                           %% initialize
0213         load_zone(bus(:, PD) ~= 0 | bus(:, QD) ~= 0) = 1;   %% FIXED loads
0214         if ~isempty(gen)
0215             load_zone(e2i(gen(ld, GEN_BUS))) = 1;   %% DISPATCHABLE loads
0216         end
0217     else                        %% use areas defined in bus data as zones
0218         load_zone = bus(:, BUS_AREA);
0219     end
0220 end
0221 
0222 %% check load_zone to make sure it's consistent with size of load vector
0223 if max(load_zone) > length(dmd)
0224     error('scale_load: load vector must have a value for each load zone specified');
0225 end
0226 
0227 %%-----  compute scale factors for each zone  -----
0228 scale = dmd;
0229 Pdd = zeros(nb, 1);     %% dispatchable P at each bus
0230 if opt.scale(1) == 'Q'  %% 'QUANTITY'
0231     %% find load capacity from dispatchable loads
0232     if ~isempty(gen)
0233         Pdd = -Cld * gen(:, PMIN);
0234     end
0235 
0236     %% compute scale factors
0237     for k = 1:length(dmd)
0238         idx = find( load_zone == k );
0239         fixed = sum(bus(idx, PD));
0240         dispatchable = sum(Pdd(idx));
0241         total = fixed + dispatchable;
0242         if opt.which(1) == 'B'      %% 'BOTH'
0243             if total ~= 0
0244                 scale(k) = dmd(k) / total;
0245             elseif dmd(k) == total
0246                 scale(k) = 1;
0247             else
0248                 error('scale_load: impossible to make zone %d load equal %g by scaling non-existent loads', k, dmd(k));
0249             end
0250         elseif opt.which(1) == 'F'  %% 'FIXED'
0251             if fixed ~= 0
0252                 scale(k) = (dmd(k) - dispatchable) / fixed;
0253             elseif dmd(k) == dispatchable
0254                 scale(k) = 1;
0255             else
0256                 error('scale_load: impossible to make zone %d load equal %g by scaling non-existent fixed load', k, dmd(k));
0257             end
0258         elseif opt.which(1) == 'D'  %% 'DISPATCHABLE'
0259             if dispatchable ~= 0
0260                 scale(k) = (dmd(k) - fixed) / dispatchable;
0261             elseif dmd(k) == fixed
0262                 scale(k) = 1;
0263             else
0264                 error('scale_load: impossible to make zone %d load equal %g by scaling non-existent dispatchable load', k, dmd(k));
0265             end
0266         end
0267     end
0268 end
0269 
0270 %%-----  do the scaling  -----
0271 %% fixed loads
0272 if opt.which(1) ~= 'D'      %% includes 'FIXED', not 'DISPATCHABLE' only
0273     for k = 1:length(scale)
0274         idx = find( load_zone == k );
0275         bus(idx, PD) = bus(idx, PD) * scale(k);
0276         if strcmp(opt.pq, 'PQ')
0277             bus(idx, QD) = bus(idx, QD) * scale(k);
0278         end
0279     end
0280 end
0281 
0282 %% dispatchable loads
0283 if opt.which(1) ~= 'F'      %% includes 'DISPATCHABLE', not 'FIXED' only
0284     for k = 1:length(scale)
0285         idx = find( load_zone == k );
0286         i = find(ismember(e2i(gen(ld, GEN_BUS)), idx));
0287         ig = ld(i);
0288 
0289         gen(ig, [PG PMIN]) = gen(ig, [PG PMIN]) * scale(k);
0290         if opt.cost
0291             gencost(ig, :) = modcost(gencost(ig, :), scale(k), 'SCALE_F');
0292             gencost(ig, :) = modcost(gencost(ig, :), scale(k), 'SCALE_X');
0293         end
0294         if strcmp(opt.pq, 'PQ')
0295             gen(ig, [QG QMIN QMAX]) = gen(ig, [QG QMIN QMAX]) * scale(k);
0296             if opt.cost
0297                 [pcost, qcost] = pqcost(gencost, ng);
0298                 if ~isempty(qcost)
0299                     qcost(ig, :) = modcost(qcost(ig, :), scale(k), 'SCALE_F');
0300                     qcost(ig, :) = modcost(qcost(ig, :), scale(k), 'SCALE_X');
0301                     gencost = [pcost; qcost];
0302                 end
0303             end
0304         end
0305     end
0306 end
0307 
0308 %% re-package outputs if necessary
0309 if use_mpc
0310     mpc.bus = bus;
0311     mpc.gen = gen;
0312     if opt.cost
0313         mpc.gencost = gencost;
0314     end
0315     bus = mpc;
0316 end

Generated on Fri 09-Oct-2020 11:21:31 by m2html © 2005