Home > matpower5.1 > 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 %   Copyright (c) 1996-2015 by Power System Engineering Research Center (PSERC)
0045 %   by Ray Zimmerman, PSERC Cornell
0046 %
0047 %   $Id: auction.m 2644 2015-03-11 19:34:22Z ray $
0048 %
0049 %   This file is part of MATPOWER.
0050 %   Covered by the 3-clause BSD License (see LICENSE file for details).
0051 %   See http://www.pserc.cornell.edu/matpower/ for more info.
0052 
0053 %%-----  initialization  -----
0054 %% define named indices into data matrices
0055 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0056     VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0057 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0058     MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0059     QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0060 
0061 %% initialize some stuff
0062 delta = 1e-3;       %% prices smaller than this are not used to determine X
0063 zero_tol = 1e-5;
0064 % zero_tol = 0.1;   %% fmincon is SO bad with prices that it is
0065                     %% NOT recommended for use with auction.m
0066 big_num = 1e6;
0067 if isempty(bids)
0068     bids = struct(  'qty', [], ...
0069                     'prc', [], ...
0070                     'lam', [], ...
0071                     'total_qty', [] );
0072 end
0073 if nargin < 4 || isempty(limit_prc)
0074     limit_prc = struct( 'max_offer', [], 'min_bid', [], ...
0075                         'max_cleared_offer', [], 'min_cleared_bid', [] );
0076 else
0077     if ~isfield(limit_prc, 'max_offer'),         limit_prc.max_offer = [];         end
0078     if ~isfield(limit_prc, 'min_bid'),           limit_prc.min_bid = [];           end
0079     if ~isfield(limit_prc, 'max_cleared_offer'), limit_prc.max_cleared_offer = []; end
0080     if ~isfield(limit_prc, 'min_cleared_bid'),   limit_prc.min_cleared_bid = [];   end
0081 end
0082 if nargin < 5 || isempty(gtee_prc)
0083     gtee_prc = struct(  'offer', 1, 'bid', 1    );
0084 else
0085     if ~isfield(gtee_prc, 'offer'), gtee_prc.offer = 1; end
0086     if ~isfield(gtee_prc, 'bid'),   gtee_prc.bid = 1;   end
0087 end
0088 
0089 [nro, nco] = size(offers.qty);
0090 [nrb, ncb] = size(bids.qty);
0091 
0092 %% determine cleared quantities
0093 if isempty(limit_prc.max_offer)
0094     [co.qty, o.on, o.off] = clear_qty(offers.qty, offers.total_qty);
0095 else
0096     mask = offers.prc <= limit_prc.max_offer;
0097     [co.qty, o.on, o.off] = clear_qty(offers.qty, offers.total_qty, mask);
0098 end
0099 if isempty(limit_prc.min_bid)
0100     [cb.qty, b.on, b.off] = clear_qty(bids.qty, bids.total_qty);
0101 else
0102     mask = bids.prc <= limit_prc.min_bid;
0103     [cb.qty, b.on, b.off] = clear_qty(bids.qty, bids.total_qty, mask);
0104 end
0105 
0106 %% initialize cleared prices
0107 co.prc = zeros(nro, nco);       %% cleared offer prices
0108 cb.prc = zeros(nrb, ncb);       %% cleared bid prices
0109 
0110 %%-----  compute exchange rates to scale lam to get desired pricing  -----
0111 %% The locationally adjusted offer/bid price, when normalized to an arbitrary
0112 %% reference location where lambda is equal to ref_lam, is:
0113 %%      norm_prc = prc * (ref_lam / lam)
0114 %% Then we can define the ratio between the normalized offer/bid prices
0115 %% and the ref_lam as an exchange rate X:
0116 %%      X = norm_prc / ref_lam = prc / lam
0117 %% This X represents the ratio between the marginal unit (setting lambda)
0118 %% and the offer/bid price in question.
0119 
0120 if auction_type == 0 || auction_type == 5   %% don't bother scaling anything
0121     X = struct( 'LAO', 1, ...
0122                 'FRO', 1, ...
0123                 'LAB', 1, ...
0124                 'FRB', 1);
0125 else
0126     X = compute_exchange_rates(offers, bids, o, b);
0127 end
0128 
0129 %% cleared offer/bid prices for different auction types
0130 if auction_type == 0        %% discriminative
0131     co.prc = offers.prc;
0132     cb.prc = bids.prc;
0133 elseif auction_type == 1    %% LAO
0134     co.prc = offers.lam * X.LAO;
0135     cb.prc = bids.lam   * X.LAO;
0136 elseif auction_type == 2    %% FRO
0137     co.prc = offers.lam * X.FRO;
0138     cb.prc = bids.lam   * X.FRO;
0139 elseif auction_type == 3    %% LAB
0140     co.prc = offers.lam * X.LAB;
0141     cb.prc = bids.lam   * X.LAB;
0142 elseif auction_type == 4    %% FRB
0143     co.prc = offers.lam * X.FRB;
0144     cb.prc = bids.lam   * X.FRB;
0145 elseif auction_type == 5    %% 1st price
0146     co.prc = offers.lam;
0147     cb.prc = bids.lam;
0148 elseif auction_type == 6    %% 2nd price
0149     if abs(1 - X.LAO) < zero_tol
0150         co.prc = offers.lam * min(X.FRO,X.LAB);
0151         cb.prc = bids.lam   * min(X.FRO,X.LAB);
0152     else
0153         co.prc = offers.lam * max(X.LAO,X.FRB);
0154         cb.prc = bids.lam   * max(X.LAO,X.FRB);
0155     end
0156 elseif auction_type == 7    %% split the difference
0157     co.prc = offers.lam * (X.LAO + X.LAB) / 2;
0158     cb.prc = bids.lam   * (X.LAO + X.LAB) / 2;
0159 elseif auction_type == 8    %% LAO seller, LAB buyer
0160     co.prc = offers.lam * X.LAO;
0161     cb.prc = bids.lam   * X.LAB;
0162 end
0163 
0164 %% guarantee that cleared offer prices are >= offers
0165 if gtee_prc.offer
0166     clip = o.on .* (offers.prc - co.prc);
0167     co.prc = co.prc + (clip > zero_tol) .* clip;
0168 end
0169 
0170 %% guarantee that cleared bid prices are <= bids
0171 if gtee_prc.bid
0172     clip = b.on .* (bids.prc - cb.prc);
0173     cb.prc = cb.prc + (clip < -zero_tol) .* clip;
0174 end
0175 
0176 %% clip cleared offer prices by limit_prc.max_cleared_offer
0177 if ~isempty(limit_prc.max_cleared_offer)
0178     co.prc = co.prc + (co.prc > limit_prc.max_cleared_offer) .* ...
0179         (limit_prc.max_cleared_offer - co.prc);
0180 end
0181 
0182 %% clip cleared bid prices by limit_prc.min_cleared_bid
0183 if ~isempty(limit_prc.min_cleared_bid)
0184     cb.prc = cb.prc + (cb.prc < limit_prc.min_cleared_bid) .* ...
0185         (limit_prc.min_cleared_bid - cb.prc);
0186 end
0187 
0188 %% make prices uniform after clipping (except for discrim auction)
0189 %% since clipping may only affect a single block of a multi-block generator
0190 if auction_type ~= 0
0191     %% equal to largest price in row
0192     if nco > 1
0193         co.prc = diag(max(co.prc')) * ones(nro,nco);
0194     end
0195     if ncb > 1
0196         cb.prc = diag(min(cb.prc')) * ones(nrb,ncb);
0197     end
0198 end
0199 
0200 
0201 function X = compute_exchange_rates(offers, bids, o, b, delta)
0202 %COMPUTE_EXCHANGE_RATES Determine the scale factors for LAO, FRO, LAB, FRB
0203 %  Inputs:
0204 %   offers, bids (same as for auction)
0205 %   o, b  - structs with on, off fields, each same dim as qty field of offers
0206 %           or bids, 1 if corresponding block is accepted, 0 otherwise
0207 %   delta - optional prices smaller than this are not used to determine X
0208 %  Outputs:
0209 %   X     - struct with fields LAO, FRO, LAB, FRB containing scale factors
0210 %           to use for each type of auction
0211 
0212 if nargin < 5
0213     delta = 1e-3;       %% prices smaller than this are not used to determine X
0214 end
0215 zero_tol = 1e-5;
0216 
0217 %% eliminate terms with lam < delta (X would not be accurate)
0218 olam = offers.lam;
0219 blam = bids.lam;
0220 olam(olam(:) < delta) = NaN;
0221 blam(blam(:) < delta) = NaN;
0222 
0223 %% eliminate rows for 0 qty offers/bids
0224 [nro, nco] = size(offers.qty);
0225 [nrb, ncb] = size(bids.qty);
0226 omask = ones(nro,nco);
0227 if nco == 1
0228     temp = offers.qty;
0229 else
0230     temp = sum(offers.qty')';
0231 end
0232 omask(temp == 0, :) = NaN;
0233 bmask = ones(nrb,ncb);
0234 if ncb == 1
0235     temp = bids.qty;
0236 else
0237     temp = sum(bids.qty')';
0238 end
0239 bmask(temp == 0, :) = NaN;
0240 
0241 %% by default, don't scale anything
0242 X.LAO = 1;
0243 X.FRO = 1;
0244 X.LAB = 1;
0245 X.FRB = 1;
0246 
0247 %% don't scale if we have any negative lambdas or all are too close to 0
0248 if all(all(offers.lam > -zero_tol))
0249     %% ratios
0250     Xo = omask .* offers.prc ./ olam;
0251     Xb = bmask .* bids.prc   ./ blam;
0252 
0253     %% exchange rate for LAO (X.LAO * lambda == LAO, for corresponding lambda)
0254     X.LAO = o.on .* Xo;
0255     X.LAO( o.off(:) ) = NaN;
0256     X.LAO( X.LAO(:) > 1+zero_tol ) = NaN;   %% don't let gens @ Pmin set price
0257     X.LAO = max( X.LAO(:) );
0258 
0259     %% exchange rate for FRO (X.FRO * lambda == FRO, for corresponding lambda)
0260     X.FRO = o.off .* Xo;
0261     X.FRO( o.on(:) ) = NaN;
0262     X.FRO = min( X.FRO(:) );
0263 
0264     if nrb
0265         %% exchange rate for LAB (X.LAB * lambda == LAB, for corresponding lambda)
0266         X.LAB = b.on .* Xb;
0267         X.LAB( b.off(:) ) = NaN;
0268         X.LAB( X.LAB(:) < 1-zero_tol ) = NaN;   %% don't let set price
0269         X.LAB = min( X.LAB(:) );
0270         
0271         %% exchange rate for FRB (X.FRB * lambda == FRB, for corresponding lambda)
0272         X.FRB = b.off .* Xb;
0273         X.FRB( b.on(:) ) = NaN;
0274         X.FRB = max( X.FRB(:) );
0275     end
0276 end
0277 
0278 
0279 function [cqty, on, off] = clear_qty(qty, total_cqty, mask)
0280 %CLEAR_QTY  Computed cleared offer/bid quantities from totals.
0281 %  Inputs:
0282 %   qty        - m x n, offer/bid quantities, m offers/bids, n blocks
0283 %   total_cqty - m x 1, total cleared quantity for each offer/bid
0284 %   mask       - m x n, boolean indicating which offers/bids are valid (not withheld)
0285 %  Outputs:
0286 %   cqty       - m x n, cleared offer/bid quantities, m offers/bids, n blocks
0287 %   on         - m x n, 1 if partially or fully accepted, 0 if rejected
0288 %   off        - m x n, 1 if rejected, 0 if partially or fully accepted
0289 
0290 [nr, nc] = size(qty);
0291 accept  = zeros(nr,nc);
0292 cqty    = zeros(nr,nc);
0293 for i = 1:nr            %% offer/bid i
0294     for j = 1:nc        %% block j
0295         if qty(i, j)    %% ignore zero quantity offers/bids
0296             %% compute fraction of the block accepted ...
0297             accept(i, j) = (total_cqty(i) - sum(qty(i, 1:j-1))) / qty(i, j);
0298             %% ... clipped to the range [0, 1]  (i.e. 0-100%)
0299             if accept(i, j) > 1
0300                 accept(i, j) = 1;
0301             elseif accept(i, j) < 1.0e-5
0302                 accept(i, j) = 0;
0303             end
0304             cqty(i, j) = qty(i, j) * accept(i, j);
0305         end
0306     end
0307 end
0308 
0309 if nargin == 3
0310     accept = mask .* accept;
0311 end
0312 
0313 on  = (accept  > 0);
0314 off = (accept == 0);

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