Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/inputs/technodata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ var_par, var_exp

ProductionRef is the production of a reference capacity (CapRef) for the cost estimate decided by the modeller before filling the input data files.

Growith constraints
Growith constraints (optional)
MaxCapacityAddition
represents the maximum addition of installed capacity per technology, per year in a period, per region.

Expand All @@ -107,6 +107,8 @@ Growith constraints
Growth constraints are applied for each single agent in a multi-agent simulation. When only one agent is present, the growth constraints
apply individually to the "New" and "Retrofit" agent, when present.

If any of the three parameters are not provided in the technodata file, that particular constraint is not applied.


TechnicalLife
represents the number of years that a technology operates before it is decommissioned.
Expand Down
23 changes: 19 additions & 4 deletions src/muse/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ def max_capacity_expansion(
search_space: xr.DataArray,
technologies: xr.Dataset,
**kwargs,
) -> Constraint:
) -> Constraint | None:
r"""Max-capacity addition, max-capacity growth, and capacity limits constraints.

Limits by how much the capacity of each technology owned by an agent can grow in
Expand Down Expand Up @@ -310,7 +310,22 @@ def max_capacity_expansion(
.. math::

\Gamma_t^{r, i} \geq 0

:math:`L_t^r(y)`, :math:`G_t^r(y)` and :math:`W_t^r(y)` default to np.inf if
not provided (i.e. no constraint).
If all three parameters are not provided, no constraint is applied (returns None).
"""
# If all three parameters are missing, don't apply the constraint
if not any(
param in technologies
for param in (
"max_capacity_addition",
"total_capacity_limit",
"max_capacity_growth",
)
):
return None

# case with technology and region in asset dimension
if capacity.region.dims != ():
names = [u for u in capacity.asset.coords if capacity[u].dims == ("asset",)]
Expand Down Expand Up @@ -344,14 +359,14 @@ def max_capacity_expansion(

# Max capacity addition constraint
time_frame = int(capacity.year[1] - capacity.year[0])
add_cap = techs.max_capacity_addition * time_frame
add_cap = techs.get("max_capacity_addition", np.inf) * time_frame

# Total capacity limit constraint
limit = techs.total_capacity_limit
limit = techs.get("total_capacity_limit", np.inf)
total_cap = (limit - forecasted).clip(min=0)

# Max capacity growth constraint
max_growth = techs.max_capacity_growth
max_growth = techs.get("max_capacity_growth", np.inf)
growth_cap = initial * (max_growth + 1) ** time_frame - forecasted

# Relax growth constraint if no existing capacity
Expand Down
18 changes: 18 additions & 0 deletions tests/test_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,24 @@ def test_max_capacity_expansion(max_capacity_expansion):
).all()


def test_max_capacity_expansion_no_limits(
market_demand, capacity, search_space, technologies
):
from muse.constraints import max_capacity_expansion

# Without growth limits, the constraint should return None
techs = technologies.drop_vars(
["max_capacity_addition", "max_capacity_growth", "total_capacity_limit"]
)
result = max_capacity_expansion(
market_demand,
capacity,
search_space,
techs,
)
assert result is None


def test_max_production(max_production):
dims = {"replacement", "asset", "commodity", "timeslice"}
assert set(max_production.capacity.dims) == dims
Expand Down
Loading