Completed
Push — dev ( 468d85...f4c061 )
by Patrik
23s queued 17s
created

variable_chp.main()   C

Complexity

Conditions 5

Size

Total Lines 366
Code Lines 249

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 249
dl 0
loc 366
rs 6.5333
c 0
b 0
f 0
cc 5
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
# -*- coding: utf-8 -*-
2
3
"""
4
General description
5
-------------------
6
This example is not a real use case of an energy system but an example to show
7
how a combined heat and power plant (chp) with an extraction turbine works in
8
contrast to a chp (eg. block device) with a fixed heat fraction. Both chp
9
plants distribute power and heat to a separate heat and power Bus with a heat
10
and power demand. The i/o balance plot shows that the fixed chp plant produces
11
heat and power excess and therefore needs more natural gas. The bar plot just
12
shows the difference in the usage of natural gas.
13
14
Code
15
----
16
Download source code: :download:`variable_chp.py </../examples/variable_chp/variable_chp.py>`
17
18
.. dropdown:: Click to display code
19
20
    .. literalinclude:: /../examples/variable_chp/variable_chp.py
21
        :language: python
22
        :lines: 53-
23
24
Data
25
----
26
Download data: :download:`variable_chp.csv </../examples/variable_chp/variable_chp.csv>`
27
28
Installation requirements
29
-------------------------
30
31
This example requires oemof.solph (v0.5.x), install by:
32
33
.. code:: bash
34
35
    pip install oemof.solph[examples]
36
37
Optional to see the i/o balance plot:
38
39
.. code:: bash
40
41
    pip install git+https://github.com/oemof/oemof_visio.git
42
43
License
44
-------
45
`MIT license <https://github.com/oemof/oemof-solph/blob/dev/LICENSE>`_
46
47
"""
48
49
###############################################################################
50
# imports
51
###############################################################################
52
53
import logging
54
import os
55
import warnings
56
57
import matplotlib.pyplot as plt
58
import pandas as pd
59
from oemof.tools import logger
60
61
from oemof import solph
62
63
# import oemof plots
64
try:
65
    from oemof.visio import plot as oeplot
66
except ImportError:
67
    oeplot = None
68
69
70
def shape_legend(node, reverse=True, **kwargs):
71
    handels = kwargs["handles"]
72
    labels = kwargs["labels"]
73
    axes = kwargs["ax"]
74
    parameter = {}
75
76
    new_labels = []
77
    for label in labels:
78
        label = label.replace("(", "")
79
        label = label.replace("), flow)", "")
80
        label = label.replace(node, "")
81
        label = label.replace(",", "")
82
        label = label.replace(" ", "")
83
        new_labels.append(label)
84
    labels = new_labels
85
86
    parameter["bbox_to_anchor"] = kwargs.get("bbox_to_anchor", (1, 0.5))
87
    parameter["loc"] = kwargs.get("loc", "center left")
88
    parameter["ncol"] = kwargs.get("ncol", 1)
89
    plotshare = kwargs.get("plotshare", 0.9)
90
91
    if reverse:
92
        handels.reverse()
93
        labels.reverse()
94
95
    box = axes.get_position()
96
    axes.set_position([box.x0, box.y0, box.width * plotshare, box.height])
97
98
    parameter["handles"] = handels
99
    parameter["labels"] = labels
100
    axes.legend(**parameter)
101
    return axes
102
103
104
def write_lp_file(model):
105
    lp_filename = os.path.join(
106
        solph.helpers.extend_basic_path("lp_files"), "variable_chp.lp"
107
    )
108
    logging.info("Store lp-file in {0}.".format(lp_filename))
109
    model.write(lp_filename, io_options={"symbolic_solver_labels": True})
110
111
112
def main(optimize=True):
113
    # Read data file
114
    filename = os.path.join(os.getcwd(), "variable_chp.csv")
115
    try:
116
        data = pd.read_csv(filename)
117
    except FileNotFoundError:
118
        msg = "Data file not found: {0}. Only one value used!"
119
        warnings.warn(msg.format(filename), UserWarning)
120
        data = pd.DataFrame(
121
            {
122
                "pv": [0.3],
123
                "wind": [0.6],
124
                "demand_el": [500],
125
                "demand_th": [344],
126
            }
127
        )
128
129
    logger.define_logging()
130
    logging.info("Initialize the energy system")
131
132
    # create time index for 192 hours in May.
133
    date_time_index = solph.create_time_index(2012, number=len(data))
134
135
    energysystem = solph.EnergySystem(
136
        timeindex=date_time_index, infer_last_interval=False
137
    )
138
139
    ##########################################################################
140
    # Create oemof.solph objects
141
    ##########################################################################
142
    logging.info("Create oemof.solph objects")
143
144
    # container for instantiated nodes
145
    noded = dict()
146
147
    # create natural gas bus
148
    noded["bgas"] = solph.Bus(label="natural_gas")
149
150
    # create commodity object for gas resource
151
    noded["rgas"] = solph.components.Source(
152
        label="rgas", outputs={noded["bgas"]: solph.Flow(variable_costs=50)}
153
    )
154
155
    # create two electricity buses and two heat buses
156
    noded["bel"] = solph.Bus(label="electricity")
157
    noded["bel2"] = solph.Bus(label="electricity_2")
158
    noded["bth"] = solph.Bus(label="heat")
159
    noded["bth2"] = solph.Bus(label="heat_2")
160
161
    # create excess components for the elec/heat bus to allow overproduction
162
    noded["excess_bth_2"] = solph.components.Sink(
163
        label="excess_bth_2", inputs={noded["bth2"]: solph.Flow()}
164
    )
165
    noded["excess_therm"] = solph.components.Sink(
166
        label="excess_therm", inputs={noded["bth"]: solph.Flow()}
167
    )
168
    noded["excess_bel_2"] = solph.components.Sink(
169
        label="excess_bel_2", inputs={noded["bel2"]: solph.Flow()}
170
    )
171
    noded["excess_elec"] = solph.components.Sink(
172
        label="excess_elec", inputs={noded["bel"]: solph.Flow()}
173
    )
174
175
    # create simple sink object for electrical demand for each electrical bus
176
    noded["demand_elec"] = solph.components.Sink(
177
        label="demand_elec",
178
        inputs={
179
            noded["bel"]: solph.Flow(fix=data["demand_el"], nominal_capacity=1)
180
        },
181
    )
182
    noded["demand_el_2"] = solph.components.Sink(
183
        label="demand_el_2",
184
        inputs={
185
            noded["bel2"]: solph.Flow(
186
                fix=data["demand_el"], nominal_capacity=1
187
            )
188
        },
189
    )
190
191
    # create simple sink object for heat demand for each thermal bus
192
    noded["demand_therm"] = solph.components.Sink(
193
        label="demand_therm",
194
        inputs={
195
            noded["bth"]: solph.Flow(
196
                fix=data["demand_th"], nominal_capacity=741000
197
            )
198
        },
199
    )
200
    noded["demand_therm_2"] = solph.components.Sink(
201
        label="demand_th_2",
202
        inputs={
203
            noded["bth2"]: solph.Flow(
204
                fix=data["demand_th"], nominal_capacity=741000
205
            )
206
        },
207
    )
208
209
    # This is just a dummy Converter with a nominal input of zero
210
    noded["fixed_chp_gas"] = solph.components.Converter(
211
        label="fixed_chp_gas",
212
        inputs={noded["bgas"]: solph.Flow(nominal_capacity=0)},
213
        outputs={noded["bel"]: solph.Flow(), noded["bth"]: solph.Flow()},
214
        conversion_factors={noded["bel"]: 0.3, noded["bth"]: 0.5},
215
    )
216
217
    # create a fixed Converter to distribute to the heat_2 and elec_2 buses
218
    noded["fixed_chp_gas_2"] = solph.components.Converter(
219
        label="fixed_chp_gas_2",
220
        inputs={noded["bgas"]: solph.Flow(nominal_capacity=10e10)},
221
        outputs={noded["bel2"]: solph.Flow(), noded["bth2"]: solph.Flow()},
222
        conversion_factors={noded["bel2"]: 0.3, noded["bth2"]: 0.5},
223
    )
224
225
    # create a fixed Converter to distribute to the heat and elec buses
226
    noded["variable_chp_gas"] = solph.components.ExtractionTurbineCHP(
227
        label="variable_chp_gas",
228
        inputs={noded["bgas"]: solph.Flow(nominal_capacity=10e10)},
229
        outputs={noded["bel"]: solph.Flow(), noded["bth"]: solph.Flow()},
230
        conversion_factors={noded["bel"]: 0.3, noded["bth"]: 0.5},
231
        conversion_factor_full_condensation={noded["bel"]: 0.5},
232
    )
233
234
    ##########################################################################
235
    # Optimise the energy system
236
    ##########################################################################
237
238
    if optimize is False:
239
        return energysystem
240
241
    logging.info("Optimise the energy system")
242
243
    energysystem.add(*noded.values())
244
245
    om = solph.Model(energysystem)
246
247
    # If uncomment the following line you can store the lp file but you should
248
    # use less timesteps (3) to make it better readable and smaller.
249
    # write_lp_file(om)
250
251
    logging.info("Solve the optimization problem")
252
    om.solve(solver="cbc", solve_kwargs={"tee": False})
253
254
    results = solph.processing.results(om)
255
256
    ##########################################################################
257
    # Plot the results
258
    ##########################################################################
259
260
    myresults = solph.views.node(results, "natural_gas")
261
    myresults = myresults["sequences"].sum(axis=0)
262
    myresults = myresults.drop(myresults.index[0]).reset_index(drop=True)
263
    myresults.rename({0: "fixed", 1: "variable", 2: "total"}, inplace=True)
264
    myresults.plot(kind="bar", rot=0, title="Usage of natural gas")
265
    plt.show()
266
267
    # Create a plot with 6 tiles that shows the difference between the
268
    # Converter and the ExtractionTurbineCHP used for chp plants.
269
    smooth_plot = True
270
271
    if oeplot:
272
        logging.info("Plot the results")
273
274
        cdict = {
275
            (("variable_chp_gas", "electricity"), "flow"): "#42c77a",
276
            (("fixed_chp_gas_2", "electricity_2"), "flow"): "#20b4b6",
277
            (("fixed_chp_gas", "electricity"), "flow"): "#20b4b6",
278
            (("fixed_chp_gas", "heat"), "flow"): "#20b4b6",
279
            (("variable_chp_gas", "heat"), "flow"): "#42c77a",
280
            (("heat", "demand_therm"), "flow"): "#5b5bae",
281
            (("heat_2", "demand_th_2"), "flow"): "#5b5bae",
282
            (("electricity", "demand_elec"), "flow"): "#5b5bae",
283
            (("electricity_2", "demand_el_2"), "flow"): "#5b5bae",
284
            (("heat", "excess_therm"), "flow"): "#f22222",
285
            (("heat_2", "excess_bth_2"), "flow"): "#f22222",
286
            (("electricity", "excess_elec"), "flow"): "#f22222",
287
            (("electricity_2", "excess_bel_2"), "flow"): "#f22222",
288
            (("fixed_chp_gas_2", "heat_2"), "flow"): "#20b4b6",
289
        }
290
291
        fig = plt.figure(figsize=(18, 9))
292
        plt.rc("legend", **{"fontsize": 13})
293
        plt.rcParams.update({"font.size": 13})
294
        fig.subplots_adjust(
295
            left=0.07,
296
            bottom=0.12,
297
            right=0.86,
298
            top=0.93,
299
            wspace=0.03,
300
            hspace=0.2,
301
        )
302
303
        # subplot of electricity bus (fixed chp) [1]
304
        electricity_2 = solph.views.node(results, "electricity_2")
305
        x_length = len(electricity_2["sequences"].index)
306
        myplot = oeplot.io_plot(
307
            bus_label="electricity_2",
308
            df=electricity_2["sequences"],
309
            cdict=cdict,
310
            smooth=smooth_plot,
311
            line_kwa={"linewidth": 4},
312
            ax=fig.add_subplot(3, 2, 1),
313
            inorder=[(("fixed_chp_gas_2", "electricity_2"), "flow")],
314
            outorder=[
315
                (("electricity_2", "demand_el_2"), "flow"),
316
                (("electricity_2", "excess_bel_2"), "flow"),
317
            ],
318
        )
319
        myplot["ax"].set_ylabel("Power in MW")
320
        myplot["ax"].set_xlabel("")
321
        myplot["ax"].get_xaxis().set_visible(False)
322
        myplot["ax"].set_xlim(0, x_length)
323
        myplot["ax"].set_title("Electricity output (fixed chp)")
324
        myplot["ax"].legend_.remove()
325
326
        # subplot of electricity bus (variable chp) [2]
327
        electricity = solph.views.node(results, "electricity")
328
        myplot = oeplot.io_plot(
329
            bus_label="electricity",
330
            df=electricity["sequences"],
331
            cdict=cdict,
332
            smooth=smooth_plot,
333
            line_kwa={"linewidth": 4},
334
            ax=fig.add_subplot(3, 2, 2),
335
            inorder=[
336
                (("fixed_chp_gas", "electricity"), "flow"),
337
                (("variable_chp_gas", "electricity"), "flow"),
338
            ],
339
            outorder=[
340
                (("electricity", "demand_elec"), "flow"),
341
                (("electricity", "excess_elec"), "flow"),
342
            ],
343
        )
344
        myplot["ax"].get_yaxis().set_visible(False)
345
        myplot["ax"].set_xlabel("")
346
        myplot["ax"].get_xaxis().set_visible(False)
347
        myplot["ax"].set_title("Electricity output (variable chp)")
348
        myplot["ax"].set_xlim(0, x_length)
349
        shape_legend("electricity", plotshare=1, **myplot)
350
351
        # subplot of heat bus (fixed chp) [3]
352
        heat_2 = solph.views.node(results, "heat_2")
353
        myplot = oeplot.io_plot(
354
            bus_label="heat_2",
355
            df=heat_2["sequences"],
356
            cdict=cdict,
357
            smooth=smooth_plot,
358
            line_kwa={"linewidth": 4},
359
            ax=fig.add_subplot(3, 2, 3),
360
            inorder=[(("fixed_chp_gas_2", "heat_2"), "flow")],
361
            outorder=[
362
                (("heat_2", "demand_th_2"), "flow"),
363
                (("heat_2", "excess_bth_2"), "flow"),
364
            ],
365
        )
366
        myplot["ax"].set_ylabel("Power in MW")
367
        myplot["ax"].set_ylim([0, 600000])
368
        myplot["ax"].get_xaxis().set_visible(False)
369
        myplot["ax"].set_title("Heat output (fixed chp)")
370
        myplot["ax"].set_xlim(0, x_length)
371
        myplot["ax"].legend_.remove()
372
373
        # subplot of heat bus (variable chp) [4]
374
        heat = solph.views.node(results, "heat")
375
        myplot = oeplot.io_plot(
376
            bus_label="heat",
377
            df=heat["sequences"],
378
            cdict=cdict,
379
            smooth=smooth_plot,
380
            line_kwa={"linewidth": 4},
381
            ax=fig.add_subplot(3, 2, 4),
382
            inorder=[
383
                (("fixed_chp_gas", "heat"), "flow"),
384
                (("variable_chp_gas", "heat"), "flow"),
385
            ],
386
            outorder=[
387
                (("heat", "demand_therm"), "flow"),
388
                (("heat", "excess_therm"), "flow"),
389
            ],
390
        )
391
        myplot["ax"].set_ylim([0, 600000])
392
        myplot["ax"].get_yaxis().set_visible(False)
393
        myplot["ax"].get_xaxis().set_visible(False)
394
        myplot["ax"].set_title("Heat output (variable chp)")
395
        myplot["ax"].set_xlim(0, x_length)
396
        shape_legend("heat", plotshare=1, **myplot)
397
398
        if smooth_plot:
399
            style = None
400
        else:
401
            style = "steps-mid"
402
403
        # subplot of efficiency (fixed chp) [5]
404
        fix_chp_gas2 = solph.views.node(results, "fixed_chp_gas_2")
405
        ngas = fix_chp_gas2["sequences"][
406
            (("natural_gas", "fixed_chp_gas_2"), "flow")
407
        ]
408
        elec = fix_chp_gas2["sequences"][
409
            (("fixed_chp_gas_2", "electricity_2"), "flow")
410
        ]
411
        heat = fix_chp_gas2["sequences"][
412
            (("fixed_chp_gas_2", "heat_2"), "flow")
413
        ]
414
        e_ef = elec.div(ngas)
415
        h_ef = heat.div(ngas)
416
        df = pd.DataFrame(pd.concat([h_ef, e_ef], axis=1))
417
        my_ax = df.reset_index(drop=True).plot(
418
            drawstyle=style, ax=fig.add_subplot(3, 2, 5), linewidth=2
419
        )
420
        my_ax.set_ylabel("efficiency")
421
        my_ax.set_ylim([0, 0.55])
422
        my_ax.set_xlabel("May 2012")
423
        my_ax = oeplot.set_datetime_ticks(
424
            my_ax,
425
            df.index,
426
            tick_distance=24,
427
            date_format="%d",
428
            offset=12,
429
            tight=True,
430
        )
431
        my_ax.set_title("Efficiency (fixed chp)")
432
        my_ax.legend_.remove()
433
434
        # subplot of efficiency (variable chp) [6]
435
        var_chp_gas = solph.views.node(results, "variable_chp_gas")
436
        ngas = var_chp_gas["sequences"][
437
            (("natural_gas", "variable_chp_gas"), "flow")
438
        ]
439
        elec = var_chp_gas["sequences"][
440
            (("variable_chp_gas", "electricity"), "flow")
441
        ]
442
        heat = var_chp_gas["sequences"][(("variable_chp_gas", "heat"), "flow")]
443
        e_ef = elec.div(ngas)
444
        h_ef = heat.div(ngas)
445
        e_ef.name = "electricity           "
446
        h_ef.name = "heat"
447
        df = pd.DataFrame(pd.concat([h_ef, e_ef], axis=1))
448
        my_ax = df.reset_index(drop=True).plot(
449
            drawstyle=style, ax=fig.add_subplot(3, 2, 6), linewidth=2
450
        )
451
        my_ax.set_ylim([0, 0.55])
452
        my_ax = oeplot.set_datetime_ticks(
453
            my_ax,
454
            df.index,
455
            tick_distance=24,
456
            date_format="%d",
457
            offset=12,
458
            tight=True,
459
        )
460
        my_ax.get_yaxis().set_visible(False)
461
        my_ax.set_xlabel("May 2012")
462
463
        my_ax.set_title("Efficiency (variable chp)")
464
        my_box = my_ax.get_position()
465
        my_ax.set_position(
466
            [my_box.x0, my_box.y0, my_box.width * 1, my_box.height]
467
        )
468
        my_ax.legend(loc="center left", bbox_to_anchor=(1, 0.5), ncol=1)
469
470
        plt.show()
471
472
    else:
473
        logging.warning(
474
            "You have to install 'oemof-visio' to see the i/o-plot"
475
        )
476
        logging.warning(
477
            "Use: pip install git+https://github.com/oemof/oemof_visio.git"
478
        )
479
480
481
if __name__ == "__main__":
482
    main()
483