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