Skip to content

Commit a2db431

Browse files
committed
Add interpolate_capacity function
1 parent ffc3684 commit a2db431

7 files changed

Lines changed: 86 additions & 49 deletions

File tree

src/muse/agents/agent.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ def next(
297297
"""
298298
from logging import getLogger
299299

300-
from muse.utilities import reduce_assets
300+
from muse.utilities import interpolate_capacity, reduce_assets
301301

302302
# Check inputs
303303
assert len(market.year) == 2
@@ -340,9 +340,10 @@ def next(
340340
search = search.sel(asset=condtechs)
341341

342342
# Calculate capacity in current and investment year
343-
capacity = reduce_assets(
344-
self.assets.capacity, coords=("technology", "region")
345-
).interp(year=[current_year, investment_year])
343+
capacity = interpolate_capacity(
344+
reduce_assets(self.assets.capacity, coords=("technology", "region")),
345+
year=[current_year, investment_year],
346+
)
346347

347348
# Calculate constraints
348349
constraints = self.constraints(

src/muse/demand_share.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -246,21 +246,27 @@ def new_and_retro(
246246

247247
from muse.commodities import is_enduse
248248
from muse.quantities import maximum_production
249-
from muse.utilities import agent_concatenation, broadcast_over_assets, reduce_assets
249+
from muse.utilities import (
250+
agent_concatenation,
251+
broadcast_over_assets,
252+
interpolate_capacity,
253+
reduce_assets,
254+
)
250255

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

253258
def decommissioning(capacity, technologies):
254259
return decommissioning_demand(
255260
technologies=technologies,
256-
capacity=capacity.interp(
257-
year=[current_year, investment_year], kwargs={"fill_value": 0.0}
261+
capacity=interpolate_capacity(
262+
capacity, year=[current_year, investment_year]
258263
),
259264
timeslice_level=timeslice_level,
260265
)
261266

262-
capacity = reduce_assets([u.assets.capacity for u in agents]).interp(
263-
year=[current_year, investment_year], kwargs={"fill_value": 0.0}
267+
capacity = interpolate_capacity(
268+
reduce_assets([u.assets.capacity for u in agents]),
269+
year=[current_year, investment_year],
264270
)
265271

266272
# Select technodata for assets
@@ -288,8 +294,8 @@ def decommissioning(capacity, technologies):
288294
id_to_share: MutableMapping[Hashable, xr.DataArray] = {}
289295
for region in demands.region.values:
290296
retro_capacity: MutableMapping[Hashable, xr.DataArray] = {
291-
agent.uuid: agent.assets.capacity.interp(
292-
year=[current_year, investment_year]
297+
agent.uuid: interpolate_capacity(
298+
agent.assets.capacity, year=[current_year, investment_year]
293299
)
294300
for agent in agents
295301
if agent.category == "retrofit" and agent.region == region
@@ -382,15 +388,20 @@ def standard_demand(
382388

383389
from muse.commodities import is_enduse
384390
from muse.quantities import maximum_production
385-
from muse.utilities import agent_concatenation, broadcast_over_assets, reduce_assets
391+
from muse.utilities import (
392+
agent_concatenation,
393+
broadcast_over_assets,
394+
interpolate_capacity,
395+
reduce_assets,
396+
)
386397

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

389400
def decommissioning(capacity, technologies):
390401
return decommissioning_demand(
391402
technologies=technologies,
392-
capacity=capacity.interp(
393-
year=[current_year, investment_year], kwargs={"fill_value": 0.0}
403+
capacity=interpolate_capacity(
404+
capacity, year=[current_year, investment_year]
394405
),
395406
timeslice_level=timeslice_level,
396407
)
@@ -401,8 +412,9 @@ def decommissioning(capacity, technologies):
401412
raise RetrofitAgentInStandardDemandShare()
402413

403414
# Calculate existing capacity
404-
capacity = reduce_assets([agent.assets.capacity for agent in agents]).interp(
405-
year=[current_year, investment_year], kwargs={"fill_value": 0.0}
415+
capacity = interpolate_capacity(
416+
reduce_assets([agent.assets.capacity for agent in agents]),
417+
year=[current_year, investment_year],
406418
)
407419

408420
# Select technodata for assets
@@ -425,8 +437,8 @@ def decommissioning(capacity, technologies):
425437
for region in demands.region.values:
426438
# Calculate current capacity
427439
current_capacity: MutableMapping[Hashable, xr.DataArray] = {
428-
agent.uuid: agent.assets.capacity.interp(
429-
year=[current_year, investment_year]
440+
agent.uuid: interpolate_capacity(
441+
agent.assets.capacity, year=[current_year, investment_year]
430442
)
431443
for agent in agents
432444
if agent.region == region
@@ -481,16 +493,21 @@ def unmet_forecasted_demand(
481493
) -> xr.DataArray:
482494
"""Forecast demand that cannot be serviced by non-decommissioned current assets."""
483495
from muse.commodities import is_enduse
484-
from muse.utilities import broadcast_over_assets, reduce_assets
496+
from muse.utilities import (
497+
broadcast_over_assets,
498+
interpolate_capacity,
499+
reduce_assets,
500+
)
485501

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

488504
comm_usage = technologies.comm_usage.sel(commodity=market.commodity)
489505
smarket: xr.Dataset = market.where(is_enduse(comm_usage), 0)
490506

491507
# Calculate existing capacity
492-
capacity = reduce_assets([agent.assets.capacity for agent in agents]).interp(
493-
year=[current_year, investment_year], kwargs={"fill_value": 0.0}
508+
capacity = interpolate_capacity(
509+
reduce_assets([agent.assets.capacity for agent in agents]),
510+
year=[current_year, investment_year],
494511
)
495512

496513
# Select data for future years

src/muse/sectors/sector.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,10 @@ def market_variables(self, market: xr.Dataset, technologies: xr.Dataset) -> Any:
275275
from muse.commodities import is_pollutant
276276
from muse.costs import levelized_cost_of_energy, supply_cost
277277
from muse.quantities import consumption
278-
from muse.utilities import broadcast_over_assets
278+
from muse.utilities import broadcast_over_assets, interpolate_capacity
279279

280280
years = market.year.values
281-
capacity = self.capacity.interp(year=years)
281+
capacity = interpolate_capacity(self.capacity, year=years)
282282

283283
# Select technology data for each asset
284284
# Each asset uses the technology data from the year it was installed
@@ -350,7 +350,7 @@ def capacity(self) -> xr.DataArray:
350350
dimensions: asset (technology, installation date,
351351
region), year.
352352
"""
353-
from muse.utilities import reduce_assets
353+
from muse.utilities import interpolate_capacity, reduce_assets
354354

355355
traded = [
356356
u.assets.capacity
@@ -372,13 +372,14 @@ def capacity(self) -> xr.DataArray:
372372
]
373373
flat_list = [item for sublist in full_list for item in sublist]
374374
years = sorted(list(set(flat_list)))
375-
return reduce_assets(
375+
capacity = reduce_assets(
376376
[
377377
u.assets.capacity
378378
for u in self.agents
379379
if "dst_region" not in u.assets.capacity.dims
380380
]
381-
).interp(year=years, kwargs={"fill_value": 0.0})
381+
)
382+
return interpolate_capacity(capacity, year=years)
382383

383384
# Only traded assets
384385
elif not nontraded:
@@ -389,25 +390,27 @@ def capacity(self) -> xr.DataArray:
389390
]
390391
flat_list = [item for sublist in full_list for item in sublist]
391392
years = sorted(list(set(flat_list)))
392-
return reduce_assets(
393+
capacity = reduce_assets(
393394
[
394395
u.assets.capacity
395396
for u in self.agents
396397
if "dst_region" in u.assets.capacity.dims
397398
]
398-
).interp(year=years, kwargs={"fill_value": 0.0})
399+
)
400+
return interpolate_capacity(capacity, year=years)
399401

400402
# Both traded and nontraded assets
401403
else:
402404
traded_results = reduce_assets(traded)
403405
nontraded_results = reduce_assets(nontraded)
404-
return reduce_assets(
406+
capacity = reduce_assets(
405407
[
406408
traded_results,
407409
nontraded_results
408410
* (nontraded_results.region == traded_results.dst_region),
409411
]
410412
)
413+
return interpolate_capacity(capacity, year=years)
411414

412415
@property
413416
def agents(self) -> Iterator[AbstractAgent]:

src/muse/utilities.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,21 +355,20 @@ def lexical_comparison(
355355
def merge_assets(
356356
capa_a: xr.DataArray,
357357
capa_b: xr.DataArray,
358-
interpolation: str = "linear",
359358
dimension: str = "asset",
360359
) -> xr.DataArray:
361360
"""Merge two capacity arrays."""
362361
# Interpolate capacity arrays to a common time framework
363362
years = sorted(set(capa_a.year.values).union(capa_b.year.values))
364363
if len(capa_a.year) == 1:
365364
capa_a_interp = capa_a
366-
capa_b_interp = capa_b.interp(year=years, method=interpolation).fillna(0)
365+
capa_b_interp = interpolate_capacity(capa_b, year=years)
367366
elif len(capa_b.year) == 1:
368-
capa_a_interp = capa_a.interp(year=years, method=interpolation).fillna(0)
367+
capa_a_interp = interpolate_capacity(capa_a, year=years)
369368
capa_b_interp = capa_b
370369
else:
371-
capa_a_interp = capa_a.interp(year=years, method=interpolation).fillna(0)
372-
capa_b_interp = capa_b.interp(year=years, method=interpolation).fillna(0)
370+
capa_a_interp = interpolate_capacity(capa_a, year=years)
371+
capa_b_interp = interpolate_capacity(capa_b, year=years)
373372

374373
# Concatenate the two capacity arrays
375374
result = xr.concat((capa_a_interp, capa_b_interp), dim=dimension)
@@ -402,6 +401,21 @@ def avoid_repetitions(data: xr.DataArray, dim: str = "year") -> xr.DataArray:
402401
return data.year[years]
403402

404403

404+
def interpolate_capacity(
405+
data: xr.DataArray, year: int | Sequence[int] | xr.DataArray
406+
) -> xr.DataArray:
407+
"""Interpolates capacity data to the given years.
408+
409+
Capacity between years is interpolated linearly. Capacity beyond the final year is
410+
set to zero.
411+
"""
412+
return data.interp(
413+
year=year,
414+
method="linear",
415+
kwargs={"fill_value": 0.0},
416+
)
417+
418+
405419
def nametuple_to_dict(nametup: Mapping | NamedTuple) -> Mapping:
406420
"""Transforms a nametuple of type GenericDict into an OrderDict."""
407421
from collections import OrderedDict

tests/test_constraints.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pytest import approx, fixture
77

88
from muse.timeslices import drop_timeslice
9-
from muse.utilities import reduce_assets
9+
from muse.utilities import interpolate_capacity, reduce_assets
1010

1111
CURRENT_YEAR = 2020
1212
INVESTMENT_YEAR = 2025
@@ -50,8 +50,9 @@ def assets(residential):
5050

5151
@fixture
5252
def capacity(assets):
53-
return reduce_assets(assets.capacity, coords=("technology", "region")).interp(
54-
year=[CURRENT_YEAR, INVESTMENT_YEAR], method="linear"
53+
return interpolate_capacity(
54+
reduce_assets(assets.capacity, coords=("technology", "region")),
55+
year=[CURRENT_YEAR, INVESTMENT_YEAR],
5556
)
5657

5758

tests/test_demand_share.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
from pytest import approx, fixture, raises
33

44
from muse.timeslices import drop_timeslice
5+
from muse.utilities import interpolate_capacity
56

67
CURRENT_YEAR = 2010
78
INVESTMENT_YEAR = 2015
89

910

1011
@fixture
1112
def _capacity(stock):
12-
return stock.capacity.interp(year=[CURRENT_YEAR, INVESTMENT_YEAR])
13+
return interpolate_capacity(stock.capacity, year=[CURRENT_YEAR, INVESTMENT_YEAR])
1314

1415

1516
@fixture

tests/test_utilities.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def test_lexical_nobin(order):
204204
def test_merge_assets():
205205
from numpy import arange
206206

207-
from muse.utilities import merge_assets
207+
from muse.utilities import interpolate_capacity, merge_assets
208208

209209
def fake(year, order=("installed", "technology")):
210210
result = xr.Dataset()
@@ -244,17 +244,17 @@ def fake(year, order=("installed", "technology")):
244244
ab_side = actual.sel(
245245
asset=((actual.installed == inst) & (actual.technology == tech))
246246
).squeeze("asset")
247-
a_side = (
248-
capa_a.sel(asset=((capa_a.installed == inst) & (capa_a.technology == tech)))
249-
.sum("asset")
250-
.interp(year=ab_side.year, method="linear")
251-
.fillna(0)
247+
a_side = interpolate_capacity(
248+
capa_a.sel(
249+
asset=((capa_a.installed == inst) & (capa_a.technology == tech))
250+
).sum("asset"),
251+
year=ab_side.year,
252252
)
253-
b_side = (
254-
capa_b.sel(asset=((capa_b.installed == inst) & (capa_b.technology == tech)))
255-
.sum("asset")
256-
.interp(year=ab_side.year, method="linear")
257-
.fillna(0)
253+
b_side = interpolate_capacity(
254+
capa_b.sel(
255+
asset=((capa_b.installed == inst) & (capa_b.technology == tech))
256+
).sum("asset"),
257+
year=ab_side.year,
258258
)
259259
assert (ab_side.capacity == approx((a_side + b_side).values)).all()
260260

0 commit comments

Comments
 (0)