test_storage_invest_tsam_integration   A
last analyzed

Complexity

Total Complexity 4

Size/Duplication

Total Lines 214
Duplicated Lines 20.09 %

Importance

Changes 0
Metric Value
wmc 4
eloc 108
dl 43
loc 214
rs 10
c 0
b 0
f 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
A test_soc() 32 32 1
A test_storage_input() 11 11 1
A test_storage_investment() 0 5 1
A test_storage_output() 0 9 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
# -*- coding: utf-8 -*-
2
3
r"""
4
General description:
5
---------------------
6
7
The example models the following energy system:
8
9
                input/output   bel
10
                     |          |
11
 wind(FixedSource)   |--------->|
12
                     |          |
13
 demand(Sink)        |<---------|
14
                     |          |
15
 storage(Storage)    |<---------|
16
                     |--------->|
17
18
19
20
An initial SOC of zero leads to infeasible solution, as last inter SOC has to
21
match first inter SOC.
22
Following equations have to be fulfilled:
23
:math:`F_{el,st}[0] = F_{el,st}[6]`
24
:math:`SOC_{init} * discharge + F_{el,st}[0] =`
25
:math:`\sum_{i=1}^{n=5}F_{st,el}[i]/eff_{out}/(1 - discharge)^i`
26
:math:`F_{el,st}[6] = (SOC_{init} + F_{el,st}[5]/eff_{out}) / (1 - discharge)`
27
28
This file is part of project oemof (github.com/oemof/oemof). It's copyrighted
29
by the contributors recorded in the version control history of the file,
30
available from its original location oemof/tests/test_scripts/test_solph/
31
test_storage_investment/test_storage_investment.py
32
33
SPDX-License-Identifier: MIT
34
"""
35
36
import logging
37
38
import pandas as pd
39
import pytest
40
from oemof.tools import economics
41
from oemof.tools import logger
42
43
from oemof import solph
44
45
##########################################################################
46
# Initialize the energy system and read/calculate necessary parameters
47
##########################################################################
48
49
logger.define_logging()
50
logging.info("Initialize the energy system")
51
52
tindex_original = pd.date_range("2022-01-01", periods=8, freq="H")
53
tindex = pd.date_range("2022-01-01", periods=4, freq="H")
54
55
energysystem = solph.EnergySystem(
56
    timeindex=tindex,
57
    periods=[tindex],
58
    tsa_parameters=[
59
        {
60
            "timesteps_per_period": 2,
61
            "order": [0, 1, 1, 0],
62
        },
63
    ],
64
    infer_last_interval=True,
65
)
66
67
##########################################################################
68
# Create oemof objects
69
##########################################################################
70
71
logging.info("Create oemof objects")
72
73
# create electricity bus
74
bel = solph.Bus(label="electricity")
75
energysystem.add(bel)
76
77
# create fixed source object representing wind power plants
78
wind = solph.components.Source(
79
    label="wind",
80
    outputs={bel: solph.Flow(fix=[1000, 0, 0, 50], nominal_value=1)},
81
)
82
83
# create simple sink object representing the electrical demand
84
demand = solph.components.Sink(
85
    label="demand",
86
    inputs={
87
        bel: solph.Flow(
88
            fix=[100] * 4,
89
            nominal_value=1,
90
        )
91
    },
92
)
93
94
# create storage object representing a battery
95
epc = economics.annuity(capex=1000, n=20, wacc=0.05)
96
storage = solph.components.GenericStorage(
97
    label="storage",
98
    inputs={bel: solph.Flow(lifetime=20)},
99
    outputs={bel: solph.Flow(lifetime=20)},
100
    nominal_capacity=solph.Investment(ep_costs=epc, lifetime=20),
101
    loss_rate=0.01,
102
    inflow_conversion_factor=0.9,
103
    outflow_conversion_factor=0.8,
104
)
105
106
excess = solph.components.Sink(
107
    label="excess",
108
    inputs={bel: solph.Flow()},
109
)
110
111
energysystem.add(wind, demand, storage, excess)
112
113
##########################################################################
114
# Optimise the energy system
115
##########################################################################
116
117
logging.info("Optimise the energy system")
118
119
# initialise the operational model
120
om = solph.Model(energysystem)
121
122
# if tee_switch is true solver messages will be displayed
123
logging.info("Solve the optimization problem")
124
om.solve(solver="cbc", solve_kwargs={"tee": True})
125
126
##########################################################################
127
# Check and plot the results
128
##########################################################################
129
130
# check if the new result object is working for custom components
131
results = solph.processing.results(om)
132
133
# Concatenate flows:
134
flows = pd.concat([flow["sequences"] for flow in results.values()], axis=1)
135
flows.columns = [
136
    f"{oemof_tuple[0]}-{oemof_tuple[1]}" for oemof_tuple in results.keys()
137
]
138
139
first_input = (
140
    (100 * 1 / 0.8) / (1 - 0.01)
141
    + (100 * 1 / 0.8) / (1 - 0.01) ** 2
142
    + (50 * 1 / 0.8) / (1 - 0.01) ** 3
143
    + (100 * 1 / 0.8) / (1 - 0.01) ** 4
144
    + (50 * 1 / 0.8) / (1 - 0.01) ** 5
145
)
146
# In this example SOC can e zero, as last SOC does not have to be equal
147
# to first SOC in investment mode (maybe this should be changed?)
148
init_soc = 0
149
150
151
def test_storage_investment():
152
    """Make sure that max SOC investment equals max load"""
153
    assert results[storage, None]["period_scalars"]["invest"].iloc[
154
        0
155
    ] == pytest.approx(first_input)
156
157
158 View Code Duplication
def test_storage_input():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
159
    assert flows["electricity-storage"][0] == pytest.approx(
160
        (first_input - 0.99 * init_soc) / 0.9
161
    )
162
    assert flows["electricity-storage"][1] == 0
163
    assert flows["electricity-storage"][2] == 0
164
    assert flows["electricity-storage"][3] == 0
165
    assert flows["electricity-storage"][4] == 0
166
    assert flows["electricity-storage"][5] == 0
167
    assert flows["electricity-storage"][6] == flows["electricity-storage"][0]
168
    assert flows["electricity-storage"][7] == 0
169
170
171
def test_storage_output():
172
    assert flows["storage-electricity"][0] == 0
173
    assert flows["storage-electricity"][1] == 100
174
    assert flows["storage-electricity"][2] == 100
175
    assert flows["storage-electricity"][3] == 50
176
    assert flows["storage-electricity"][4] == 100
177
    assert flows["storage-electricity"][5] == 50
178
    assert flows["storage-electricity"][6] == 0
179
    assert flows["storage-electricity"][7] == 100
180
181
182 View Code Duplication
def test_soc():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
183
    assert flows["storage-None"][0] == pytest.approx(init_soc)
184
    assert flows["storage-None"][1] == pytest.approx(
185
        (100 * 1 / 0.8) / (1 - 0.01)
186
        + (100 * 1 / 0.8) / (1 - 0.01) ** 2
187
        + (50 * 1 / 0.8) / (1 - 0.01) ** 3
188
        + (100 * 1 / 0.8) / (1 - 0.01) ** 4
189
        + (50 * 1 / 0.8) / (1 - 0.01) ** 5,
190
        abs=1e-2,
191
    )
192
    assert flows["storage-None"][2] == pytest.approx(
193
        (100 * 1 / 0.8) / (1 - 0.01)
194
        + (50 * 1 / 0.8) / (1 - 0.01) ** 2
195
        + (100 * 1 / 0.8) / (1 - 0.01) ** 3
196
        + (50 * 1 / 0.8) / (1 - 0.01) ** 4,
197
        abs=1e-2,
198
    )
199
    assert flows["storage-None"][3] == pytest.approx(
200
        (50 * 1 / 0.8) / (1 - 0.01)
201
        + (100 * 1 / 0.8) / (1 - 0.01) ** 2
202
        + (50 * 1 / 0.8) / (1 - 0.01) ** 3,
203
        abs=1e-2,
204
    )
205
    assert flows["storage-None"][4] == pytest.approx(
206
        (100 * 1 / 0.8) / (1 - 0.01) + (50 * 1 / 0.8) / (1 - 0.01) ** 2,
207
        abs=1e-2,
208
    )
209
    assert flows["storage-None"][5] == pytest.approx(
210
        (50 * 1 / 0.8) / (1 - 0.01), abs=1e-2
211
    )
212
    assert flows["storage-None"][6] == pytest.approx(0, abs=1e-2)
213
    assert flows["storage-None"][7] == pytest.approx(first_input)
214