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