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