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
14 changes: 7 additions & 7 deletions src/muse/constraints.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
r"""Investment constraints.

Constraints on investements ensure that investements match some given criteria. For
Constraints on investments ensure that investments match some given criteria. For
instance, the constraints could ensure that only so much of a new asset can be built
every year.

Functions to compute constraints should be registered via the decorator
:py:meth:`~muse.constraints.register_constraints`. This registration step makes it
possible for constraints to be declared in the TOML file.

Generally, LP solvers accept linear constraint defined as:
Generally, LP solvers accept linear constraints defined as:

.. math::

A x \\leq b

with :math:`A` a matrix, :math:`x` the decision variables, and :math:`b` a vector.
However, these quantities are dimensionless. They do no have timeslices, assets, or
replacement technologies, or any other dimensions that users have set-up in their model.
The crux is to translates from MUSE's data-structures to a consistent dimensionless
replacement technologies, or any other dimensions that users have set up in their model.
The crux is to translate from MUSE's data-structures to a consistent dimensionless
format.

In MUSE, users can register constraints functions that return fully dimensional
Expand All @@ -44,8 +44,8 @@
- Any dimension in :math:`A_c .* x_c` (:math:`A_p .* x_p`) that is also in :math:`b`
defines diagonal entries into the left (right) submatrix of :math:`A`.
- Any dimension in :math:`A_c .* x_c` (:math:`A_p .* x_b`) and missing from
:math:`b` is reduce by summation over a row in the left (right) submatrix of
:math:`A`. In other words, those dimension do become part of a standard tensor
:math:`b` is reduced by summation over a row in the left (right) submatrix of
:math:`A`. In other words, those dimensions become part of a standard tensor
reduction or matrix multiplication.

There are two additional rules. However, they are likely to be the result of an
Expand Down Expand Up @@ -288,7 +288,7 @@ def max_capacity_expansion(
:math:`y=y_1` is the year marking the end of the investment period.

Let :math:`\mathcal{A}^{i, r}_{t, \iota}(y)` be the current assets, before
invesment, and let :math:`\Delta\mathcal{A}^{i,r}_t` be the future investements.
investment, and let :math:`\Delta\mathcal{A}^{i,r}_t` be the future investments.
The the constraint on agent :math:`i` are given as:

.. math::
Expand Down
15 changes: 13 additions & 2 deletions src/muse/readers/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ def to_agent_share(name):

if "year" in result.dims and len(result.year) == 1:
result = result.isel(year=0, drop=True)

check_minimum_service_factors_in_range(data, filename)

return result


Expand All @@ -129,7 +132,7 @@ def read_technodata_timeslices(filename: Union[Text, Path]) -> xr.Dataset:
data = csv[csv.technology != "Unit"]

data = data.apply(lambda x: pd.to_numeric(x, errors="ignore"))
data = check_utilization_not_all_zero(data, filename)
check_utilization_not_all_zero(data, filename)

ts = pd.MultiIndex.from_frame(
data.drop(
Expand Down Expand Up @@ -921,4 +924,12 @@ def check_utilization_not_all_zero(data, filename):
"""A technology can not have a utilization factor of 0 for every
timeslice. Please check file {}.""".format(filename)
)
return data


def check_minimum_service_factors_in_range(data, filename):
min_service_factor = data["minimum_service_factor"]
if not np.all((0 <= min_service_factor) & (min_service_factor <= 1)):
raise ValueError(
f"""Minimum service factor values must all be between 0 and 1 inclusive.
Please check file {filename}."""
)
29 changes: 15 additions & 14 deletions tests/test_minimum_service.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
from itertools import permutations

import numpy as np
from pytest import mark


def modify_minimum_service_factors(
model_path, sector, process_name, minimum_service_factor
model_path, sector, processes, minimum_service_factors
):
import pandas as pd

technodata_timeslices = pd.read_csv(
model_path / "technodata" / sector / "TechnodataTimeslices.csv"
)

technodata_timeslices.loc[
technodata_timeslices["ProcessName"] == process_name[0], "MinimumServiceFactor"
] = minimum_service_factor[0]

technodata_timeslices.loc[
technodata_timeslices["ProcessName"] == process_name[1], "MinimumServiceFactor"
] = minimum_service_factor[1]
for process, minimum in zip(processes, minimum_service_factors):
technodata_timeslices.loc[
technodata_timeslices["ProcessName"] == process, "MinimumServiceFactor"
] = minimum

return technodata_timeslices


@mark.parametrize("process_name", [("gasCCGT", "windturbine")])
@mark.parametrize(
"minimum_service_factor", [([1, 2, 3, 4, 5, 6], [0] * 6), ([0], [1, 2, 3, 4, 5, 6])]
"minimum_service_factors",
permutations((np.linspace(0, 1, 6), [0] * 6)),
)
def test_minimum_service_factor(tmpdir, minimum_service_factor, process_name):
def test_minimum_service_factor(tmpdir, minimum_service_factors):
import pandas as pd
from muse import examples
from muse.mca import MCA

sector = "power"
processes = ("gasCCGT", "windturbine")

# Copy the model inputs to tmpdir
model_path = examples.copy_model(
Expand All @@ -40,8 +41,8 @@ def test_minimum_service_factor(tmpdir, minimum_service_factor, process_name):
technodata_timeslices = modify_minimum_service_factors(
model_path=model_path,
sector=sector,
process_name=process_name,
minimum_service_factor=minimum_service_factor,
processes=processes,
minimum_service_factors=minimum_service_factors,
)

technodata_timeslices.to_csv(
Expand All @@ -53,7 +54,7 @@ def test_minimum_service_factor(tmpdir, minimum_service_factor, process_name):

supply_timeslice = pd.read_csv(tmpdir / "Results/MCAMetric_Supply.csv")

for process, service_factor in zip(process_name, minimum_service_factor):
for process, service_factor in zip(processes, minimum_service_factors):
for i, factor in enumerate(service_factor):
assert (
supply_timeslice[
Expand Down