Passed
Pull Request — dev (#850)
by Uwe
01:30
created

simple_dispatch   A

Complexity

Total Complexity 4

Size/Duplication

Total Lines 278
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 4
eloc 150
dl 0
loc 278
rs 10
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B main() 0 224 4
1
# -*- coding: utf-8 -*-
2
3
"""
4
General description
5
-------------------
6
This example shows how to create an energysystem with oemof objects and
7
solve it with the solph module. Results are plotted with solph.
8
9
Dispatch modelling is a typical thing to do with solph. However cost does not
10
have to be monetary but can be emissions etc. In this example a least cost
11
dispatch of different generators that meet an inelastic demand is undertaken.
12
Some of the generators are renewable energies with marginal costs of zero.
13
Additionally, it shows how combined heat and power units may be easily modelled
14
as well.
15
16
Data
17
----
18
input_data.csv
19
20
Installation requirements
21
-------------------------
22
23
This example requires oemof.solph (v0.5.x), install by:
24
25
    pip install oemof.solph[examples]
26
27
28
License
29
-------
30
`MIT license <https://github.com/oemof/oemof-solph/blob/dev/LICENSE>`_
31
"""
32
33
import os
34
import warnings
35
36
import matplotlib.pyplot as plt
37
import pandas as pd
38
39
from oemof.solph import Bus
40
from oemof.solph import EnergySystem
41
from oemof.solph import Flow
42
from oemof.solph import Model
43
from oemof.solph import create_time_index
44
from oemof.solph import views
45
from oemof.solph.components import Sink
46
from oemof.solph.components import Source
47
from oemof.solph.components import Transformer
48
49
50
def main():
51
    # Read data file
52
    filename = os.path.join(os.getcwd(), "input_data.csv")
53
    try:
54
        data = pd.read_csv(filename)
55
    except FileNotFoundError:
56
        msg = "Data file not found: {0}. Only one value used!"
57
        warnings.warn(msg.format(filename), UserWarning)
58
        data = pd.DataFrame(
59
            {
60
                "pv": [0.3, 0.7],
61
                "wind": [0.6, 0.5],
62
                "demand_el": [500, 400],
63
                "demand_th": [400, 300],
64
            }
65
        )
66
67
    solver = "cbc"
68
69
    # Create an energy system and optimize the dispatch at least costs.
70
    # ####################### initialize and provide data #####################
71
    datetimeindex = create_time_index(2016, number=len(data))
72
    energysystem = EnergySystem(
73
        timeindex=datetimeindex, infer_last_interval=False
74
    )
75
76
    # ######################### create energysystem components ################
77
78
    # resource buses
79
    bcoal = Bus(label="coal", balanced=False)
80
    bgas = Bus(label="gas", balanced=False)
81
    boil = Bus(label="oil", balanced=False)
82
    blig = Bus(label="lignite", balanced=False)
83
84
    # electricity and heat
85
    bel = Bus(label="bel")
86
    bth = Bus(label="bth")
87
88
    energysystem.add(bcoal, bgas, boil, blig, bel, bth)
89
90
    # an excess and a shortage variable can help to avoid infeasible problems
91
    energysystem.add(Sink(label="excess_el", inputs={bel: Flow()}))
92
    # shortage_el = Source(label='shortage_el',
93
    #                      outputs={bel: Flow(variable_costs=200)})
94
95
    # sources
96
    energysystem.add(
97
        Source(
98
            label="wind",
99
            outputs={bel: Flow(fix=data["wind"], nominal_value=66.3)},
100
        )
101
    )
102
103
    energysystem.add(
104
        Source(
105
            label="pv", outputs={bel: Flow(fix=data["pv"], nominal_value=65.3)}
106
        )
107
    )
108
109
    # demands (electricity/heat)
110
    energysystem.add(
111
        Sink(
112
            label="demand_el",
113
            inputs={bel: Flow(nominal_value=85, fix=data["demand_el"])},
114
        )
115
    )
116
117
    energysystem.add(
118
        Sink(
119
            label="demand_th",
120
            inputs={bth: Flow(nominal_value=40, fix=data["demand_th"])},
121
        )
122
    )
123
124
    # power plants
125
    energysystem.add(
126
        Transformer(
127
            label="pp_coal",
128
            inputs={bcoal: Flow()},
129
            outputs={bel: Flow(nominal_value=20.2, variable_costs=25)},
130
            conversion_factors={bel: 0.39},
131
        )
132
    )
133
134
    energysystem.add(
135
        Transformer(
136
            label="pp_lig",
137
            inputs={blig: Flow()},
138
            outputs={bel: Flow(nominal_value=11.8, variable_costs=19)},
139
            conversion_factors={bel: 0.41},
140
        )
141
    )
142
143
    energysystem.add(
144
        Transformer(
145
            label="pp_gas",
146
            inputs={bgas: Flow()},
147
            outputs={bel: Flow(nominal_value=41, variable_costs=40)},
148
            conversion_factors={bel: 0.50},
149
        )
150
    )
151
152
    energysystem.add(
153
        Transformer(
154
            label="pp_oil",
155
            inputs={boil: Flow()},
156
            outputs={bel: Flow(nominal_value=5, variable_costs=50)},
157
            conversion_factors={bel: 0.28},
158
        )
159
    )
160
161
    # combined heat and power plant (chp)
162
    energysystem.add(
163
        Transformer(
164
            label="pp_chp",
165
            inputs={bgas: Flow()},
166
            outputs={
167
                bel: Flow(nominal_value=30, variable_costs=42),
168
                bth: Flow(nominal_value=40),
169
            },
170
            conversion_factors={bel: 0.3, bth: 0.4},
171
        )
172
    )
173
174
    # heat pump with a coefficient of performance (COP) of 3
175
    b_heat_source = Bus(label="b_heat_source")
176
    energysystem.add(b_heat_source)
177
178
    energysystem.add(
179
        Source(label="heat_source", outputs={b_heat_source: Flow()})
180
    )
181
182
    cop = 3
183
    energysystem.add(
184
        Transformer(
185
            label="heat_pump",
186
            inputs={bel: Flow(), b_heat_source: Flow()},
187
            outputs={bth: Flow(nominal_value=10)},
188
            conversion_factors={bel: 1 / 3, b_heat_source: (cop - 1) / cop},
189
        )
190
    )
191
192
    # ################################ optimization ###########################
193
194
    # create optimization model based on energy_system
195
    optimization_model = Model(energysystem=energysystem)
196
197
    # solve problem
198
    optimization_model.solve(
199
        solver=solver, solve_kwargs={"tee": True, "keepfiles": False}
200
    )
201
202
    # write back results from optimization object to energysystem
203
    optimization_model.results()
204
205
    # ################################ results ################################
206
207
    # subset of results that includes all flows into and from electrical bus
208
    # sequences are stored within a pandas.DataFrames and scalars e.g.
209
    # investment values within a pandas.Series object.
210
    # in this case the entry data['scalars'] does not exist since no investment
211
    # variables are used
212
    data = views.node(optimization_model.results(), "bel")
213
    data["sequences"].info()
214
    print("Optimization successful. Showing some results:")
215
216
    # see: https://pandas.pydata.org/pandas-docs/stable/visualization.html
217
    node_results_bel = views.node(optimization_model.results(), "bel")
218
    node_results_flows = node_results_bel["sequences"]
219
220
    fig, ax = plt.subplots(figsize=(10, 5))
221
    node_results_flows.plot(
222
        ax=ax, kind="bar", stacked=True, linewidth=0, width=1
223
    )
224
    ax.set_title("Sums for optimization period")
225
    ax.legend(loc="upper right", bbox_to_anchor=(1, 1))
226
    ax.set_xlabel("Energy (MWh)")
227
    ax.set_ylabel("Flow")
228
    plt.legend(loc="center left", prop={"size": 8}, bbox_to_anchor=(1, 0.5))
229
    fig.subplots_adjust(right=0.8)
230
231
    dates = node_results_flows.index
232
    tick_distance = int(len(dates) / 7) - 1
233
    ax.set_xticks(range(0, len(dates), tick_distance), minor=False)
234
    if tick_distance > 0:
235
        ax.set_xticklabels(
236
            [
237
                item.strftime("%d-%m-%Y")
238
                for item in dates.tolist()[0::tick_distance]
239
            ],
240
            rotation=90,
241
            minor=False,
242
        )
243
244
    plt.show()
245
246
    node_results_bth = views.node(optimization_model.results(), "bth")
247
    node_results_flows = node_results_bth["sequences"]
248
249
    fig, ax = plt.subplots(figsize=(10, 5))
250
    node_results_flows.plot(
251
        ax=ax, kind="bar", stacked=True, linewidth=0, width=1
252
    )
253
    ax.set_title("Sums for optimization period")
254
    ax.legend(loc="upper right", bbox_to_anchor=(1, 1))
255
    ax.set_xlabel("Energy (MWh)")
256
    ax.set_ylabel("Flow")
257
    plt.legend(loc="center left", prop={"size": 8}, bbox_to_anchor=(1, 0.5))
258
    fig.subplots_adjust(right=0.8)
259
260
    dates = node_results_flows.index
261
    tick_distance = int(len(dates) / 7) - 1
262
    ax.set_xticks(range(0, len(dates), tick_distance), minor=False)
263
    if tick_distance > 0:
264
        ax.set_xticklabels(
265
            [
266
                item.strftime("%d-%m-%Y")
267
                for item in dates.tolist()[0::tick_distance]
268
            ],
269
            rotation=90,
270
            minor=False,
271
        )
272
273
    plt.show()
274
275
276
if __name__ == "__main__":
277
    main()
278