Home > matpower7.1 > lib > extract_islands.m

extract_islands

PURPOSE ^

function mpck = extract_islands(mpc, groups, k, custom)

SYNOPSIS ^

function mpck = extract_islands(mpc, varargin)

DESCRIPTION ^

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_label{b} contains a label for bus b, and mpc.gen_name{g},
       mpc.emissions.rate(g, :), and mpc.genloc(:, g) contain,
       respectively, the generator's name, emission rates and
       location coordinates:
           custom.bus{1} = {'bus_label'};
           custom.gen{1} = {'gen_name', {'emissions', 'rate'}};
           custom.gen{2} = {'genloc'};
           mpc = extract_islands(mpc, 1, custom);

       Note: Fields bus_name, gentype and genfuel are handled automatically
             and do not need to be included in custom.

   See also FIND_ISLANDS, CASE_INFO, CONNECTED_COMPONENTS.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

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

Generated on Fri 09-Oct-2020 11:21:31 by m2html © 2005