Passed
Pull Request — dev (#799)
by Uwe
01:54
created

TransformerBlock._create()   B

Complexity

Conditions 7

Size

Total Lines 57
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 33
dl 0
loc 57
rs 7.688
c 0
b 0
f 0
cc 7
nop 2

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
solph version of oemof.network.Transformer including
5
sets, variables, constraints and parts of the objective function
6
for TransformerBlock objects.
7
8
SPDX-FileCopyrightText: Uwe Krien <[email protected]>
9
SPDX-FileCopyrightText: Simon Hilpert
10
SPDX-FileCopyrightText: Cord Kaldemeyer
11
SPDX-FileCopyrightText: Patrik Schönfeldt
12
SPDX-FileCopyrightText: Stephan Günther
13
SPDX-FileCopyrightText: Birgit Schachler
14
SPDX-FileCopyrightText: jnnr
15
SPDX-FileCopyrightText: jmloenneberga
16
17
SPDX-License-Identifier: MIT
18
19
"""
20
21
from oemof.network import network as on
22
from pyomo.core import BuildAction
23
from pyomo.core import Constraint
24
from pyomo.core.base.block import ScalarBlock
25
26
from oemof.solph._helpers import check_node_object_for_missing_attribute
27
from oemof.solph._plumbing import sequence
28
29
30
class Transformer(on.Transformer):
31
    """A linear converter object with n inputs and n outputs.
32
33
    Parameters
34
    ----------
35
    conversion_factors : dict
36
        Dictionary containing conversion factors for conversion of each flow.
37
        Keys are the connected bus objects.
38
        The dictionary values can either be a scalar or an iterable with length
39
        of time horizon for simulation.
40
41
    Examples
42
    --------
43
    Defining an linear transformer:
44
45
    >>> from oemof import solph
46
    >>> bgas = solph.buses.Bus(label='natural_gas')
47
    >>> bcoal = solph.buses.Bus(label='hard_coal')
48
    >>> bel = solph.buses.Bus(label='electricity')
49
    >>> bheat = solph.buses.Bus(label='heat')
50
51
    >>> trsf = solph.components.Transformer(
52
    ...    label='pp_gas_1',
53
    ...    inputs={bgas: solph.flows.Flow(), bcoal: solph.flows.Flow()},
54
    ...    outputs={bel: solph.flows.Flow(), bheat: solph.flows.Flow()},
55
    ...    conversion_factors={bel: 0.3, bheat: 0.5,
56
    ...                        bgas: 0.8, bcoal: 0.2})
57
    >>> print(sorted([x[1][5] for x in trsf.conversion_factors.items()]))
58
    [0.2, 0.3, 0.5, 0.8]
59
60
    >>> type(trsf)
61
    <class 'oemof.solph.components._transformer.Transformer'>
62
63
    >>> sorted([str(i) for i in trsf.inputs])
64
    ['hard_coal', 'natural_gas']
65
66
    >>> trsf_new = solph.components.Transformer(
67
    ...    label='pp_gas_2',
68
    ...    inputs={bgas: solph.flows.Flow()},
69
    ...    outputs={bel: solph.flows.Flow(), bheat: solph.flows.Flow()},
70
    ...    conversion_factors={bel: 0.3, bheat: 0.5})
71
    >>> trsf_new.conversion_factors[bgas][3]
72
    1
73
74
    Notes
75
    -----
76
    The following sets, variables, constraints and objective parts are created
77
     * :py:class:`~oemof.solph.components._transformer.TransformerBlock`
78
    """
79
80
    def __init__(self, *args, **kwargs):
81
        super().__init__(*args, **kwargs)
82
83
        check_node_object_for_missing_attribute(self, "inputs")
84
        check_node_object_for_missing_attribute(self, "outputs")
85
86
        self.conversion_factors = {
87
            k: sequence(v)
88
            for k, v in kwargs.get("conversion_factors", {}).items()
89
        }
90
91
        missing_conversion_factor_keys = (
92
            set(self.outputs) | set(self.inputs)
93
        ) - set(self.conversion_factors)
94
95
        for cf in missing_conversion_factor_keys:
96
            self.conversion_factors[cf] = sequence(1)
97
98
    def constraint_group(self):
99
        return TransformerBlock
100
101
102
class TransformerBlock(ScalarBlock):
103
    r"""
104
    Block for the linear relation of nodes with type
105
    :class:`~oemof.solph.network.transformer.Transformer`
106
107
    **The following constraints are created:**
108
109
    Linear relation `om.Transformer.relation[i,o,t]`
110
        .. math::
111
            P_{i}(t) \cdot \eta_{o}(t) =
112
            P_{o}(t) \cdot \eta_{i}(t), \\
113
            \forall t \in \textrm{TIMESTEPS}, \\
114
            \forall i \in \textrm{INPUTS}, \\
115
            \forall o \in \textrm{OUTPUTS}
116
117
    While INPUTS is the set of Bus objects connected with the input of the
118
    Transformer and OUPUTS the set of Bus objects connected with the output of
119
    the Transformer. The constraint above will be created for all combinations
120
    of INPUTS and OUTPUTS for all TIMESTEPS. A Transformer with two inflows and
121
    two outflows for one day with an hourly resolution will lead to 96
122
    constraints.
123
124
    The index :math: n is the index for the Transformer node itself. Therefore,
125
    a `flow[i, n, t]` is a flow from the Bus i to the Transformer n at
126
    time step t.
127
128
    ======================  ============================  ====================
129
    symbol                  attribute                     explanation
130
    ======================  ============================  ====================
131
    :math:`P_{i}(t)`        `flow[i, n, t]`               Transformer, inflow
132
133
    :math:`P_{o}(t)`        `flow[n, o, t]`               Transformer, outflow
134
135
    :math:`\eta_{i}(t)`     `conversion_factor[i, n, t]`  Inflow, efficiency
136
137
    :math:`\eta_{o}(t)`     `conversion_factor[n, o, t]`  Outflow, efficiency
138
139
    ======================  ============================  ====================
140
141
    """
142
143
    def __init__(self, *args, **kwargs):
144
        super().__init__(*args, **kwargs)
145
146
    def _create(self, group=None):
147
        """Creates the linear constraint for the class:`TransformerBlock`
148
        block.
149
        Parameters
150
        ----------
151
        group : list
152
            List of oemof.solph.components.Transformers objects for which
153
            the linear relation of inputs and outputs is created
154
            e.g. group = [trsf1, trsf2, trsf3, ...]. Note that the relation
155
            is created for all existing relations of all inputs and all outputs
156
            of the transformer. The components inside the list need to hold
157
            an attribute `conversion_factors` of type dict containing the
158
            conversion factors for all inputs to outputs.
159
        """
160
        if group is None:
161
            return None
162
163
        m = self.parent_block()
164
165
        in_flows = {n: [i for i in n.inputs.keys()] for n in group}
166
        out_flows = {n: [o for o in n.outputs.keys()] for n in group}
167
168
        self.relation = Constraint(
169
            [
170
                (n, i, o, t)
171
                for t in m.TIMESTEPS
172
                for n in group
173
                for o in out_flows[n]
174
                for i in in_flows[n]
175
            ],
176
            noruleinit=True,
177
        )
178
179
        def _input_output_relation(block):
180
            for t in m.TIMESTEPS:
0 ignored issues
show
introduced by
The variable m does not seem to be defined for all execution paths.
Loading history...
181
                for n in group:
182
                    for o in out_flows[n]:
0 ignored issues
show
introduced by
The variable out_flows does not seem to be defined for all execution paths.
Loading history...
183
                        for i in in_flows[n]:
0 ignored issues
show
introduced by
The variable in_flows does not seem to be defined for all execution paths.
Loading history...
184
                            try:
185
                                lhs = (
186
                                    m.flow[i, n, t]
187
                                    * n.conversion_factors[o][t]
188
                                )
189
                                rhs = (
190
                                    m.flow[n, o, t]
191
                                    * n.conversion_factors[i][t]
192
                                )
193
                            except ValueError:
194
                                raise ValueError(
195
                                    "Error in constraint creation",
196
                                    "source: {0}, target: {1}".format(
197
                                        n.label, o.label
198
                                    ),
199
                                )
200
                            block.relation.add((n, i, o, t), (lhs == rhs))
201
202
        self.relation_build = BuildAction(rule=_input_output_relation)
203