MATPOWER / most

MOST – MATPOWER Optimal Scheduling Tool, for steady-state power systems scheduling problems.
https://matpower.org/
Other
31 stars 11 forks source link

Solving multiperiod UC problem using MOST, UC does not change #33

Closed yadong-zhang closed 5 months ago

yadong-zhang commented 1 year ago

I am working on the case118 power grid, it has 54 generators and 99 loads. Among the 54 gens, 16 are selected as wind gens while the rest are considered as thermal gens. For that purpose, I set the CommitKey = -1 (off) for those 16 gens and add additional settings for 16 wind gens in the ‘wind_uc’ file. A 'wind_profile' is used to provide wind power generation. Also, the 99 loads are added as dispatchable loads in ‘mpc.gen’, and ‘load_profile’ is provided as load input. Overall 12 time steps (nt = 12) are computed. Here are the settings:

% Set power grid case file
clc;

% Read casefile
casefile = PowerGrid(num_zones, num_gens);     
mpc = loadcase(casefile);

% Set mpc.bus 
mpc.bus(load_buses, PD) = 1;     %%%%%%%%%%%%% Initial Pd, it will impact the calculation %%%%%%%%%
mpc.bus(load_buses, QD) = 0;    % Set Qd = 0

% Set mpc.gen
% Gen buses 
mpc.gen(1:num_gens, PG) = 0;     % Set initial Pg
mpc.gen(1:num_gens, [QG QMAX QMIN ...
    PMIN PC1 PC2 QC1MIN QC1MAX QC2MIN ...
    QC2MAX RAMP_Q APF]) = 0;     % Set unnecessary values as 0
mpc.gen(1:num_gens, RAMP_AGC) = 0;     % Set constraint for ramp rate for load following/AGC (MW/min)
mpc.gen(1:num_gens, RAMP_10) = 0; 
mpc.gen(1:num_gens, RAMP_30) = 100;     %%%%%%%%%%%%% Must be a proper value %%%%%%%%%%%%%
% Dispatchable loads
mpc.gen(num_gens+1:end, PG) = 0;
mpc.gen(num_gens+1:end, [QG QMAX QMIN ...
    PC1 PC2 QC1MIN QC1MAX QC2MIN ...
    QC2MAX RAMP_10 RAMP_30 RAMP_Q APF]) = 0;
mpc.gen(num_gens+1:end, VG) = 1;    % Set Vg
mpc.gen(num_gens+1:end, 7) = 100;   % Set mBase = 100
mpc.gen(num_gens+1:end, 8) = 1;   % Set status = 1
mpc.gen(num_gens+1:end, PMAX) = 0;
mpc.gen(num_gens+1:end, PMIN) = -1;      %%%%%%%%%%%%% Cannot be > 0 %%%%%%%%%%%%%%%
mpc.gen(num_gens+1:end, RAMP_AGC) = 0;    % Set unlimited load following ramp rate
mpc.gen(num_gens+1:end, RAMP_10) = 0;
mpc.gen(num_gens+1:end, RAMP_30) = 0;     % Cannot be negative

% Set mpc.branch

% Set mpc.gencost
% Gens
mpc.gencost(1:num_gens, 1) = 2;     % Set cost model
mpc.gencost(1:num_gens, 2) = 0;   % Set StartUp cost for thermal gens
mpc.gencost(1:num_gens, 3) = 0;   % Set ShudDown cost for thermal gens
% Dispatchable loads
mpc.gencost(num_gens+1:end, 1) = 2;
mpc.gencost(num_gens+1:end, [2 3]) = 0;     % Set StartUp and StutDown cost = 0
mpc.gencost(num_gens+1:end, 4) = 3;     % Set number of parameters
mpc.gencost(num_gens+1:end, [5 6 7]) = 0;

% Set mpc.reserves
temp1 = zeros(1, num_gens);
bidx = ismember(gen_buses, zone1_gens);
temp1(bidx) = 1;

temp2 = zeros(1, num_gens);
bidx = ismember(gen_buses, zone2_gens);
temp2(bidx) = 1;

temp3 = zeros(1, num_gens);
bidx = ismember(gen_buses, zone3_gens);
temp3(bidx) = 1;

temp4 = zeros(1, num_loads);    % Dispatchable loads

mpc.reserves.zones(1, :) = cat(2, temp1, temp4);
mpc.reserves.zones(2, :) = cat(2, temp2, temp4);
mpc.reserves.zones(3, :) = cat(2, temp3, temp4);

mpc.reserves.req = [200; 200; 200];     % Should be consistent with "num_zones"

mpc.reserves.cost = 5*ones(num_gens, 1);    % Skip dispatchable loads

mpc.reserves.qty = zeros(num_gens, 1);

%% Set XGD file
clc;

% Read xgd table
xgd_table = XGDTable;

% Gens
xgd_table.data(1:num_gens, 1) = 1;      % Set thermal gens UC = commitable
xgd_table.data(1:num_gens, 2) = 1;      
xgd_table.data(1:num_gens, [3 4]) = 3;  % Set thermal gens MinUp and MinDown
xgd_table.data(1:num_gens, 5) = 1e-2;   % PositiveActiveReservePrice
xgd_table.data(1:num_gens, 6) = 100;    % PositiveActiveReserveQuantity
xgd_table.data(1:num_gens, 7) = 1e-2;   % NegativeActiveReservePrice
xgd_table.data(1:num_gens, 8) = 100;    % NegativeActiveReserveQuantity
xgd_table.data(1:num_gens, 9) = 1e-2;   % PositiveActiveDeltaPrice
xgd_table.data(1:num_gens, 10) = 1e-2;  % NegativeActiveDeltaPrice
xgd_table.data(1:num_gens, 11) = 1e-2;  % PositiveLoadFollowReservePrice
xgd_table.data(1:num_gens, 12) = 100;   % PositiveLoadFollowReserveQuantity
xgd_table.data(1:num_gens, 13) = 1e-2;  % NegativeLoadFollowReservePrice
xgd_table.data(1:num_gens, 14) = 100;   % NegativeLoadFollowReserveQuantity

temp1 = ismember(gen_buses, wind_buses);    % Set UC = off for thermal gens at wind gen location
temp2 = zeros(num_loads, 1);
bidx = logical(cat(1, temp1, temp2));
xgd_table.data(bidx, 1) = -1;

% Dispatchable loads
xgd_table.data(num_gens+1:end, 1) = 2;       % Set dispatchable loads UC = 2
xgd_table.data(num_gens+1:end, 1) = 1;
xgd_table.data(num_gens+1:end, [3 4]) = 1; % Set dispatchable loads MinUp/MinDown
xgd_table.data(num_gens+1:end, 5) = 1e-2;   % PositiveActiveReservePrice
xgd_table.data(num_gens+1:end, 6) = 1e6;    % PositiveActiveReserveQuantity
xgd_table.data(num_gens+1:end, 7) = 1e-2;   % NegativeActiveReservePrice
xgd_table.data(num_gens+1:end, 8) = 1e6;    % NegativeActiveReserveQuantity
xgd_table.data(num_gens+1:end, 9) = 1e-2;   % PositiveActiveDeltaPrice
xgd_table.data(num_gens+1:end, 10) = 1e-2;  % NegativeActiveDeltaPrice
xgd_table.data(num_gens+1:end, 11) = 1e-2;  % PositiveLoadFollowReservePrice
xgd_table.data(num_gens+1:end, 12) = 1e6;   % PositiveLoadFollowReserveQuantity
xgd_table.data(num_gens+1:end, 13) = 1e-2;  % NegativeLoadFollowReservePrice
xgd_table.data(num_gens+1:end, 14) = 1e6;   % NegativeLoadFollowReserveQuantity

%% Set WindUC file
clc;

% Read wind UC file
wind_UC = WindUC;

% Gens
wind_UC.gen(:, PG) = 0;
wind_UC.gen(:, [QG QMAX QMIN PMIN]) = 0;
wind_UC.gen(:, PMAX) = 1e6;
wind_UC.gen(:, RAMP_AGC) = 1e6;     % Set unlimited ramp rate
wind_UC.gen(:, RAMP_AGC) = 1e6;
wind_UC.gen(:, RAMP_AGC) = 1e6;

% xgd_table
wind_UC.xgd_table.data(:, 1) = 2;
wind_UC.xgd_table.data(:, 2) = 1;
wind_UC.xgd_table.data(:, 3) = 0;       % Set initial value of Pg
wind_UC.xgd_table.data(:, 4:end) = 1e-2;   % Set all cost = 0
wind_UC.xgd_table.data(:, [6 8 12 14]) = 1e6;   % Set unlimited reserve and load follow capacity

When I run the code, I encountered following problems:

  1. What is the influence of ‘Pd’ in ‘mpc.bus’? Shouldn’t ‘Pd’ come from the ‘load_profile’ during the computing process? I tried many times, different ‘Pd’ values lead to different results, even if ‘load_profile’ is the same; when ‘Pd’ = 0, the results will be all 0. What’s more, the ‘Pd’ in results also changes with ‘Pd’ in ‘mpc.bus’.
  2. How to set RAMP_AGC, RAMP_10 and RAMP_30? I tried different combinations, it seems only RAMP_30 has influence on the computing process, while RAMP_AGC, RAMP_10 do not.
  3. Is there a way to force that wind power will be preferably used? That is, wind power will be used towards meeting load before non-wind generators.
  4. How to set ‘mpc.gen.Pmin’ for dispatchable loads. If set as -1, ‘Pd’ in the results will be 1/2 of that in the ‘load_profile’; if set as -2, ‘Pd’ will be 1/3 of the value in ‘load_profile’, and so on.
  5. Why UC doesn’t change even if various load scenarios are used?
  6. Why there is no power generation but UC = 1?

Can anyone help with these? I am new to MATPOWER, it is a great tool, I really want to learn it well to empower my research. Thanks a lot for your support!

rdzman commented 1 year ago
  1. The PD column in mpc.bus defines the nominal load fixed power demand at the bus. How it interacts with the load profile depends on how the profile is defined. But, if you have defined all of your loads as dispatchable in the gen table, you should set PD to 0 in the bus table.
  2. MOST does not use RAMP_AGC at all. The RAMP_10 value provides an additional limit on the contingency reserves and the RAMP_30 on the load following reserves.
  3. First, the CommitKey for wind units should be set to 2 (forced on, but with PMIN = 0, i.e. still able to be dispatched at 0), rather than 0 (forced off, i.e. not permitted to generate). Then you could "force" it to be used via the cost, by setting it to zero, or even to a negative value.
  4. For dispatchable loads, PMIN should be set to the negative of the nominal load.
  5. The UC will change only for units with CommitKey set to 0 or 1, and only if doing so will actually result in a lower cost feasible solution. Either it is not economical to change the UC, or it is not feasible for some reason.
  6. If the PMIN column for a generator is 0, then it can be dispatched at 0 without setting the commitment status to 0 (which could potentially increase startup and shutdown costs). If you want to disallow that solution, set PMIN to some positive value.
yadong-zhang commented 1 year ago

I see my problem! Thank you!!!