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

basic_example.main()   B

Complexity

Conditions 3

Size

Total Lines 215
Code Lines 107

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 107
dl 0
loc 215
rs 7
c 0
b 0
f 0
cc 3
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
7
A basic example to show how to model a simple energy system with oemof.solph.
8
9
The following energy system is modeled:
10
11
.. code-block:: text
12
13
                     input/output  bgas     bel
14
                         |          |        |
15
                         |          |        |
16
     wind(FixedSource)   |------------------>|
17
                         |          |        |
18
     pv(FixedSource)     |------------------>|
19
                         |          |        |
20
     rgas(Commodity)     |--------->|        |
21
                         |          |        |
22
     demand(Sink)        |<------------------|
23
                         |          |        |
24
                         |          |        |
25
     pp_gas(Transformer) |<---------|        |
26
                         |------------------>|
27
                         |          |        |
28
     storage(Storage)    |<------------------|
29
                         |------------------>|
30
31
32
Data
33
----
34
basic_example.csv
35
36
37
Installation requirements
38
-------------------------
39
This example requires oemof.solph (v0.5.x), install by:
40
41
    pip install oemof.solph[examples]
42
43
License
44
-------
45
`MIT license <https://github.com/oemof/oemof-solph/blob/dev/LICENSE>`_
46
"""
47
###########################################################################
48
# imports
49
###########################################################################
50
51
import logging
52
import os
53
import pprint as pp
54
import warnings
55
from datetime import datetime
56
57
import matplotlib.pyplot as plt
58
import pandas as pd
59
from oemof.tools import logger
60
61
from oemof.solph import EnergySystem
62
from oemof.solph import Model
63
from oemof.solph import buses
64
from oemof.solph import components as cmp
65
from oemof.solph import create_time_index
66
from oemof.solph import flows
67
from oemof.solph import helpers
68
from oemof.solph import processing
69
from oemof.solph import views
70
71
72
def main():
73
    # *************************************************************************
74
    # ********** PART 1 - Define and optimise the energy system ***************
75
    # *************************************************************************
76
77
    # Read data file
78
79
    filename = os.path.join(os.getcwd(), "basic_example.csv")
80
    try:
81
        data = pd.read_csv(filename)
82
    except FileNotFoundError:
83
        msg = "Data file not found: {0}. Only one value used!"
84
        warnings.warn(msg.format(filename), UserWarning)
85
        data = pd.DataFrame({"pv": [0.3], "wind": [0.6], "demand_el": [500]})
86
87
    solver = "cbc"  # 'glpk', 'gurobi',....
88
    debug = False  # Set number_of_timesteps to 3 to get a readable lp-file.
89
    number_of_time_steps = len(data)
90
    solver_verbose = False  # show/hide solver output
91
92
    # initiate the logger (see the API docs for more information)
93
    logger.define_logging(
94
        logfile="oemof_example.log",
95
        screen_level=logging.INFO,
96
        file_level=logging.INFO,
97
    )
98
99
    logging.info("Initialize the energy system")
100
    date_time_index = create_time_index(2012, number=number_of_time_steps)
101
102
    energysystem = EnergySystem(
103
        timeindex=date_time_index, infer_last_interval=False
104
    )
105
106
    ##########################################################################
107
    # Create oemof object
108
    ##########################################################################
109
110
    logging.info("Create oemof objects")
111
112
    # The bus objects were assigned to variables which makes it easier to
113
    # connect components to these buses (see below).
114
115
    # create natural gas bus
116
    bgas = buses.Bus(label="natural_gas")
117
118
    # create electricity bus
119
    bel = buses.Bus(label="electricity")
120
121
    # adding the buses to the energy system
122
    energysystem.add(bgas, bel)
123
124
    # create excess component for the electricity bus to allow overproduction
125
    energysystem.add(cmp.Sink(label="excess_bel", inputs={bel: flows.Flow()}))
126
127
    # create source object representing the gas commodity (annual limit)
128
    energysystem.add(
129
        cmp.Source(
130
            label="rgas",
131
            outputs={bgas: flows.Flow()},
132
        )
133
    )
134
135
    # create fixed source object representing wind power plants
136
    energysystem.add(
137
        cmp.Source(
138
            label="wind",
139
            outputs={bel: flows.Flow(fix=data["wind"], nominal_value=1000000)},
140
        )
141
    )
142
143
    # create fixed source object representing pv power plants
144
    energysystem.add(
145
        cmp.Source(
146
            label="pv",
147
            outputs={bel: flows.Flow(fix=data["pv"], nominal_value=582000)},
148
        )
149
    )
150
151
    # create simple sink object representing the electrical demand
152
    energysystem.add(
153
        cmp.Sink(
154
            label="demand",
155
            inputs={bel: flows.Flow(fix=data["demand_el"], nominal_value=1)},
156
        )
157
    )
158
159
    # create simple transformer object representing a gas power plant
160
    energysystem.add(
161
        cmp.Transformer(
162
            label="pp_gas",
163
            inputs={bgas: flows.Flow()},
164
            outputs={bel: flows.Flow(nominal_value=10e10, variable_costs=50)},
165
            conversion_factors={bel: 0.58},
166
        )
167
    )
168
169
    # create storage object representing a battery
170
    storage = cmp.GenericStorage(
171
        nominal_storage_capacity=10077997,
172
        label="storage",
173
        inputs={bel: flows.Flow(nominal_value=10077997 / 6)},
174
        outputs={
175
            bel: flows.Flow(nominal_value=10077997 / 6, variable_costs=0.001)
176
        },
177
        loss_rate=0.00,
178
        initial_storage_level=None,
179
        inflow_conversion_factor=1,
180
        outflow_conversion_factor=0.8,
181
    )
182
183
    energysystem.add(storage)
184
185
    ##########################################################################
186
    # Optimise the energy system and plot the results
187
    ##########################################################################
188
189
    logging.info("Optimise the energy system")
190
191
    # initialise the operational model
192
    model = Model(energysystem)
193
194
    # This is for debugging only. It is not(!) necessary to solve the problem
195
    # and should be set to False to save time and disc space in normal use. For
196
    # debugging the timesteps should be set to 3, to increase the readability
197
    # of the lp-file.
198
    if debug:
199
        filename = os.path.join(
200
            helpers.extend_basic_path("lp_files"), "basic_example.lp"
201
        )
202
        logging.info("Store lp-file in {0}.".format(filename))
203
        model.write(filename, io_options={"symbolic_solver_labels": True})
204
205
    # if tee_switch is true solver messages will be displayed
206
    logging.info("Solve the optimization problem")
207
    model.solve(solver=solver, solve_kwargs={"tee": solver_verbose})
208
209
    logging.info("Store the energy system with the results.")
210
211
    # The processing module of the outputlib can be used to extract the results
212
    # from the model transfer them into a homogeneous structured dictionary.
213
214
    # add results to the energy system to make it possible to store them.
215
    energysystem.results["main"] = processing.results(model)
216
    energysystem.results["meta"] = processing.meta_results(model)
217
218
    # The default path is the '.oemof' folder in your $HOME directory.
219
    # The default filename is 'es_dump.oemof'.
220
    # You can omit the attributes (as None is the default value) for testing
221
    # cases. You should use unique names/folders for valuable results to avoid
222
    # overwriting.
223
224
    # store energy system with results
225
    energysystem.dump(dpath=None, filename=None)
226
227
    # *************************************************************************
228
    # ********** PART 2 - Processing the results ******************************
229
    # *************************************************************************
230
231
    logging.info("**** The script can be divided into two parts here.")
232
    logging.info("Restore the energy system and the results.")
233
    energysystem = EnergySystem()
234
    energysystem.restore(dpath=None, filename=None)
235
236
    # define an alias for shorter calls below (optional)
237
    results = energysystem.results["main"]
238
    storage = energysystem.groups["storage"]
239
240
    # print a time slice of the state of charge
241
    print("")
242
    print("********* State of Charge (slice) *********")
243
    print(
244
        results[(storage, None)]["sequences"][
245
            datetime(2012, 2, 25, 8, 0, 0) : datetime(2012, 2, 25, 17, 0, 0)
246
        ]
247
    )
248
    print("")
249
250
    # get all variables of a specific component/bus
251
    custom_storage = views.node(results, "storage")
252
    electricity_bus = views.node(results, "electricity")
253
254
    # plot the time series (sequences) of a specific component/bus
255
256
    fig, ax = plt.subplots(figsize=(10, 5))
257
    custom_storage["sequences"].plot(
258
        ax=ax, kind="line", drawstyle="steps-post"
259
    )
260
    plt.legend(
261
        loc="upper center",
262
        prop={"size": 8},
263
        bbox_to_anchor=(0.5, 1.25),
264
        ncol=2,
265
    )
266
    fig.subplots_adjust(top=0.8)
267
    plt.show()
268
269
    fig, ax = plt.subplots(figsize=(10, 5))
270
    electricity_bus["sequences"].plot(
271
        ax=ax, kind="line", drawstyle="steps-post"
272
    )
273
    plt.legend(
274
        loc="upper center", prop={"size": 8}, bbox_to_anchor=(0.5, 1.3), ncol=2
275
    )
276
    fig.subplots_adjust(top=0.8)
277
    plt.show()
278
279
    # print the solver results
280
    print("********* Meta results *********")
281
    pp.pprint(energysystem.results["meta"])
282
    print("")
283
284
    # print the sums of the flows around the electricity bus
285
    print("********* Main results *********")
286
    print(electricity_bus["sequences"].sum(axis=0))
287
288
289
if __name__ == "__main__":
290
    main()
291