Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
fa59017
Add comments and simplify sector.next
tsmbland Oct 2, 2024
697ff3f
Simplify agent module, more comments
tsmbland Oct 3, 2024
b47c811
Simplify retirment profile code
tsmbland Oct 3, 2024
a86e07f
Simplify merge_assets
tsmbland Oct 3, 2024
3e51311
Revert change to merge_assets
tsmbland Oct 4, 2024
941a5a6
Delete unused factory
tsmbland Oct 4, 2024
9d2cac9
More comments added to code
tsmbland Oct 4, 2024
e386da1
Revert some changes to fix tests
tsmbland Oct 4, 2024
018ca5c
Fix tests
tsmbland Oct 4, 2024
4fd2e79
Small fix to another test
tsmbland Oct 4, 2024
51a5273
Delete legacy sector
tsmbland Oct 4, 2024
1518034
Delete tests and documentation
tsmbland Oct 4, 2024
3b0cb49
Remove more redundant code
tsmbland Oct 4, 2024
3a05344
Delete new_to_old_timeslice function
tsmbland Oct 4, 2024
977647d
Remove unnecessary convert_timeslice operations
tsmbland Oct 8, 2024
647d3fe
Use global TIMESLICE variable throughout
tsmbland Oct 8, 2024
8faf468
Simplify some other parts of the code accordingly
tsmbland Oct 8, 2024
65c3e48
Draft new function with intended behaviour
tsmbland Oct 9, 2024
d9eb060
Use new function wherever possible
tsmbland Oct 10, 2024
7ebab9e
Update tests
tsmbland Oct 10, 2024
a0fe43c
Remove represent_hours function
tsmbland Oct 10, 2024
c2b94e7
Fix issue with timeslice ordering
tsmbland Oct 11, 2024
5cbc8f2
Remove remaining convert_timeslice calls
tsmbland Oct 11, 2024
81e7a6a
Simplify timeslice_op function
tsmbland Oct 11, 2024
19cf269
Delete old convert_timeslice function
tsmbland Oct 11, 2024
57c1c73
Delete unused functions
tsmbland Oct 11, 2024
e4150e3
Simplify timeslie import process
tsmbland Oct 11, 2024
dc8b8b8
Formatting
tsmbland Oct 11, 2024
0288459
Default arguments for convert_timeslice
tsmbland Oct 11, 2024
c7f67f4
Update results files
tsmbland Oct 11, 2024
9360ad1
Merge branch 'refactor' into legacy
tsmbland Oct 14, 2024
b2e8294
Merge branch 'legacy' into convert_timeslice2
tsmbland Oct 14, 2024
94ef9b7
Merge branch 'legacy' into convert_timeslice2
tsmbland Oct 14, 2024
cc9d237
Fix test
tsmbland Oct 14, 2024
acdcbf8
Merge branch 'refactor' into legacy
tsmbland Oct 14, 2024
89f8c61
Carry changes from fix_supply_issue2 branch
tsmbland Oct 16, 2024
793aacf
More benign changes
tsmbland Oct 16, 2024
22c141e
Fix incorrect convert_timeslice usage in tests
tsmbland Oct 16, 2024
a59580c
Fix timeslice import in tests
tsmbland Oct 16, 2024
993af9f
Delete unused fixture
tsmbland Oct 16, 2024
908872a
Fix market fixtures
tsmbland Oct 16, 2024
e0a8c3a
More test fixes
tsmbland Oct 16, 2024
8034807
Fix a fixture
tsmbland Oct 16, 2024
86d7dd2
Merge branch 'legacy' into convert_timeslice2
tsmbland Oct 16, 2024
1bd7c84
Move default timeslice settings to conftest
tsmbland Oct 16, 2024
c616694
Fix docstring tests
tsmbland Oct 17, 2024
d054a3b
A few more tiny changes (e.g. typing)
tsmbland Oct 17, 2024
0c84ba9
Remove inline comment
tsmbland Oct 17, 2024
65313de
Merge branch 'v1.3' into refactor
tsmbland Oct 21, 2024
4ce54e6
Merge branch 'refactor' into legacy
tsmbland Oct 21, 2024
ad3766e
Merge branch 'legacy' into convert_timeslice2
tsmbland Oct 21, 2024
a02088e
Small changes
tsmbland Oct 21, 2024
4785412
Fix constraints tests
tsmbland Oct 22, 2024
88d40b4
Fix remaining tests
tsmbland Oct 22, 2024
4fbc1ff
Create separate functions for broadcasting and distributing timeslices
tsmbland Oct 22, 2024
0258ae9
Check for existing timeslice dimension in broadcast_timeslice
tsmbland Oct 22, 2024
b0ce228
Fix test
tsmbland Oct 22, 2024
8d06e85
Merge branch 'v1.3' into refactor
tsmbland Oct 25, 2024
5c5fc45
Merge branch 'refactor' into legacy
tsmbland Oct 25, 2024
8149020
Merge branch 'legacy' into convert_timeslice2
tsmbland Oct 25, 2024
885f752
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 25, 2024
433c39c
Fix merge conflicts
tsmbland Oct 25, 2024
6975787
Merge branch 'broadcast_errors2' into refactor
tsmbland Oct 25, 2024
2e601ea
Merge branch 'v1.2.2' into refactor
tsmbland Oct 25, 2024
423fafe
Merge branch 'main' into refactor
tsmbland Oct 28, 2024
c270dfa
Merge branch 'main' into refactor
tsmbland Oct 28, 2024
b521d93
Merge branch 'refactor' into legacy
tsmbland Oct 28, 2024
fde592b
Merge branch 'legacy' into convert_timeslice2
tsmbland Oct 28, 2024
d5875f9
Fix tests
tsmbland Oct 28, 2024
46ab820
Remove timeslice arguments
tsmbland Oct 28, 2024
d5b5676
Fix tests
tsmbland Oct 28, 2024
ae3c06c
Turn off automatic broadcasting over the timeslice dimension (#530)
tsmbland Oct 30, 2024
366c37c
Drop convert_market_timeslice
tsmbland Nov 1, 2024
908be7b
Remove timeslice attribute from sectors
tsmbland Nov 4, 2024
15ebf84
Add dummy timeslice_level argument
tsmbland Nov 4, 2024
8b36797
Read timeslice_level from settings file
tsmbland Nov 4, 2024
0d2a19e
Add basic transforms
tsmbland Nov 5, 2024
d3604dc
Merge branch 'v1.3' into convert_timeslice2
tsmbland Nov 5, 2024
a552029
Merge branch 'convert_timeslice2' into timeslice_level
tsmbland Nov 5, 2024
8c4a8c4
Merge branch 'v1.3' into timeslice_level
tsmbland Nov 13, 2024
4ff56c2
Fix some errors from merge
tsmbland Nov 13, 2024
738e07d
Placeholder functions for sector conversion
tsmbland Nov 13, 2024
ff847bb
Functions working with single timeslice level
tsmbland Nov 14, 2024
cb5b9a1
Working compress_timeslice function
tsmbland Nov 14, 2024
62ab9ac
Typing, remove aggregates, skeleton for tests
tsmbland Nov 14, 2024
b51143e
Skeleton for tests
tsmbland Nov 14, 2024
1f35e8d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 14, 2024
8c772d7
Restore patch to tests
tsmbland Nov 14, 2024
66bbd5a
Merge branch 'timeslice_level' of https://github.com/EnergySystemsMod…
tsmbland Nov 14, 2024
597a203
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 14, 2024
08234e2
Tests for broadcast and distribute, replace transforms with compress
tsmbland Nov 14, 2024
78f50f4
Test for compress_timeslice
tsmbland Nov 14, 2024
ef8ecf2
Finish functions and tests
tsmbland Nov 14, 2024
270ffff
Change type hinting to work with 3.9
tsmbland Nov 14, 2024
0188872
Same again
tsmbland Nov 14, 2024
8414c28
Lint
tsmbland Nov 14, 2024
1eab863
Improve tests
tsmbland Nov 14, 2024
7901d1a
Add parameter descriptions
tsmbland Nov 15, 2024
6dadde1
Docstrings for new functions, use get_level
tsmbland Nov 15, 2024
5904acd
Add documentation
tsmbland Nov 15, 2024
ddeedeb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 15, 2024
d57d324
Finish compress_timeslice (still small todo)
tsmbland Nov 15, 2024
cf273c0
Merge branch 'timeslice_level' of https://github.com/EnergySystemsMod…
tsmbland Nov 15, 2024
4fd085c
sort_timeslice and timeslice_max functions
tsmbland Nov 15, 2024
dcbed0d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 15, 2024
1014751
New tests, some robustness improvements
tsmbland Nov 18, 2024
88e0540
Move import statements
tsmbland Nov 18, 2024
959148d
Add check to sector init
tsmbland Nov 18, 2024
4a81d94
Variable names, docstrings
tsmbland Nov 18, 2024
dff094f
Apply default timeslice level to sector
tsmbland Nov 18, 2024
82f5861
Fix adhoc bug, add warning
tsmbland Nov 18, 2024
8ca30ba
Fix error in convert_to_global_timeslicing
tsmbland Nov 18, 2024
45aa865
Merge branch 'v1.3' into timeslice_level
tsmbland Nov 19, 2024
6171d32
Merge branch 'v1.3' into timeslice_level
tsmbland Nov 20, 2024
07074cd
Use modern syntax for type annotations
tsmbland Nov 21, 2024
220fb27
Address reviewer comments
tsmbland Nov 26, 2024
26904c9
Merge branch 'v1.3' into timeslice_level
tsmbland Nov 26, 2024
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
52 changes: 26 additions & 26 deletions docs/inputs/toml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,32 @@ A sector accepts these attributes:
Additional methods can be registered with
:py:func:`muse.production.register_production`

*technodata*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing to do with the PR, but I've always found the use of cursive headers in the documentation pretty useless: they do not highlight that much the text and you cannot directly link the section from somewhere else. I'd suggest at some point to revamp the docs and use, eg. level 5 headers or something like that. See the Sphinx docs for that

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish we were using markdown as it's so much nicer to work with, but I guess it's too late for that

Path to a csv file containing the characterization of the technologies involved in
the sector, e.g. lifetime, capital costs, etc... See :ref:`inputs-technodata`.

*technodata_timeslices*
Optional. Path to a csv file describing the utilization factor and minimum service
factor of each technology in each timeslice.
See :ref:`user_guide/inputs/technodata_timeslices`.

*commodities_in*
Path to a csv file describing the inputs of each technology involved in the sector.
See :ref:`inputs-iocomms`.

*commodities_out*
Path to a csv file describing the outputs of each technology involved in the sector.
See :ref:`inputs-iocomms`.

*timeslice_level*
Optional. This represents the level of timeslice granularity over which commodity
flows out of the sector are balanced (e.g. if "day", the sector will aim to meet
commodity demands on a daily basis, rather than an hourly basis).
If not given, defaults to the finest level defined in the global `timeslices` section.
Note: If *technodata_timeslices* is used, the data in this file must match the timeslice
level of the sector (e.g. with global timeslice levels "month", "day" and "hour", if a sector has "day" as
the timeslice level, then *technodata_timeslices* must have columns "month" and "day", but not "hour")

Sectors contain a number of subsections:
*interactions*
Defines interactions between agents. These interactions take place right before new
Expand Down Expand Up @@ -372,32 +398,6 @@ Sectors contain a number of subsections:
"new_to_retro" type of network has been defined but no retro agents are included in
the sector.

*technodata*

Defines technologies and their features, in terms of costs, efficiencies, and emissions.

*technodata* are specified as an inline TOML table, e.g. with single
brackets. A technodata section would look like:

.. code-block:: TOML

[sectors.residential.technodata]
technodata = '{path}/technodata/residential/Technodata.csv'
commodities_in = '{path}/technodata/residential/CommIn.csv'
commodities_out = '{path}/technodata/residential/CommOut.csv'

Where:
*technodata*
Path to a csv file containing the characterization of the technologies involved in
the sector, e.g. lifetime, capital costs, etc... See :ref:`inputs-technodata`.

*commodities_in*
Path to a csv file describing the inputs of each technology involved in the sector.
See :ref:`inputs-iocomms`.

*commodities_out*
Path to a csv file describing the outputs of each technology involved in the sector.
See :ref:`inputs-iocomms`.

*subsectors*

Expand Down
18 changes: 17 additions & 1 deletion src/muse/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def __init__(
interpolation: str = "linear",
category: Optional[str] = None,
quantity: Optional[float] = 1,
timeslice_level: Optional[str] = None,
):
"""Creates a standard MUSE agent.

Expand All @@ -39,6 +40,9 @@ def __init__(
together.
quantity: optional value to classify different agents' share of the
population.
timeslice_level: the timeslice level over which investments/production
will be optimized (e.g "hour", "day"). If None, the agent will use the
finest timeslice level.
"""
from uuid import uuid4

Expand All @@ -57,6 +61,8 @@ def __init__(
"""Attribute to classify different sets of agents."""
self.quantity = quantity
"""Attribute to classify different agents' share of the population."""
self.timeslice_level = timeslice_level
"""Timeslice level for the agent."""

def filter_input(
self,
Expand Down Expand Up @@ -114,6 +120,7 @@ def __init__(
asset_threshold: float = 1e-4,
quantity: Optional[float] = 1,
spend_limit: int = 0,
timeslice_level: Optional[str] = None,
**kwargs,
):
"""Creates a standard agent.
Expand Down Expand Up @@ -141,6 +148,9 @@ def __init__(
asset_threshold: Threshold below which assets are not added.
quantity: different agents' share of the population
spend_limit: The cost above which agents will not invest
timeslice_level: the timeslice level over which the agent invesments will
be optimized (e.g "hour", "day"). If None, the agent will use the finest
timeslice level.
**kwargs: Extra arguments
"""
from muse.decisions import factory as decision_factory
Expand All @@ -155,6 +165,7 @@ def __init__(
interpolation=interpolation,
category=category,
quantity=quantity,
timeslice_level=timeslice_level,
)

self.year = year
Expand Down Expand Up @@ -331,6 +342,7 @@ def next(
market,
technologies,
year=current_year,
timeslice_level=self.timeslice_level,
)

# Calculate investments
Expand All @@ -339,6 +351,7 @@ def next(
technologies,
constraints,
year=current_year,
timeslice_level=self.timeslice_level,
)

# Add investments
Expand Down Expand Up @@ -379,7 +392,10 @@ def compute_decision(

# Compute the objectives
objectives = self.objectives(
technologies=techs, demand=reduced_demand, prices=prices
technologies=techs,
demand=reduced_demand,
prices=prices,
timeslice_level=self.timeslice_level,
)

# Compute the decision metric
Expand Down
63 changes: 45 additions & 18 deletions src/muse/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def constraints(
search_space: xr.DataArray,
market: xr.Dataset,
technologies: xr.Dataset,
year: Optional[int] = None,
year: int | None = None,
**kwargs,
) -> Constraint:
pass
Expand Down Expand Up @@ -115,7 +115,7 @@ def constraints(
from mypy_extensions import KwArg

from muse.registration import registrator
from muse.timeslices import drop_timeslice
from muse.timeslices import broadcast_timeslice, distribute_timeslice, drop_timeslice

CAPACITY_DIMS = "asset", "replacement", "region"
"""Default dimensions for capacity decision variables."""
Expand Down Expand Up @@ -248,11 +248,20 @@ def constraints(
market: xr.Dataset,
technologies: xr.Dataset,
year: int | None = None,
timeslice_level: str | None = None,
) -> list[Constraint]:
if year is None:
year = int(market.year.min())
constraints = [
function(demand, assets, search_space, market, technologies, year=year)
function(
demand,
assets,
search_space,
market,
technologies,
year=year,
timeslice_level=timeslice_level,
)
for function in constraint_closures
]
return [constraint for constraint in constraints if constraint is not None]
Expand All @@ -270,6 +279,7 @@ def max_capacity_expansion(
year: int | None = None,
forecast: int | None = None,
interpolation: str = "linear",
**kwargs,
) -> Constraint:
r"""Max-capacity addition, max-capacity growth, and capacity limits constraints.

Expand Down Expand Up @@ -400,6 +410,7 @@ def demand(
year: int | None = None,
forecast: int = 5,
interpolation: str = "linear",
**kwargs,
) -> Constraint:
"""Constraints production to meet demand."""
from muse.commodities import is_enduse
Expand All @@ -423,6 +434,7 @@ def search_space(
technologies: xr.Dataset,
year: int | None = None,
forecast: int = 5,
**kwargs,
) -> Constraint | None:
"""Removes disabled technologies."""
if search_space.all():
Expand All @@ -442,6 +454,8 @@ def max_production(
market: xr.Dataset,
technologies: xr.Dataset,
year: int | None = None,
timeslice_level: str | None = None,
**kwargs,
) -> Constraint:
"""Constructs constraint between capacity and maximum production.

Expand All @@ -451,7 +465,6 @@ def max_production(
from xarray import ones_like, zeros_like

from muse.commodities import is_enduse
from muse.timeslices import broadcast_timeslice, distribute_timeslice

if year is None:
year = int(market.year.min())
Expand All @@ -470,9 +483,9 @@ def max_production(
.sel(**kwargs)
.drop_vars("technology")
)
capacity = distribute_timeslice(techs.fixed_outputs) * broadcast_timeslice(
techs.utilization_factor
)
capacity = distribute_timeslice(
techs.fixed_outputs, level=timeslice_level
) * broadcast_timeslice(techs.utilization_factor, level=timeslice_level)
if "asset" not in capacity.dims and "asset" in search_space.dims:
capacity = capacity.expand_dims(asset=search_space.asset)
production = ones_like(capacity)
Expand All @@ -489,8 +502,8 @@ def max_production(
maxadd = maxadd.rename(technology="replacement")
maxadd = maxadd.where(maxadd == 0, 0.0)
maxadd = maxadd.where(maxadd > 0, -1.0)
capacity = capacity * broadcast_timeslice(maxadd)
production = production * broadcast_timeslice(maxadd)
capacity = capacity * broadcast_timeslice(maxadd, level=timeslice_level)
production = production * broadcast_timeslice(maxadd, level=timeslice_level)
b = b.rename(region="src_region")
return xr.Dataset(
dict(capacity=-cast(np.ndarray, capacity), production=production, b=b),
Expand All @@ -506,6 +519,8 @@ def demand_limiting_capacity(
market: xr.Dataset,
technologies: xr.Dataset,
year: int | None = None,
timeslice_level: str | None = None,
**kwargs,
) -> Constraint:
"""Limits the maximum combined capacity to match the demand.

Expand All @@ -521,7 +536,13 @@ def demand_limiting_capacity(
"""
# We start with the maximum production constraint and the demand constraint
capacity_constraint = max_production(
demand_, assets, search_space, market, technologies, year=year
demand_,
assets,
search_space,
market,
technologies,
year=year,
timeslice_level=timeslice_level,
)
demand_constraint = demand(
demand_, assets, search_space, market, technologies, year=year
Expand Down Expand Up @@ -714,12 +735,13 @@ def minimum_service(
market: xr.Dataset,
technologies: xr.Dataset,
year: int | None = None,
timeslice_level: str | None = None,
**kwargs,
) -> Constraint | None:
"""Constructs constraint between capacity and minimum service."""
from xarray import ones_like, zeros_like

from muse.commodities import is_enduse
from muse.timeslices import broadcast_timeslice, distribute_timeslice

if "minimum_service_factor" not in technologies.data_vars:
return None
Expand All @@ -742,9 +764,9 @@ def minimum_service(
.sel(**kwargs)
.drop_vars("technology")
)
capacity = distribute_timeslice(techs.fixed_outputs) * broadcast_timeslice(
techs.minimum_service_factor
)
capacity = distribute_timeslice(
techs.fixed_outputs, level=timeslice_level
) * broadcast_timeslice(techs.minimum_service_factor, level=timeslice_level)
if "asset" not in capacity.dims:
capacity = capacity.expand_dims(asset=search_space.asset)
production = ones_like(capacity)
Expand All @@ -755,7 +777,9 @@ def minimum_service(
)


def lp_costs(technologies: xr.Dataset, costs: xr.DataArray) -> xr.Dataset:
def lp_costs(
technologies: xr.Dataset, costs: xr.DataArray, timeslice_level: str | None = None
) -> xr.Dataset:
"""Creates costs for solving with scipy's LP solver.

Example:
Expand Down Expand Up @@ -805,7 +829,6 @@ def lp_costs(technologies: xr.Dataset, costs: xr.DataArray) -> xr.Dataset:
from xarray import zeros_like

from muse.commodities import is_enduse
from muse.timeslices import broadcast_timeslice, distribute_timeslice

assert "year" not in technologies.dims

Expand All @@ -818,7 +841,10 @@ def lp_costs(technologies: xr.Dataset, costs: xr.DataArray) -> xr.Dataset:
selection["region"] = costs.region
fouts = technologies.fixed_outputs.sel(selection).rename(technology="replacement")

production = zeros_like(broadcast_timeslice(costs) * distribute_timeslice(fouts))
production = zeros_like(
broadcast_timeslice(costs, level=timeslice_level)
* distribute_timeslice(fouts, level=timeslice_level)
)
for dim in production.dims:
if isinstance(production.get_index(dim), pd.MultiIndex):
production = drop_timeslice(production)
Expand Down Expand Up @@ -1133,8 +1159,9 @@ def factory(
technologies: xr.Dataset,
costs: xr.DataArray,
*constraints: Constraint,
timeslice_level: str | None = None,
) -> ScipyAdapter:
lpcosts = lp_costs(technologies, costs)
lpcosts = lp_costs(technologies, costs, timeslice_level=timeslice_level)

data = cls._unified_dataset(technologies, lpcosts, *constraints)

Expand Down
Loading