Home > matpower5.0 > extras > smartmarket > auction.m

auction

PURPOSE ^

AUCTION Clear auction based on OPF results (qty's and lambdas).

SYNOPSIS ^

function [co, cb] = auction(offers, bids, auction_type, limit_prc, gtee_prc)

DESCRIPTION ^

AUCTION  Clear auction based on OPF results (qty's and lambdas).
   [CO, CB] = AUCTION(OFFERS, BIDS, AUCTION_TYPE, LIMIT_PRC, GTEE_PRC)
   Clears a set of BIDS and OFFERS based on the results of an OPF, where the
   pricing is adjusted for network losses and binding constraints.
   The arguments OFFERS and BIDS are structs with the following fields:
       qty       - m x n, offer/bid quantities, m offers/bids, n blocks
       prc       - m x n, offer/bid prices
       lam       - m x n, corresponding lambdas
       total_qty - m x 1, total quantity cleared for each offer/bid

   There are 8 types of auctions implemented, specified by AUCTION_TYPE.

      0 - discriminative pricing (price equal to offer or bid)
      1 - last accepted offer auction
      2 - first rejected offer auction
      3 - last accepted bid auction
      4 - first rejected bid auction
      5 - first price auction (marginal unit, offer or bid, sets the price)
      6 - second price auction (if offer is marginal, price set by
             min(FRO,LAB), else max(FRB,LAO)
      7 - split the difference pricing (set by last accepted offer & bid)
      8 - LAO sets seller price, LAB sets buyer price

   Whether or not cleared offer (bid) prices are guaranteed to be greater
   (less) than or equal to the corresponding offer (bid) price is specified by
   a flag GTEE_PRC.offer (GTEE_PRC.bid). The default is value true.
   
   Offer/bid and cleared offer/bid min and max prices are specified in the
   LIMIT_PRC struct with the following fields:
       max_offer
       min_bid
       max_cleared_offer
       min_cleared_bid
   Offers (bids) above (below) max_offer (min_bid) are treated as withheld
   and cleared offer (bid) prices above (below) max_cleared_offer
   (min_cleared_bid) are clipped to max_cleared offer (min_cleared_bid) if
   given. All of these limit prices are ignored if the field is missing
   or is empty.

   See also RUNMARKET, SMARTMKT.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [co, cb] = auction(offers, bids, auction_type, limit_prc, gtee_prc)
0002 %AUCTION  Clear auction based on OPF results (qty's and lambdas).
0003 %   [CO, CB] = AUCTION(OFFERS, BIDS, AUCTION_TYPE, LIMIT_PRC, GTEE_PRC)
0004 %   Clears a set of BIDS and OFFERS based on the results of an OPF, where the
0005 %   pricing is adjusted for network losses and binding constraints.
0006 %   The arguments OFFERS and BIDS are structs with the following fields:
0007 %       qty       - m x n, offer/bid quantities, m offers/bids, n blocks
0008 %       prc       - m x n, offer/bid prices
0009 %       lam       - m x n, corresponding lambdas
0010 %       total_qty - m x 1, total quantity cleared for each offer/bid
0011 %
0012 %   There are 8 types of auctions implemented, specified by AUCTION_TYPE.
0013 %
0014 %      0 - discriminative pricing (price equal to offer or bid)
0015 %      1 - last accepted offer auction
0016 %      2 - first rejected offer auction
0017 %      3 - last accepted bid auction
0018 %      4 - first rejected bid auction
0019 %      5 - first price auction (marginal unit, offer or bid, sets the price)
0020 %      6 - second price auction (if offer is marginal, price set by
0021 %             min(FRO,LAB), else max(FRB,LAO)
0022 %      7 - split the difference pricing (set by last accepted offer & bid)
0023 %      8 - LAO sets seller price, LAB sets buyer price
0024 %
0025 %   Whether or not cleared offer (bid) prices are guaranteed to be greater
0026 %   (less) than or equal to the corresponding offer (bid) price is specified by
0027 %   a flag GTEE_PRC.offer (GTEE_PRC.bid). The default is value true.
0028 %
0029 %   Offer/bid and cleared offer/bid min and max prices are specified in the
0030 %   LIMIT_PRC struct with the following fields:
0031 %       max_offer
0032 %       min_bid
0033 %       max_cleared_offer
0034 %       min_cleared_bid
0035 %   Offers (bids) above (below) max_offer (min_bid) are treated as withheld
0036 %   and cleared offer (bid) prices above (below) max_cleared_offer
0037 %   (min_cleared_bid) are clipped to max_cleared offer (min_cleared_bid) if
0038 %   given. All of these limit prices are ignored if the field is missing
0039 %   or is empty.
0040 %
0041 %   See also RUNMARKET, SMARTMKT.
0042 
0043 %   MATPOWER
0044 %   $Id: auction.m 2194 2013-09-03 19:12:26Z ray $
0045 %   by Ray Zimmerman, PSERC Cornell
0046 %   Copyright (c) 1996-2010 by Power System Engineering Research Center (PSERC)
0047 %
0048 %   This file is part of MATPOWER.
0049 %   See http://www.pserc.cornell.edu/matpower/ for more info.
0050 %
0051 %   MATPOWER is free software: you can redistribute it and/or modify
0052 %   it under the terms of the GNU General Public License as published
0053 %   by the Free Software Foundation, either version 3 of the License,
0054 %   or (at your option) any later version.
0055 %
0056 %   MATPOWER is distributed in the hope that it will be useful,
0057 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
0058 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0059 %   GNU General Public License for more details.
0060 %
0061 %   You should have received a copy of the GNU General Public License
0062 %   along with MATPOWER. If not, see <http://www.gnu.org/licenses/>.
0063 %
0064 %   Additional permission under GNU GPL version 3 section 7
0065 %
0066 %   If you modify MATPOWER, or any covered work, to interface with
0067 %   other modules (such as MATLAB code and MEX-files) available in a
0068 %   MATLAB(R) or comparable environment containing parts covered
0069 %   under other licensing terms, the licensors of MATPOWER grant
0070 %   you additional permission to convey the resulting work.
0071 
0072 %%-----  initialization  -----
0073 %% define named indices into data 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 %% initialize some stuff
0081 delta = 1e-3;       %% prices smaller than this are not used to determine X
0082 zero_tol = 1e-5;
0083 % zero_tol = 0.1;   %% fmincon is SO bad with prices that it is
0084                     %% NOT recommended for use with auction.m
0085 big_num = 1e6;
0086 if isempty(bids)
0087     bids = struct(  'qty', [], ...
0088                     'prc', [], ...
0089                     'lam', [], ...
0090                     'total_qty', [] );
0091 end
0092 if nargin < 4 || isempty(limit_prc)
0093     limit_prc = struct( 'max_offer', [], 'min_bid', [], ...
0094                         'max_cleared_offer', [], 'min_cleared_bid', [] );
0095 else
0096     if ~isfield(limit_prc, 'max_offer'),         limit_prc.max_offer = [];         end
0097     if ~isfield(limit_prc, 'min_bid'),           limit_prc.min_bid = [];           end
0098     if ~isfield(limit_prc, 'max_cleared_offer'), limit_prc.max_cleared_offer = []; end
0099     if ~isfield(limit_prc, 'min_cleared_bid'),   limit_prc.min_cleared_bid = [];   end
0100 end
0101 if nargin < 5 || isempty(gtee_prc)
0102     gtee_prc = struct(  'offer', 1, 'bid', 1    );
0103 else
0104     if ~isfield(gtee_prc, 'offer'), gtee_prc.offer = 1; end
0105     if ~isfield(gtee_prc, 'bid'),   gtee_prc.bid = 1;   end
0106 end
0107 
0108 [nro, nco] = size(offers.qty);
0109 [nrb, ncb] = size(bids.qty);
0110 
0111 %% determine cleared quantities
0112 if isempty(limit_prc.max_offer)
0113     [co.qty, o.on, o.off] = clear_qty(offers.qty, offers.total_qty);
0114 else
0115     mask = offers.prc <= limit_prc.max_offer;
0116     [co.qty, o.on, o.off] = clear_qty(offers.qty, offers.total_qty, mask);
0117 end
0118 if isempty(limit_prc.min_bid)
0119     [cb.qty, b.on, b.off] = clear_qty(bids.qty, bids.total_qty);
0120 else
0121     mask = bids.prc <= limit_prc.min_bid;
0122     [cb.qty, b.on, b.off] = clear_qty(bids.qty, bids.total_qty, mask);
0123 end
0124 
0125 %% initialize cleared prices
0126 co.prc = zeros(nro, nco);       %% cleared offer prices
0127 cb.prc = zeros(nrb, ncb);       %% cleared bid prices
0128 
0129 %%-----  compute exchange rates to scale lam to get desired pricing  -----
0130 %% The locationally adjusted offer/bid price, when normalized to an arbitrary
0131 %% reference location where lambda is equal to ref_lam, is:
0132 %%      norm_prc = prc * (ref_lam / lam)
0133 %% Then we can define the ratio between the normalized offer/bid prices
0134 %% and the ref_lam as an exchange rate X:
0135 %%      X = norm_prc / ref_lam = prc / lam
0136 %% This X represents the ratio between the marginal unit (setting lambda)
0137 %% and the offer/bid price in question.
0138 
0139 if auction_type == 0 || auction_type == 5   %% don't bother scaling anything
0140     X = struct( 'LAO', 1, ...
0141                 'FRO', 1, ...
0142                 'LAB', 1, ...
0143                 'FRB', 1);
0144 else
0145     X = compute_exchange_rates(offers, bids, o, b);
0146 end
0147 
0148 %% cleared offer/bid prices for different auction types
0149 if auction_type == 0        %% discriminative
0150     co.prc = offers.prc;
0151     cb.prc = bids.prc;
0152 elseif auction_type == 1    %% LAO
0153     co.prc = offers.lam * X.LAO;
0154     cb.prc = bids.lam   * X.LAO;
0155 elseif auction_type == 2    %% FRO
0156     co.prc = offers.lam * X.FRO;
0157     cb.prc = bids.lam   * X.FRO;
0158 elseif auction_type == 3    %% LAB
0159     co.prc = offers.lam * X.LAB;
0160     cb.prc = bids.lam   * X.LAB;
0161 elseif auction_type == 4    %% FRB
0162     co.prc = offers.lam * X.FRB;
0163     cb.prc = bids.lam   * X.FRB;
0164 elseif auction_type == 5    %% 1st price
0165     co.prc = offers.lam;
0166     cb.prc = bids.lam;
0167 elseif auction_type == 6    %% 2nd price
0168     if abs(1 - X.LAO) < zero_tol
0169         co.prc = offers.lam * min(X.FRO,X.LAB);
0170         cb.prc = bids.lam   * min(X.FRO,X.LAB);
0171     else
0172         co.prc = offers.lam * max(X.LAO,X.FRB);
0173         cb.prc = bids.lam   * max(X.LAO,X.FRB);
0174     end
0175 elseif auction_type == 7    %% split the difference
0176     co.prc = offers.lam * (X.LAO + X.LAB) / 2;
0177     cb.prc = bids.lam   * (X.LAO + X.LAB) / 2;
0178 elseif auction_type == 8    %% LAO seller, LAB buyer
0179     co.prc = offers.lam * X.LAO;
0180     cb.prc = bids.lam   * X.LAB;
0181 end
0182 
0183 %% guarantee that cleared offer prices are >= offers
0184 if gtee_prc.offer
0185     clip = o.on .* (offers.prc - co.prc);
0186     co.prc = co.prc + (clip > zero_tol) .* clip;
0187 end
0188 
0189 %% guarantee that cleared bid prices are <= bids
0190 if gtee_prc.bid
0191     clip = b.on .* (bids.prc - cb.prc);
0192     cb.prc = cb.prc + (clip < -zero_tol) .* clip;
0193 end
0194 
0195 %% clip cleared offer prices by limit_prc.max_cleared_offer
0196 if ~isempty(limit_prc.max_cleared_offer)
0197     co.prc = co.prc + (co.prc > limit_prc.max_cleared_offer) .* ...
0198         (limit_prc.max_cleared_offer - co.prc);
0199 end
0200 
0201 %% clip cleared bid prices by limit_prc.min_cleared_bid
0202 if ~isempty(limit_prc.min_cleared_bid)
0203     cb.prc = cb.prc + (cb.prc < limit_prc.min_cleared_bid) .* ...
0204         (limit_prc.min_cleared_bid - cb.prc);
0205 end
0206 
0207 %% make prices uniform after clipping (except for discrim auction)
0208 %% since clipping may only affect a single block of a multi-block generator
0209 if auction_type ~= 0
0210     %% equal to largest price in row
0211     if nco > 1
0212         co.prc = diag(max(co.prc')) * ones(nro,nco);
0213     end
0214     if ncb > 1
0215         cb.prc = diag(min(cb.prc')) * ones(nrb,ncb);
0216     end
0217 end
0218 
0219 
0220 function X = compute_exchange_rates(offers, bids, o, b, delta)
0221 %COMPUTE_EXCHANGE_RATES Determine the scale factors for LAO, FRO, LAB, FRB
0222 %  Inputs:
0223 %   offers, bids (same as for auction)
0224 %   o, b  - structs with on, off fields, each same dim as qty field of offers
0225 %           or bids, 1 if corresponding block is accepted, 0 otherwise
0226 %   delta - optional prices smaller than this are not used to determine X
0227 %  Outputs:
0228 %   X     - struct with fields LAO, FRO, LAB, FRB containing scale factors
0229 %           to use for each type of auction
0230 
0231 if nargin < 5
0232     delta = 1e-3;       %% prices smaller than this are not used to determine X
0233 end
0234 zero_tol = 1e-5;
0235 
0236 %% eliminate terms with lam < delta (X would not be accurate)
0237 olam = offers.lam;
0238 blam = bids.lam;
0239 olam(olam(:) < delta) = NaN;
0240 blam(blam(:) < delta) = NaN;
0241 
0242 %% eliminate rows for 0 qty offers/bids
0243 [nro, nco] = size(offers.qty);
0244 [nrb, ncb] = size(bids.qty);
0245 omask = ones(nro,nco);
0246 if nco == 1
0247     temp = offers.qty;
0248 else
0249     temp = sum(offers.qty')';
0250 end
0251 omask(temp == 0, :) = NaN;
0252 bmask = ones(nrb,ncb);
0253 if ncb == 1
0254     temp = bids.qty;
0255 else
0256     temp = sum(bids.qty')';
0257 end
0258 bmask(temp == 0, :) = NaN;
0259 
0260 %% by default, don't scale anything
0261 X.LAO = 1;
0262 X.FRO = 1;
0263 X.LAB = 1;
0264 X.FRB = 1;
0265 
0266 %% don't scale if we have any negative lambdas or all are too close to 0
0267 if all(all(offers.lam > -zero_tol))
0268     %% ratios
0269     Xo = omask .* offers.prc ./ olam;
0270     Xb = bmask .* bids.prc   ./ blam;
0271 
0272     %% exchange rate for LAO (X.LAO * lambda == LAO, for corresponding lambda)
0273     X.LAO = o.on .* Xo;
0274     X.LAO( o.off(:) ) = NaN;
0275     X.LAO( X.LAO(:) > 1+zero_tol ) = NaN;   %% don't let gens @ Pmin set price
0276     X.LAO = max( X.LAO(:) );
0277 
0278     %% exchange rate for FRO (X.FRO * lambda == FRO, for corresponding lambda)
0279     X.FRO = o.off .* Xo;
0280     X.FRO( o.on(:) ) = NaN;
0281     X.FRO = min( X.FRO(:) );
0282 
0283     if nrb
0284         %% exchange rate for LAB (X.LAB * lambda == LAB, for corresponding lambda)
0285         X.LAB = b.on .* Xb;
0286         X.LAB( b.off(:) ) = NaN;
0287         X.LAB( X.LAB(:) < 1-zero_tol ) = NaN;   %% don't let set price
0288         X.LAB = min( X.LAB(:) );
0289         
0290         %% exchange rate for FRB (X.FRB * lambda == FRB, for corresponding lambda)
0291         X.FRB = b.off .* Xb;
0292         X.FRB( b.on(:) ) = NaN;
0293         X.FRB = max( X.FRB(:) );
0294     end
0295 end
0296 
0297 
0298 function [cqty, on, off] = clear_qty(qty, total_cqty, mask)
0299 %CLEAR_QTY  Computed cleared offer/bid quantities from totals.
0300 %  Inputs:
0301 %   qty        - m x n, offer/bid quantities, m offers/bids, n blocks
0302 %   total_cqty - m x 1, total cleared quantity for each offer/bid
0303 %   mask       - m x n, boolean indicating which offers/bids are valid (not withheld)
0304 %  Outputs:
0305 %   cqty       - m x n, cleared offer/bid quantities, m offers/bids, n blocks
0306 %   on         - m x n, 1 if partially or fully accepted, 0 if rejected
0307 %   off        - m x n, 1 if rejected, 0 if partially or fully accepted
0308 
0309 [nr, nc] = size(qty);
0310 accept  = zeros(nr,nc);
0311 cqty    = zeros(nr,nc);
0312 for i = 1:nr            %% offer/bid i
0313     for j = 1:nc        %% block j
0314         if qty(i, j)    %% ignore zero quantity offers/bids
0315             %% compute fraction of the block accepted ...
0316             accept(i, j) = (total_cqty(i) - sum(qty(i, 1:j-1))) / qty(i, j);
0317             %% ... clipped to the range [0, 1]  (i.e. 0-100%)
0318             if accept(i, j) > 1
0319                 accept(i, j) = 1;
0320             elseif accept(i, j) < 1.0e-5
0321                 accept(i, j) = 0;
0322             end
0323             cqty(i, j) = qty(i, j) * accept(i, j);
0324         end
0325     end
0326 end
0327 
0328 if nargin == 3
0329     accept = mask .* accept;
0330 end
0331 
0332 on  = (accept  > 0);
0333 off = (accept == 0);

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