diff --git a/src/muse/agents/factories.py b/src/muse/agents/factories.py index 7fcde0a9..5f86a071 100644 --- a/src/muse/agents/factories.py +++ b/src/muse/agents/factories.py @@ -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, technologies: xr.Dataset, regions: Sequence[str] | None = None, year: int | None = None, @@ -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()) diff --git a/src/muse/sectors/subsector.py b/src/muse/sectors/subsector.py index 3b2ddee5..7852d689 100644 --- a/src/muse/sectors/subsector.py +++ b/src/muse/sectors/subsector.py @@ -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, @@ -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) @@ -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()), @@ -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 @@ -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() diff --git a/tests/test_subsector.py b/tests/test_subsector.py index 23406139..efcbc1fb 100644 --- a/tests/test_subsector.py +++ b/tests/test_subsector.py @@ -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]) @@ -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,