Skip to content

Commit e07c847

Browse files
committed
wip
Signed-off-by: Davey Elder <iandavidelder@gmail.com>
1 parent be883c7 commit e07c847

10 files changed

Lines changed: 334 additions & 316 deletions

File tree

docs/source/extensions/unit_commitment.rst

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ Unit Commitment
55

66
The **unit_commitment** extension adds commitment-level operational constraints
77
to selected technologies: online/started/stopped unit accounting, minimum
8-
output floors, maximum output ceilings (replacing the default capacity
9-
constraint), and minimum up-time and down-time windows. It also supports
10-
discounted startup costs and startup emissions and input flows.
8+
output floors, maximum output ceilings, and minimum up-time and down-time windows.
9+
It also supports discounted startup costs and startup emissions and input flows.
1110

1211
It is disabled by default and enabled per run through configuration:
1312

@@ -32,9 +31,33 @@ and :math:`\textbf{UCSP}` (stopped) — count whole units and are promoted to no
3231
integers by default (MIP). In **linearized mode** (:code:`linearized = 1`), these
3332
variables are kept continuous. This is equivalent to imagining that :math:`UC_{r,t}` is
3433
infinitesimally small: the commitment variables become fractional occupancy factors rather
35-
than discrete unit counts, and the min-output/max-output bounds act as simple lower and
36-
upper capacity-factor constraints without any integer requirements. Linearized mode is
37-
useful for reducing solve time during early model development or sensitivity analysis.
34+
than discrete unit counts, and the min-output bound acts as a simple lower capacity-factor
35+
constraint without any integer requirements. Linearized mode is useful for reducing solve
36+
time.
37+
38+
Integration with Core Constraints
39+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40+
41+
For some existing core constraints, the extension overrides a utility function —
42+
:func:`~temoa.components.utils.get_available_output` — that computes
43+
the maximum available output for a process in a given time slice. For UC technologies,
44+
this function returns a commitment-aware expression based on online units rather than total
45+
installed capacity. Because this function is used throughout the core model, the following
46+
constraints automatically become UC-aware for registered technologies with no further changes:
47+
48+
- :code:`capacity_constraint` — output bounded by online capacity
49+
- :code:`storage_charge_rate_constraint`, :code:`storage_discharge_rate_constraint`,
50+
:code:`storage_throughput_constraint` — storage rates scale with online units
51+
- :code:`reserve_margin_constraint` (dynamic mode only) — reserve contribution from online units only
52+
53+
Ramp constraints are the only exception: they require explicit knowledge of
54+
started/stopped units to compute the ramp envelope and are therefore fully replaced by
55+
UC-aware versions for technologies that appear in both :code:`unit_commitment` and the
56+
ramp tables.
57+
58+
.. autofunction:: temoa.components.utils.available_output_base
59+
60+
.. autofunction:: temoa.extensions.unit_commitment.components.commitment.uc_available_output
3861

3962
.. warning::
4063

@@ -51,13 +74,6 @@ useful for reducing solve time during early model development or sensitivity ana
5174
:code:`linearized = 1` in the :code:`unit_commitment` table for a
5275
particular technology to keep those variables continuous (LP relaxation).
5376

54-
.. note::
55-
56-
The :code:`uc_max_output_constraint` **replaces** the default
57-
:code:`capacity_constraint` for processes listed in the
58-
:code:`unit_commitment` table. Non-UC processes retain the standard
59-
capacity constraint unchanged.
60-
6177
Overview
6278
--------
6379

@@ -70,7 +86,7 @@ Overview
7086
- Key interaction
7187
* - :code:`unit_commitment`
7288
- Core UC parameters (unit size, output fractions, up/down times).
73-
- Enables UC constraints; replaces capacity constraint for UC techs.
89+
- Enables UC constraints; overrides available output calculation for UC techs.
7490
Commitment results are written to :code:`output_unit_commitment`.
7591
* - :code:`unit_commitment_startup_cost`
7692
- Direct startup cost per unit of capacity started.
@@ -165,6 +181,11 @@ capacity started. Startup inputs are summed into the
165181
":code:`tech`", ":math:`t`", "technology name"
166182
":code:`input_per_cap`", ":math:`UCSI_{r,i,t}`", "input commodity consumed per unit of capacity started"
167183

184+
.. note::
185+
186+
These inputs are **not** considered in network checking. If no other process produces or consumes the
187+
input commodity in this region and period, it may be removed from the model and lead to errors.
188+
168189
Decision Variables
169190
------------------
170191

@@ -200,9 +221,14 @@ Commitment Transition
200221
Output Bounds
201222
~~~~~~~~~~~~~
202223

203-
.. autofunction:: temoa.extensions.unit_commitment.components.commitment.uc_min_output_constraint
224+
The minimum output constraint enforces a floor on generation per online unit.
225+
The maximum output (capacity) constraint is handled by the standard core-model
226+
:code:`capacity_constraint` — the extension overrides
227+
:func:`~temoa.components.utils.get_available_output` so that available output
228+
is based on online units rather than total installed capacity, requiring no
229+
separate replacement constraint.
204230

205-
.. autofunction:: temoa.extensions.unit_commitment.components.commitment.uc_max_output_constraint
231+
.. autofunction:: temoa.extensions.unit_commitment.components.commitment.uc_min_output_constraint
206232

207233
Minimum Up/Down Time
208234
~~~~~~~~~~~~~~~~~~~~
@@ -224,16 +250,14 @@ The core ramp constraint bounds the change in hourly activity against a fraction
224250
total installed capacity. The UC version replaces this with a commitment-aware
225251
expression: only online units contribute to the ramp envelope, and the operating
226252
point assumed for units that start or stop during the transition adds or removes
227-
headroom according to the effective minimum output fraction. See
228-
:func:`~temoa.extensions.unit_commitment.components.commitment._ramp_constraint`
229-
for the full mathematical derivation.
253+
headroom according to the effective minimum output fraction. Units are assumed to
254+
start and stop at their minimum viable output level, taken as the larger of their
255+
:code:`min_output_fraction` and :code:`ramp_up_fraction` / :code:`ramp_down_fraction`.
230256

231257
.. autofunction:: temoa.extensions.unit_commitment.components.commitment.uc_ramp_up_constraint
232258

233259
.. autofunction:: temoa.extensions.unit_commitment.components.commitment.uc_ramp_down_constraint
234260

235-
.. autofunction:: temoa.extensions.unit_commitment.components.commitment._ramp_constraint
236-
237261
Objective Contributions
238262
-----------------------
239263

temoa/_internal/run_actions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ def solve_instance(
251251
dual_suffix.direction = Suffix.LOCAL
252252
result = optimizer.solve(instance)
253253
else:
254-
result = optimizer.solve(instance, suffixes=solver_suffixes_list)
254+
result = optimizer.solve(instance, suffixes=solver_suffixes_list, tee=True)
255255
except RuntimeError as error:
256256
logger.exception('Solver failed to solve and returned an error: %s', error)
257257
logger.error(

temoa/components/capacity.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from temoa.components import geography, technology
2222

23-
from .utils import get_adjusted_existing_capacity, get_capacity_factor
23+
from .utils import get_adjusted_existing_capacity, get_available_output
2424

2525
if TYPE_CHECKING:
2626
from temoa.core.model import TemoaModel
@@ -463,21 +463,9 @@ def capacity_constraint(
463463
for S_i in model.process_inputs[r, p, t, v]
464464
for S_o in model.process_outputs_by_input[r, p, t, v, S_i]
465465
)
466-
return (
467-
get_capacity_factor(model, r, s, d, t, v)
468-
* value(model.capacity_to_activity[r, t])
469-
* value(model.segment_fraction[s, d])
470-
* model.v_capacity[r, p, t, v]
471-
== useful_activity + curtailment
472-
)
466+
return get_available_output(model, r, p, s, d, t, v) == useful_activity + curtailment
473467
else:
474-
return (
475-
get_capacity_factor(model, r, s, d, t, v)
476-
* value(model.capacity_to_activity[r, t])
477-
* value(model.segment_fraction[s, d])
478-
* model.v_capacity[r, p, t, v]
479-
>= useful_activity
480-
)
468+
return get_available_output(model, r, p, s, d, t, v) >= useful_activity
481469

482470

483471
def adjusted_capacity_constraint(

temoa/components/operations.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,12 @@ def _ramp_constraint(
265265
p: Period,
266266
s: Season,
267267
d: TimeOfDay,
268-
s_next: Season,
269-
d_next: TimeOfDay,
270268
t: Technology,
271269
v: Vintage,
272270
) -> ExprLike:
273271
"""Helper that composes :func:`_ramp_activity_increase` and
274272
:func:`_rampable_activity` into the core-model ramp constraint."""
273+
s_next, d_next = model.time_next[s, d]
275274
result = _ramp_activity_increase(model, ramp_up, r, p, s, d, s_next, d_next, t, v)
276275
if result is None:
277276
return Constraint.Skip
@@ -336,17 +335,13 @@ def ramp_up_constraint(
336335
i.e. :math:`(H_d + H_{d_{next}}) / 2`
337336
- :math:`CAP \cdot C2A / (24 \cdot DPP)` gives the maximum hourly capacity
338337
"""
339-
340-
s_next, d_next = model.time_next[s, d]
341338
return _ramp_constraint(
342339
model=model,
343340
ramp_up=True,
344341
r=r,
345342
p=p,
346343
s=s,
347344
d=d,
348-
s_next=s_next,
349-
d_next=d_next,
350345
t=t,
351346
v=v,
352347
)
@@ -387,17 +382,13 @@ def ramp_down_constraint(
387382
\\
388383
\text{where: } \Delta H = \frac{H_d + H_{d_{next}}}{2}
389384
"""
390-
391-
s_next, d_next = model.time_next[s, d]
392385
return _ramp_constraint(
393386
model=model,
394387
ramp_up=False,
395388
r=r,
396389
p=p,
397390
s=s,
398391
d=d,
399-
s_next=s_next,
400-
d_next=d_next,
401392
t=t,
402393
v=v,
403394
)

0 commit comments

Comments
 (0)