Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 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
3b0cb49
Remove more redundant code
tsmbland Oct 4, 2024
cc9d237
Fix test
tsmbland Oct 14, 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
8d06e85
Merge branch 'v1.3' into refactor
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
2adde92
Small changes to tidy up
tsmbland Oct 28, 2024
e770c2e
Merge branch 'refactor' of https://github.com/EnergySystemsModellingL…
tsmbland Oct 28, 2024
1396110
Change the way that agent.year is incremented
tsmbland Oct 29, 2024
7f3370a
Be more explicit in _inner_split
tsmbland Oct 29, 2024
789b093
Apply suggestions from code review
tsmbland Oct 30, 2024
557efd8
Switch copy to deepcopy
tsmbland Oct 30, 2024
4a6ee5b
Merge branch 'refactor' into agent_year
tsmbland Oct 30, 2024
5ab0333
Revert some changes
tsmbland Oct 30, 2024
6a0f318
Revert "Revert some changes"
tsmbland Oct 30, 2024
8cdb043
Fix tests
tsmbland Oct 30, 2024
4373bdb
Merge branch 'v1.3' into agent_year
tsmbland Nov 12, 2024
8c8bb53
Use iterable for time framework
tsmbland Nov 12, 2024
5253208
Merge branch 'v1.3' into agent_year
tsmbland Nov 20, 2024
2691753
Merge branch 'v1.3' into agent_year
tsmbland Nov 28, 2024
aab0b3a
Merge branch 'main' into agent_year
tsmbland Dec 3, 2024
84e116b
Merge branch 'main' into agent_year
tsmbland Dec 18, 2024
16405a2
Merge branch 'main' into agent_year
tsmbland Dec 19, 2024
ed7c2ee
Merge branch 'main' into agent_year
tsmbland Jan 15, 2025
34de48d
Fix year list format
tsmbland Jan 15, 2025
b630150
Change names to current_year and investment_year
tsmbland Jan 15, 2025
118e0d6
As before
tsmbland Jan 15, 2025
7017b93
Fix tests
tsmbland Jan 15, 2025
104956d
Fix error at start of simulation
tsmbland Jan 15, 2025
6c22a01
Fix more tests
tsmbland Jan 15, 2025
fa77f07
Correct investment year for agents
tsmbland Jan 15, 2025
3660d99
Clarifying generic `year` arguments
tsmbland Jan 15, 2025
073ccfc
Update kwarg name
tsmbland Jan 15, 2025
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
91 changes: 46 additions & 45 deletions src/muse/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ def next(
technologies: xr.Dataset,
market: xr.Dataset,
demand: xr.DataArray,
time_period: int,
) -> None:
"""Increments agent to the next time point (e.g. performing investments)."""

Expand All @@ -110,9 +109,8 @@ def __init__(
search_rules: Optional[Callable] = None,
objectives: Optional[Callable] = None,
decision: Optional[Callable] = None,
year: int = 2010,
years: list[int] = [2010],
maturity_threshold: float = 0,
forecast: int = 5,
housekeeping: Optional[Callable] = None,
merge_transform: Optional[Callable] = None,
demand_threshold: Optional[float] = None,
Expand All @@ -134,10 +132,9 @@ def __init__(
search_rules: method used to filter the search space
objectives: One or more objectives by which to decide next investments.
decision: single decision objective from one or more objectives.
year: year the agent is created / current year
years: time framework over which the agent will iterate
maturity_threshold: threshold when filtering replacement
technologies with respect to market share
forecast: Number of years the agent will forecast
housekeeping: transform applied to the assets at the start of
iteration. Defaults to doing nothing.
merge_transform: transform merging current and newly invested assets
Expand Down Expand Up @@ -168,68 +165,75 @@ def __init__(
timeslice_level=timeslice_level,
)

self.year = year
""" Current year. Incremented by one every time next is called."""
self.forecast = forecast
"""Number of years to look into the future for forecating purposed."""
if search_rules is None:
search_rules = filter_factory()
self.search_rules: Callable = search_rules
"""Years to iterate over."""
self.years = iter(years)

"""Current year. Incremented every time `next` is called."""
self.current_year: int | None = None

"""Investment year"""
self.investment_year: int = next(self.years)

"""Search rule(s) determining potential replacement technologies.

This is a string referring to a filter, or a sequence of strings
referring to multiple filters, applied one after the other. Any
function registered via `muse.filters.register_filter` can be
used to filter the search space.
"""
self.maturity_threshold = maturity_threshold
""" Market share threshold.
if search_rules is None:
search_rules = filter_factory()
self.search_rules: Callable = search_rules

"""Market share threshold.

Threshold when and if filtering replacement technologies with respect
to market share.
"""
self.maturity_threshold = maturity_threshold

self.spend_limit = spend_limit

"""One or more objectives by which to decide next investments."""
if objectives is None:
objectives = objectives_factory()
self.objectives = objectives
"""One or more objectives by which to decide next investments."""

"""Creates single decision objective from one or more objectives."""
if decision is None:
decision = decision_factory()
self.decision = decision
"""Creates single decision objective from one or more objectives."""
if housekeeping is None:
housekeeping = housekeeping_factory()
self._housekeeping = housekeeping

"""Transforms applied on the assets at the start of each iteration.

It could mean keeping the assets as are, or removing assets with no
capacity in the current year and beyond, etc...
It can be any function registered with
:py:func:`~muse.hooks.register_initial_asset_transform`.
"""
if merge_transform is None:
merge_transform = asset_merge_factory()
self.merge_transform = merge_transform
if housekeeping is None:
housekeeping = housekeeping_factory()
self._housekeeping = housekeeping

"""Transforms applied on the old and new assets.

It could mean using only the new assets, or merging old and new, etc...
It can be any function registered with
:py:func:`~muse.hooks.register_final_asset_transform`.
"""
self.demand_threshold = demand_threshold
if merge_transform is None:
merge_transform = asset_merge_factory()
self.merge_transform = merge_transform

"""Threshold below which the demand share is zero.

This criteria avoids fulfilling demand for very small values. If None,
then the criteria is not applied.
"""
self.asset_threshold = asset_threshold
"""Threshold below which assets are not added."""
self.demand_threshold = demand_threshold

@property
def forecast_year(self):
"""Year to consider when forecasting."""
return self.year + self.forecast
"""Threshold below which assets are not added."""
self.asset_threshold = asset_threshold

def asset_housekeeping(self):
"""Reduces memory footprint of assets.
Expand All @@ -250,9 +254,9 @@ def next(
technologies: xr.Dataset,
market: xr.Dataset,
demand: xr.DataArray,
time_period: int,
) -> None:
self.year += time_period
self.current_year = self.investment_year
self.investment_year = next(self.years)


class InvestingAgent(Agent):
Expand Down Expand Up @@ -288,7 +292,6 @@ def next(
technologies: xr.Dataset,
market: xr.Dataset,
demand: xr.DataArray,
time_period: int,
) -> None:
"""Iterates agent one turn.

Expand All @@ -303,11 +306,12 @@ def next(

from muse.utilities import reduce_assets

current_year = self.year
# Increment the year
self.current_year = self.investment_year
self.investment_year = next(self.years)

# Skip forward if demand is zero
if demand.size == 0 or demand.sum() < 1e-12:
self.year += time_period
return None

# Calculate the search space
Expand All @@ -318,7 +322,6 @@ def next(
# Skip forward if the search space is empty
if any(u == 0 for u in search_space.shape):
getLogger(__name__).critical("Search space is empty")
self.year += time_period
return None

# Calculate the decision metric
Expand All @@ -337,12 +340,12 @@ def next(
search = search.sel(asset=condtechs)

# Get technology parameters for the investment year
techs = self.filter_input(technologies, year=current_year + time_period)
techs = self.filter_input(technologies, year=self.investment_year)

# Calculate capacity in current and forecast year
# Calculate capacity in current and investment year
capacity = reduce_assets(
self.assets.capacity, coords=("technology", "region")
).interp(year=[current_year, current_year + self.forecast], method="linear")
).interp(year=[self.current_year, self.investment_year], method="linear")

# Calculate constraints
constraints = self.constraints(
Expand All @@ -358,33 +361,31 @@ def next(
search[["search_space", "decision"]],
technologies,
constraints,
year=current_year,
current_year=self.current_year,
timeslice_level=self.timeslice_level,
)

# Add investments
time_period = self.investment_year - self.current_year
self.add_investments(
technologies,
investments,
current_year=current_year,
current_year=self.current_year,
time_period=time_period,
)

# Increment the year
self.year += time_period

def compute_decision(
self,
technologies: xr.Dataset,
market: xr.Dataset,
demand: xr.DataArray,
search_space: xr.DataArray,
) -> xr.DataArray:
# Filter technologies according to the search space, forecast year and region
# Filter technologies according to the search space, investment year and region
techs = self.filter_input(
technologies,
technology=search_space.replacement,
year=self.forecast_year,
year=self.investment_year,
).drop_vars("technology")

# Reduce dimensions of the demand array
Expand Down
Loading
Loading