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

Generated on Mon 26-Jan-2015 15:21:31 by m2html © 2005