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 and BRANCH, 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). AREAS is completely ignored and is only included here for backward compatibility of the API. 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 or branches 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 bus branch gen gencost A N bus e2i i2e status on off gen e2i i2e status on off branch 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 and BRANCH, 0014 % which are returned along with a vector of indices I2E that can be 0015 % passed to INT2EXT to perform the reverse conversion, where 0016 % EXTERNAL_BUS_NUMBER = I2E(INTERNAL_BUS_NUMBER). 0017 % AREAS is completely ignored and is only included here for backward 0018 % compatibility of the API. 0019 % 0020 % Examples: 0021 % [i2e, bus, gen, branch, areas] = ext2int(bus, gen, branch, areas); 0022 % [i2e, bus, gen, branch] = ext2int(bus, gen, branch); 0023 % 0024 % 2. MPC = EXT2INT(MPC) 0025 % 0026 % If the input is a single MATPOWER case struct, then all isolated 0027 % buses, off-line generators and branches are removed along with any 0028 % generators or branches connected to isolated buses. Then the 0029 % buses are renumbered consecutively, beginning at 1, and the 0030 % generators are sorted by increasing bus number. Any 'ext2int' 0031 % callback routines registered in the case are also invoked 0032 % automatically. All of the related indexing information and the 0033 % original data matrices are stored in an 'order' field in the struct 0034 % to be used by INT2EXT to perform the reverse conversions. If the 0035 % case is already using internal numbering it is returned unchanged. 0036 % 0037 % Example: 0038 % mpc = ext2int(mpc); 0039 % 0040 % The 'order' field of MPC used to store the indexing information 0041 % needed for subsequent internal to external conversion is structured 0042 % as: 0043 % 0044 % order 0045 % state 'i' | 'e' 0046 % ext | int 0047 % bus 0048 % branch 0049 % gen 0050 % gencost 0051 % A 0052 % N 0053 % bus 0054 % e2i 0055 % i2e 0056 % status 0057 % on 0058 % off 0059 % gen 0060 % e2i 0061 % i2e 0062 % status 0063 % on 0064 % off 0065 % branch 0066 % status 0067 % on 0068 % off 0069 % 0070 % See also INT2EXT, E2I_FIELD, E2I_DATA. 0071 0072 % MATPOWER 0073 % Copyright (c) 1996-2016, Power Systems Engineering Research Center (PSERC) 0074 % by Ray Zimmerman, PSERC Cornell 0075 % 0076 % This file is part of MATPOWER. 0077 % Covered by the 3-clause BSD License (see LICENSE file for details). 0078 % See http://www.pserc.cornell.edu/matpower/ for more info. 0079 0080 if isstruct(bus) 0081 mpc = bus; 0082 if nargin == 1 0083 first = ~isfield(mpc, 'order'); 0084 if first || mpc.order.state == 'e' 0085 %% define names for columns to data matrices 0086 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE] = idx_bus; 0087 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS] = idx_gen; 0088 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ... 0089 TAP, SHIFT, BR_STATUS] = idx_brch; 0090 0091 %% initialize order 0092 if first 0093 status = struct('on', [], ... 0094 'off', [] ); 0095 tmp = struct( ... 0096 'e2i', [], ... 0097 'i2e', [], ... 0098 'status', status ... 0099 ); 0100 o = struct( ... 0101 'ext', struct( ... 0102 'bus', [], ... 0103 'branch', [], ... 0104 'gen', [] ... 0105 ), ... 0106 'bus', tmp, ... 0107 'gen', tmp, ... 0108 'branch', struct('status', status) ... 0109 ); 0110 else 0111 o = mpc.order; 0112 end 0113 0114 %% sizes 0115 nb = size(mpc.bus, 1); 0116 ng = size(mpc.gen, 1); 0117 ng0 = ng; 0118 if isfield(mpc, 'A') && size(mpc.A, 2) < 2*nb + 2*ng 0119 dc = 1; 0120 elseif isfield(mpc, 'N') && size(mpc.N, 2) < 2*nb + 2*ng 0121 dc = 1; 0122 else 0123 dc = 0; 0124 end 0125 0126 %% save data matrices with external ordering 0127 o.ext.bus = mpc.bus; 0128 o.ext.branch = mpc.branch; 0129 o.ext.gen = mpc.gen; 0130 0131 %% check that all buses have a valid BUS_TYPE 0132 bt = mpc.bus(:, BUS_TYPE); 0133 err = find(~(bt == PQ | bt == PV | bt == REF | bt == NONE)); 0134 if ~isempty(err) 0135 error('ext2int: bus %d has an invalid BUS_TYPE', err); 0136 end 0137 0138 %% determine which buses, branches, gens are connected & in-service 0139 n2i = sparse(mpc.bus(:, BUS_I), ones(nb, 1), 1:nb, max(mpc.bus(:, BUS_I)), 1); 0140 bs = (bt ~= NONE); %% bus status 0141 o.bus.status.on = find( bs ); %% connected 0142 o.bus.status.off = find( ~bs ); %% isolated 0143 gs = ( mpc.gen(:, GEN_STATUS) > 0 & ... %% gen status 0144 bs(n2i(mpc.gen(:, GEN_BUS))) ); 0145 o.gen.status.on = find( gs ); %% on and connected 0146 o.gen.status.off = find( ~gs ); %% off or isolated 0147 brs = ( mpc.branch(:, BR_STATUS) & ... %% branch status 0148 bs(n2i(mpc.branch(:, F_BUS))) & ... 0149 bs(n2i(mpc.branch(:, T_BUS))) ); 0150 o.branch.status.on = find( brs ); %% on and connected 0151 o.branch.status.off = find( ~brs ); 0152 0153 %% delete stuff that is "out" 0154 if ~isempty(o.bus.status.off) 0155 mpc.bus(o.bus.status.off, :) = []; 0156 end 0157 if ~isempty(o.branch.status.off) 0158 mpc.branch(o.branch.status.off, :) = []; 0159 end 0160 if ~isempty(o.gen.status.off) 0161 mpc.gen(o.gen.status.off, :) = []; 0162 end 0163 0164 %% update size 0165 nb = size(mpc.bus, 1); 0166 0167 %% apply consecutive bus numbering 0168 o.bus.i2e = mpc.bus(:, BUS_I); 0169 o.bus.e2i = sparse(max(o.bus.i2e), 1); 0170 o.bus.e2i(o.bus.i2e) = (1:nb)'; 0171 mpc.bus(:, BUS_I) = o.bus.e2i( mpc.bus(:, BUS_I) ); 0172 mpc.gen(:, GEN_BUS) = o.bus.e2i( mpc.gen(:, GEN_BUS) ); 0173 mpc.branch(:, F_BUS) = o.bus.e2i( mpc.branch(:, F_BUS) ); 0174 mpc.branch(:, T_BUS) = o.bus.e2i( mpc.branch(:, T_BUS) ); 0175 0176 %% reorder gens in order of increasing bus number 0177 [tmp, o.gen.e2i] = sort(mpc.gen(:, GEN_BUS)); 0178 [tmp, o.gen.i2e] = sort(o.gen.e2i); 0179 mpc.gen = mpc.gen(o.gen.e2i, :); 0180 0181 if isfield(o, 'int') 0182 o = rmfield(o, 'int'); 0183 end 0184 o.state = 'i'; 0185 mpc.order = o; 0186 0187 %% update gencost, A and N 0188 if isfield(mpc, 'gencost') 0189 ordering = {'gen'}; %% Pg cost only 0190 if size(mpc.gencost, 1) == 2*ng0 0191 ordering{2} = 'gen'; %% include Qg cost 0192 end 0193 mpc = e2i_field(mpc, 'gencost', ordering); 0194 end 0195 if isfield(mpc, 'A') || isfield(mpc, 'N') 0196 if dc 0197 ordering = {'bus', 'gen'}; 0198 else 0199 ordering = {'bus', 'bus', 'gen', 'gen'}; 0200 end 0201 end 0202 if isfield(mpc, 'A') 0203 mpc = e2i_field(mpc, 'A', ordering, 2); 0204 end 0205 if isfield(mpc, 'N') 0206 mpc = e2i_field(mpc, 'N', ordering, 2); 0207 end 0208 0209 %% execute userfcn callbacks for 'ext2int' stage 0210 if isfield(mpc, 'userfcn') 0211 mpc = run_userfcn(mpc.userfcn, 'ext2int', mpc); 0212 end 0213 end 0214 0215 i2e = mpc; 0216 else %% convert extra data 0217 ordering = branch; %% rename argument 0218 if nargin < 4 0219 dim = 1; 0220 else 0221 dim = areas; %% rename argument 0222 end 0223 if ischar(gen) || iscell(gen) %% field 0224 warning('Calls of the form MPC = EXT2INT(MPC, ''FIELD_NAME'', ...) have been deprecated. Please replace EXT2INT with E2I_FIELD.'); 0225 i2e = e2i_field(mpc, gen, branch, dim); 0226 else %% value 0227 warning('Calls of the form VAL = EXT2INT(MPC, VAL, ...) have been deprecated. Please replace EXT2INT with E2I_DATA.'); 0228 i2e = e2i_data(mpc, gen, branch, dim); 0229 end 0230 end 0231 else %% old form 0232 %% define names for columns to data matrices 0233 [PQ, PV, REF, NONE, BUS_I] = idx_bus; 0234 [GEN_BUS] = idx_gen; 0235 [F_BUS, T_BUS] = idx_brch; 0236 0237 %% create map of external bus numbers to bus indices 0238 i2e = bus(:, BUS_I); 0239 e2i = sparse(max(i2e), 1); 0240 e2i(i2e) = (1:size(bus, 1))'; 0241 0242 %% renumber buses consecutively 0243 bus(:, BUS_I) = e2i( bus(:, BUS_I) ); 0244 gen(:, GEN_BUS) = e2i( gen(:, GEN_BUS) ); 0245 branch(:, F_BUS) = e2i( branch(:, F_BUS) ); 0246 branch(:, T_BUS) = e2i( branch(:, T_BUS) ); 0247 end