Skip to content

Commit 4f74da9

Browse files
committed
Finish initial market reader
1 parent dec3ea5 commit 4f74da9

File tree

3 files changed

+75
-45
lines changed

3 files changed

+75
-45
lines changed
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
id,season,day,time_of_day,fraction
2-
1,all,all,night,0.1667
3-
2,all,all,morning,0.1667
4-
3,all,all,afternoon,0.1667
5-
4,all,all,early-peak,0.1667
6-
5,all,all,late-peak,0.1667
7-
6,all,all,evening,0.1667
1+
id,month,day,hour,fraction
2+
1,all-year,all-week,night,0.1667
3+
2,all-year,all-week,morning,0.1667
4+
3,all-year,all-week,afternoon,0.1667
5+
4,all-year,all-week,early-peak,0.1667
6+
5,all-year,all-week,late-peak,0.1667
7+
6,all-year,all-week,evening,0.1667

src/muse/new_input/readers.py

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import pandas as pd
44
import xarray as xr
55

6+
from muse.timeslices import QuantityType
7+
68

79
def read_inputs(data_dir):
810
data = {}
@@ -42,17 +44,15 @@ def read_inputs(data_dir):
4244
def read_timeslices_csv(buffer_, con):
4345
sql = """CREATE TABLE timeslices (
4446
id BIGINT PRIMARY KEY,
45-
season VARCHAR,
47+
month VARCHAR,
4648
day VARCHAR,
47-
time_of_day VARCHAR,
49+
hour VARCHAR,
4850
fraction DOUBLE CHECK (fraction >= 0 AND fraction <= 1),
4951
);
5052
"""
5153
con.sql(sql)
5254
rel = con.read_csv(buffer_, header=True, delimiter=",") # noqa: F841
53-
con.sql(
54-
"INSERT INTO timeslices SELECT id, season, day, time_of_day, fraction FROM rel;"
55-
)
55+
con.sql("INSERT INTO timeslices SELECT id, month, day, hour, fraction FROM rel;")
5656
return con.sql("SELECT * from timeslices").fetchnumpy()
5757

5858

@@ -278,17 +278,19 @@ def calculate_initial_market(
278278
- If price data is not specified for a commodity/region combination, the price is
279279
zero
280280
281-
"""
282-
from muse.timeslices import QuantityType, convert_timeslice
281+
Todo:
282+
- Allow data to be specified on a timeslice level (optional)
283+
- Interpolation, missing year field, flexible timeslice specification as above
283284
285+
"""
284286
# Prepare dataframes
285287
df_trade = pd.DataFrame(commodity_trade).set_index(["commodity", "region", "year"])
286288
df_costs = (
287289
pd.DataFrame(commodity_costs)
288290
.set_index(["commodity", "region", "year"])
289291
.rename(columns={"value": "prices"})
290292
)
291-
df_timeslices = pd.DataFrame(timeslices).set_index(["season", "day", "time_of_day"])
293+
df_timeslices = pd.DataFrame(timeslices).set_index(["month", "day", "hour"])
292294

293295
# DataArray dimensions
294296
all_commodities = commodities["id"].astype(np.dtype("str"))
@@ -320,13 +322,17 @@ def calculate_initial_market(
320322
# Calculate static trade
321323
df_trade["static_trade"] = df_trade["export"] - df_trade["import"]
322324

323-
# Create Data
324-
df_full = df_costs.join(df_trade)
325-
data = df_full.to_xarray()
326-
ts = df_timeslices.to_xarray()["fraction"]
327-
ts = ts.stack(timeslice=("season", "day", "time_of_day"))
328-
convert_timeslice(data, ts, QuantityType.EXTENSIVE)
325+
# Create xarray datasets
326+
xr_costs = df_costs.to_xarray()
327+
xr_trade = df_trade.to_xarray()
328+
329+
# Project over timeslices
330+
ts = df_timeslices.to_xarray()["fraction"].stack(timeslice=("month", "day", "hour"))
331+
xr_costs = project_timeslice(xr_costs, ts, QuantityType.EXTENSIVE)
332+
xr_trade = project_timeslice(xr_trade, ts, QuantityType.INTENSIVE)
329333

334+
# Combine data
335+
data = xr.merge([xr_costs, xr_trade])
330336
return data
331337

332338

@@ -353,3 +359,30 @@ def check_all_values_specified(
353359
).all():
354360
msg = "" # TODO
355361
raise DataValidationError(msg)
362+
363+
364+
def project_timeslice(
365+
data: xr.Dataset, timeslices: xr.DataArray, quantity_type: QuantityType
366+
) -> xr.Dataset:
367+
"""Project a dataset over a new timeslice dimension.
368+
369+
The projection can be done in one of two ways, depending on whether the
370+
quantity type is extensive or intensive. See `QuantityType`.
371+
372+
Args:
373+
data: Dataset to project
374+
timeslices: DataArray of timeslice levels, with values between 0 and 1
375+
representing the timeslice length (fraction of the year)
376+
quantity_type: Type of projection to perform. QuantityType.EXTENSIVE or
377+
QuantityType.INTENSIVE
378+
379+
Returns:
380+
Projected dataset
381+
"""
382+
assert "timeslice" in timeslices.dims
383+
assert "timeslice" not in data.dims
384+
385+
if quantity_type is QuantityType.INTENSIVE:
386+
return data * timeslices
387+
if quantity_type is QuantityType.EXTENSIVE:
388+
return data * xr.ones_like(timeslices)

tests/test_new_readers.py

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import duckdb
44
import numpy as np
55
import xarray as xr
6-
from pytest import approx, fixture, mark, raises
6+
from pytest import approx, fixture, raises
77

88

99
@fixture
@@ -206,9 +206,9 @@ def test_calculate_demand(
206206
assert data.dtype == np.float64
207207

208208
assert set(data.dims) == {"year", "commodity", "region", "timeslice"}
209-
assert list(data.coords["region"].values) == ["R1"]
209+
assert set(data.coords["region"].values) == {"R1"}
210210
assert set(data.coords["timeslice"].values) == set(range(1, 7))
211-
assert list(data.coords["year"].values) == [2020, 2050]
211+
assert set(data.coords["year"].values) == {2020, 2050}
212212
assert set(data.coords["commodity"].values) == {
213213
"electricity",
214214
"gas",
@@ -220,7 +220,6 @@ def test_calculate_demand(
220220
assert data.sel(year=2020, commodity="heat", region="R1", timeslice=1) == 1
221221

222222

223-
@mark.xfail
224223
def test_calculate_initial_market(
225224
populate_commodities,
226225
populate_regions,
@@ -240,12 +239,8 @@ def test_calculate_initial_market(
240239

241240
assert isinstance(data, xr.Dataset)
242241
assert set(data.dims) == {"region", "year", "commodity", "timeslice"}
243-
assert dict(data.dtypes) == dict(
244-
prices=np.float64,
245-
exports=np.float64,
246-
imports=np.float64,
247-
static_trade=np.float64,
248-
)
242+
for dt in data.dtypes.values():
243+
assert dt == np.dtype("float64")
249244
assert set(data.coords["region"].values) == {"R1"}
250245
assert set(data.coords["year"].values) == set(range(2010, 2105, 5))
251246
assert set(data.coords["commodity"].values) == {
@@ -266,28 +261,30 @@ def test_calculate_initial_market(
266261
"evening",
267262
]
268263

269-
assert list(data.coords["timeslice"].values) == list(
264+
assert set(data.coords["timeslice"].values) == set(
270265
zip(month_values, day_values, hour_values)
271266
)
272-
assert list(data.coords["month"]) == month_values
273-
assert list(data.coords["day"]) == day_values
274-
assert list(data.coords["hour"]) == hour_values
267+
assert set(data.coords["month"].values) == set(month_values)
268+
assert set(data.coords["day"].values) == set(day_values)
269+
assert set(data.coords["hour"].values) == set(hour_values)
275270

276271
assert all(var.coords.equals(data.coords) for var in data.data_vars.values())
277272

278273
prices = data.data_vars["prices"]
279-
assert approx(
280-
prices.sel(
281-
year=2010,
282-
region="R1",
283-
commodity="electricity",
284-
timeslice=("all-year", "all-week", "night"),
274+
assert (
275+
approx(
276+
prices.sel(
277+
year=2010,
278+
region="R1",
279+
commodity="electricity",
280+
timeslice=("all-year", "all-week", "night"),
281+
),
282+
abs=1e-4,
285283
)
286-
- 14.81481,
287-
abs=1e-4,
284+
== 14.81481
288285
)
289286

290-
exports = data.data_vars["exports"]
287+
exports = data.data_vars["export"]
291288
assert (
292289
exports.sel(
293290
year=2010,
@@ -297,7 +294,7 @@ def test_calculate_initial_market(
297294
)
298295
) == 0
299296

300-
imports = data.data_vars["imports"]
297+
imports = data.data_vars["import"]
301298
assert (
302299
imports.sel(
303300
year=2010,

0 commit comments

Comments
 (0)