test_storage_tsam_vs_original   A
last analyzed

Complexity

Total Complexity 3

Size/Duplication

Total Lines 189
Duplicated Lines 26.98 %

Importance

Changes 0
Metric Value
wmc 3
eloc 105
dl 51
loc 189
rs 10
c 0
b 0
f 0

3 Functions

Rating   Name   Duplication   Size   Complexity  
A test_soc() 31 31 1
A test_storage_output() 10 10 1
A test_storage_input() 10 10 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
"""
4
General description:
5
---------------------
6
7
The example models the same setup as in test_storage_tsam_integration,
8
but instead of aggregating timeseries, timeseries are left untouched.
9
Nevertheless, storage input/output and SOC should equal TSAM example.
10
11
This file is part of project oemof (github.com/oemof/oemof). It's copyrighted
12
by the contributors recorded in the version control history of the file,
13
available from its original location oemof/tests/test_scripts/test_solph/
14
test_storage_investment/test_storage_investment.py
15
16
SPDX-License-Identifier: MIT
17
"""
18
19
import logging
20
21
import pandas as pd
22
import pytest
23
from oemof.tools import logger
24
25
from oemof import solph
26
27
##########################################################################
28
# Initialize the energy system and read/calculate necessary parameters
29
##########################################################################
30
31
logger.define_logging()
32
logging.info("Initialize the energy system")
33
34
tindex = pd.date_range("2022-01-01", periods=8, freq="h")
35
36
energysystem = solph.EnergySystem(
37
    timeindex=tindex,
38
    infer_last_interval=True,
39
)
40
41
##########################################################################
42
# Create oemof objects
43
##########################################################################
44
45
logging.info("Create oemof objects")
46
47
# create electricity bus
48
bel = solph.Bus(label="electricity")
49
energysystem.add(bel)
50
51
# create fixed source object representing wind power plants
52
wind = solph.components.Source(
53
    label="wind",
54
    outputs={
55
        bel: solph.Flow(
56
            fix=[1000, 0, 0, 50, 0, 50, 1000, 0],
57
            nominal_capacity=1,
58
        )
59
    },
60
)
61
62
# create simple sink object representing the electrical demand
63
demand = solph.components.Sink(
64
    label="demand",
65
    inputs={
66
        bel: solph.Flow(
67
            fix=[100] * 8,
68
            nominal_capacity=1,
69
        )
70
    },
71
)
72
73
# Solving equations from above, needed initial SOC is as follows:
74
first_input = (
75
    (100 * 1 / 0.8) / (1 - 0.01)
76
    + (100 * 1 / 0.8) / (1 - 0.01) ** 2
77
    + (50 * 1 / 0.8) / (1 - 0.01) ** 3
78
    + (100 * 1 / 0.8) / (1 - 0.01) ** 4
79
    + (50 * 1 / 0.8) / (1 - 0.01) ** 5
80
)
81
last_output = (100 * 1 / 0.8) / 0.99
82
init_soc = (first_input - last_output) / (1 / 0.99 + 0.99)
83
84
# create storage object representing a battery
85
storage = solph.components.GenericStorage(
86
    label="storage",
87
    nominal_capacity=2000,
88
    initial_storage_level=init_soc / 2000,
89
    inputs={bel: solph.Flow()},
90
    outputs={bel: solph.Flow()},
91
    loss_rate=0.01,
92
    inflow_conversion_factor=0.9,
93
    outflow_conversion_factor=0.8,
94
)
95
96
excess = solph.components.Sink(
97
    label="excess",
98
    inputs={bel: solph.Flow()},
99
)
100
101
energysystem.add(wind, demand, storage, excess)
102
103
##########################################################################
104
# Optimise the energy system
105
##########################################################################
106
107
logging.info("Optimise the energy system")
108
109
# initialise the operational model
110
om = solph.Model(energysystem)
111
112
# if tee_switch is true solver messages will be displayed
113
logging.info("Solve the optimization problem")
114
om.solve(solver="cbc", solve_kwargs={"tee": True})
115
116
##########################################################################
117
# Check and plot the results
118
##########################################################################
119
120
# check if the new result object is working for custom components
121
results = solph.processing.results(om)
122
123
# Concatenate flows:
124
flows = pd.concat([flow["sequences"] for flow in results.values()], axis=1)
125
flows = flows.drop(
126
    "storage_losses", axis=1
127
)  # todo: why are storage losses not return of results.keys()?
128
129
flows.columns = [
130
    f"{oemof_tuple[0]}-{oemof_tuple[1]}" for oemof_tuple in results.keys()
131
]
132
133
134 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...
135
    flow = flows["electricity-storage"]
136
    assert flow.iloc[0] == pytest.approx((first_input - 0.99 * init_soc) / 0.9)
137
    assert flow.iloc[1] == 0
138
    assert flow.iloc[2] == 0
139
    assert flow.iloc[3] == 0
140
    assert flow.iloc[4] == 0
141
    assert flow.iloc[5] == 0
142
    assert flow.iloc[6] == flow.iloc[0]
143
    assert flow.iloc[7] == 0
144
145
146 View Code Duplication
def test_storage_output():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
147
    flow = flows["storage-electricity"]
148
    assert flow.iloc[0] == 0
149
    assert flow.iloc[1] == 100
150
    assert flow.iloc[2] == 100
151
    assert flow.iloc[3] == 50
152
    assert flow.iloc[4] == 100
153
    assert flow.iloc[5] == 50
154
    assert flow.iloc[6] == 0
155
    assert flow.iloc[7] == 100
156
157
158 View Code Duplication
def test_soc():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
159
    flow = flows["storage-None"]
160
    assert flow.iloc[0] == pytest.approx(init_soc)
161
    assert flow.iloc[1] == pytest.approx(
162
        (100 * 1 / 0.8) / (1 - 0.01)
163
        + (100 * 1 / 0.8) / (1 - 0.01) ** 2
164
        + (50 * 1 / 0.8) / (1 - 0.01) ** 3
165
        + (100 * 1 / 0.8) / (1 - 0.01) ** 4
166
        + (50 * 1 / 0.8) / (1 - 0.01) ** 5,
167
        abs=1e-2,
168
    )
169
    assert flow.iloc[2] == pytest.approx(
170
        (100 * 1 / 0.8) / (1 - 0.01)
171
        + (50 * 1 / 0.8) / (1 - 0.01) ** 2
172
        + (100 * 1 / 0.8) / (1 - 0.01) ** 3
173
        + (50 * 1 / 0.8) / (1 - 0.01) ** 4,
174
        abs=1e-2,
175
    )
176
    assert flow.iloc[3] == pytest.approx(
177
        (50 * 1 / 0.8) / (1 - 0.01)
178
        + (100 * 1 / 0.8) / (1 - 0.01) ** 2
179
        + (50 * 1 / 0.8) / (1 - 0.01) ** 3,
180
        abs=1e-2,
181
    )
182
    assert flow.iloc[4] == pytest.approx(
183
        (100 * 1 / 0.8) / (1 - 0.01) + (50 * 1 / 0.8) / (1 - 0.01) ** 2,
184
        abs=1e-2,
185
    )
186
    assert flow.iloc[5] == pytest.approx((50 * 1 / 0.8) / (1 - 0.01), abs=1e-2)
187
    assert flow.iloc[6] == pytest.approx(0, abs=1e-2)
188
    assert flow.iloc[7] == pytest.approx((init_soc + (100 * 1 / 0.8)) / 0.99)
189