|
1
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
""" |
|
3
|
|
|
Example that shows how to use "Offset-Invest". |
|
4
|
|
|
|
|
5
|
|
|
Installation requirements |
|
6
|
|
|
------------------------- |
|
7
|
|
|
This example requires oemof.solph (v0.5.x), install by: |
|
8
|
|
|
|
|
9
|
|
|
pip install oemof.solph[examples] |
|
10
|
|
|
|
|
11
|
|
|
License |
|
12
|
|
|
------- |
|
13
|
|
|
Johannes Röder <https://www.uni-bremen.de/en/res/team/johannes-roeder-m-sc> |
|
14
|
|
|
|
|
15
|
|
|
`MIT license <https://github.com/oemof/oemof-solph/blob/dev/LICENSE>`_ |
|
16
|
|
|
|
|
17
|
|
|
""" |
|
18
|
|
|
|
|
19
|
|
|
import logging |
|
20
|
|
|
import os |
|
21
|
|
|
|
|
22
|
|
|
import pandas as pd |
|
23
|
|
|
from matplotlib import pyplot as plt |
|
24
|
|
|
|
|
25
|
|
|
from oemof import solph |
|
26
|
|
|
|
|
27
|
|
|
|
|
28
|
|
|
def main(): |
|
29
|
|
|
data = [0, 15, 30, 35, 20, 25, 27, 10, 5, 2, 15, 40, 20, 0, 0] |
|
30
|
|
|
|
|
31
|
|
|
# create an energy system |
|
32
|
|
|
idx = solph.create_time_index(2017, number=len(data)) |
|
33
|
|
|
es = solph.EnergySystem(timeindex=idx, infer_last_interval=False) |
|
34
|
|
|
|
|
35
|
|
|
bus_0 = solph.Bus(label="bus_0") |
|
36
|
|
|
bus_1 = solph.Bus(label="bus_1") |
|
37
|
|
|
es.add(bus_0, bus_1) |
|
38
|
|
|
|
|
39
|
|
|
c_0 = 10 |
|
40
|
|
|
c_1 = 100 |
|
41
|
|
|
|
|
42
|
|
|
es.add( |
|
43
|
|
|
solph.components.Source( |
|
44
|
|
|
label="source_0", outputs={bus_0: solph.Flow(variable_costs=c_0)} |
|
45
|
|
|
) |
|
46
|
|
|
) |
|
47
|
|
|
|
|
48
|
|
|
es.add( |
|
49
|
|
|
solph.components.Source( |
|
50
|
|
|
label="source_1", outputs={bus_1: solph.Flow(variable_costs=c_1)} |
|
51
|
|
|
) |
|
52
|
|
|
) |
|
53
|
|
|
|
|
54
|
|
|
es.add( |
|
55
|
|
|
solph.components.Sink( |
|
56
|
|
|
label="demand", |
|
57
|
|
|
inputs={bus_1: solph.Flow(fix=data, nominal_value=1)}, |
|
58
|
|
|
) |
|
59
|
|
|
) |
|
60
|
|
|
|
|
61
|
|
|
# solph.Sink(label='excess_1', inputs={ |
|
62
|
|
|
# bus_1: solph.Flow()}) |
|
63
|
|
|
|
|
64
|
|
|
# parameter |
|
65
|
|
|
p_install_min = 20 |
|
66
|
|
|
p_install_max = 35000 |
|
67
|
|
|
c_fix = 2000 |
|
68
|
|
|
c_var = 180 |
|
69
|
|
|
eta = 0.8 |
|
70
|
|
|
|
|
71
|
|
|
# non offset invest |
|
72
|
|
|
trafo = solph.components.Transformer( |
|
73
|
|
|
label="transformer", |
|
74
|
|
|
inputs={bus_0: solph.Flow()}, |
|
75
|
|
|
outputs={ |
|
76
|
|
|
bus_1: solph.Flow( |
|
77
|
|
|
nominal_value=None, |
|
78
|
|
|
investment=solph.Investment( |
|
79
|
|
|
ep_costs=c_var, |
|
80
|
|
|
maximum=p_install_max, |
|
81
|
|
|
minimum=p_install_min, |
|
82
|
|
|
# existing=10, |
|
83
|
|
|
nonconvex=True, |
|
84
|
|
|
offset=c_fix, |
|
85
|
|
|
), |
|
86
|
|
|
# min=0.1, |
|
87
|
|
|
# fixed=True, |
|
88
|
|
|
# actual_value=[0.5, 0.5, 0.5, 0.5, 0.5], |
|
89
|
|
|
) |
|
90
|
|
|
}, |
|
91
|
|
|
conversion_factors={bus_1: eta}, |
|
92
|
|
|
) |
|
93
|
|
|
es.add(trafo) |
|
94
|
|
|
# create an optimization problem and solve it |
|
95
|
|
|
om = solph.Model(es) |
|
96
|
|
|
|
|
97
|
|
|
# export lp file |
|
98
|
|
|
filename = os.path.join( |
|
99
|
|
|
solph.helpers.extend_basic_path("lp_files"), "OffsetInvestor.lp" |
|
100
|
|
|
) |
|
101
|
|
|
logging.info("Store lp-file in {0}.".format(filename)) |
|
102
|
|
|
om.write(filename, io_options={"symbolic_solver_labels": True}) |
|
103
|
|
|
|
|
104
|
|
|
# solve model |
|
105
|
|
|
om.solve(solver="cbc", solve_kwargs={"tee": True}) |
|
106
|
|
|
|
|
107
|
|
|
# create result object |
|
108
|
|
|
results = solph.processing.results(om) |
|
109
|
|
|
|
|
110
|
|
|
bus1 = solph.views.node(results, "bus_1")["sequences"] |
|
111
|
|
|
|
|
112
|
|
|
# plot the time series (sequences) of a specific component/bus |
|
113
|
|
|
if plt is not None: |
|
114
|
|
|
bus1.plot(kind="line", drawstyle="steps-mid") |
|
115
|
|
|
plt.legend() |
|
116
|
|
|
plt.show() |
|
117
|
|
|
|
|
118
|
|
|
# Nachvollziehen der Berechnung |
|
119
|
|
|
# Kosten Invest |
|
120
|
|
|
p_invest = solph.views.node(results, "transformer")["scalars"][ |
|
121
|
|
|
(("transformer", "bus_1"), "invest") |
|
122
|
|
|
] |
|
123
|
|
|
invest_binary = solph.views.node(results, "transformer")["scalars"][ |
|
124
|
|
|
(("transformer", "bus_1"), "invest_status") |
|
125
|
|
|
] |
|
126
|
|
|
c_invest = p_invest * c_var + c_fix * invest_binary |
|
127
|
|
|
|
|
128
|
|
|
# costs analysis |
|
129
|
|
|
e_source_0 = solph.views.node(results, "source_0")["sequences"][ |
|
130
|
|
|
(("source_0", "bus_0"), "flow") |
|
131
|
|
|
].sum() |
|
132
|
|
|
c_source_0 = c_0 * e_source_0 |
|
133
|
|
|
e_source_1 = solph.views.node(results, "source_1")["sequences"][ |
|
134
|
|
|
(("source_1", "bus_1"), "flow") |
|
135
|
|
|
].sum() |
|
136
|
|
|
c_source_1 = c_1 * e_source_1 |
|
137
|
|
|
|
|
138
|
|
|
c_total = c_invest + c_source_0 + c_source_1 |
|
139
|
|
|
|
|
140
|
|
|
es.results["meta"] = solph.processing.meta_results(om) |
|
141
|
|
|
objective = pd.DataFrame.from_dict(es.results["meta"]).at[ |
|
142
|
|
|
"Lower bound", "objective" |
|
143
|
|
|
] |
|
144
|
|
|
|
|
145
|
|
|
print(" objective:", objective) |
|
146
|
|
|
print(" berechnet:", c_total) |
|
147
|
|
|
|
|
148
|
|
|
print("") |
|
149
|
|
|
print("Max. zulässige Investleistung", p_install_max) |
|
150
|
|
|
print("Erforderlicher Mindest-Invest", p_install_min) |
|
151
|
|
|
print("Installierte Leistung:", p_invest) |
|
152
|
|
|
print( |
|
153
|
|
|
"Maximale Leistung - demand:", |
|
154
|
|
|
solph.views.node(results, "bus_1")["sequences"][ |
|
155
|
|
|
(("bus_1", "demand"), "flow") |
|
156
|
|
|
].max(), |
|
157
|
|
|
) |
|
158
|
|
|
print( |
|
159
|
|
|
"Maximale Leistung im Einsatz", |
|
160
|
|
|
solph.views.node(results, "transformer")["sequences"][ |
|
161
|
|
|
(("transformer", "bus_1"), "flow") |
|
162
|
|
|
].max(), |
|
163
|
|
|
) |
|
164
|
|
|
if p_invest > max(data): |
|
165
|
|
|
print("Anlage wurde überdimensioniert") |
|
166
|
|
|
|
|
167
|
|
|
|
|
168
|
|
|
if __name__ == "__main__": |
|
169
|
|
|
main() |
|
170
|
|
|
|