Skip to content

Commit 7fd4c8a

Browse files
authored
Merge branch 'techs' into foresight
2 parents 07a326f + b145990 commit 7fd4c8a

File tree

3 files changed

+48
-37
lines changed

3 files changed

+48
-37
lines changed

src/muse/__main__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ def patched_broadcast_compat_data(self, other):
8989
"`broadcast_timeslice` or `distribute_timeslice` (see `muse.timeslices`)."
9090
)
9191

92+
if (isinstance(other, Variable)) and {"technology", "asset"}.issubset(
93+
set(self.dims) | set(getattr(other, "dims", []))
94+
):
95+
raise ValueError()
96+
9297
# The rest of the function is copied directly from
9398
# xarray.core.variable._broadcast_compat_data
9499
if all(hasattr(other, attr) for attr in ["dims", "data", "shape", "encoding"]):

src/muse/utilities.py

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,9 @@ def operation(x):
180180

181181

182182
def broadcast_techs(
183-
technologies: xr.Dataset | xr.DataArray,
183+
x: xr.Dataset | xr.DataArray,
184184
template: xr.DataArray | xr.Dataset,
185185
dimension: str = "asset",
186-
interpolation: str = "linear",
187-
installed_as_year: bool = True,
188-
**kwargs,
189186
) -> xr.Dataset | xr.DataArray:
190187
"""Broadcasts technologies to the shape of template in given dimension.
191188
@@ -201,39 +198,49 @@ def broadcast_techs(
201198
This function broadcast the first representation to the shape and coordinates
202199
of the second.
203200
204-
This function does not support technologies with a 'year' dimension. Please select
205-
technology data for a specific year before calling this function.
201+
This function does not support arrays with a 'year' dimension. Please select
202+
data for a specific year before calling this function.
206203
207204
Arguments:
208-
technologies: The dataset to broadcast
205+
x: The dataset to broadcast
209206
template: the dataset or data-array to use as a template
210-
dimension: the name of the dimensiom from `template` over which to
211-
broadcast
212-
interpolation: interpolation method used across `year`
213-
installed_as_year: if the coordinate `installed` exists, then it is
214-
applied to the `year` dimension of the technologies dataset
215-
kwargs: further arguments are used initial filters over the
216-
`technologies` dataset.
217-
"""
218-
assert "year" not in technologies.dims
207+
dimension: TODO
208+
209+
Example:
210+
Define the example array:
211+
>>> import xarray as xr
212+
>>> x = xr.DataArray(
213+
... data=[[1, 2, 3], [4, 5, 6]],
214+
... dims=['technology', 'region'],
215+
... coords={'technology': ['gasboiler', 'heatpump'],
216+
... 'region': ['R1', 'R2', 'R3']},
217+
... )
219218
220-
# this assert will trigger if 'year' is changed to 'installed' in
221-
# technologies, because then this function should be modified.
222-
assert "installed" not in technologies.dims
223-
names = [u for u in template.coords if template[u].dims == (dimension,)]
224-
# the first selection reduces the size of technologies without affecting the
225-
# dimensions.
226-
first_sel = {
227-
n: technologies[n].isin(template[n])
228-
for n in names
229-
if n in technologies.dims and n != "year"
230-
}
231-
first_sel.update({k: v for k, v in kwargs.items() if k != "year"})
232-
techs = technologies.sel(first_sel)
219+
Define the assets template:
220+
>>> template = xr.DataArray(
221+
... data=[0, 0],
222+
... dims=["asset"],
223+
... coords={
224+
... "region": (["asset"], ["R1", "R2"]),
225+
... "technology": (["asset"], ["gasboiler", "heatpump"]),
226+
... "installed": (["asset"], [2020, 2025])},
227+
... )
233228
234-
second_sel = {n: template[n] for n in template.coords if n in techs.dims}
229+
Reshape the data to match the template:
230+
>>> broadcast_techs(x, template)
231+
<xarray.DataArray (asset: 2)> Size: 16B
232+
array([1, 5])
233+
Coordinates:
234+
technology (asset) <U9 72B 'gasboiler' 'heatpump'
235+
region (asset) <U2 16B 'R1' 'R2'
236+
installed (asset) int64 16B 2020 2025
237+
Dimensions without coordinates: asset
238+
"""
239+
assert "year" not in x.dims
240+
assert "installed" not in x.dims
235241

236-
return techs.sel(second_sel)
242+
sel = {n: template[n] for n in template.coords if n in x.dims}
243+
return x.sel(sel)
237244

238245

239246
def clean_assets(assets: xr.Dataset, years: int | Sequence[int]):
@@ -313,7 +320,7 @@ def filter_with_template(
313320
`data` transformed to match the form of `template`
314321
"""
315322
if asset_dimension in template.dims:
316-
return broadcast_techs(data, template, dimension=asset_dimension, **kwargs)
323+
return broadcast_techs(data, template, dimension=asset_dimension)
317324

318325
match_indices = set(data.dims).intersection(template.dims) - set(kwargs)
319326
match = {d: template[d].isin(data[d]).values for d in match_indices if d != "year"}

tests/test_utilities.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ def test_reduce_assets_with_zero_size(capacity: xr.DataArray):
4343
def test_broadcast_tech(technologies, capacity):
4444
from muse.utilities import broadcast_techs
4545

46+
technologies = technologies.sel(year=2010)
4647
regions = make_array(technologies.region)
4748
commodities = make_array(technologies.commodity)
48-
years = make_array(technologies.year)
4949
techs = make_array(technologies.technology)
50-
technologies["fixed_outputs"] = regions * commodities * years * techs
50+
technologies["fixed_outputs"] = regions * commodities * techs
5151

5252
actual = broadcast_techs(technologies.fixed_outputs, capacity)
5353

@@ -57,16 +57,15 @@ def test_broadcast_tech(technologies, capacity):
5757

5858
for asset in capacity.asset:
5959
region = regions.sel(region=asset.region)
60-
year = years.interp(year=asset.installed, method="linear")
6160
tech = techs.sel(technology=asset.technology)
62-
expected = region * year * tech * commodities
61+
expected = region * tech * commodities
6362
assert actual.isel(asset=int(asset)).values == approx(expected.values)
6463

6564

6665
def test_broadcast_tech_idempotent(technologies, capacity):
6766
from muse.utilities import broadcast_techs
6867

69-
first = broadcast_techs(technologies, capacity)
68+
first = broadcast_techs(technologies.sel(year=2010), capacity)
7069
second = broadcast_techs(first, capacity)
7170
assert (first == second).all()
7271

0 commit comments

Comments
 (0)