Home > matpower4.0 > toggle_reserves.m

toggle_reserves

PURPOSE ^

TOGGLE_RESERVES Enable or disable fixed reserve requirements.

SYNOPSIS ^

function mpc = toggle_reserves(mpc, on_off)

DESCRIPTION ^

TOGGLE_RESERVES Enable or disable fixed reserve requirements.
   MPC = TOGGLE_RESERVES(MPC, 'on')
   MPC = TOGGLE_RESERVES(MPC, 'off')

   Enables or disables a set of OPF userfcn callbacks to implement
   co-optimization of reserves with fixed zonal reserve requirements.

   These callbacks expect to find a 'reserves' field in the input MPC,
   where MPC.reserves is a struct with the following fields:
       zones   nrz x ng, zone(i, j) = 1, if gen j belongs to zone i
                                      0, otherwise
       req     nrz x 1, zonal reserve requirement in MW
       cost    (ng or ngr) x 1, cost of reserves in $/MW
       qty     (ng or ngr) x 1, max quantity of reserves in MW (optional)
   where nrz is the number of reserve zones and ngr is the number of
   generators belonging to at least one reserve zone and ng is the total
   number of generators.

   The 'int2ext' callback also packages up results and stores them in
   the following output fields of results.reserves:
       R       - ng x 1, reserves provided by each gen in MW
       Rmin    - ng x 1, lower limit on reserves provided by each gen, (MW)
       Rmax    - ng x 1, upper limit on reserves provided by each gen, (MW)
       mu.l    - ng x 1, shadow price on reserve lower limit, ($/MW)
       mu.u    - ng x 1, shadow price on reserve upper limit, ($/MW)
       mu.Pmax - ng x 1, shadow price on Pg + R <= Pmax constraint, ($/MW)
       prc     - ng x 1, reserve price for each gen equal to maximum of the
                         shadow prices on the zonal requirement constraint
                         for each zone the generator belongs to

   See also RUNOPF_W_RES, ADD_USERFCN, REMOVE_USERFCN, RUN_USERFCN,
   T_CASE30_USERFCNS.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function mpc = toggle_reserves(mpc, on_off)
0002 %TOGGLE_RESERVES Enable or disable fixed reserve requirements.
0003 %   MPC = TOGGLE_RESERVES(MPC, 'on')
0004 %   MPC = TOGGLE_RESERVES(MPC, 'off')
0005 %
0006 %   Enables or disables a set of OPF userfcn callbacks to implement
0007 %   co-optimization of reserves with fixed zonal reserve requirements.
0008 %
0009 %   These callbacks expect to find a 'reserves' field in the input MPC,
0010 %   where MPC.reserves is a struct with the following fields:
0011 %       zones   nrz x ng, zone(i, j) = 1, if gen j belongs to zone i
0012 %                                      0, otherwise
0013 %       req     nrz x 1, zonal reserve requirement in MW
0014 %       cost    (ng or ngr) x 1, cost of reserves in $/MW
0015 %       qty     (ng or ngr) x 1, max quantity of reserves in MW (optional)
0016 %   where nrz is the number of reserve zones and ngr is the number of
0017 %   generators belonging to at least one reserve zone and ng is the total
0018 %   number of generators.
0019 %
0020 %   The 'int2ext' callback also packages up results and stores them in
0021 %   the following output fields of results.reserves:
0022 %       R       - ng x 1, reserves provided by each gen in MW
0023 %       Rmin    - ng x 1, lower limit on reserves provided by each gen, (MW)
0024 %       Rmax    - ng x 1, upper limit on reserves provided by each gen, (MW)
0025 %       mu.l    - ng x 1, shadow price on reserve lower limit, ($/MW)
0026 %       mu.u    - ng x 1, shadow price on reserve upper limit, ($/MW)
0027 %       mu.Pmax - ng x 1, shadow price on Pg + R <= Pmax constraint, ($/MW)
0028 %       prc     - ng x 1, reserve price for each gen equal to maximum of the
0029 %                         shadow prices on the zonal requirement constraint
0030 %                         for each zone the generator belongs to
0031 %
0032 %   See also RUNOPF_W_RES, ADD_USERFCN, REMOVE_USERFCN, RUN_USERFCN,
0033 %   T_CASE30_USERFCNS.
0034 
0035 %   MATPOWER
0036 %   $Id: toggle_reserves.m,v 1.15 2010/04/26 19:45:26 ray Exp $
0037 %   by Ray Zimmerman, PSERC Cornell
0038 %   Copyright (c) 2009-2010 by Power System Engineering Research Center (PSERC)
0039 %
0040 %   This file is part of MATPOWER.
0041 %   See http://www.pserc.cornell.edu/matpower/ for more info.
0042 %
0043 %   MATPOWER is free software: you can redistribute it and/or modify
0044 %   it under the terms of the GNU General Public License as published
0045 %   by the Free Software Foundation, either version 3 of the License,
0046 %   or (at your option) any later version.
0047 %
0048 %   MATPOWER is distributed in the hope that it will be useful,
0049 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
0050 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0051 %   GNU General Public License for more details.
0052 %
0053 %   You should have received a copy of the GNU General Public License
0054 %   along with MATPOWER. If not, see <http://www.gnu.org/licenses/>.
0055 %
0056 %   Additional permission under GNU GPL version 3 section 7
0057 %
0058 %   If you modify MATPOWER, or any covered work, to interface with
0059 %   other modules (such as MATLAB code and MEX-files) available in a
0060 %   MATLAB(R) or comparable environment containing parts covered
0061 %   under other licensing terms, the licensors of MATPOWER grant
0062 %   you additional permission to convey the resulting work.
0063 
0064 if strcmp(on_off, 'on')
0065     %% check for proper reserve inputs
0066     if ~isfield(mpc, 'reserves') || ~isstruct(mpc.reserves) || ...
0067             ~isfield(mpc.reserves, 'zones') || ...
0068             ~isfield(mpc.reserves, 'req') || ...
0069             ~isfield(mpc.reserves, 'cost')
0070         error('toggle_reserves: case must contain a ''reserves'' field, a struct defining ''zones'', ''req'' and ''cost''');
0071     end
0072     
0073     %% add callback functions
0074     %% note: assumes all necessary data included in 1st arg (mpc, om, results)
0075     %%       so, no additional explicit args are needed
0076     mpc = add_userfcn(mpc, 'ext2int', @userfcn_reserves_ext2int);
0077     mpc = add_userfcn(mpc, 'formulation', @userfcn_reserves_formulation);
0078     mpc = add_userfcn(mpc, 'int2ext', @userfcn_reserves_int2ext);
0079     mpc = add_userfcn(mpc, 'printpf', @userfcn_reserves_printpf);
0080     mpc = add_userfcn(mpc, 'savecase', @userfcn_reserves_savecase);
0081 elseif strcmp(on_off, 'off')
0082     mpc = remove_userfcn(mpc, 'savecase', @userfcn_reserves_savecase);
0083     mpc = remove_userfcn(mpc, 'printpf', @userfcn_reserves_printpf);
0084     mpc = remove_userfcn(mpc, 'int2ext', @userfcn_reserves_int2ext);
0085     mpc = remove_userfcn(mpc, 'formulation', @userfcn_reserves_formulation);
0086     mpc = remove_userfcn(mpc, 'ext2int', @userfcn_reserves_ext2int);
0087 else
0088     error('toggle_reserves: 2nd argument must be either ''on'' or ''off''');
0089 end
0090 
0091 
0092 %%-----  ext2int  ------------------------------------------------------
0093 function mpc = userfcn_reserves_ext2int(mpc, args)
0094 %
0095 %   mpc = userfcn_reserves_ext2int(mpc, args)
0096 %
0097 %   This is the 'ext2int' stage userfcn callback that prepares the input
0098 %   data for the formulation stage. It expects to find a 'reserves' field
0099 %   in mpc as described above. The optional args are not currently used.
0100 
0101 %% initialize some things
0102 r = mpc.reserves;
0103 o = mpc.order;
0104 ng0 = size(o.ext.gen, 1);   %% number of original gens (+ disp loads)
0105 nrz = size(r.req, 1);       %% number of reserve zones
0106 if nrz > 1
0107     mpc.reserves.rgens = any(r.zones);  %% mask of gens available to provide reserves
0108 else
0109     mpc.reserves.rgens = r.zones;
0110 end
0111 igr = find(mpc.reserves.rgens); %% indices of gens available to provide reserves
0112 ngr = length(igr);              %% number of gens available to provide reserves
0113 
0114 %% check data for consistent dimensions
0115 if size(r.zones, 1) ~= nrz
0116     error('userfcn_reserves_ext2int: the number of rows in mpc.reserves.req (%d) and mpc.reserves.zones (%d) must match', nrz, size(r.zones, 1));
0117 end
0118 if size(r.cost, 1) ~= ng0 && size(r.cost, 1) ~= ngr
0119     error('userfcn_reserves_ext2int: the number of rows in mpc.reserves.cost (%d) must equal the total number of generators (%d) or the number of generators able to provide reserves (%d)', size(r.cost, 1), ng0, ngr);
0120 end
0121 if isfield(r, 'qty') && size(r.qty, 1) ~= size(r.cost, 1)
0122     error('userfcn_reserves_ext2int: mpc.reserves.cost (%d x 1) and mpc.reserves.qty (%d x 1) must be the same dimension', size(r.cost, 1), size(r.qty, 1));
0123 end
0124 
0125 %% convert both cost and qty from ngr x 1 to full ng x 1 vectors if necessary
0126 if size(r.cost, 1) < ng0
0127     mpc.reserves.original.cost = r.cost;    %% save original
0128     cost = zeros(ng0, 1);
0129     cost(igr) = r.cost;
0130     mpc.reserves.cost = cost;
0131     if isfield(r, 'qty')
0132         mpc.reserves.original.qty = r.qty;  %% save original
0133         qty = zeros(ng0, 1);
0134         qty(igr) = r.qty;
0135         mpc.reserves.qty = qty;
0136     end
0137 end
0138 
0139 %%-----  convert stuff to internal indexing  -----
0140 %% convert all reserve parameters (zones, costs, qty, rgens)
0141 if isfield(r, 'qty')
0142     mpc = ext2int(mpc, {'reserves', 'qty'}, 'gen');
0143 end
0144 mpc = ext2int(mpc, {'reserves', 'cost'}, 'gen');
0145 mpc = ext2int(mpc, {'reserves', 'zones'}, 'gen', 2);
0146 mpc = ext2int(mpc, {'reserves', 'rgens'}, 'gen', 2);
0147 
0148 %% save indices of gens available to provide reserves
0149 mpc.order.ext.reserves.igr = igr;               %% external indexing
0150 mpc.reserves.igr = find(mpc.reserves.rgens);    %% internal indexing
0151 
0152 
0153 %%-----  formulation  --------------------------------------------------
0154 function om = userfcn_reserves_formulation(om, args)
0155 %
0156 %   om = userfcn_reserves_formulation(om, args)
0157 %
0158 %   This is the 'formulation' stage userfcn callback that defines the
0159 %   user costs and constraints for fixed reserves. It expects to find
0160 %   a 'reserves' field in the mpc stored in om, as described above.
0161 %   By the time it is passed to this callback, mpc.reserves should
0162 %   have two additional fields:
0163 %       igr     1 x ngr, indices of generators available for reserves
0164 %       rgens   1 x ng, 1 if gen avaiable for reserves, 0 otherwise
0165 %   It is also assumed that if cost or qty were ngr x 1, they have been
0166 %   expanded to ng x 1 and that everything has been converted to
0167 %   internal indexing, i.e. all gens are on-line (by the 'ext2int'
0168 %   callback). The optional args are not currently used.
0169 
0170 %% define named indices into data matrices
0171 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0172     MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0173     QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0174 
0175 %% initialize some things
0176 mpc = get_mpc(om);
0177 r = mpc.reserves;
0178 igr = r.igr;                %% indices of gens available to provide reserves
0179 ngr = length(igr);          %% number of gens available to provide reserves
0180 ng  = size(mpc.gen, 1);     %% number of on-line gens (+ disp loads)
0181 
0182 %% variable bounds
0183 Rmin = zeros(ngr, 1);               %% bound below by 0
0184 Rmax = Inf * ones(ngr, 1);          %% bound above by ...
0185 k = find(mpc.gen(igr, RAMP_10));
0186 Rmax(k) = mpc.gen(igr(k), RAMP_10); %% ... ramp rate and ...
0187 if isfield(r, 'qty')
0188     k = find(r.qty(igr) < Rmax);
0189     Rmax(k) = r.qty(igr(k));        %% ... stated max reserve qty
0190 end
0191 Rmax = Rmax / mpc.baseMVA;
0192 
0193 %% constraints
0194 I = speye(ngr);                     %% identity matrix
0195 Ar = [sparse(1:ngr, igr, 1, ngr, ng) I];
0196 ur = mpc.gen(igr, PMAX) / mpc.baseMVA;
0197 lreq = r.req / mpc.baseMVA;
0198 
0199 %% cost
0200 Cw = r.cost(igr) * mpc.baseMVA;     %% per unit cost coefficients
0201 
0202 %% add them to the model
0203 om = add_vars(om, 'R', ngr, [], Rmin, Rmax);
0204 om = add_constraints(om, 'Pg_plus_R', Ar, [], ur, {'Pg', 'R'});
0205 om = add_constraints(om, 'Rreq', r.zones(:, igr), lreq, [], {'R'});
0206 om = add_costs(om, 'Rcost', struct('N', I, 'Cw', Cw), {'R'});
0207 
0208 
0209 %%-----  int2ext  ------------------------------------------------------
0210 function results = userfcn_reserves_int2ext(results, args)
0211 %
0212 %   results = userfcn_reserves_int2ext(results, args)
0213 %
0214 %   This is the 'int2ext' stage userfcn callback that converts everything
0215 %   back to external indexing and packages up the results. It expects to
0216 %   find a 'reserves' field in the results struct as described for mpc
0217 %   above, including the two additional fields 'igr' and 'rgens'. It also
0218 %   expects the results to contain a variable 'R' and linear constraints
0219 %   'Pg_plus_R' and 'Rreq' which are used to populate output fields in
0220 %   results.reserves. The optional args are not currently used.
0221 
0222 %% initialize some things
0223 r = results.reserves;
0224 
0225 %% grab some info in internal indexing order
0226 igr = r.igr;                %% indices of gens available to provide reserves
0227 ng  = size(results.gen, 1); %% number of on-line gens (+ disp loads)
0228 
0229 %%-----  convert stuff back to external indexing  -----
0230 %% convert all reserve parameters (zones, costs, qty, rgens)
0231 if isfield(r, 'qty')
0232     results = int2ext(results, {'reserves', 'qty'}, 'gen');
0233 end
0234 results = int2ext(results, {'reserves', 'cost'}, 'gen');
0235 results = int2ext(results, {'reserves', 'zones'}, 'gen', 2);
0236 results = int2ext(results, {'reserves', 'rgens'}, 'gen', 2);
0237 results.order.int.reserves.igr = results.reserves.igr;  %% save internal version
0238 results.reserves.igr = results.order.ext.reserves.igr;  %% use external version
0239 r = results.reserves;       %% update
0240 o = results.order;          %% update
0241 
0242 %% grab same info in external indexing order
0243 igr0 = r.igr;               %% indices of gens available to provide reserves
0244 ng0  = size(o.ext.gen, 1);  %% number of gens (+ disp loads)
0245 
0246 %%-----  results post-processing  -----
0247 %% get the results (per gen reserves, multipliers) with internal gen indexing
0248 %% and convert from p.u. to per MW units
0249 [R0, Rl, Ru] = getv(results.om, 'R');
0250 R       = zeros(ng, 1);
0251 Rmin    = zeros(ng, 1);
0252 Rmax    = zeros(ng, 1);
0253 mu_l    = zeros(ng, 1);
0254 mu_u    = zeros(ng, 1);
0255 mu_Pmax = zeros(ng, 1);
0256 R(igr)       = results.var.val.R * results.baseMVA;
0257 Rmin(igr)    = Rl * results.baseMVA;
0258 Rmax(igr)    = Ru * results.baseMVA;
0259 mu_l(igr)    = results.var.mu.l.R / results.baseMVA;
0260 mu_u(igr)    = results.var.mu.u.R / results.baseMVA;
0261 mu_Pmax(igr) = results.lin.mu.u.Pg_plus_R / results.baseMVA;
0262 
0263 %% store in results in results struct
0264 z = zeros(ng0, 1);
0265 results.reserves.R       = int2ext(results, R, z, 'gen');
0266 results.reserves.Rmin    = int2ext(results, Rmin, z, 'gen');
0267 results.reserves.Rmax    = int2ext(results, Rmax, z, 'gen');
0268 results.reserves.mu.l    = int2ext(results, mu_l, z, 'gen');
0269 results.reserves.mu.u    = int2ext(results, mu_u, z, 'gen');
0270 results.reserves.mu.Pmax = int2ext(results, mu_Pmax, z, 'gen');
0271 results.reserves.prc     = z;
0272 for k = igr0
0273     iz = find(r.zones(:, k));
0274     results.reserves.prc(k) = max(results.lin.mu.l.Rreq(iz)) / results.baseMVA;
0275 end
0276 results.reserves.totalcost = results.cost.Rcost;
0277 
0278 %% replace ng x 1 cost, qty with ngr x 1 originals
0279 if isfield(r, 'original')
0280     if isfield(r, 'qty')
0281         results.reserves.qty = r.original.qty;
0282     end
0283     results.reserves.cost = r.original.cost;
0284     results.reserves = rmfield(results.reserves, 'original');
0285 end
0286 
0287 
0288 %%-----  printpf  ------------------------------------------------------
0289 function results = userfcn_reserves_printpf(results, fd, mpopt, args)
0290 %
0291 %   results = userfcn_reserves_printpf(results, fd, mpopt, args)
0292 %
0293 %   This is the 'printpf' stage userfcn callback that pretty-prints the
0294 %   results. It expects a results struct, a file descriptor and a MATPOWER
0295 %   options vector. The optional args are not currently used.
0296 
0297 %% define named indices into data matrices
0298 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0299     MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0300     QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0301 
0302 %%-----  print results  -----
0303 r = results.reserves;
0304 nrz = size(r.req, 1);
0305 OUT_ALL = mpopt(32);
0306 if OUT_ALL ~= 0
0307     fprintf(fd, '\n================================================================================');
0308     fprintf(fd, '\n|     Reserves                                                                 |');
0309     fprintf(fd, '\n================================================================================');
0310     fprintf(fd, '\n Gen   Bus   Status  Reserves   Price');
0311     fprintf(fd, '\n  #     #              (MW)     ($/MW)     Included in Zones ...');
0312     fprintf(fd, '\n----  -----  ------  --------  --------   ------------------------');
0313     for k = r.igr
0314         iz = find(r.zones(:, k));
0315         fprintf(fd, '\n%3d %6d     %2d ', k, results.gen(k, GEN_BUS), results.gen(k, GEN_STATUS));
0316         if results.gen(k, GEN_STATUS) > 0 && abs(results.reserves.R(k)) > 1e-6
0317             fprintf(fd, '%10.2f', results.reserves.R(k));
0318         else
0319             fprintf(fd, '       -  ');
0320         end
0321         fprintf(fd, '%10.2f     ', results.reserves.prc(k));
0322         for i = 1:length(iz)
0323             if i ~= 1
0324                 fprintf(fd, ', ');
0325             end
0326             fprintf(fd, '%d', iz(i));
0327         end
0328     end
0329     fprintf(fd, '\n                     --------');
0330     fprintf(fd, '\n            Total:%10.2f              Total Cost: $%.2f', ...
0331         sum(results.reserves.R(r.igr)), results.reserves.totalcost);
0332     fprintf(fd, '\n');
0333     
0334     fprintf(fd, '\nZone  Reserves   Price  ');
0335     fprintf(fd, '\n  #     (MW)     ($/MW) ');
0336     fprintf(fd, '\n----  --------  --------');
0337     for k = 1:nrz
0338         iz = find(r.zones(k, :));     %% gens in zone k
0339         fprintf(fd, '\n%3d%10.2f%10.2f', k, sum(results.reserves.R(iz)), ...
0340                     results.lin.mu.l.Rreq(k) / results.baseMVA);
0341     end
0342     fprintf(fd, '\n');
0343     
0344     fprintf(fd, '\n================================================================================');
0345     fprintf(fd, '\n|     Reserve Limits                                                           |');
0346     fprintf(fd, '\n================================================================================');
0347     fprintf(fd, '\n Gen   Bus   Status  Rmin mu     Rmin    Reserves    Rmax    Rmax mu   Pmax mu ');
0348     fprintf(fd, '\n  #     #             ($/MW)     (MW)      (MW)      (MW)     ($/MW)    ($/MW) ');
0349     fprintf(fd, '\n----  -----  ------  --------  --------  --------  --------  --------  --------');
0350     for k = r.igr
0351         fprintf(fd, '\n%3d %6d     %2d ', k, results.gen(k, GEN_BUS), results.gen(k, GEN_STATUS));
0352         if results.gen(k, GEN_STATUS) > 0 && results.reserves.mu.l(k) > 1e-6
0353             fprintf(fd, '%10.2f', results.reserves.mu.l(k));
0354         else
0355             fprintf(fd, '       -  ');
0356         end
0357         fprintf(fd, '%10.2f', results.reserves.Rmin(k));
0358         if results.gen(k, GEN_STATUS) > 0 && abs(results.reserves.R(k)) > 1e-6
0359             fprintf(fd, '%10.2f', results.reserves.R(k));
0360         else
0361             fprintf(fd, '       -  ');
0362         end
0363         fprintf(fd, '%10.2f', results.reserves.Rmax(k));
0364         if results.gen(k, GEN_STATUS) > 0 && results.reserves.mu.u(k) > 1e-6
0365             fprintf(fd, '%10.2f', results.reserves.mu.u(k));
0366         else
0367             fprintf(fd, '       -  ');
0368         end
0369         if results.gen(k, GEN_STATUS) > 0 && results.reserves.mu.Pmax(k) > 1e-6
0370             fprintf(fd, '%10.2f', results.reserves.mu.Pmax(k));
0371         else
0372             fprintf(fd, '       -  ');
0373         end
0374     end
0375     fprintf(fd, '\n                                         --------');
0376     fprintf(fd, '\n                                Total:%10.2f', sum(results.reserves.R(r.igr)));
0377     fprintf(fd, '\n');
0378 end
0379 
0380 
0381 %%-----  savecase  -----------------------------------------------------
0382 function mpc = userfcn_reserves_savecase(mpc, fd, prefix, args)
0383 %
0384 %   mpc = userfcn_reserves_savecase(mpc, fd, mpopt, args)
0385 %
0386 %   This is the 'savecase' stage userfcn callback that prints the M-file
0387 %   code to save the 'reserves' field in the case file. It expects a
0388 %   MATPOWER case struct (mpc), a file descriptor and variable prefix
0389 %   (usually 'mpc.'). The optional args are not currently used.
0390 
0391 r = mpc.reserves;
0392 
0393 fprintf(fd, '\n%%%%-----  Reserve Data  -----%%%%\n');
0394 fprintf(fd, '%%%% reserve zones, element i, j is 1 if gen j is in zone i, 0 otherwise\n');
0395 fprintf(fd, '%sreserves.zones = [\n', prefix);
0396 template = '';
0397 for i = 1:size(r.zones, 2)
0398     template = [template, '\t%d'];
0399 end
0400 template = [template, ';\n'];
0401 fprintf(fd, template, r.zones.');
0402 fprintf(fd, '];\n');
0403 
0404 fprintf(fd, '\n%%%% reserve requirements for each zone in MW\n');
0405 fprintf(fd, '%sreserves.req = [\t%g', prefix, r.req(1));
0406 if length(r.req) > 1
0407     fprintf(fd, ';\t%g', r.req(2:end));
0408 end
0409 fprintf(fd, '\t];\n');
0410 
0411 fprintf(fd, '\n%%%% reserve costs in $/MW for each gen that belongs to at least 1 zone\n');
0412 fprintf(fd, '%%%% (same order as gens, but skipping any gen that does not belong to any zone)\n');
0413 fprintf(fd, '%sreserves.cost = [\t%g', prefix, r.cost(1));
0414 if length(r.cost) > 1
0415     fprintf(fd, ';\t%g', r.cost(2:end));
0416 end
0417 fprintf(fd, '\t];\n');
0418 
0419 if isfield(r, 'qty')
0420     fprintf(fd, '\n%%%% OPTIONAL max reserve quantities for each gen that belongs to at least 1 zone\n');
0421     fprintf(fd, '%%%% (same order as gens, but skipping any gen that does not belong to any zone)\n');
0422     fprintf(fd, '%sreserves.qty = [\t%g', prefix, r.qty(1));
0423     if length(r.qty) > 1
0424         fprintf(fd, ';\t%g', r.qty(2:end));
0425     end
0426     fprintf(fd, '\t];\n');
0427 end
0428 
0429 %% save output fields for solved case
0430 if isfield(r, 'R')
0431     if exist('serialize', 'file') == 2
0432         fprintf(fd, '\n%%%% solved values\n');
0433         fprintf(fd, '%sreserves.R = %s\n', prefix, serialize(r.R));
0434         fprintf(fd, '%sreserves.Rmin = %s\n', prefix, serialize(r.Rmin));
0435         fprintf(fd, '%sreserves.Rmax = %s\n', prefix, serialize(r.Rmax));
0436         fprintf(fd, '%sreserves.mu.l = %s\n', prefix, serialize(r.mu.l));
0437         fprintf(fd, '%sreserves.mu.u = %s\n', prefix, serialize(r.mu.u));
0438         fprintf(fd, '%sreserves.prc = %s\n', prefix, serialize(r.prc));
0439         fprintf(fd, '%sreserves.totalcost = %s\n', prefix, serialize(r.totalcost));
0440     else
0441         url = 'http://www.mathworks.com/matlabcentral/fileexchange/12063';
0442         warning('MATPOWER:serialize', ...
0443             'userfcn_reserves_savecase: Cannot save the ''reserves'' output fields without the ''serialize'' function, which is available as a free download from:\n<%s>\n\n', url);
0444     end
0445 end

Generated on Mon 26-Jan-2015 14:56:45 by m2html © 2005