|
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
|
|
|
|