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
6 changes: 2 additions & 4 deletions src/muse/agents/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def create_agent(agent_type: str, **kwargs) -> Agent:

def agents_factory(
params_or_path: str | Path | list,
capacity: xr.DataArray | str | Path,
capacity: xr.DataArray,
Copy link

Copilot AI May 8, 2025

Choose a reason for hiding this comment

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

Since capacity is now strictly expected to be a DataArray, consider updating related documentation and usages to make it clear that file paths are no longer supported.

Copilot uses AI. Check for mistakes.
technologies: xr.Dataset,
regions: Sequence[str] | None = None,
year: int | None = None,
Expand All @@ -179,14 +179,12 @@ def agents_factory(
from copy import deepcopy
from logging import getLogger

from muse.readers import read_csv_agent_parameters, read_initial_assets
from muse.readers import read_csv_agent_parameters

if isinstance(params_or_path, (str, Path)):
params = read_csv_agent_parameters(params_or_path)
else:
params = params_or_path
if isinstance(capacity, (str, Path)):
capacity = read_initial_assets(capacity)
assert isinstance(capacity, xr.DataArray)
if year is None:
year = int(capacity.year.min())
Expand Down
37 changes: 21 additions & 16 deletions src/muse/sectors/subsector.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def aggregate_lp(
# Select commodity demands for the subsector
demands = market.consumption.sel(commodity=self.commodities)

# Remove commodities that have no demand in the investment year
mask = (demands.isel(year=1, drop=True) > 0).any(dim=["timeslice", "region"])
demands = demands.sel(commodity=mask)

# Split demand across agents
demands = self.demand_share(
agents=self.agents,
Expand Down Expand Up @@ -120,6 +124,7 @@ def factory(
from muse import investments as iv
from muse.agents import InvestingAgent, agents_factory
from muse.commodities import is_enduse
from muse.readers import read_initial_assets
from muse.readers.toml import undo_damage

# Raise error for renamed asset_threshhold parameter (PR #447)
Expand All @@ -142,9 +147,13 @@ def factory(
)
getLogger(__name__).warning(msg)

# Read existing capacity file
existing_capacity = read_initial_assets(settings.existing_capacity)

# Create agents
agents = agents_factory(
settings.agents,
settings.existing_capacity,
capacity=existing_capacity,
technologies=technologies,
regions=regions,
year=current_year or int(technologies.year.min()),
Expand Down Expand Up @@ -172,11 +181,14 @@ def factory(
if np.sum(outputs) == 0.0:
raise RuntimeError(msg)

# Get list of commodities for the subsector
if hasattr(settings, "commodities"):
commodities = settings.commodities
else:
# If commodities aren't explicitly specified, we infer the commodities from
# the existing capacity file
commodities = aggregate_enduses(
[agent.assets for agent in agents], technologies
technologies.sel(technology=existing_capacity.technology.values)
)

# len(commodities) == 0 may happen only if
Expand Down Expand Up @@ -208,21 +220,14 @@ def factory(
)


def aggregate_enduses(
assets: Sequence[xr.Dataset | xr.DataArray], technologies: xr.Dataset
) -> Sequence[str]:
"""Aggregate enduse commodities for input assets.
def aggregate_enduses(technologies: xr.Dataset) -> list[str]:
"""Aggregate enduse commodities for a set of technologies.

This function is meant as a helper to figure out the commodities attached to a group
of agents.
Returns a list of all enduse commodities associated with the technologies in the
input dataset. Enduse commodities are determined using based on the `comm_usage`
attribute of the technologies, using the `is_enduse` function from the
`muse.commodities` module.
"""
from muse.commodities import is_enduse

techs = set.union(*(set(data.technology.values) for data in assets))
outputs = technologies.fixed_outputs.sel(
commodity=is_enduse(technologies.comm_usage), technology=list(techs)
)

return outputs.commodity.sel(
commodity=outputs.any([u for u in outputs.dims if u != "commodity"])
).values.tolist()
return technologies.commodity.values[is_enduse(technologies.comm_usage)].tolist()
6 changes: 2 additions & 4 deletions tests/test_subsector.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ def test_subsector_investing_aggregation():
agents = list(examples.sector(sname, model).agents)
sector = next(sector for sector in mca.sectors if sector.name == sname)
technologies = sector.technologies
commodities = aggregate_enduses(
(agent.assets for agent in agents), technologies
)
commodities = aggregate_enduses(technologies)
market = mca.market.sel(
commodity=technologies.commodity, region=technologies.region
).interp(year=[2020, 2025])
Expand Down Expand Up @@ -89,7 +87,7 @@ def test_subsector_noninvesting_aggregation(market, model, technologies, tmp_pat
param["decision"]["parameters"] = ("ALCOE", False, 1)
param.pop("quantity")
agents = [create_agent(technologies=technologies, **param) for param in params]
commodities = aggregate_enduses((agent.assets for agent in agents), technologies)
commodities = aggregate_enduses(technologies)

subsector = Subsector(
agents,
Expand Down
Loading