Skip to content

Commit

Permalink
Speed up building UC (min up/down time) constraints.
Browse files Browse the repository at this point in the history
Improvement can be quite substantial on large problems.
  • Loading branch information
rdzman committed Nov 8, 2023
1 parent 116971a commit 7923b99
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 46 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Change history for MOST
since 1.2
---------

#### 11/8/23
- Speed up building unit commitment (min up/down time) constraints.
Improvement can be quite substantial on large problems.

#### 11/6/23
- Reduce memory requirements for long horizon cases with storage by
forming/storing transposes of matrices for storage constraints.
Expand Down
7 changes: 4 additions & 3 deletions docs/src/MOST-manual/MOST-manual.tex
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
\newcommand{\mostname}[0]{{{\bf M}{\sc atpower} \textbf{O}ptimal \textbf{S}cheduling \textbf{T}ool}}
\newcommand{\mosturl}[0]{https://github.com/MATPOWER/most}
\newcommand{\mostlink}[0]{\href{\mosturl}{\most{}}}
\newcommand{\mostver}[0]{1.2}
\newcommand{\mostver}[0]{1.2+}
\newcommand{\md}[0]{{\most{} Data struct}}
\newcommand{\powerweb}[0]{{\sc PowerWeb}}
\newcommand{\pserc}[0]{{\sc PSerc}}
Expand Down Expand Up @@ -240,7 +240,7 @@
%%% BEFORE PUBLISHING A NEW VERSION:
%%% Update the publication year for \bibitem{matpower} and
%%% \bibitem{matpower_manual} to the year of the latest release
\date{December 13, 2022} % comment this line to display the current date
%\date{December 13, 2022} % comment this line to display the current date
%\date{December 14, 2011\thanks{Second revision. First revision was December 13, 2011}} % comment this line to display the current date

%%% BEGIN DOCUMENT
Expand All @@ -250,7 +250,7 @@
\vfill
\begin{center}
{\scriptsize
\copyright~2011--2022~\PSERC{}\\
\copyright~2011--2023~\PSERC{}\\
All Rights Reserved}
\end{center}

Expand Down Expand Up @@ -3438,6 +3438,7 @@ \subsubsection*{Changes}
\begin{itemize}
\item Reduce memory requirements for long horizon cases with storage by forming/storing transposes of matrices for storage constraints.\\
\emph{Requires \mpomlink{} version~$>$~4.1.}
\item Speed up building unit commitment (min up/down time) constraints. Improvement can be quite substantial on large problems.

\end{itemize}

Expand Down
134 changes: 92 additions & 42 deletions lib/most.m
Original file line number Diff line number Diff line change
Expand Up @@ -1574,59 +1574,109 @@
end
om.add_lin_constraint('uvw', {t}, A, b, b, vs);
end
% Then continue with minimimum up time constraints. Again, two
% different forms depending on whether the horizon is cyclical or not
om.init_indexed_name('lin', 'minup', {nt, ng});
% Continue with minimimum up time constraints, with option for
% cyclical horizon.
om.init_indexed_name('lin', 'minup', {nt});
% Sum of startups in "min up window" (win) must be <= u
for t = 1:nt
% beginning of win
w0 = t - mdi.UC.MinUp + 1; % full win(t,i) is w0(i):t
if mdi.UC.CyclicCommitment % window is circular
% any window that starts before t=1 wraps back to end of horizon
w0(w0 < 1) = w0(w0 < 1) + nt;
% if we wrap all the way back to before t=1 again,
% include entire horizon, i.e. always ON
if t < nt
w0(w0 < 1) = t + 1;
else
w0(w0 < 1) = 1;
end
else
% clip non-positive w0
w0(w0 < 1) = 1;
end

% b = -(sum of startups in win before t=1)
b = zeros(ng, 1);
% next line not necessary, since it is handled above by direct bounds on u
% b(mdi.UC.InitialState > 0 & w0 <= -mdi.UC.InitialState +1) = -1;

% period index list from t back to beginning of biggest win
if any(w0 > t) % w/wrapping back to end of horizon
max_win = [t:-1:1 nt:-1:min(w0(w0 > t))];
else % no wrapping back to end of horizon
max_win = [t:-1:min(w0)];
end

vs = struct('name', {'u'}, 'idx', {{t}});
A = [-speye(ng, ng) sparse(ng, ng*length(max_win))];
for tt = 1:length(max_win)
vs(end+1).name = 'v';
vs(end).idx = {max_win(tt)};
end
for i = 1:ng
ti = t-mdi.UC.MinUp(i)+1:t;
if mdi.UC.CyclicCommitment % window is circular
for tt = 1:length(ti)
if ti(tt) < 1
ti(tt) = nt + ti(tt);
end
end
if w0(i) > t
win = [t:-1:1 nt:-1:w0(i)];
else
win = [t:-1:w0(i)];
end
% limit to positive time
% even with CyclicCommitment, in case MinUp is longer than horizon
% (which implies always ON or always OFF)
ti = ti(ti>0);
vs = struct('name', {'u'}, 'idx', {{t}});
A = sparse(1, i, -1, 1, ng);
for tt = 1:length(ti)
vs(end+1).name = 'v';
vs(end).idx = {ti(tt)};
A = [A sparse(1, i, 1, 1, ng)];
for tt = 1:length(win)
A(i, ng*tt+i) = 1;
end
om.add_lin_constraint('minup', {t, i}, A, [], 0, vs);
end
om.add_lin_constraint('minup', {t}, A, [], b, vs);
end
% Continue with minimimum downtime constraints. Two
% different forms depending on whether the horizon is cyclical or not
om.init_indexed_name('lin', 'mindown', {nt, ng});
% Continue with minimimum downtime constraints, with option for
% cyclical horizon.
om.init_indexed_name('lin', 'mindown', {nt});
% Sum of shutdowns in "min down window" (win) must be <= (1-u)
for t = 1:nt
% beginning of win
w0 = t - mdi.UC.MinDown + 1; % full win(t,i) is w0(i):t
if mdi.UC.CyclicCommitment % window is circular
% any window that starts before t=1 wraps back to end of horizon
w0(w0 < 1) = w0(w0 < 1) + nt;
% if we wrap all the way back to before t=1 again,
% include entire horizon, i.e. always ON
if t < nt
w0(w0 < 1) = t + 1;
else
w0(w0 < 1) = 1;
end
else
% clip non-positive w0
w0(w0 < 1) = 1;
end

% b = 1-(sum of shutdowns in win before t=1)
b = ones(ng, 1);
% next line not necessary, since it is handled above by direct bounds on u
% b(mdi.UC.InitialState < 0 & w0 <= -mdi.UC.InitialState +1) = 0;

% period index list from t back to beginning of biggest win
if any(w0 > t) % w/wrapping back to end of horizon
max_win = [t:-1:1 nt:-1:min(w0(w0 > t))];
else % no wrapping back to end of horizon
max_win = [t:-1:min(w0)];
end

vs = struct('name', {'u'}, 'idx', {{t}});
A = [speye(ng, ng) sparse(ng, ng*length(max_win))];
for tt = 1:length(max_win)
vs(end+1).name = 'w';
vs(end).idx = {max_win(tt)};
end
for i = 1:ng
ti = t-mdi.UC.MinDown(i)+1:t;
if mdi.UC.CyclicCommitment % window is circular
for tt = 1:length(ti)
if ti(tt) < 1
ti(tt) = nt + ti(tt);
end
end
if w0(i) > t
win = [t:-1:1 nt:-1:w0(i)];
else
win = [t:-1:w0(i)];
end
% limit to positive time
% even with CyclicCommitment, in case MinDown is longer than horizon
% (which implies always ON or always OFF)
ti = ti(ti>0);
vs = struct('name', {'u'}, 'idx', {{t}});
A = sparse(1, i, 1, 1, ng);
for tt = 1:length(ti)
vs(end+1).name = 'w';
vs(end).idx = {ti(tt)};
A = [A sparse(1, i, 1, 1, ng)];
for tt = 1:length(win)
A(i, ng*tt+i) = 1;
end
om.add_lin_constraint('mindown', {t, i}, A, [], 1, vs);
end
om.add_lin_constraint('mindown', {t}, A, [], b, vs);
end
% Limit generation ranges based on commitment status; first Pmax;
% p - u*Pmax <= 0
Expand Down
2 changes: 1 addition & 1 deletion lib/mostver.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
v = struct( 'Name', 'MOST', ...
'Version', '1.2+', ...
'Release', '', ...
'Date', '06-Nov-2023' );
'Date', '08-Nov-2023' );
if nargout > 0
if nargin > 0
rv = v;
Expand Down

0 comments on commit 7923b99

Please sign in to comment.