Home > matpower5.1 > toggle_reserves.m

toggle_reserves

PURPOSE ^

TOGGLE_RESERVES Enable, disable or check status of fixed reserve requirements.

SYNOPSIS ^

function mpc = toggle_reserves(mpc, on_off)

DESCRIPTION ^

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

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

Generated on Fri 20-Mar-2015 18:23:34 by m2html © 2005