Skip to content

Commit c797b1d

Browse files
committed
Refactor existing components in preparation for unit_commitment connections
Signed-off-by: Davey Elder <iandavidelder@gmail.com>
1 parent 5e448e7 commit c797b1d

6 files changed

Lines changed: 262 additions & 233 deletions

File tree

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: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from temoa.components import time
2121

2222
if TYPE_CHECKING:
23+
from pyomo.core.base import Expression
24+
2325
from temoa.core.model import TemoaModel
2426
from temoa.types import ExprLike
2527
from temoa.types.core_types import Period, Region, Season, Technology, TimeOfDay, Vintage
@@ -192,7 +194,7 @@ def create_operational_vintage_sets(model: TemoaModel) -> None:
192194
model.is_seasonal_storage[t] = t in model.tech_seasonal_storage
193195

194196

195-
def _ramp_constraint(
197+
def _ramp_activity_increase(
196198
model: TemoaModel,
197199
ramp_up: bool,
198200
r: Region,
@@ -203,25 +205,12 @@ def _ramp_constraint(
203205
d_next: TimeOfDay,
204206
t: Technology,
205207
v: Vintage,
206-
) -> ExprLike:
207-
"""
208-
Helper function to compute ramping constraints for both ramp-up and ramp-down.
209-
210-
Args:
211-
model (TemoaModel): The Temoa model instance.
212-
ramp_up (bool): True for ramp-up constraints, False for ramp-down constraints.
213-
r (Region): The region.
214-
p (Period): The period.
215-
s (Season): The season.
216-
d (TimeOfDay): The time of day.
217-
s_next (Season): The next season.
218-
d_next (TimeOfDay): The next time of day.
219-
t (Technology): The technology.
220-
v (Vintage): The vintage.
221-
222-
Returns:
223-
Expression | Constraint.Skip: A tuple containing the activity increase
224-
and rampable activity expressions or a constraint skip.
208+
) -> tuple[Expression, float] | None:
209+
"""Compute the hourly activity increase between adjacent time slices and the
210+
ramp fraction for the given direction.
211+
212+
Returns ``(activity_increase, ramp_fraction)`` or ``None`` when the ramp
213+
rate is so large that the constraint would never bind (skip).
225214
"""
226215
ramping_param = model.ramp_up_hourly if ramp_up else model.ramp_down_hourly
227216

@@ -246,19 +235,51 @@ def _ramp_constraint(
246235
f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.'
247236
)
248237
logger.warning(msg.format(ramping_param.name, r, t, p, s, d, p, s_next, d_next))
249-
return Constraint.Skip
238+
return None
250239

251240
activity_increase = hourly_activity_sd_next - hourly_activity_sd
252-
rampable_activity = (
241+
return activity_increase, ramp_fraction
242+
243+
244+
def _rampable_activity(
245+
model: TemoaModel,
246+
r: Region,
247+
p: Period,
248+
t: Technology,
249+
v: Vintage,
250+
ramp_fraction: float,
251+
) -> ExprLike:
252+
"""Rampable activity for the core model: fraction of total installed capacity."""
253+
return (
253254
ramp_fraction
254255
* model.v_capacity[r, p, t, v]
255256
* value(model.capacity_to_activity[r, t])
256257
/ (24 * value(model.days_per_period))
257258
)
259+
260+
261+
def _ramp_constraint(
262+
model: TemoaModel,
263+
ramp_up: bool,
264+
r: Region,
265+
p: Period,
266+
s: Season,
267+
d: TimeOfDay,
268+
t: Technology,
269+
v: Vintage,
270+
) -> ExprLike:
271+
"""Helper that composes :func:`_ramp_activity_increase` and
272+
:func:`_rampable_activity` into the core-model ramp constraint."""
273+
s_next, d_next = model.time_next[s, d]
274+
result = _ramp_activity_increase(model, ramp_up, r, p, s, d, s_next, d_next, t, v)
275+
if result is None:
276+
return Constraint.Skip
277+
activity_increase, ramp_fraction = result
278+
rampable = _rampable_activity(model, r, p, t, v, ramp_fraction)
258279
if ramp_up:
259-
return activity_increase <= rampable_activity
280+
return activity_increase <= rampable
260281
else:
261-
return -activity_increase <= rampable_activity
282+
return -activity_increase <= rampable
262283

263284

264285
def ramp_up_constraint(
@@ -314,17 +335,13 @@ def ramp_up_constraint(
314335
i.e. :math:`(H_d + H_{d_{next}}) / 2`
315336
- :math:`CAP \cdot C2A / (24 \cdot DPP)` gives the maximum hourly capacity
316337
"""
317-
318-
s_next, d_next = model.time_next[s, d]
319338
return _ramp_constraint(
320339
model=model,
321340
ramp_up=True,
322341
r=r,
323342
p=p,
324343
s=s,
325344
d=d,
326-
s_next=s_next,
327-
d_next=d_next,
328345
t=t,
329346
v=v,
330347
)
@@ -365,17 +382,13 @@ def ramp_down_constraint(
365382
\\
366383
\text{where: } \Delta H = \frac{H_d + H_{d_{next}}}{2}
367384
"""
368-
369-
s_next, d_next = model.time_next[s, d]
370385
return _ramp_constraint(
371386
model=model,
372387
ramp_up=False,
373388
r=r,
374389
p=p,
375390
s=s,
376391
d=d,
377-
s_next=s_next,
378-
d_next=d_next,
379392
t=t,
380393
v=v,
381394
)

0 commit comments

Comments
 (0)