Passed
Pull Request — dev (#1174)
by Patrik
02:01
created

example_generic_invest_offset   A

Complexity

Total Complexity 3

Size/Duplication

Total Lines 275
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 3
eloc 130
dl 0
loc 275
rs 10
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B main() 0 187 3
1
# -*- coding: utf-8 -*-
2
r"""
3
General description
4
-------------------
5
Example that shows how to use "Generic Investment Limit With Offset".
6
7
There are two supply chains. The energy systems looks like that:
8
9
.. code-block:: text
10
11
                  bus_a_0          bus_a_1
12
                   |                 |
13
    source_a_0 --->|---> trafo_a --->|--->demand_a
14
                                     |
15
                       source_a_1--->|
16
                                     |
17
18
                  bus_b_0          bus_b_1
19
                   |                 |
20
    source_b_0 --->|---> trafo_b --->|--->demand_b
21
                                     |
22
                       source_b_1--->|
23
                                     |
24
                                     v
25
                              generic_storage_b
26
                               /            \
27
                              |              |
28
                              v              v
29
                            bus_b_1        bus_b_1
30
31
32
Everything is identical - the costs for the sources, the demand, the efficiency
33
of the Converter. And both Converter have an investment at the output.
34
The source '\*_1' is in both cases very expensive, so that
35
a investment is probably done in the converter. The demand and the
36
maximum investment in Converter b1 is so set, that an investment in a generic
37
storage is beneficial to not use source b0.
38
Now, all investments share a third resource, which is called "space" in this
39
example. (This could be anything, and you could use as many additional
40
resources as you want.) And this resource is limited. In this case, every
41
converter and storage capacity unit, which might be installed, needs 2 space
42
for each installed capacity as well as an offset.
43
See what happens, have fun ;)
44
45
Code
46
----
47
Download source code: :download:`example_generic_invest.py </../examples/generic_invest_limit/example_generic_invest_offset.py>`
48
49
.. dropdown:: Click to display code
50
51
    .. literalinclude:: /../examples/generic_invest_limit/example_generic_invest_offset.py
52
        :language: python
53
        :lines: 62-
54
55
Installation requirements
56
-------------------------
57
This example requires oemof.solph (v0.5.x), install by:
58
59
.. code:: bash
60
61
    pip install oemof.solph[examples]
62
63
License
64
-------
65
Maximilian Hillen <[email protected]>
66
67
`MIT license <https://github.com/oemof/oemof-solph/blob/dev/LICENSE>`_
68
"""
69
70
import logging
71
import os
72
73
from PIL.ImageChops import offset
74
75
try:
76
    import matplotlib.pyplot as plt
77
except ModuleNotFoundError:
78
    plt = None
79
80
from oemof import solph
81
82
83
def main(optimize=True):
84
85
    data = [2, 2, 12, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
86
    # create an energy system
87
    idx = solph.create_time_index(2020, number=len(data))
88
    es = solph.EnergySystem(timeindex=idx, infer_last_interval=False)
89
90
    # Parameter: costs for the sources
91
    c_0 = 10
92
    c_1 = 100
93
94
    epc_invest = 50
95
96
    # commodity a
97
    bus_a_0 = solph.Bus(label="bus_a_0")
98
    bus_a_1 = solph.Bus(label="bus_a_1")
99
    es.add(bus_a_0, bus_a_1)
100
101
    es.add(
102
        solph.components.Source(
103
            label="source_a_0",
104
            outputs={bus_a_0: solph.Flow(variable_costs=c_0)},
105
        )
106
    )
107
108
    es.add(
109
        solph.components.Source(
110
            label="source_a_1",
111
            outputs={bus_a_1: solph.Flow(variable_costs=c_1 * 10000)},
112
        )
113
    )
114
115
    es.add(
116
        solph.components.Sink(
117
            label="demand_a",
118
            inputs={bus_a_1: solph.Flow(fix=data, nominal_capacity=1)},
119
        )
120
    )
121
122
    # commodity b
123
    bus_b_0 = solph.Bus(label="bus_b_0")
124
    bus_b_1 = solph.Bus(label="bus_b_1")
125
    es.add(bus_b_0, bus_b_1)
126
    es.add(
127
        solph.components.Source(
128
            label="source_b_0",
129
            outputs={bus_b_0: solph.Flow(variable_costs=c_0)},
130
        )
131
    )
132
133
    es.add(
134
        solph.components.Source(
135
            label="source_b_1",
136
            outputs={bus_b_1: solph.Flow(variable_costs=c_1 * 10000)},
137
        )
138
    )
139
140
    es.add(
141
        solph.components.Sink(
142
            label="demand_b",
143
            inputs={bus_b_1: solph.Flow(fix=data, nominal_capacity=1)},
144
        )
145
    )
146
147
    # Converter a
148
    es.add(
149
        solph.components.Converter(
150
            label="trafo_a",
151
            inputs={bus_a_0: solph.Flow()},
152
            outputs={
153
                bus_a_1: solph.Flow(
154
                    nominal_capacity=solph.Investment(
155
                        ep_costs=epc_invest,
156
                        custom_attributes={"space": {"cost": 1, "offset": 20}},
157
                        nonconvex=True,
158
                        maximum=20,
159
                    ),
160
                    custom_attributes={"space": 0.1},
161
                )
162
            },
163
            conversion_factors={bus_a_1: 1},
164
        )
165
    )
166
167
    # Converter b
168
    es.add(
169
        solph.components.Converter(
170
            label="trafo_b",
171
            inputs={bus_b_0: solph.Flow()},
172
            outputs={
173
                bus_b_1: solph.Flow(
174
                    nominal_capacity=solph.Investment(
175
                        ep_costs=epc_invest,
176
                        custom_attributes={"space": {"cost": 1}},
177
                        nonconvex=True,
178
                        maximum=10,
179
                    ),
180
                    custom_attributes={"space": 0.1},
181
                )
182
            },
183
        )
184
    )
185
    # Generic Storage b_0
186
    generic_storage_b_0 = solph.components.GenericStorage(
187
        label="generic_storage_b_0",
188
        inputs={bus_b_1: solph.Flow()},
189
        outputs={bus_b_1: solph.Flow()},
190
        inflow_conversion_factor=1,
191
        nominal_capacity=solph.Investment(
192
            ep_costs=epc_invest,
193
            nonconvex=True,
194
            maximum=1,
195
            custom_attributes={"space": {"cost": 0.5, "offset": 1}},
196
        ),
197
        invest_relation_input_capacity=0.5,
198
        invest_relation_output_capacity=0.5,
199
    )
200
201
    es.add(generic_storage_b_0)
202
203
    # Generic Storage b_1
204
    generic_storage_b_1 = solph.components.GenericStorage(
205
        label="generic_storage_b_1",
206
        inputs={bus_b_1: solph.Flow()},
207
        outputs={bus_b_1: solph.Flow()},
208
        inflow_conversion_factor=1,
209
        nominal_capacity=solph.Investment(
210
            ep_costs=epc_invest * 100,
211
            nonconvex=True,
212
            maximum=2,
213
            custom_attributes={"space": {"cost": 1, "offset": 5}},
214
        ),
215
    )
216
217
    es.add(generic_storage_b_1)
218
    if optimize is False:
219
        return es
220
221
    # create an optimization problem and solve it
222
    om = solph.Model(es)
223
224
    # add constraint for generic investment limit
225
    om = solph.constraints.additional_total_limit(om, "space", limit=100)
226
    # export lp file
227
    filename = os.path.join(
228
        solph.helpers.extend_basic_path("lp_files"), "GenericInvest.lp"
229
    )
230
    logging.info("Store lp-file in {0}.".format(filename))
231
    om.write(filename, io_options={"symbolic_solver_labels": True})
232
233
    # solve model
234
    om.solve(solver="gurobi", solve_kwargs={"tee": True})
235
236
    # create result object
237
    results = solph.processing.results(om)
238
239
    bus1 = solph.views.node(results, "bus_a_1")["sequences"]
240
    bus2 = solph.views.node(results, "bus_b_1")["sequences"]
241
242
    # plot the time series (sequences) of a specific component/bus
243
    if plt is not None:
244
        bus1.plot(kind="line", drawstyle="steps-mid")
245
        plt.legend()
246
        plt.show()
247
        bus2.plot(kind="line", drawstyle="steps-mid")
248
        plt.legend()
249
        plt.show()
250
251
    space_used = om.total_limit_space()
252
    print("Space value: ", space_used)
253
    print(
254
        "Investment trafo_a: ",
255
        solph.views.node(results, "trafo_a")["scalars"][0],
256
    )
257
    print(
258
        "Investment trafo_b: ",
259
        solph.views.node(results, "trafo_b")["scalars"][0],
260
    )
261
262
    print(
263
        "Investment generic_storage_b_0: ",
264
        results[generic_storage_b_0, None]["scalars"]["total"],
265
    )
266
267
    print(
268
        "Investment generic_storage_b_1: ",
269
        results[generic_storage_b_1, None]["scalars"]["total"],
270
    )
271
272
273
if __name__ == "__main__":
274
    main()
275