function mpck = extract_islands(mpc, groups, k, custom) EXTRACT_ISLANDS Extracts each island in a network with islands MPC_ARRAY = EXTRACT_ISLANDS(MPC) MPC_ARRAY = EXTRACT_ISLANDS(MPC, GROUPS) MPC_K = EXTRACT_ISLANDS(MPC, K) MPC_K = EXTRACT_ISLANDS(MPC, GROUPS, K) MPC_K = EXTRACT_ISLANDS(MPC, K, CUSTOM) MPC_K = EXTRACT_ISLANDS(MPC, GROUPS, K, CUSTOM) Returns a cell array of MATPOWER case structs for each island in the input case struct. If the optional second argument is a cell array GROUPS it is assumed to be a cell array of vectors of bus indices for each island (as returned by FIND_ISLANDS). Providing the GROUPS avoids the need for another traversal of the network connectivity and can save a significant amount of time on very large systems. If an additional argument K is included, it indicates which island(s) to return and the return value is a single case struct, rather than a cell array. If K is a scalar or vector, it it specifies the index(indices) of the island(s) to include in the resulting case file. K can also be the string 'all' which will include all islands. This is the same as simply eliminating all isolated buses. A final optional argument CUSTOM is a struct that can be used to indicate custom fields of MPC from which to extract data corresponding to buses generators, branches or DC lines. It has the following structure: CUSTOM.<ORDERING>{DIM} = FIELDS <ORDERING> is either 'bus', 'gen', 'branch' or 'dcline' and indicates that dimension DIM of FIELDS has dimensions corresponding to this <ORDERING> and should have the appropriate dimension extracted as well. FIELDS is a cell array, where each element is either a single string (field name of MPC) or a cell array of strings (nested fields of MPC). Examples: Extract each island into it's own case struct: mpc_list = extract_islands(mpc); Extract the 2nd (that is, 2nd largest) island: mpc2 = extract_islands(mpc, 2); Extract the first and 3rd islands without a re-traverals of the network: groups = find_islands(mpc); mpc1 = extract_islands(mpc, groups, 1); mpc3 = extract_islands(mpc, groups, 3); Extract the 2nd island, including custom fields, where mpc.bus_name{b} contains the name of bus b, and mpc.genfuel{g}, mpc.emissions.rate(g, :), and mpc.genloc(:, g) contain, respectively, the generator's fuel type, emission rates and location coordinates: custom.bus{1} = {'bus_name'}; custom.gen{1} = {'genfuel', {'emissions', 'rate'}}; custom.gen{2} = {'genloc'}; mpc = extract_islands(mpc, 1, custom); See also FIND_ISLANDS, CASE_INFO, CONNECTED_COMPONENTS.
0001 function mpck = extract_islands(mpc, varargin) 0002 %function mpck = extract_islands(mpc, groups, k, custom) 0003 %EXTRACT_ISLANDS Extracts each island in a network with islands 0004 % MPC_ARRAY = EXTRACT_ISLANDS(MPC) 0005 % MPC_ARRAY = EXTRACT_ISLANDS(MPC, GROUPS) 0006 % MPC_K = EXTRACT_ISLANDS(MPC, K) 0007 % MPC_K = EXTRACT_ISLANDS(MPC, GROUPS, K) 0008 % MPC_K = EXTRACT_ISLANDS(MPC, K, CUSTOM) 0009 % MPC_K = EXTRACT_ISLANDS(MPC, GROUPS, K, CUSTOM) 0010 % 0011 % Returns a cell array of MATPOWER case structs for each island in 0012 % the input case struct. If the optional second argument is a cell 0013 % array GROUPS it is assumed to be a cell array of vectors of bus 0014 % indices for each island (as returned by FIND_ISLANDS). Providing 0015 % the GROUPS avoids the need for another traversal of the network 0016 % connectivity and can save a significant amount of time on very 0017 % large systems. If an additional argument K is included, it indicates 0018 % which island(s) to return and the return value is a single case 0019 % struct, rather than a cell array. If K is a scalar or vector, it 0020 % it specifies the index(indices) of the island(s) to include in 0021 % the resulting case file. K can also be the string 'all' which 0022 % will include all islands. This is the same as simply eliminating 0023 % all isolated buses. 0024 % 0025 % A final optional argument CUSTOM is a struct that can be used to 0026 % indicate custom fields of MPC from which to extract data 0027 % corresponding to buses generators, branches or DC lines. It has 0028 % the following structure: 0029 % 0030 % CUSTOM.<ORDERING>{DIM} = FIELDS 0031 % 0032 % <ORDERING> is either 'bus', 'gen', 'branch' or 'dcline' and 0033 % indicates that dimension DIM of FIELDS has dimensions 0034 % corresponding to this <ORDERING> and should have the appropriate 0035 % dimension extracted as well. FIELDS is a cell array, where 0036 % each element is either a single string (field name of MPC) or 0037 % a cell array of strings (nested fields of MPC). 0038 % 0039 % Examples: 0040 % Extract each island into it's own case struct: 0041 % mpc_list = extract_islands(mpc); 0042 % 0043 % Extract the 2nd (that is, 2nd largest) island: 0044 % mpc2 = extract_islands(mpc, 2); 0045 % 0046 % Extract the first and 3rd islands without a re-traverals of the 0047 % network: 0048 % groups = find_islands(mpc); 0049 % mpc1 = extract_islands(mpc, groups, 1); 0050 % mpc3 = extract_islands(mpc, groups, 3); 0051 % 0052 % Extract the 2nd island, including custom fields, where 0053 % mpc.bus_name{b} contains the name of bus b, and mpc.genfuel{g}, 0054 % mpc.emissions.rate(g, :), and mpc.genloc(:, g) contain, 0055 % respectively, the generator's fuel type, emission rates and 0056 % location coordinates: 0057 % custom.bus{1} = {'bus_name'}; 0058 % custom.gen{1} = {'genfuel', {'emissions', 'rate'}}; 0059 % custom.gen{2} = {'genloc'}; 0060 % mpc = extract_islands(mpc, 1, custom); 0061 % 0062 % See also FIND_ISLANDS, CASE_INFO, CONNECTED_COMPONENTS. 0063 0064 % MATPOWER 0065 % $Id: extract_islands.m 2373 2014-08-11 13:56:55Z ray $ 0066 % by Ray Zimmerman, PSERC Cornell 0067 % Copyright (c) 2012, 2014 by Power System Engineering Research Center (PSERC) 0068 % 0069 % This file is part of MATPOWER. 0070 % See http://www.pserc.cornell.edu/matpower/ for more info. 0071 % 0072 % MATPOWER is free software: you can redistribute it and/or modify 0073 % it under the terms of the GNU General Public License as published 0074 % by the Free Software Foundation, either version 3 of the License, 0075 % or (at your option) any later version. 0076 % 0077 % MATPOWER is distributed in the hope that it will be useful, 0078 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0079 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0080 % GNU General Public License for more details. 0081 % 0082 % You should have received a copy of the GNU General Public License 0083 % along with MATPOWER. If not, see <http://www.gnu.org/licenses/>. 0084 % 0085 % Additional permission under GNU GPL version 3 section 7 0086 % 0087 % If you modify MATPOWER, or any covered work, to interface with 0088 % other modules (such as MATLAB code and MEX-files) available in a 0089 % MATLAB(R) or comparable environment containing parts covered 0090 % under other licensing terms, the licensors of MATPOWER grant 0091 % you additional permission to convey the resulting work. 0092 0093 %% define named indices into data matrices 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 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ... 0097 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ... 0098 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen; 0099 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ... 0100 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ... 0101 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch; 0102 c = idx_dcline; 0103 0104 %% set up connectivity matrices 0105 nb = size(mpc.bus, 1); %% number of buses 0106 nl = size(mpc.branch, 1); %% number of branches 0107 if isfield(mpc, 'dcline') %% number of DC lines 0108 ndc = size(mpc.dcline, 1); 0109 else 0110 ndc = 0; 0111 end 0112 ng = size(mpc.gen, 1); %% number of dispatchable injections 0113 0114 e2i = sparse(mpc.bus(:, BUS_I), ones(nb, 1), 1:nb, max(mpc.bus(:, BUS_I)), 1); 0115 C_on = sparse(1:nl, e2i(mpc.branch(:, F_BUS)), -mpc.branch(:, BR_STATUS), nl, nb) + ... 0116 sparse(1:nl, e2i(mpc.branch(:, T_BUS)), mpc.branch(:, BR_STATUS), nl, nb); 0117 C = sparse(1:nl, e2i(mpc.branch(:, F_BUS)), -1, nl, nb) + ... 0118 sparse(1:nl, e2i(mpc.branch(:, T_BUS)), 1, nl, nb); 0119 if ndc 0120 Cdc_on = sparse(1:ndc, e2i(mpc.dcline(:, c.F_BUS)), -mpc.dcline(:, c.BR_STATUS), ndc, nb) + ... 0121 sparse(1:ndc, e2i(mpc.dcline(:, c.T_BUS)), mpc.dcline(:, c.BR_STATUS), ndc, nb); 0122 Cdc = sparse(1:ndc, e2i(mpc.dcline(:, c.F_BUS)), -1, ndc, nb) + ... 0123 sparse(1:ndc, e2i(mpc.dcline(:, c.T_BUS)), 1, ndc, nb); 0124 end 0125 Cg_on = sparse(1:ng, e2i(mpc.gen(:, GEN_BUS)), mpc.gen(:, GEN_STATUS), ng, nb); 0126 Cg = sparse(1:ng, e2i(mpc.gen(:, GEN_BUS)), 1, ng, nb); 0127 0128 if nnz(C) 0129 n = length(varargin); 0130 if n >= 1 && iscell(varargin{1}) 0131 groups = varargin{1}; 0132 z = 1; 0133 else 0134 groups = {}; 0135 z = 0; 0136 end 0137 if z+1 <= n 0138 k = varargin{z+1}; 0139 else 0140 k = []; 0141 end 0142 if z+2 <= n 0143 custom = varargin{z+2}; 0144 else 0145 custom = struct(); 0146 end 0147 0148 %% find islands, if not provided 0149 if isempty(groups) 0150 groups = connected_components(C_on); 0151 end 0152 0153 %% check inputs 0154 if isempty(k) 0155 g1 = 1; 0156 gn = length(groups); 0157 else 0158 if ischar(k) 0159 if strcmp(upper(k), 'ALL') 0160 k = (1:length(groups))'; 0161 else 0162 error('extract_islands: K = ''%s'' is not a valid input', k); 0163 end 0164 end 0165 if max(k) > length(groups) 0166 error('extract_islands: cannot extract island %d, network has only %d islands', ... 0167 max(k), length(groups)); 0168 end 0169 if length(k) > 1 %% extract multiple islands as one case 0170 tmpgroup = groups{k(1)}; 0171 for j = 2:length(k) 0172 tmpgroup = union(tmpgroup, groups{k(j)}); 0173 end 0174 groups = { tmpgroup }; 0175 g1 = 1; 0176 gn = 1; 0177 else %% extract single island 0178 g1 = k; 0179 gn = k; 0180 end 0181 end 0182 0183 %% extract islands 0184 for i = g1:gn 0185 kk = i-g1+1; 0186 b = groups{i}; %% buses in group i 0187 %% branches with both ends in group i 0188 ibr = find(sum(abs(C(:, b)), 2) & ~sum(C(:, b), 2)); 0189 ig = find(sum(Cg(:, b), 2)); %% gens in group i 0190 %% DC lines with both ends in group i 0191 if ndc 0192 idc = find(sum(abs(Cdc(:, b)), 2) & ~sum(Cdc(:, b), 2)); 0193 else 0194 idc = []; 0195 end 0196 0197 mpck{kk} = mpc; 0198 mpck{kk}.bus = mpc.bus(b, :); 0199 mpck{kk}.branch = mpc.branch(ibr, :); 0200 mpck{kk}.gen = mpc.gen(ig, :); 0201 if isfield(mpck{kk}, 'gencost') 0202 if size(mpck{kk}.gencost, 1) == 2*ng 0203 mpck{kk}.gencost = mpc.gencost([ig; ng+ig], :); 0204 else 0205 mpck{kk}.gencost = mpc.gencost(ig, :); 0206 end 0207 end 0208 if ndc 0209 mpck{kk}.dcline = mpc.dcline(idc, :); 0210 if isfield(mpck{kk}, 'dclinecost') 0211 mpck{kk}.dclinecost = mpc.dclinecost(idc, :); 0212 end 0213 end 0214 0215 %% handle custom fields 0216 orderings = {'bus', 'gen', 'branch', 'dcline'}; 0217 indexes = {b, ig, ibr, idc}; 0218 0219 for n = 1:length(orderings) 0220 ord = orderings{n}; 0221 if isfield(custom, ord) 0222 for dim = 1:length(custom.(ord)) 0223 for j = 1:length(custom.(ord){dim}) 0224 s = []; 0225 field = custom.(ord){dim}{j}; 0226 if ischar(field) 0227 field = { field }; 0228 end 0229 0230 tmp = mpck{kk}; %% check this for presence of sub-fields 0231 skip = 0; 0232 for i = 1:length(field) 0233 s(i).type = '.'; 0234 s(i).subs = field{i}; 0235 if isfield(tmp, field{i}) && ~isempty(tmp.(field{i})) 0236 %% have sub-field, continue 0237 tmp = tmp.(field{i}); 0238 else 0239 %% sub-field doesn't exist, skip it 0240 skip = 1; 0241 break; 0242 end 0243 end 0244 if ~skip 0245 mpck{kk} = subsasgn(mpck{kk}, s, get_reorder(subsref(mpck{kk}, s), indexes{n}, dim)); 0246 end 0247 end 0248 end 0249 end 0250 end 0251 end 0252 0253 %% convert from cell array to single MATPOWER case struct as appropriate 0254 if ~isempty(k) 0255 mpck = mpck{1}; 0256 end 0257 else 0258 mpck = []; 0259 end