test_add_constraints   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 5
eloc 66
dl 0
loc 134
rs 10
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B test_add_constraints_example() 0 105 5
1
# -*- coding: utf-8 -*-
2
3
"""
4
This script shows how to a an individual constraint to the oemof solph
5
Model.
6
The constraint we add forces a flow to be greater or equal a certain share
7
of all inflows of its target bus. Moreover we will set an emission constraint.
8
9
This file is part of project oemof (github.com/oemof/oemof). It's copyrighted
10
by the contributors recorded in the version control history of the file,
11
available from its original location oemof/tests/test_scripts/test_solph/
12
test_flexible_modelling/test_add_constraints.py
13
14
SPDX-License-Identifier: MIT
15
"""
16
17
import logging
18
19
import pandas as pd
20
from pyomo import environ as po
21
22
from oemof.solph import EnergySystem
23
from oemof.solph import Model
24
from oemof.solph import components
25
from oemof.solph.buses import Bus
26
from oemof.solph.flows import Flow
27
28
29
def test_add_constraints_example(solver="cbc", nologg=False):
30
    if not nologg:
31
        logging.basicConfig(level=logging.INFO)
32
    # ##### creating an oemof solph optimization model, nothing special here ##
33
    # create an energy system object for the oemof solph nodes
34
    es = EnergySystem(
35
        timeindex=pd.date_range("1/1/2012", periods=4, freq="h"),
36
        infer_last_interval=True,
37
    )
38
39
    # add some nodes
40
    boil = Bus(label="oil", balanced=False)
41
    blig = Bus(label="lignite", balanced=False)
42
    b_el = Bus(label="b_el")
43
    es.add(boil, blig, b_el)
44
45
    es.add(
46
        components.Sink(
47
            label="Sink",
48
            inputs={b_el: Flow(nominal_capacity=40, fix=[0.5, 0.4, 0.3, 1])},
49
        )
50
    )
51
    pp_oil = components.Converter(
52
        label="pp_oil",
53
        inputs={boil: Flow()},
54
        outputs={b_el: Flow(nominal_capacity=50, variable_costs=25)},
55
        conversion_factors={b_el: 0.39},
56
    )
57
58
    es.add(pp_oil)
59
    es.add(
60
        components.Converter(
61
            label="pp_lig",
62
            inputs={blig: Flow()},
63
            outputs={b_el: Flow(nominal_capacity=50, variable_costs=10)},
64
            conversion_factors={b_el: 0.41},
65
        )
66
    )
67
68
    # create the model
69
    om = Model(energysystem=es)
70
71
    # add specific emission values to flow objects if source is a commodity bus
72
    for s, t in om.flows.keys():
73
        if s is boil:
74
            om.flows[s, t].emission_factor = 0.27  # t/MWh
75
        if s is blig:
76
            om.flows[s, t].emission_factor = 0.39  # t/MWh
77
    emission_limit = 60e3
78
79
    # add the outflow share
80
    om.flows[(boil, pp_oil)].outflow_share = [1, 0.5, 0, 0.3]
81
82
    # Now we are going to add a 'sub-model' and add a user specific constraint
83
    # first we add ad pyomo Block() instance that we can use to add our
84
    # constraints. Then, we add this Block to our previous defined
85
    # Model instance and add the constraints.
86
    myblock = po.Block()
87
88
    # create a pyomo set with the flows (i.e. list of tuples),
89
    # there will of course be only one flow inside this set, the one we used to
90
    # add outflow_share
91
    myblock.MYFLOWS = po.Set(
92
        initialize=[
93
            k for (k, v) in om.flows.items() if hasattr(v, "outflow_share")
94
        ]
95
    )
96
97
    # pyomo does not need a po.Set, we can use a simple list as well
98
    myblock.COMMODITYFLOWS = [
99
        k for (k, v) in om.flows.items() if hasattr(v, "emission_factor")
100
    ]
101
102
    # add the sub-model to the oemof Model instance
103
    om.add_component("MyBlock", myblock)
104
105
    def _inflow_share_rule(m, si, e, ti):
106
        """pyomo rule definition: Here we can use all objects from the block or
107
        the om object, in this case we don't need anything from the block
108
        except the newly defined set MYFLOWS.
109
        """
110
        expr = om.flow[si, e, ti] >= om.flows[si, e].outflow_share[ti] * sum(
111
            om.flow[i, o, ti] for (i, o) in om.FLOWS if o == e
112
        )
113
        return expr
114
115
    myblock.inflow_share = po.Constraint(
116
        myblock.MYFLOWS, om.TIMESTEPS, rule=_inflow_share_rule
117
    )
118
    # add emission constraint
119
    myblock.emission_constr = po.Constraint(
120
        expr=(
121
            sum(
122
                om.flow[i, o, t]
123
                for (i, o) in myblock.COMMODITYFLOWS
124
                for t in om.TIMESTEPS
125
            )
126
            <= emission_limit
127
        )
128
    )
129
130
    # solve and write results to dictionary
131
    # you may print the model with om.pprint()
132
    assert om.solve(solver=solver)
133
    logging.info("Successfully finished.")
134