1
|
|
|
# -*- coding: utf-8 - |
2
|
|
|
|
3
|
|
|
"""Test the definition of the time index of the model. |
4
|
|
|
|
5
|
|
|
SPDX-FileCopyrightText: Uwe Krien <[email protected]> |
6
|
|
|
|
7
|
|
|
SPDX-License-Identifier: MIT |
8
|
|
|
""" |
9
|
|
|
import datetime |
10
|
|
|
import random |
11
|
|
|
|
12
|
|
|
import pandas as pd |
13
|
|
|
import pytest |
14
|
|
|
|
15
|
|
|
from oemof import solph |
16
|
|
|
from oemof.solph import EnergySystem |
17
|
|
|
from oemof.solph import Investment |
18
|
|
|
from oemof.solph import Model |
19
|
|
|
from oemof.solph import buses |
20
|
|
|
from oemof.solph import components as cmp |
21
|
|
|
from oemof.solph import flows |
22
|
|
|
|
23
|
|
|
def _setup_energy_system(dtindex, timeincrement=None): |
24
|
|
|
es = EnergySystem( |
25
|
|
|
timeindex=dtindex, |
26
|
|
|
timeincrement=timeincrement, |
27
|
|
|
infer_last_interval=False, |
28
|
|
|
) |
29
|
|
|
|
30
|
|
|
# BUSSES |
31
|
|
|
b_el1 = buses.Bus(label="b_el1") |
32
|
|
|
b_diesel = buses.Bus(label="b_diesel", balanced=False) |
33
|
|
|
es.add(b_el1, b_diesel) |
34
|
|
|
|
35
|
|
|
# TEST DIESEL: |
36
|
|
|
dg = cmp.Converter( |
37
|
|
|
label="diesel_generator", |
38
|
|
|
inputs={b_diesel: flows.Flow(variable_costs=2)}, |
39
|
|
|
outputs={ |
40
|
|
|
b_el1: flows.Flow( |
41
|
|
|
variable_costs=1, nominal_capacity=Investment(ep_costs=500) |
42
|
|
|
) |
43
|
|
|
}, |
44
|
|
|
conversion_factors={b_el1: 0.5}, |
45
|
|
|
) |
46
|
|
|
|
47
|
|
|
batt = cmp.GenericStorage( |
48
|
|
|
label="storage", |
49
|
|
|
nominal_capacity=1000, |
50
|
|
|
inputs={b_el1: flows.Flow(variable_costs=3)}, |
51
|
|
|
outputs={b_el1: flows.Flow(variable_costs=2.5)}, |
52
|
|
|
loss_rate=0.00, |
53
|
|
|
invest_relation_input_capacity=1 / 6, |
54
|
|
|
invest_relation_output_capacity=1 / 6, |
55
|
|
|
inflow_conversion_factor=1, |
56
|
|
|
outflow_conversion_factor=0.9, |
57
|
|
|
) |
58
|
|
|
|
59
|
|
|
random.seed(1) |
60
|
|
|
demand_values = random.sample(range(40, 120), 72) |
61
|
|
|
demand = cmp.Sink( |
62
|
|
|
label="demand_el", |
63
|
|
|
inputs={ |
64
|
|
|
b_el1: flows.Flow( |
65
|
|
|
nominal_capacity=1, |
66
|
|
|
fix=demand_values, |
67
|
|
|
) |
68
|
|
|
}, |
69
|
|
|
) |
70
|
|
|
es.add(dg, batt, demand) |
71
|
|
|
|
72
|
|
|
return es |
73
|
|
|
|
74
|
|
|
class TestParameterResult: |
75
|
|
|
@classmethod |
76
|
|
|
def setup_class(cls): |
77
|
|
|
dtindex1 = pd.date_range("1/1/2012", periods=24, freq="h") |
78
|
|
|
dtindex2 = pd.date_range("1/2/2012", periods=49, freq="30min") |
79
|
|
|
dtindex = dtindex1.union(dtindex2) |
80
|
|
|
es = _setup_energy_system(dtindex) |
81
|
|
|
model = Model(es) |
82
|
|
|
model.receive_duals() |
83
|
|
|
model.solve() |
84
|
|
|
results = solph.Results(model) |
85
|
|
|
cls.flows = results["flow"] |
86
|
|
|
cls.storage_content = results["storage_content"] |
87
|
|
|
cls.es = es |
88
|
|
|
cls.model = model |
89
|
|
|
|
90
|
|
View Code Duplication |
def test_timesteps_timeincrements_with_storage_charging(self): |
|
|
|
|
91
|
|
|
|
92
|
|
|
assert ( |
93
|
|
|
self.storage_content.iloc[0] == self.storage_content.iloc[-1] |
94
|
|
|
).all() |
95
|
|
|
|
96
|
|
|
charge = self.flows[(self.es.node["b_el1"], self.es.node["storage"])] |
97
|
|
|
# Calculate the next storage content and verify it with the storage |
98
|
|
|
# content of the results (charging). |
99
|
|
|
# Charging - timestep (ts) with its timeincrement (ti) |
100
|
|
|
time = [(23, 1), (24, 0.5)] |
101
|
|
|
for ts, ti in time: |
102
|
|
|
content_manual = self.storage_content.iloc[ts, 0] + charge.iloc[ |
103
|
|
|
ts |
104
|
|
|
] * ti |
105
|
|
|
content_model = self.storage_content.iloc[ts + 1, 0] |
106
|
|
|
assert content_manual == pytest.approx(content_model) |
107
|
|
|
assert self.es.timeincrement[ts] == ti |
108
|
|
|
|
109
|
|
View Code Duplication |
def test_timesteps_timeincrements_with_storage_discharging(self): |
|
|
|
|
110
|
|
|
# Storage content at the last time point is equal to the content of |
111
|
|
|
# the first time point because the storage is balanced. |
112
|
|
|
assert ( |
113
|
|
|
self.storage_content.iloc[0] == self.storage_content.iloc[-1] |
114
|
|
|
).all() |
115
|
|
|
|
116
|
|
|
discharge = self.flows[ |
117
|
|
|
(self.es.node["storage"], self.es.node["b_el1"]) |
118
|
|
|
] |
119
|
|
|
|
120
|
|
|
# Calculate the next storage content and verify it with the storage |
121
|
|
|
# content of the results (discharging). |
122
|
|
|
# Discharging - timestep (ts) with its timeincrement (ti) |
123
|
|
|
time = [(7, 1), (40, 0.5)] |
124
|
|
|
|
125
|
|
|
for ts, ti in time: |
126
|
|
|
content_manual = ( |
127
|
|
|
self.storage_content.iloc[ts, 0] |
128
|
|
|
- (discharge.iloc[ts] + (discharge.iloc[ts] * 1 / 9)) * ti |
129
|
|
|
) |
130
|
|
|
content_model = self.storage_content.iloc[ts + 1, 0] |
131
|
|
|
assert content_manual == pytest.approx(content_model) |
132
|
|
|
assert self.es.timeincrement[ts] == ti |
133
|
|
|
|
134
|
|
|
def test_timeincrements(self): |
135
|
|
|
assert self.es.timeincrement.sum() == 48 |
136
|
|
|
|
137
|
|
|
def test_time_index_with_last_time_point(self): |
138
|
|
|
storage_content = self.storage_content[self.es.node["storage"]] |
139
|
|
|
assert storage_content.iloc[0] == storage_content.iloc[-1] |
140
|
|
|
|
141
|
|
|
charge = self.flows[(self.es.node["b_el1"], self.es.node["storage"])] |
142
|
|
|
assert storage_content.index[0] == datetime.datetime( |
143
|
|
|
2012, 1, 1, 0, 0, 0 |
144
|
|
|
) |
145
|
|
|
assert charge.index[0] == datetime.datetime(2012, 1, 1, 0, 0, 0) |
146
|
|
|
assert storage_content.index[-1] == datetime.datetime( |
147
|
|
|
2012, 1, 3, 0, 0, 0 |
148
|
|
|
) |
149
|
|
|
assert charge.index[-1] == datetime.datetime(2012, 1, 2, 23, 30, 0) |
150
|
|
|
|
151
|
|
|
|
152
|
|
|
def test_numeric_index(): |
153
|
|
|
es = _setup_energy_system(dtindex=None, timeincrement=24 * [1]+ 48 * [0.5]) |
154
|
|
|
|
155
|
|
|
model = Model(es) |
156
|
|
|
model.receive_duals() |
157
|
|
|
model.solve() |
158
|
|
|
results = solph.Results(model) |
159
|
|
|
flow = results["flow"] |
160
|
|
|
|
161
|
|
|
assert flow.index[0] == 0 |
162
|
|
|
assert flow.index[-1] == pytest.approx(47.5) |
163
|
|
|
assert len(flow) == 72 |
164
|
|
|
|
165
|
|
|
storage_content = results["storage_content"] |
166
|
|
|
assert (storage_content.iloc[0] == storage_content.iloc[-1]).all() |
167
|
|
|
assert len(storage_content) == 73 |
168
|
|
|
|
169
|
|
|
charge = flow[(es.node["b_el1"], es.node["storage"])] |
170
|
|
|
# Calculate the next storage content and verify it with the storage |
171
|
|
|
# content of the results (charging). |
172
|
|
|
# Charging - timestep (ts) with its timeincrement (ti) |
173
|
|
|
time = [(23, 1), (24, 0.5)] |
174
|
|
|
for ts, ti in time: |
175
|
|
|
content_manual = storage_content.iloc[ts, 0] + charge.iloc[ |
176
|
|
|
ts |
177
|
|
|
] * ti |
178
|
|
|
content_model = storage_content.iloc[ts + 1, 0] |
179
|
|
|
assert content_manual == pytest.approx(content_model) |
180
|
|
|
assert es.timeincrement[ts] == ti |
181
|
|
|
|