EXT2INT Converts external to internal indexing. This function has two forms, (1) the old form that operates on and returns individual matrices and (2) the new form that operates on and returns an entire MATPOWER case struct. 1. [I2E, BUS, GEN, BRANCH, AREAS] = EXT2INT(BUS, GEN, BRANCH, AREAS) [I2E, BUS, GEN, BRANCH] = EXT2INT(BUS, GEN, BRANCH) If the first argument is a matrix, it simply converts from (possibly non-consecutive) external bus numbers to consecutive internal bus numbers which start at 1. Changes are made to BUS, GEN, BRANCH and optionally AREAS matrices, which are returned along with a vector of indices I2E that can be passed to INT2EXT to perform the reverse conversion, where EXTERNAL_BUS_NUMBER = I2E(INTERNAL_BUS_NUMBER) Examples: [i2e, bus, gen, branch, areas] = ext2int(bus, gen, branch, areas); [i2e, bus, gen, branch] = ext2int(bus, gen, branch); 2. MPC = EXT2INT(MPC) If the input is a single MATPOWER case struct, then all isolated buses, off-line generators and branches are removed along with any generators, branches or areas connected to isolated buses. Then the buses are renumbered consecutively, beginning at 1, and the generators are sorted by increasing bus number. Any 'ext2int' callback routines registered in the case are also invoked automatically. All of the related indexing information and the original data matrices are stored in an 'order' field in the struct to be used by INT2EXT to perform the reverse conversions. If the case is already using internal numbering it is returned unchanged. Example: mpc = ext2int(mpc); The 'order' field of MPC used to store the indexing information needed for subsequent internal to external conversion is structured as: order state 'i' | 'e' ext | int areas bus branch gen gencost A N bus e2i i2e status on off gen e2i i2e status on off branch status on off areas status on off See also INT2EXT, E2I_FIELD, E2I_DATA.
0001 function [i2e, bus, gen, branch, areas] = ext2int(bus, gen, branch, areas) 0002 %EXT2INT Converts external to internal indexing. 0003 % 0004 % This function has two forms, (1) the old form that operates on 0005 % and returns individual matrices and (2) the new form that operates 0006 % on and returns an entire MATPOWER case struct. 0007 % 0008 % 1. [I2E, BUS, GEN, BRANCH, AREAS] = EXT2INT(BUS, GEN, BRANCH, AREAS) 0009 % [I2E, BUS, GEN, BRANCH] = EXT2INT(BUS, GEN, BRANCH) 0010 % 0011 % If the first argument is a matrix, it simply converts from (possibly 0012 % non-consecutive) external bus numbers to consecutive internal bus 0013 % numbers which start at 1. Changes are made to BUS, GEN, BRANCH and 0014 % optionally AREAS matrices, which are returned along with a vector of 0015 % indices I2E that can be passed to INT2EXT to perform the reverse 0016 % conversion, where EXTERNAL_BUS_NUMBER = I2E(INTERNAL_BUS_NUMBER) 0017 % 0018 % Examples: 0019 % [i2e, bus, gen, branch, areas] = ext2int(bus, gen, branch, areas); 0020 % [i2e, bus, gen, branch] = ext2int(bus, gen, branch); 0021 % 0022 % 2. MPC = EXT2INT(MPC) 0023 % 0024 % If the input is a single MATPOWER case struct, then all isolated 0025 % buses, off-line generators and branches are removed along with any 0026 % generators, branches or areas connected to isolated buses. Then the 0027 % buses are renumbered consecutively, beginning at 1, and the 0028 % generators are sorted by increasing bus number. Any 'ext2int' 0029 % callback routines registered in the case are also invoked 0030 % automatically. All of the related indexing information and the 0031 % original data matrices are stored in an 'order' field in the struct 0032 % to be used by INT2EXT to perform the reverse conversions. If the 0033 % case is already using internal numbering it is returned unchanged. 0034 % 0035 % Example: 0036 % mpc = ext2int(mpc); 0037 % 0038 % The 'order' field of MPC used to store the indexing information 0039 % needed for subsequent internal to external conversion is structured 0040 % as: 0041 % 0042 % order 0043 % state 'i' | 'e' 0044 % ext | int 0045 % areas 0046 % bus 0047 % branch 0048 % gen 0049 % gencost 0050 % A 0051 % N 0052 % bus 0053 % e2i 0054 % i2e 0055 % status 0056 % on 0057 % off 0058 % gen 0059 % e2i 0060 % i2e 0061 % status 0062 % on 0063 % off 0064 % branch 0065 % status 0066 % on 0067 % off 0068 % areas 0069 % status 0070 % on 0071 % off 0072 % 0073 % See also INT2EXT, E2I_FIELD, E2I_DATA. 0074 0075 % MATPOWER 0076 % $Id: ext2int.m,v 1.20 2011/11/09 21:32:13 cvs Exp $ 0077 % by Ray Zimmerman, PSERC Cornell 0078 % Copyright (c) 1996-2011 by Power System Engineering Research Center (PSERC) 0079 % 0080 % This file is part of MATPOWER. 0081 % See http://www.pserc.cornell.edu/matpower/ for more info. 0082 % 0083 % MATPOWER is free software: you can redistribute it and/or modify 0084 % it under the terms of the GNU General Public License as published 0085 % by the Free Software Foundation, either version 3 of the License, 0086 % or (at your option) any later version. 0087 % 0088 % MATPOWER is distributed in the hope that it will be useful, 0089 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0090 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0091 % GNU General Public License for more details. 0092 % 0093 % You should have received a copy of the GNU General Public License 0094 % along with MATPOWER. If not, see <http://www.gnu.org/licenses/>. 0095 % 0096 % Additional permission under GNU GPL version 3 section 7 0097 % 0098 % If you modify MATPOWER, or any covered work, to interface with 0099 % other modules (such as MATLAB code and MEX-files) available in a 0100 % MATLAB(R) or comparable environment containing parts covered 0101 % under other licensing terms, the licensors of MATPOWER grant 0102 % you additional permission to convey the resulting work. 0103 0104 if isstruct(bus) 0105 mpc = bus; 0106 if nargin == 1 0107 first = ~isfield(mpc, 'order'); 0108 if first || mpc.order.state == 'e' 0109 %% define names for columns to data matrices 0110 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE] = idx_bus; 0111 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS] = idx_gen; 0112 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ... 0113 TAP, SHIFT, BR_STATUS] = idx_brch; 0114 [AREA_I, PRICE_REF_BUS] = idx_area; 0115 0116 %% initialize order 0117 if first 0118 status = struct('on', [], ... 0119 'off', [] ); 0120 tmp = struct( ... 0121 'e2i', [], ... 0122 'i2e', [], ... 0123 'status', status ... 0124 ); 0125 o = struct( ... 0126 'ext', struct( ... 0127 'bus', [], ... 0128 'branch', [], ... 0129 'gen', [] ... 0130 ), ... 0131 'bus', tmp, ... 0132 'gen', tmp, ... 0133 'branch', struct('status', status) ... 0134 ); 0135 else 0136 o = mpc.order; 0137 end 0138 0139 %% sizes 0140 nb = size(mpc.bus, 1); 0141 ng = size(mpc.gen, 1); 0142 ng0 = ng; 0143 if isfield(mpc, 'A') && size(mpc.A, 2) < 2*nb + 2*ng 0144 dc = 1; 0145 elseif isfield(mpc, 'N') && size(mpc.N, 2) < 2*nb + 2*ng 0146 dc = 1; 0147 else 0148 dc = 0; 0149 end 0150 0151 %% save data matrices with external ordering 0152 o.ext.bus = mpc.bus; 0153 o.ext.branch = mpc.branch; 0154 o.ext.gen = mpc.gen; 0155 if isfield(mpc, 'areas') 0156 if isempty(mpc.areas) %% if areas field is empty 0157 mpc = rmfield(mpc, 'areas'); %% delete it (so it gets ignored) 0158 else %% otherwise 0159 o.ext.areas = mpc.areas; %% save it 0160 end 0161 end 0162 0163 %% check that all buses have a valid BUS_TYPE 0164 bt = mpc.bus(:, BUS_TYPE); 0165 err = find(~(bt == PQ | bt == PV | bt == REF | bt == NONE)); 0166 if ~isempty(err) 0167 error('ext2int: bus %d has an invalid BUS_TYPE', err); 0168 end 0169 0170 %% determine which buses, branches, gens are connected & in-service 0171 n2i = sparse(mpc.bus(:, BUS_I), ones(nb, 1), 1:nb, max(mpc.bus(:, BUS_I)), 1); 0172 bs = (bt ~= NONE); %% bus status 0173 o.bus.status.on = find( bs ); %% connected 0174 o.bus.status.off = find( ~bs ); %% isolated 0175 gs = ( mpc.gen(:, GEN_STATUS) > 0 & ... %% gen status 0176 bs(n2i(mpc.gen(:, GEN_BUS))) ); 0177 o.gen.status.on = find( gs ); %% on and connected 0178 o.gen.status.off = find( ~gs ); %% off or isolated 0179 brs = ( mpc.branch(:, BR_STATUS) & ... %% branch status 0180 bs(n2i(mpc.branch(:, F_BUS))) & ... 0181 bs(n2i(mpc.branch(:, T_BUS))) ); 0182 o.branch.status.on = find( brs ); %% on and connected 0183 o.branch.status.off = find( ~brs ); 0184 if isfield(mpc, 'areas') 0185 as = bs(n2i(mpc.areas(:, PRICE_REF_BUS))); 0186 o.areas.status.on = find( as ); 0187 o.areas.status.off = find( ~as ); 0188 end 0189 0190 %% delete stuff that is "out" 0191 if ~isempty(o.bus.status.off) 0192 mpc.bus(o.bus.status.off, :) = []; 0193 end 0194 if ~isempty(o.branch.status.off) 0195 mpc.branch(o.branch.status.off, :) = []; 0196 end 0197 if ~isempty(o.gen.status.off) 0198 mpc.gen(o.gen.status.off, :) = []; 0199 end 0200 if isfield(mpc, 'areas') && ~isempty(o.areas.status.off) 0201 mpc.areas(o.areas.status.off, :) = []; 0202 end 0203 0204 %% update size 0205 nb = size(mpc.bus, 1); 0206 0207 %% apply consecutive bus numbering 0208 o.bus.i2e = mpc.bus(:, BUS_I); 0209 o.bus.e2i = sparse(max(o.bus.i2e), 1); 0210 o.bus.e2i(o.bus.i2e) = (1:nb)'; 0211 mpc.bus(:, BUS_I) = o.bus.e2i( mpc.bus(:, BUS_I) ); 0212 mpc.gen(:, GEN_BUS) = o.bus.e2i( mpc.gen(:, GEN_BUS) ); 0213 mpc.branch(:, F_BUS) = o.bus.e2i( mpc.branch(:, F_BUS) ); 0214 mpc.branch(:, T_BUS) = o.bus.e2i( mpc.branch(:, T_BUS) ); 0215 if isfield(mpc, 'areas') 0216 mpc.areas(:, PRICE_REF_BUS) = o.bus.e2i( mpc.areas(:, PRICE_REF_BUS) ); 0217 end 0218 0219 %% reorder gens in order of increasing bus number 0220 [tmp, o.gen.e2i] = sort(mpc.gen(:, GEN_BUS)); 0221 [tmp, o.gen.i2e] = sort(o.gen.e2i); 0222 mpc.gen = mpc.gen(o.gen.e2i, :); 0223 0224 if isfield(o, 'int') 0225 o = rmfield(o, 'int'); 0226 end 0227 o.state = 'i'; 0228 mpc.order = o; 0229 0230 %% update gencost, A and N 0231 if isfield(mpc, 'gencost') 0232 ordering = {'gen'}; %% Pg cost only 0233 if size(mpc.gencost, 1) == 2*ng0 0234 ordering{2} = 'gen'; %% include Qg cost 0235 end 0236 mpc = e2i_field(mpc, 'gencost', ordering); 0237 end 0238 if isfield(mpc, 'A') || isfield(mpc, 'N') 0239 if dc 0240 ordering = {'bus', 'gen'}; 0241 else 0242 ordering = {'bus', 'bus', 'gen', 'gen'}; 0243 end 0244 end 0245 if isfield(mpc, 'A') 0246 mpc = e2i_field(mpc, 'A', ordering, 2); 0247 end 0248 if isfield(mpc, 'N') 0249 mpc = e2i_field(mpc, 'N', ordering, 2); 0250 end 0251 0252 %% execute userfcn callbacks for 'ext2int' stage 0253 if isfield(mpc, 'userfcn') 0254 mpc = run_userfcn(mpc.userfcn, 'ext2int', mpc); 0255 end 0256 end 0257 0258 i2e = mpc; 0259 else %% convert extra data 0260 ordering = branch; %% rename argument 0261 if nargin < 4 0262 dim = 1; 0263 else 0264 dim = areas; %% rename argument 0265 end 0266 if ischar(gen) || iscell(gen) %% field 0267 warning('Calls of the form MPC = EXT2INT(MPC, ''FIELD_NAME'', ...) have been deprecated. Please replace EXT2INT with E2I_FIELD.'); 0268 i2e = e2i_field(mpc, gen, branch, dim); 0269 else %% value 0270 warning('Calls of the form VAL = EXT2INT(MPC, VAL, ...) have been deprecated. Please replace EXT2INT with E2I_DATA.'); 0271 i2e = e2i_data(mpc, gen, branch, dim); 0272 end 0273 end 0274 else %% old form 0275 %% define names for columns to data matrices 0276 [PQ, PV, REF, NONE, BUS_I] = idx_bus; 0277 [GEN_BUS] = idx_gen; 0278 [F_BUS, T_BUS] = idx_brch; 0279 [AREA_I, PRICE_REF_BUS] = idx_area; 0280 0281 %% create map of external bus numbers to bus indices 0282 i2e = bus(:, BUS_I); 0283 e2i = sparse(max(i2e), 1); 0284 e2i(i2e) = (1:size(bus, 1))'; 0285 0286 %% renumber buses consecutively 0287 bus(:, BUS_I) = e2i( bus(:, BUS_I) ); 0288 gen(:, GEN_BUS) = e2i( gen(:, GEN_BUS) ); 0289 branch(:, F_BUS) = e2i( branch(:, F_BUS) ); 0290 branch(:, T_BUS) = e2i( branch(:, T_BUS) ); 0291 if nargin > 3 && nargout > 4 && ~isempty(areas) 0292 areas(:, PRICE_REF_BUS) = e2i( areas(:, PRICE_REF_BUS) ); 0293 end 0294 end