UOPF Solves combined unit decommitment / optimal power flow. [RESULTS, SUCCESS] = UOPF(MPC, MPOPT) Returns either a RESULTS struct and an optional SUCCESS flag, or individual data matrices, the objective function value and a SUCCESS flag. In the latter case, there are additional optional return values. See Examples below for the possible calling syntax options. Examples: Output argument options: results = uopf(...) [results, success] = uopf(...) [bus, gen, branch, f, success] = uopf(...) [bus, gen, branch, f, success, info, et, g, jac, xr, pimul] = uopf(...) Input arguments options: uopf(mpc) uopf(mpc, mpopt) uopf(mpc, userfcn, mpopt) uopf(mpc, A, l, u) uopf(mpc, A, l, u, mpopt) uopf(mpc, A, l, u, mpopt, N, fparm, H, Cw) uopf(mpc, A, l, u, mpopt, N, fparm, H, Cw, z0, zl, zu) uopf(baseMVA, bus, gen, branch, areas, gencost) uopf(baseMVA, bus, gen, branch, areas, gencost, mpopt) uopf(baseMVA, bus, gen, branch, areas, gencost, userfcn, mpopt) uopf(baseMVA, bus, gen, branch, areas, gencost, A, l, u) uopf(baseMVA, bus, gen, branch, areas, gencost, A, l, u, mpopt) uopf(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... mpopt, N, fparm, H, Cw) uopf(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... mpopt, N, fparm, H, Cw, z0, zl, zu) See OPF for more information on input and output arguments. Solves a combined unit decommitment and optimal power flow for a single time period. Uses an algorithm similar to dynamic programming. It proceeds through a sequence of stages, where stage N has N generators shut down, starting with N=0. In each stage, it forms a list of candidates (gens at their Pmin limits) and computes the cost with each one of them shut down. It selects the least cost case as the starting point for the next stage, continuing until there are no more candidates to be shut down or no more improvement can be gained by shutting something down. If MPOPT.verbose (see MPOPTION) is true, it prints progress info, if it is > 1 it prints the output of each individual opf. See also OPF, RUNUOPF.
0001 function [bus, gen, branch, f, success, info, et, g, jac, xr, pimul] = ... 0002 uopf(varargin) 0003 %UOPF Solves combined unit decommitment / optimal power flow. 0004 % [RESULTS, SUCCESS] = UOPF(MPC, MPOPT) 0005 % 0006 % Returns either a RESULTS struct and an optional SUCCESS flag, or individual 0007 % data matrices, the objective function value and a SUCCESS flag. In the 0008 % latter case, there are additional optional return values. See Examples 0009 % below for the possible calling syntax options. 0010 % 0011 % Examples: 0012 % Output argument options: 0013 % 0014 % results = uopf(...) 0015 % [results, success] = uopf(...) 0016 % [bus, gen, branch, f, success] = uopf(...) 0017 % [bus, gen, branch, f, success, info, et, g, jac, xr, pimul] = uopf(...) 0018 % 0019 % Input arguments options: 0020 % 0021 % uopf(mpc) 0022 % uopf(mpc, mpopt) 0023 % uopf(mpc, userfcn, mpopt) 0024 % uopf(mpc, A, l, u) 0025 % uopf(mpc, A, l, u, mpopt) 0026 % uopf(mpc, A, l, u, mpopt, N, fparm, H, Cw) 0027 % uopf(mpc, A, l, u, mpopt, N, fparm, H, Cw, z0, zl, zu) 0028 % 0029 % uopf(baseMVA, bus, gen, branch, areas, gencost) 0030 % uopf(baseMVA, bus, gen, branch, areas, gencost, mpopt) 0031 % uopf(baseMVA, bus, gen, branch, areas, gencost, userfcn, mpopt) 0032 % uopf(baseMVA, bus, gen, branch, areas, gencost, A, l, u) 0033 % uopf(baseMVA, bus, gen, branch, areas, gencost, A, l, u, mpopt) 0034 % uopf(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... 0035 % mpopt, N, fparm, H, Cw) 0036 % uopf(baseMVA, bus, gen, branch, areas, gencost, A, l, u, ... 0037 % mpopt, N, fparm, H, Cw, z0, zl, zu) 0038 % 0039 % See OPF for more information on input and output arguments. 0040 % 0041 % Solves a combined unit decommitment and optimal power flow for a single 0042 % time period. Uses an algorithm similar to dynamic programming. It proceeds 0043 % through a sequence of stages, where stage N has N generators shut down, 0044 % starting with N=0. In each stage, it forms a list of candidates (gens at 0045 % their Pmin limits) and computes the cost with each one of them shut down. 0046 % It selects the least cost case as the starting point for the next stage, 0047 % continuing until there are no more candidates to be shut down or no 0048 % more improvement can be gained by shutting something down. 0049 % If MPOPT.verbose (see MPOPTION) is true, it prints progress 0050 % info, if it is > 1 it prints the output of each individual opf. 0051 % 0052 % See also OPF, RUNUOPF. 0053 0054 % MATPOWER 0055 % Copyright (c) 1996-2016, Power Systems Engineering Research Center (PSERC) 0056 % by Ray Zimmerman, PSERC Cornell 0057 % 0058 % This file is part of MATPOWER. 0059 % Covered by the 3-clause BSD License (see LICENSE file for details). 0060 % See https://matpower.org for more info. 0061 0062 %%----- initialization ----- 0063 t0 = tic; %% start timer 0064 0065 %% process input arguments 0066 [mpc, mpopt] = opf_args(varargin{:}); 0067 0068 %% options 0069 if mpopt.verbose %% turn down verbosity one level for calls to opf 0070 mpopt = mpoption(mpopt, 'verbose', mpopt.verbose-1); 0071 end 0072 0073 %% define named indices into bus, gen, branch matrices 0074 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ... 0075 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus; 0076 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ... 0077 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ... 0078 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen; 0079 0080 %%----- do combined unit commitment/optimal power flow ----- 0081 0082 %% check for sum(Pmin) > total load, decommit as necessary 0083 on = find( mpc.gen(:, GEN_STATUS) > 0 & ~isload(mpc.gen) ); %% gens in service 0084 onld = find( mpc.gen(:, GEN_STATUS) > 0 & isload(mpc.gen) ); %% disp loads in serv 0085 load_capacity = sum(mpc.bus(:, PD)) - sum(mpc.gen(onld, PMIN)); %% total load capacity 0086 Pmin = mpc.gen(on, PMIN); 0087 while sum(Pmin) > load_capacity 0088 %% shut down most expensive unit 0089 avgPmincost = totcost(mpc.gencost(on, :), Pmin) ./ Pmin; 0090 [junk, i] = fairmax(avgPmincost); %% pick one with max avg cost at Pmin 0091 i = on(i); %% convert to generator index 0092 0093 if mpopt.verbose 0094 fprintf('Shutting down generator %d so all Pmin limits can be satisfied.\n', i); 0095 end 0096 0097 %% set generation to zero 0098 mpc.gen(i, [ PG QG GEN_STATUS ]) = 0; 0099 0100 %% update minimum gen capacity 0101 on = find( mpc.gen(:, GEN_STATUS) > 0 & ~isload(mpc.gen) ); %% gens in service 0102 Pmin = mpc.gen(on, PMIN); 0103 end 0104 if ~any(mpc.gen(:, GEN_STATUS) > 0) %% don't bother to run anything if 0105 success = 0; %% everything has been shut down 0106 results0 = mpc; 0107 results0.success = success; 0108 results0.f = NaN; 0109 results0.et = 0; 0110 if mpopt.verbose 0111 fprintf('Infeasible problem, Pmin limits cannot be satisfied without shutting down all generators.\n'); 0112 end 0113 else 0114 %% run initial opf 0115 [results, success] = opf(mpc, mpopt); 0116 0117 %% best case so far 0118 results1 = results; 0119 0120 %% best case for this stage (ie. with n gens shut down, n=0,1,2 ...) 0121 results0 = results1; 0122 mpc.bus = results0.bus; %% use these V as starting point for OPF 0123 0124 while 1 0125 %% get candidates for shutdown 0126 candidates = find(results0.gen(:, MU_PMIN) > 0 & results0.gen(:, PMIN) > 0); 0127 if isempty(candidates) 0128 break; 0129 end 0130 done = 1; %% do not check for further decommitment unless we 0131 %% see something better during this stage 0132 for i = 1:length(candidates) 0133 k = candidates(i); 0134 %% start with best for this stage 0135 mpc.gen = results0.gen; 0136 0137 %% shut down gen k 0138 mpc.gen(k, [ PG QG GEN_STATUS ]) = 0; 0139 0140 %% run opf 0141 if any(mpc.gen(:, GEN_STATUS) > 0) 0142 [results, success] = opf(mpc, mpopt); 0143 else 0144 success = 0; 0145 end 0146 0147 %% something better? 0148 if success && results.f < results1.f 0149 results1 = results; 0150 k1 = k; 0151 done = 0; %% make sure we check for further decommitment 0152 end 0153 end 0154 0155 if done 0156 %% decommits at this stage did not help, so let's quit 0157 break; 0158 else 0159 %% shutting something else down helps, so let's keep going 0160 if mpopt.verbose 0161 fprintf('Shutting down generator %d.\n', k1); 0162 end 0163 0164 results0 = results1; 0165 mpc.bus = results0.bus; %% use these V as starting point for OPF 0166 end 0167 end 0168 end 0169 0170 %% compute elapsed time 0171 et = toc(t0); 0172 0173 %% finish preparing output 0174 if nargout > 0 0175 success = results0.success; 0176 if nargout <= 2 0177 results0.et = et; 0178 bus = results0; 0179 gen = success; 0180 else 0181 [bus, gen, branch, f, info, xr, pimul] = deal(results0.bus, results0.gen, ... 0182 results0.branch, results0.f, results0.raw.info, ... 0183 results0.raw.xr, results0.raw.pimul); 0184 if isfield(results0, 'g') 0185 g = results0.g; 0186 end 0187 if isfield(results0, 'dg') 0188 jac = results0.dg; 0189 end 0190 end 0191 elseif results0.success 0192 results0.et = et; 0193 printpf(results0, 1, mpopt); 0194 end 0195 0196 0197 function [val, idx] = fairmax(x) 0198 %FAIRMAX Same as built-in MAX, except breaks ties randomly. 0199 % [VAL, IDX] = FAIRMAX(X) takes a vector as an argument and returns 0200 % the same output as the built-in function MAX with two output 0201 % parameters, except that where the maximum value occurs at more 0202 % than one position in the vector, the index is chosen randomly 0203 % from these positions as opposed to just choosing the first occurance. 0204 % 0205 % See also MAX. 0206 0207 val = max(x); %% find max value 0208 i = find(x == val); %% find all positions where this occurs 0209 n = length(i); %% number of occurences 0210 idx = i( fix(n*rand)+1 ); %% select index randomly among occurances