Skip to content
4 changes: 2 additions & 2 deletions src/muse/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ def patched_broadcast_compat_data(self, other):
"(e.g. a capacity dataset with an 'asset' dimension) with a fully explicit "
"technology dataset (e.g. a technology dataset with 'region' and "
"'technology' dimensions). "
"Please use `broadcast_techs` on the latter object before performing this "
"operation."
"Please use `broadcast_over_assets` on the latter object before performing "
"this operation."
)

return self_data, other_data, dims
Expand Down
1 change: 0 additions & 1 deletion src/muse/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ def asset_housekeeping(self):

- remove empty assets
- remove years prior to current
- interpolate current year and forecasted year
"""
# TODO: move this into search and make sure filters, demand_share and
# what not use assets from search. That would remove another bit of
Expand Down
50 changes: 35 additions & 15 deletions src/muse/demand_share.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,11 @@ def new_and_retro(

from muse.commodities import is_enduse
from muse.quantities import maximum_production
from muse.utilities import agent_concatenation, reduce_assets
from muse.utilities import agent_concatenation, broadcast_over_assets, reduce_assets

current_year, investment_year = map(int, market.year.values)

def decommissioning(capacity):
def decommissioning(capacity, technologies):
return decommissioning_demand(
technologies=technologies,
capacity=capacity.interp(
Expand All @@ -263,10 +263,13 @@ def decommissioning(capacity):
year=[current_year, investment_year], kwargs={"fill_value": 0.0}
)

# Select technodata for assets
technodata = broadcast_over_assets(technologies, capacity, installed_as_year=True)

demands = new_and_retro_demands(
capacity,
market,
technologies,
technodata,
timeslice_level=timeslice_level,
)

Expand All @@ -284,19 +287,20 @@ def decommissioning(capacity):

id_to_share: MutableMapping[Hashable, xr.DataArray] = {}
for region in demands.region.values:
regional_techs = technologies.sel(region=region)
retro_capacity: MutableMapping[Hashable, xr.DataArray] = {
agent.uuid: agent.assets.capacity
for agent in agents
if agent.category == "retrofit" and agent.region == region
}

retro_technodata: MutableMapping[Hashable, xr.Dataset] = {
agent_uuid: technodata.sel(asset=retro_capacity[agent_uuid].asset)
for agent_uuid in retro_capacity.keys()
}
name_to_id = {
(agent.name, agent.region): agent.uuid
for agent in agents
if agent.category == "retrofit" and agent.region == region
}

id_to_rquantity = {
agent.uuid: (agent.name, agent.region, agent.quantity)
for agent in agents
Expand All @@ -305,6 +309,7 @@ def decommissioning(capacity):

retro_demands: MutableMapping[Hashable, xr.DataArray] = _inner_split(
retro_capacity,
retro_technodata,
demands.retrofit.sel(region=region),
decommissioning,
id_to_rquantity,
Expand All @@ -319,18 +324,21 @@ def decommissioning(capacity):
for agent in agents
if agent.category != "retrofit" and agent.region == region
}

new_technodata: MutableMapping[Hashable, xr.Dataset] = {
agent_uuid: technodata.sel(asset=new_capacity[agent_uuid].asset)
for agent_uuid in new_capacity.keys()
}
id_to_nquantity = {
agent.uuid: (agent.name, agent.region, agent.quantity)
for agent in agents
if agent.category != "retrofit" and agent.region == region
}
new_demands = _inner_split(
new_capacity,
new_technodata,
demands.new.sel(region=region),
partial(
maximum_production,
technologies=regional_techs,
year=current_year,
timeslice_level=timeslice_level,
),
Expand Down Expand Up @@ -372,11 +380,11 @@ def standard_demand(

from muse.commodities import is_enduse
from muse.quantities import maximum_production
from muse.utilities import agent_concatenation, reduce_assets
from muse.utilities import agent_concatenation, broadcast_over_assets, reduce_assets

current_year, investment_year = map(int, market.year.values)

def decommissioning(capacity):
def decommissioning(capacity, technologies):
return decommissioning_demand(
technologies=technologies,
capacity=capacity.interp(
Expand All @@ -395,11 +403,14 @@ def decommissioning(capacity):
year=[current_year, investment_year], kwargs={"fill_value": 0.0}
)

# Select technodata for assets
technodata = broadcast_over_assets(technologies, capacity, installed_as_year=True)

# Calculate new and retrofit demands
demands = new_and_retro_demands(
capacity=capacity,
market=market,
technologies=technologies,
technologies=technodata,
timeslice_level=timeslice_level,
)

Expand All @@ -416,6 +427,10 @@ def decommissioning(capacity):
for agent in agents
if agent.region == region
}
current_technodata: MutableMapping[Hashable, xr.Dataset] = {
agent_uuid: technodata.sel(asset=current_capacity[agent_uuid].asset)
for agent_uuid in current_capacity.keys()
}

# Split demands between agents
id_to_quantity = {
Expand All @@ -425,16 +440,17 @@ def decommissioning(capacity):
}
retro_demands: MutableMapping[Hashable, xr.DataArray] = _inner_split(
current_capacity,
current_technodata,
demands.retrofit.sel(region=region),
decommissioning,
id_to_quantity,
)
new_demands = _inner_split(
current_capacity,
current_technodata,
demands.new.sel(region=region),
partial(
maximum_production,
technologies=technologies.sel(region=region),
year=current_year,
timeslice_level=timeslice_level,
),
Expand All @@ -461,7 +477,7 @@ def unmet_forecasted_demand(
) -> xr.DataArray:
"""Forecast demand that cannot be serviced by non-decommissioned current assets."""
from muse.commodities import is_enduse
from muse.utilities import reduce_assets
from muse.utilities import broadcast_over_assets, reduce_assets

current_year, investment_year = map(int, market.year.values)

Expand All @@ -477,11 +493,14 @@ def unmet_forecasted_demand(
future_market = smarket.sel(year=investment_year, drop=True)
future_capacity = capacity.sel(year=investment_year)

# Select technology data for assets
techs = broadcast_over_assets(technologies, capacity, installed_as_year=True)

# Calculate unmet demand
result = unmet_demand(
market=future_market,
capacity=future_capacity,
technologies=technologies,
technologies=techs,
timeslice_level=timeslice_level,
)
assert "year" not in result.dims
Expand All @@ -490,6 +509,7 @@ def unmet_forecasted_demand(

def _inner_split(
assets: Mapping[Hashable, xr.DataArray],
technologies: Mapping[Hashable, xr.DataSet],
demand: xr.DataArray,
method: Callable,
quantity: Mapping,
Expand All @@ -503,7 +523,7 @@ def _inner_split(

# Find decrease in capacity production by each asset over time
shares: Mapping[Hashable, xr.DataArray] = {
key: method(capacity=capacity)
key: method(capacity=capacity, technologies=technologies[key])
.groupby("technology")
.sum("asset")
.rename(technology="asset")
Expand Down
12 changes: 5 additions & 7 deletions src/muse/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,21 +264,19 @@ def matching_market(sector: str, model: str = "default") -> xr.Dataset:
from muse.examples import sector as load_sector
from muse.quantities import consumption, maximum_production
from muse.sectors import Sector
from muse.utilities import agent_concatenation
from muse.utilities import agent_concatenation, broadcast_over_assets

loaded_sector = cast(Sector, load_sector(sector, model))
assets = agent_concatenation({u.uuid: u.assets for u in list(loaded_sector.agents)})

market = xr.Dataset()
production = cast(
xr.DataArray,
maximum_production(loaded_sector.technologies, assets.capacity),
)
techs = broadcast_over_assets(loaded_sector.technologies, assets.capacity)
production = maximum_production(techs, assets.capacity)
market["supply"] = production.sum("asset")
if "dst_region" in market.dims:
market = market.rename(dst_region="region")
if market.region.dims:
consump = consumption(loaded_sector.technologies, production)
consump = consumption(techs, production)
market["consumption"] = drop_timeslice(
consump.groupby("region").sum(
{"asset", "dst_region"}.intersection(consump.dims)
Expand All @@ -287,7 +285,7 @@ def matching_market(sector: str, model: str = "default") -> xr.Dataset:
)
else:
market["consumption"] = (
consumption(loaded_sector.technologies, production).sum(
consumption(techs, production).sum(
{"asset", "dst_region"}.intersection(market.dims)
)
+ market.supply
Expand Down
5 changes: 3 additions & 2 deletions src/muse/investments.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,15 @@ def adhoc_match_demand(
) -> xr.DataArray:
from muse.demand_matching import demand_matching
from muse.quantities import capacity_in_use, maximum_production
from muse.utilities import broadcast_over_assets

assert "year" not in technologies.dims

demand = next(c for c in constraints if c.name == "demand").b

max_capacity = next(c for c in constraints if c.name == "max capacity expansion").b
max_prod = maximum_production(
technologies,
broadcast_over_assets(technologies, max_capacity),
max_capacity,
technology=costs.replacement,
commodity=demand.commodity,
Expand All @@ -254,7 +255,7 @@ def adhoc_match_demand(

capacity = capacity_in_use(
production,
technologies,
broadcast_over_assets(technologies, production),
technology=production.replacement,
timeslice_level=timeslice_level,
).drop_vars("technology")
Expand Down
Loading