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 % Copyright (c) 2012-2015 by Power System Engineering Research Center (PSERC) 0066 % by Ray Zimmerman, PSERC Cornell 0067 % 0068 % $Id: extract_islands.m 2644 2015-03-11 19:34:22Z ray $ 0069 % 0070 % This file is part of MATPOWER. 0071 % Covered by the 3-clause BSD License (see LICENSE file for details). 0072 % See http://www.pserc.cornell.edu/matpower/ for more info. 0073 0074 %% define named indices into data matrices 0075 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ... 0076 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus; 0077 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ... 0078 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ... 0079 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen; 0080 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ... 0081 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ... 0082 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch; 0083 c = idx_dcline; 0084 0085 %% set up connectivity matrices 0086 nb = size(mpc.bus, 1); %% number of buses 0087 nl = size(mpc.branch, 1); %% number of branches 0088 if isfield(mpc, 'dcline') %% number of DC lines 0089 ndc = size(mpc.dcline, 1); 0090 else 0091 ndc = 0; 0092 end 0093 ng = size(mpc.gen, 1); %% number of dispatchable injections 0094 0095 e2i = sparse(mpc.bus(:, BUS_I), ones(nb, 1), 1:nb, max(mpc.bus(:, BUS_I)), 1); 0096 C_on = sparse(1:nl, e2i(mpc.branch(:, F_BUS)), -mpc.branch(:, BR_STATUS), nl, nb) + ... 0097 sparse(1:nl, e2i(mpc.branch(:, T_BUS)), mpc.branch(:, BR_STATUS), nl, nb); 0098 C = sparse(1:nl, e2i(mpc.branch(:, F_BUS)), -1, nl, nb) + ... 0099 sparse(1:nl, e2i(mpc.branch(:, T_BUS)), 1, nl, nb); 0100 if ndc 0101 Cdc_on = sparse(1:ndc, e2i(mpc.dcline(:, c.F_BUS)), -mpc.dcline(:, c.BR_STATUS), ndc, nb) + ... 0102 sparse(1:ndc, e2i(mpc.dcline(:, c.T_BUS)), mpc.dcline(:, c.BR_STATUS), ndc, nb); 0103 Cdc = sparse(1:ndc, e2i(mpc.dcline(:, c.F_BUS)), -1, ndc, nb) + ... 0104 sparse(1:ndc, e2i(mpc.dcline(:, c.T_BUS)), 1, ndc, nb); 0105 end 0106 Cg_on = sparse(1:ng, e2i(mpc.gen(:, GEN_BUS)), mpc.gen(:, GEN_STATUS), ng, nb); 0107 Cg = sparse(1:ng, e2i(mpc.gen(:, GEN_BUS)), 1, ng, nb); 0108 0109 if nnz(C) 0110 n = length(varargin); 0111 if n >= 1 && iscell(varargin{1}) 0112 groups = varargin{1}; 0113 z = 1; 0114 else 0115 groups = {}; 0116 z = 0; 0117 end 0118 if z+1 <= n 0119 k = varargin{z+1}; 0120 else 0121 k = []; 0122 end 0123 if z+2 <= n 0124 custom = varargin{z+2}; 0125 else 0126 custom = struct(); 0127 end 0128 0129 %% find islands, if not provided 0130 if isempty(groups) 0131 groups = connected_components(C_on); 0132 end 0133 0134 %% check inputs 0135 if isempty(k) 0136 g1 = 1; 0137 gn = length(groups); 0138 else 0139 if ischar(k) 0140 if strcmp(upper(k), 'ALL') 0141 k = (1:length(groups))'; 0142 else 0143 error('extract_islands: K = ''%s'' is not a valid input', k); 0144 end 0145 end 0146 if max(k) > length(groups) 0147 error('extract_islands: cannot extract island %d, network has only %d islands', ... 0148 max(k), length(groups)); 0149 end 0150 if length(k) > 1 %% extract multiple islands as one case 0151 tmpgroup = groups{k(1)}; 0152 for j = 2:length(k) 0153 tmpgroup = union(tmpgroup, groups{k(j)}); 0154 end 0155 groups = { tmpgroup }; 0156 g1 = 1; 0157 gn = 1; 0158 else %% extract single island 0159 g1 = k; 0160 gn = k; 0161 end 0162 end 0163 0164 %% extract islands 0165 for i = g1:gn 0166 kk = i-g1+1; 0167 b = groups{i}; %% buses in group i 0168 %% branches with both ends in group i 0169 ibr = find(sum(abs(C(:, b)), 2) & ~sum(C(:, b), 2)); 0170 ig = find(sum(Cg(:, b), 2)); %% gens in group i 0171 %% DC lines with both ends in group i 0172 if ndc 0173 idc = find(sum(abs(Cdc(:, b)), 2) & ~sum(Cdc(:, b), 2)); 0174 else 0175 idc = []; 0176 end 0177 0178 mpck{kk} = mpc; 0179 mpck{kk}.bus = mpc.bus(b, :); 0180 mpck{kk}.branch = mpc.branch(ibr, :); 0181 mpck{kk}.gen = mpc.gen(ig, :); 0182 if isfield(mpck{kk}, 'gencost') 0183 if size(mpck{kk}.gencost, 1) == 2*ng 0184 mpck{kk}.gencost = mpc.gencost([ig; ng+ig], :); 0185 else 0186 mpck{kk}.gencost = mpc.gencost(ig, :); 0187 end 0188 end 0189 if ndc 0190 mpck{kk}.dcline = mpc.dcline(idc, :); 0191 if isfield(mpck{kk}, 'dclinecost') 0192 mpck{kk}.dclinecost = mpc.dclinecost(idc, :); 0193 end 0194 end 0195 0196 %% handle custom fields 0197 orderings = {'bus', 'gen', 'branch', 'dcline'}; 0198 indexes = {b, ig, ibr, idc}; 0199 0200 for n = 1:length(orderings) 0201 ord = orderings{n}; 0202 if isfield(custom, ord) 0203 for dim = 1:length(custom.(ord)) 0204 for j = 1:length(custom.(ord){dim}) 0205 s = []; 0206 field = custom.(ord){dim}{j}; 0207 if ischar(field) 0208 field = { field }; 0209 end 0210 0211 tmp = mpck{kk}; %% check this for presence of sub-fields 0212 skip = 0; 0213 for i = 1:length(field) 0214 s(i).type = '.'; 0215 s(i).subs = field{i}; 0216 if isfield(tmp, field{i}) && ~isempty(tmp.(field{i})) 0217 %% have sub-field, continue 0218 tmp = tmp.(field{i}); 0219 else 0220 %% sub-field doesn't exist, skip it 0221 skip = 1; 0222 break; 0223 end 0224 end 0225 if ~skip 0226 mpck{kk} = subsasgn(mpck{kk}, s, get_reorder(subsref(mpck{kk}, s), indexes{n}, dim)); 0227 end 0228 end 0229 end 0230 end 0231 end 0232 end 0233 0234 %% convert from cell array to single MATPOWER case struct as appropriate 0235 if ~isempty(k) 0236 mpck = mpck{1}; 0237 end 0238 else 0239 mpck = []; 0240 end