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

Generated on Fri 09-Oct-2020 11:21:31 by m2html © 2005