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

variable_chp.main()   B

Complexity

Conditions 4

Size

Total Lines 361
Code Lines 246

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 246
dl 0
loc 361
rs 7
c 0
b 0
f 0
cc 4
nop 0

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