Home > matpower7.1 > extras > sdp_pf > insolvablepf_limitQ.m

insolvablepf_limitQ

PURPOSE ^

INSOLVABLEPF_LIMITQ A sufficient condition for power flow insolvability

SYNOPSIS ^

function [insolvable,eta,mineigratio] = insolvablepf_limitQ(mpc,mpopt)

DESCRIPTION ^

INSOLVABLEPF_LIMITQ A sufficient condition for power flow insolvability
considering generator reactive power limits

   [INSOLVABLE,VSLACK_MIN,SIGMA,ETA,MINEIGRATIO] =
       INSOLVABLEPF_LIMITQ(MPC,MPOPT)

   Evaluates a sufficient condition for insolvability of the power flow
   equations considering generator reactive power limits. This function
   uses a mixed-integer semidefinite programming formulation of the power
   flow equations with generator reactive power limits that maximizes the
   power injections in a uniform, constant power factor profile. eta
   indicates the factor by which the power injections can be increased in
   this profile. If eta < 1, no power flow solution exists that satisfies
   the generator reactive power limits. The converse does not
   necessarily hold; a power flow solution may not exist even for cases
   that this function does not indicate are insolvable. See [1] for
   further details.

   Note that this function is only suitable for small systems due to the
   computational requirements of the mixed-integer semidefinite
   programming solver in YALMIP.

   Inputs:
       MPC : A MATPOWER case specifying the desired power flow equations.
       MPOPT : A MATPOWER options struct. If not specified, it is
           assumed to be the default mpoption.

   Outputs:
       INSOLVABLE : Binary variable. A value of 1 indicates that the
           specified power flow equations are insolvable, while a value of
           0 means that the insolvability condition is indeterminant (a
           solution may or may not exist).
       ETA : Power injection margin to the power flow solvability
           boundary in the profile of a uniform, constant power factor
           change in power injections.
       MINEIGRATIO : A measure of satisfaction of the rank relaxation.
           Large values indicate satisfaction. (Note that satisfaction of
           the rank relaxation is not required for correctness of the
           insolvability condition).

   [1] D.K. Molzahn, V. Dawar, B.C. Lesieutre, and C.L. DeMarco, "Sufficient
       Conditions for Power Flow Insolvability Considering Reactive Power
       Limited Generators with Applications to Voltage Stability Margins,"
       in Bulk Power System Dynamics and Control - IX. Optimization,
       Security and Control of the Emerging Power Grid, 2013 IREP Symposium,
       25-30 August 2013.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [insolvable,eta,mineigratio] = insolvablepf_limitQ(mpc,mpopt)
0002 %INSOLVABLEPF_LIMITQ A sufficient condition for power flow insolvability
0003 %considering generator reactive power limits
0004 %
0005 %   [INSOLVABLE,VSLACK_MIN,SIGMA,ETA,MINEIGRATIO] =
0006 %       INSOLVABLEPF_LIMITQ(MPC,MPOPT)
0007 %
0008 %   Evaluates a sufficient condition for insolvability of the power flow
0009 %   equations considering generator reactive power limits. This function
0010 %   uses a mixed-integer semidefinite programming formulation of the power
0011 %   flow equations with generator reactive power limits that maximizes the
0012 %   power injections in a uniform, constant power factor profile. eta
0013 %   indicates the factor by which the power injections can be increased in
0014 %   this profile. If eta < 1, no power flow solution exists that satisfies
0015 %   the generator reactive power limits. The converse does not
0016 %   necessarily hold; a power flow solution may not exist even for cases
0017 %   that this function does not indicate are insolvable. See [1] for
0018 %   further details.
0019 %
0020 %   Note that this function is only suitable for small systems due to the
0021 %   computational requirements of the mixed-integer semidefinite
0022 %   programming solver in YALMIP.
0023 %
0024 %   Inputs:
0025 %       MPC : A MATPOWER case specifying the desired power flow equations.
0026 %       MPOPT : A MATPOWER options struct. If not specified, it is
0027 %           assumed to be the default mpoption.
0028 %
0029 %   Outputs:
0030 %       INSOLVABLE : Binary variable. A value of 1 indicates that the
0031 %           specified power flow equations are insolvable, while a value of
0032 %           0 means that the insolvability condition is indeterminant (a
0033 %           solution may or may not exist).
0034 %       ETA : Power injection margin to the power flow solvability
0035 %           boundary in the profile of a uniform, constant power factor
0036 %           change in power injections.
0037 %       MINEIGRATIO : A measure of satisfaction of the rank relaxation.
0038 %           Large values indicate satisfaction. (Note that satisfaction of
0039 %           the rank relaxation is not required for correctness of the
0040 %           insolvability condition).
0041 %
0042 %   [1] D.K. Molzahn, V. Dawar, B.C. Lesieutre, and C.L. DeMarco, "Sufficient
0043 %       Conditions for Power Flow Insolvability Considering Reactive Power
0044 %       Limited Generators with Applications to Voltage Stability Margins,"
0045 %       in Bulk Power System Dynamics and Control - IX. Optimization,
0046 %       Security and Control of the Emerging Power Grid, 2013 IREP Symposium,
0047 %       25-30 August 2013.
0048 
0049 %   MATPOWER
0050 %   Copyright (c) 2013-2019, Power Systems Engineering Research Center (PSERC)
0051 %   by Daniel Molzahn, PSERC U of Wisc, Madison
0052 %
0053 %   This file is part of MATPOWER/mx-sdp_pf.
0054 %   Covered by the 3-clause BSD License (see LICENSE file for details).
0055 %   See https://github.com/MATPOWER/mx-sdp_pf/ for more info.
0056 
0057 if nargin < 2
0058     mpopt = mpoption;
0059 end
0060 
0061 mpc = loadcase(mpc);
0062 
0063 % Unpack options
0064 ignore_angle_lim    = mpopt.opf.ignore_angle_lim;
0065 verbose             = mpopt.verbose;
0066 ndisplay            = mpopt.sdp_pf.ndisplay;    %% Determine display frequency of diagonastic information
0067 
0068 maxSystemSize = 57;
0069 fixPVbusInjection = 0; % If equal to 1, don't allow changes in active power injections at PV buses.
0070 
0071 if ~have_feature('yalmip')
0072     error('insolvablepf_limitQ: The software package YALMIP is required to run insolvablepf_limitQ. See https://yalmip.github.io');
0073 end
0074 
0075 % set YALMIP options struct in SDP_PF (for details, see help sdpsettings)
0076 sdpopts = yalmip_options([], mpopt);
0077 
0078 % Change solver to YALMIP's branch-and-bound algorithm
0079 sdpopts = sdpsettings(sdpopts,'solver','bnb','bnb.solver',sdpopts.solver);
0080 
0081 if strcmp(sdpopts.solver, 'sedumi') || strcmp(sdpopts.solver,'sdpt3')
0082     sdpopts = sdpsettings(sdpopts,'solver','bnb');
0083 end
0084 
0085 %% define named indices into data matrices
0086 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0087     VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0088 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0089     MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0090     QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0091 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
0092     TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
0093     ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
0094 [PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;
0095 
0096 
0097 %% Load mpc data
0098 
0099 mpc = ext2int(mpc);
0100 
0101 if toggle_dcline(mpc, 'status')
0102     error('insolvablepf_limitQ: DC lines are not implemented in insolvablepf');
0103 end
0104 
0105 nbus = size(mpc.bus,1);
0106 ngen = size(mpc.gen,1);
0107 
0108 if nbus > maxSystemSize
0109     error('insolvablepf_limitQ: System is too large (more than 57 buses) to solve with insolvablepf_limitQ');
0110 end
0111 
0112 if ~ignore_angle_lim && (any(mpc.branch(:,ANGMIN) ~= -360) || any(mpc.branch(:,ANGMAX) ~= 360))
0113     warning('insolvablepf_limitQ: Angle difference constraints are not implemented in SDP_PF. Ignoring angle difference constraints.');
0114 end
0115 
0116 % Some of the larger system (e.g., case2746wp) have generators
0117 % corresponding to buses that have bustype == PQ. Change these
0118 % to PV buses.
0119 for i=1:ngen
0120     busidx = find(mpc.bus(:,BUS_I) == mpc.gen(i,GEN_BUS));
0121     if isempty(busidx) || ~(mpc.bus(busidx,BUS_TYPE) == PV || mpc.bus(busidx,BUS_TYPE) == REF)
0122         mpc.bus(busidx,BUS_TYPE) = PV;
0123         if verbose >= 1
0124             warning('insolvablepf_limitQ: Bus %s has generator(s) but is listed as a PQ bus. Changing to a PV bus.',int2str(busidx));
0125         end
0126     end
0127 end
0128 
0129 % Buses may be listed as PV buses without associated generators. Change
0130 % these buses to PQ.
0131 for i=1:nbus
0132     if mpc.bus(i,BUS_TYPE) == PV
0133         genidx = find(mpc.gen(:,GEN_BUS) == mpc.bus(i,BUS_I), 1);
0134         if isempty(genidx)
0135             mpc.bus(i,BUS_TYPE) = PQ;
0136             if verbose >= 1
0137                 warning('insolvablepf_limitQ: PV bus %i has no associated generator! Changing these buses to PQ.',i);
0138             end
0139         end
0140     end
0141 end
0142 
0143 
0144 Sbase = mpc.baseMVA;
0145 
0146 % Create vectors of power injections and voltage magnitudes
0147 Qd = mpc.bus(:,QD) / Sbase;
0148 Qinj = -Qd;
0149 Vmag = mpc.bus(:,VM);
0150 
0151 Pd = mpc.bus(:,PD) / Sbase;
0152 Pg = zeros(nbus,1);
0153 Qmin = zeros(nbus,1);
0154 Qmax = zeros(nbus,1);
0155 for i=1:nbus
0156     genidx = find(mpc.gen(:,GEN_BUS) == i);
0157     if ~isempty(genidx)
0158         Pg(i) = sum(mpc.gen(genidx,PG)) / Sbase;
0159         Vmag(i) = mpc.gen(genidx(1),VG);
0160         Qmin(i) = sum(mpc.gen(genidx,QMIN)) / Sbase - Qd(i);
0161         Qmax(i) = sum(mpc.gen(genidx,QMAX)) / Sbase - Qd(i);
0162     end
0163 end
0164 Pinj = Pg - Pd;
0165 
0166 
0167 %% Functions to build matrices
0168 
0169 [Yk,Yk_,Mk,Ylineft,Ylinetf,Y_lineft,Y_linetf] = makesdpmat(mpc);
0170 
0171 %% Create primal SDP variables
0172 
0173 [junk1,uniqueGenIdx,junk2] = unique(mpc.gen(:,GEN_BUS));
0174 mpc.gen = mpc.gen(uniqueGenIdx,:);
0175 ngen = size(mpc.gen,1);
0176 
0177 W = sdpvar(2*nbus,2*nbus);
0178 eta = sdpvar(1,1);
0179 constraints = [];
0180 
0181 % Binary variables
0182 yL = binvar(ngen,1);
0183 yU = binvar(ngen,1);
0184 
0185 % We need a number greater than any plausible value of V^2, but too large
0186 % of a value causes numerical problems
0187 bigM = 10*max(Vmag)^2; 
0188 
0189 %% Build primal problem
0190 
0191 for k=1:nbus
0192     
0193     if ~fixPVbusInjection
0194         % PQ and PV buses have uniform active power injection changes
0195         if mpc.bus(k,BUS_TYPE) == PQ || mpc.bus(k,BUS_TYPE) == PV
0196             constraints = [constraints; 
0197                 trace(Yk(k)*W) == eta*Pinj(k)];
0198         end
0199     else
0200         % Alternatively, we can fix PV bus active power injections for a
0201         % different power injection profile.
0202         if mpc.bus(k,BUS_TYPE) == PQ 
0203             constraints = [constraints; 
0204                 trace(Yk(k)*W) == eta*Pinj(k)];
0205         end
0206         if mpc.bus(k,BUS_TYPE) == PV
0207             constraints = [constraints; 
0208                 trace(Yk(k)*W) == Pinj(k)];
0209         end    
0210     end
0211         
0212     % PQ buses have uniform reactive power injection changes
0213     if mpc.bus(k,BUS_TYPE) == PQ
0214             constraints = [constraints;
0215                 trace(Yk_(k)*W) == eta*Qinj(k)];
0216     end
0217     
0218     % Mixed integer formulation for generator reactive power limits
0219     if mpc.bus(k,BUS_TYPE) == PV || mpc.bus(k,BUS_TYPE) == REF
0220         
0221         genidx = find(mpc.gen(:,GEN_BUS) == k,1);
0222         
0223         constraints = [constraints;
0224             trace(Yk_(k)*W) <= Qmin(k)*yL(genidx) + Qmax(k)*(1-yL(genidx));
0225             trace(Yk_(k)*W) >= Qmax(k)*yU(genidx) + Qmin(k)*(1-yU(genidx))];
0226 
0227         constraints = [constraints;
0228             trace(Mk(k)*W) >= Vmag(k)^2*(1-yU(genidx));
0229             trace(Mk(k)*W) <= Vmag(k)^2*(1-yL(genidx)) + bigM*(yL(genidx))];
0230         
0231         constraints = [constraints;
0232             yU(genidx) + yL(genidx) <= 1];
0233         
0234     end
0235     
0236     if verbose >= 2 && mod(k,ndisplay) == 0
0237         fprintf('SDP creation: Bus %i of %i\n',k,nbus);
0238     end
0239     
0240 end % Loop through all buses
0241 
0242 % Force at least one bus to supply reactive power balance
0243 % genbuses = (mpc.bus(:,BUS_TYPE) == PV | mpc.bus(:,BUS_TYPE) == REF);
0244 % constraints = [constraints;
0245 %     sum(yL(genbuses)+yU(genbuses)) <= ngen - 1];
0246 constraints = [constraints;
0247     sum(yL + yU) <= ngen - 1];
0248 
0249 constraints = [constraints; W >= 0];
0250 
0251 
0252 
0253 %% Solve the SDP
0254 
0255 % Preserve warning settings
0256 S = warning;
0257 
0258 % Run sdp solver
0259 sdpinfo = solvesdp(constraints, -eta, sdpopts);
0260 if sdpinfo.problem == 2 || sdpinfo.problem == -2 || sdpinfo.problem == -3
0261     error(yalmiperror(sdpinfo.problem));
0262 end
0263 if ~have_feature('octave') || have_feature('octave', 'vnum') >= 4.001
0264     %% (avoid bug in Octave 4.0.x, where warning state is left corrupted)
0265     warning(S);
0266 end
0267 
0268 if verbose >= 2
0269     fprintf('Solver exit message: %s\n',sdpinfo.info);
0270 end
0271 
0272 
0273 %% Calculate rank characteristics of the solution
0274 
0275 evl = sort(eig(double(W)));
0276 mineigratio = abs(evl(end) / evl(end-2));
0277 
0278 
0279 %% Output results
0280 
0281 eta = double(eta);
0282 insolvable = eta < 1; % Is this right? I think it should be the other way around...

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