From 46efbee8f490622bec5620150dabb332a2eef05f Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 11 Mar 2025 08:50:26 +0000 Subject: [PATCH 1/3] Exclude capacity constraint if parameters are not specified --- docs/inputs/technodata.rst | 2 +- src/muse/constraints.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/inputs/technodata.rst b/docs/inputs/technodata.rst index 8bb51c386..eca549317 100644 --- a/docs/inputs/technodata.rst +++ b/docs/inputs/technodata.rst @@ -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. diff --git a/src/muse/constraints.py b/src/muse/constraints.py index ff297175f..72194e44b 100644 --- a/src/muse/constraints.py +++ b/src/muse/constraints.py @@ -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 @@ -311,6 +311,17 @@ def max_capacity_expansion( \Gamma_t^{r, i} \geq 0 """ + # 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",)] @@ -344,14 +355,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 From 32e47d8d747071df620e8193a11ab406e27dd726 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 11 Mar 2025 09:53:42 +0000 Subject: [PATCH 2/3] Better documentation --- docs/inputs/technodata.rst | 2 ++ src/muse/constraints.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/docs/inputs/technodata.rst b/docs/inputs/technodata.rst index eca549317..768bacc5f 100644 --- a/docs/inputs/technodata.rst +++ b/docs/inputs/technodata.rst @@ -107,6 +107,8 @@ Growith constraints (optional) 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. diff --git a/src/muse/constraints.py b/src/muse/constraints.py index 72194e44b..460d95916 100644 --- a/src/muse/constraints.py +++ b/src/muse/constraints.py @@ -310,6 +310,10 @@ 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( From 16b86bae8bbc34d8baa5c3806c036fba7f25da61 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 12 Mar 2025 19:28:09 +0000 Subject: [PATCH 3/3] Add test --- tests/test_constraints.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_constraints.py b/tests/test_constraints.py index 571f56351..82c5df0c3 100644 --- a/tests/test_constraints.py +++ b/tests/test_constraints.py @@ -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