0001 function [co, cb, r, dispatch, success] = ...
0002 smartmkt(mpc, offers, bids, mkt, mpopt)
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 if nargin < 5
0018 mpopt = mpoption;
0019 end
0020
0021
0022 G = find( ~isload(mpc.gen) );
0023 L = find( isload(mpc.gen) );
0024 nL = length(L);
0025 if isfield(offers, 'Q') || isfield(bids, 'Q')
0026 haveQ = 1;
0027 else
0028 haveQ = 0;
0029 end
0030
0031 if haveQ && mkt.auction_type ~= 0 && mkt.auction_type ~= 5
0032 error(['smartmkt: Combined active/reactive power markets ', ...
0033 'are only implemented for auction types 0 and 5']);
0034 end
0035
0036
0037 mpopt = mpoption(mpopt, 'model', upper(mkt.OPF));
0038
0039
0040 [PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
0041 VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
0042 [GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
0043 MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
0044 QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
0045 [PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;
0046 [QUANTITY, PRICE, FCOST, VCOST, SCOST, PENALTY] = idx_disp;
0047
0048
0049 mkt.lim = pricelimits(mkt.lim, isfield(offers, 'Q') || isfield(bids, 'Q'));
0050 [gen, genoffer] = off2case(mpc.gen, mpc.gencost, offers, bids, mkt.lim);
0051
0052
0053
0054
0055 if any(find(genoffer(:, MODEL) == PW_LINEAR))
0056 gg = find( ~isload(gen) );
0057 gen(gg, PMIN) = gen(gg, PMIN) - 100 * mpopt.opf.violation * ones(size(gg));
0058 gen(gg, PMAX) = gen(gg, PMAX) + 100 * mpopt.opf.violation * ones(size(gg));
0059 end
0060
0061
0062
0063 mpc2 = mpc;
0064 mpc2.gen = gen;
0065 mpc2.gencost = genoffer;
0066 [r, success] = uopf(mpc2, mpopt);
0067 r.genoffer = r.gencost;
0068 r.gencost = mpc.gencost;
0069 [bus, gen] = deal(r.bus, r.gen);
0070 if mpopt.verbose && ~success
0071 fprintf('\nSMARTMARKET: non-convergent UOPF');
0072 end
0073
0074
0075
0076 ng = size(gen, 1);
0077 if success
0078
0079 i2e = bus(:, BUS_I);
0080 e2i = sparse(max(i2e), 1);
0081 e2i(i2e) = (1:size(bus, 1))';
0082
0083
0084 gbus = e2i(gen(:, GEN_BUS));
0085 nPo = size(offers.P.qty, 2);
0086 nPb = size(bids.P.qty, 2);
0087 nP = max([ nPo nPb ]);
0088 lamP = sparse(1:ng, 1:ng, bus(gbus, LAM_P), ng, ng) * ones(ng, nP);
0089 lamQ = sparse(1:ng, 1:ng, bus(gbus, LAM_Q), ng, ng) * ones(ng, nP);
0090
0091
0092 pf = zeros(length(L), 1);
0093 Qlim = (gen(L, QMIN) == 0) .* gen(L, QMAX) + ...
0094 (gen(L, QMAX) == 0) .* gen(L, QMIN);
0095 pf = Qlim ./ gen(L, PMIN);
0096
0097 gtee_prc.offer = 1;
0098 Poffer = offers.P;
0099 Poffer.lam = lamP(G,1:nPo);
0100 Poffer.total_qty = gen(G, PG);
0101
0102 Pbid = bids.P;
0103 Pbid.total_qty = -gen(L, PG);
0104 if haveQ
0105 Pbid.lam = lamP(L,1:nPb);
0106 gtee_prc.bid = 0;
0107 else
0108 Pbid.lam = lamP(L,1:nPb) + sparse(1:nL, 1:nL, pf, nL, nL) * lamQ(L,1:nPb);
0109 gtee_prc.bid = 1;
0110 end
0111
0112 [co.P, cb.P] = auction(Poffer, Pbid, mkt.auction_type, mkt.lim.P, gtee_prc);
0113
0114 if haveQ
0115 nQo = size(offers.Q.qty, 2);
0116 nQb = size(bids.Q.qty, 2);
0117 nQ = max([ nQo nQb ]);
0118
0119
0120 lamQ = sparse(1:ng, 1:ng, bus(gbus, LAM_Q), ng, ng) * ones(ng, nQ);
0121
0122 Qoffer = offers.Q;
0123 Qoffer.lam = lamQ(:,1:nQo);
0124 Qoffer.total_qty = (gen(:, QG) > 0) .* gen(:, QG);
0125
0126 Qbid = bids.Q;
0127 Qbid.lam = lamQ(:,1:nQb);
0128 Qbid.total_qty = (gen(:, QG) < 0) .* -gen(:, QG);
0129
0130
0131
0132 [co.Q, cb.Q] = auction(Qoffer, Qbid, mkt.auction_type, mkt.lim.Q, gtee_prc);
0133 end
0134
0135 quantity = gen(:, PG);
0136 quantityQ = gen(:, QG);
0137 price = zeros(ng, 1);
0138 price(G) = co.P.prc(:, 1);
0139 price(L) = cb.P.prc(:, 1);
0140 if nP == 1
0141 k = find( co.P.qty );
0142 price(G(k)) = co.P.prc(k, :);
0143 k = find( cb.P.qty );
0144 price(L(k)) = cb.P.prc(k, :);
0145 else
0146 k = find( sum( co.P.qty' )' );
0147 price(G(k)) = sum( co.P.qty(k, :)' .* co.P.prc(k, :)' )' ./ sum( co.P.qty(k, :)' )';
0148 k = find( sum( cb.P.qty' )' );
0149 price(L(k)) = sum( cb.P.qty(k, :)' .* cb.P.prc(k, :)' )' ./ sum( cb.P.qty(k, :)' )';
0150 end
0151 else
0152 quantity = zeros(ng, 1);
0153 quantityQ = zeros(ng, 1);
0154 if isempty(mkt.lim.P.max_offer)
0155 price = NaN(ng, 1);
0156 else
0157 price = mkt.lim.P.max_offer * ones(ng, 1);
0158 end
0159 co.P.qty = zeros(size(offers.P.qty));
0160 co.P.prc = zeros(size(offers.P.prc));
0161 cb.P.qty = zeros(size(bids.P.qty));
0162 cb.P.prc = zeros(size(bids.P.prc));
0163 if haveQ
0164 co.Q.qty = zeros(size(offers.Q.qty));
0165 co.Q.prc = zeros(size(offers.Q.prc));
0166 cb.Q.qty = zeros(size(bids.Q.qty));
0167 cb.Q.prc = zeros(size(bids.Q.prc));
0168 end
0169 end
0170
0171
0172
0173 if size(mpc.gencost, 1) == ng
0174 pgcost = mpc.gencost;
0175 fcost = mkt.t * totcost(pgcost, zeros(ng, 1));
0176 vcost = mkt.t * totcost(pgcost, quantity ) - fcost;
0177 scost = (~mkt.u0 & gen(:, GEN_STATUS) > 0) .* ...
0178 pgcost(:, STARTUP) + ...
0179 ( mkt.u0 & gen(:, GEN_STATUS) <= 0) .* ...
0180 pgcost(:, SHUTDOWN);
0181 else
0182 pgcost = mpc.gencost(1:ng, :);
0183 qgcost = mpc.gencost(ng+(1:ng), :);
0184 fcost = mkt.t * ( totcost(pgcost, zeros(ng, 1)) + ...
0185 totcost(qgcost, zeros(ng, 1)) );
0186 vcost = mkt.t * ( totcost(pgcost, quantity) + ...
0187 totcost(qgcost, quantityQ) ) - fcost;
0188 scost = (~mkt.u0 & gen(:, GEN_STATUS) > 0) .* ...
0189 (pgcost(:, STARTUP) + qgcost(:, STARTUP)) + ...
0190 ( mkt.u0 & gen(:, GEN_STATUS) <= 0) .* ...
0191 (pgcost(:, SHUTDOWN) + qgcost(:, SHUTDOWN));
0192 end
0193
0194
0195 dispatch = zeros(ng, PENALTY);
0196 dispatch(:, [QUANTITY PRICE FCOST VCOST SCOST]) = [quantity price fcost vcost scost];