|
1
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
|
|
3
|
|
|
""" |
|
4
|
|
|
General description |
|
5
|
|
|
------------------- |
|
6
|
|
|
|
|
7
|
|
|
A basic example to show how to get the dual variables from the system. Try |
|
8
|
|
|
to understand the plot. |
|
9
|
|
|
|
|
10
|
|
|
Code |
|
11
|
|
|
---- |
|
12
|
|
|
Download source code: :download:`dual_variable_example.py </../examples/dual_variable_example/dual_variable_example.py>` |
|
13
|
|
|
|
|
14
|
|
|
.. dropdown:: Click to display code |
|
15
|
|
|
|
|
16
|
|
|
.. literalinclude:: /../examples/dual_variable_example/dual_variable_example.py |
|
17
|
|
|
:language: python |
|
18
|
|
|
:lines: 34-297 |
|
19
|
|
|
|
|
20
|
|
|
|
|
21
|
|
|
Installation requirements |
|
22
|
|
|
------------------------- |
|
23
|
|
|
|
|
24
|
|
|
This example requires the version v0.6.x of oemof.solph: |
|
25
|
|
|
|
|
26
|
|
|
.. code:: bash |
|
27
|
|
|
|
|
28
|
|
|
pip install 'oemof.solph[examples]>=0.6,<0.7' |
|
29
|
|
|
|
|
30
|
|
|
SPDX-FileCopyrightText: Uwe Krien <[email protected]> |
|
31
|
|
|
SPDX-FileCopyrightText: Pierre-François Duc |
|
32
|
|
|
|
|
33
|
|
|
SPDX-License-Identifier: MIT |
|
34
|
|
|
""" |
|
35
|
|
|
|
|
36
|
|
|
from oemof.solph.components import Converter, Source, Sink |
|
37
|
|
|
from oemof.solph.flows import Flow |
|
38
|
|
|
from oemof.solph.buses import Bus |
|
39
|
|
|
|
|
40
|
|
|
from oemof.solph._facades import Facade |
|
41
|
|
|
|
|
42
|
|
|
|
|
43
|
|
|
class DSO(Facade): |
|
44
|
|
|
def __init__(self, label, el_bus, *args, energy_price, feedin_tariff): |
|
45
|
|
|
self.energy_price = energy_price |
|
46
|
|
|
self.feedin_tariff = feedin_tariff |
|
47
|
|
|
self.el_bus = el_bus |
|
48
|
|
|
super().__init__(*args, label=label, facade_type=type(self)) |
|
49
|
|
|
|
|
50
|
|
|
def define_subnetwork(self): |
|
51
|
|
|
internal_bus = Bus(custom_properties={"sub_label": "internal_bus"}) |
|
52
|
|
|
|
|
53
|
|
|
feedin = Converter( |
|
54
|
|
|
inputs={self.el_bus: Flow(variable_costs=self.feedin_tariff)}, |
|
55
|
|
|
outputs={internal_bus: Flow()}, |
|
56
|
|
|
label=self.sub_component_labelling("feedin_converter"), |
|
57
|
|
|
) |
|
58
|
|
|
sink = Sink( |
|
59
|
|
|
inputs={internal_bus: Flow()}, |
|
60
|
|
|
label=self.sub_component_labelling("feedin_sink"), |
|
61
|
|
|
) |
|
62
|
|
|
|
|
63
|
|
|
bus_c = Bus() |
|
64
|
|
|
consumption = Converter( |
|
65
|
|
|
inputs={bus_c: Flow()}, |
|
66
|
|
|
outputs={self.el_bus: Flow(variable_costs=self.energy_price)}, |
|
67
|
|
|
label=self.sub_component_labelling("consumption_converter"), |
|
68
|
|
|
) |
|
69
|
|
|
source = Source( |
|
70
|
|
|
outputs={internal_bus: Flow()}, |
|
71
|
|
|
label=self.sub_component_labelling("consumption_sink"), |
|
72
|
|
|
) |
|
73
|
|
|
self.append_subnodes( |
|
74
|
|
|
bus_c, source, consumption, sink, feedin, internal_bus |
|
75
|
|
|
) |
|
76
|
|
|
|
|
77
|
|
|
|
|
78
|
|
|
# class CriticalDemand(Facade): |
|
79
|
|
|
# """ |
|
80
|
|
|
# Defines a non dispatchable sink to serve critical and non-critical demand. |
|
81
|
|
|
# |
|
82
|
|
|
# See :py:func:`~.sink` for more information, including parameters. |
|
83
|
|
|
# |
|
84
|
|
|
# Notes |
|
85
|
|
|
# ----- |
|
86
|
|
|
# Tested with: |
|
87
|
|
|
# - test_sink_non_dispatchable_single_input_bus() |
|
88
|
|
|
# - test_sink_non_dispatchable_multiple_input_busses() |
|
89
|
|
|
# |
|
90
|
|
|
# Returns |
|
91
|
|
|
# ------- |
|
92
|
|
|
# Indirectly updated `model` and dict of asset in `kwargs` with the sink |
|
93
|
|
|
# object. |
|
94
|
|
|
# |
|
95
|
|
|
# """ |
|
96
|
|
|
# |
|
97
|
|
|
# # sink_non_dispatchable(model, dict_asset, **kwargs) |
|
98
|
|
|
# |
|
99
|
|
|
# def __init__( |
|
100
|
|
|
# self, name, el_bus, demand_reduction_factor, total_demand, *args |
|
101
|
|
|
# ): |
|
102
|
|
|
# super().__init__(*args, name=name) |
|
103
|
|
|
# self.facade_type = "dso" |
|
104
|
|
|
# self.demand_reduction_factor = demand_reduction_factor |
|
105
|
|
|
# self.total_demand = total_demand |
|
106
|
|
|
# |
|
107
|
|
|
# self.el_bus = el_bus |
|
108
|
|
|
# |
|
109
|
|
|
# def build_subnetwork(self): |
|
110
|
|
|
# |
|
111
|
|
|
# demand_reduction_factor = 1 - dict_asset[EFFICIENCY][VALUE] |
|
112
|
|
|
# tot_demand = dict_asset[TIMESERIES] |
|
113
|
|
|
# non_critical_demand_ts = tot_demand * demand_reduction_factor |
|
114
|
|
|
# non_critical_demand_peak = non_critical_demand_ts.max() |
|
115
|
|
|
# if non_critical_demand_peak == 0: |
|
116
|
|
|
# max_non_critical = 1 |
|
117
|
|
|
# else: |
|
118
|
|
|
# max_non_critical = ( |
|
119
|
|
|
# non_critical_demand_ts / non_critical_demand_peak |
|
120
|
|
|
# ) |
|
121
|
|
|
# critical_demand_ts = tot_demand * dict_asset[EFFICIENCY][VALUE] |
|
122
|
|
|
# |
|
123
|
|
|
# # # check if the sink has multiple input busses |
|
124
|
|
|
# # if isinstance(dict_asset[INFLOW_DIRECTION], list): |
|
125
|
|
|
# # pass |
|
126
|
|
|
# # # inputs_noncritical = {} |
|
127
|
|
|
# # # inputs_critical = {} |
|
128
|
|
|
# # # index = 0 |
|
129
|
|
|
# # # for bus in dict_asset[INFLOW_DIRECTION]: |
|
130
|
|
|
# # # inputs_critical[kwargs[OEMOF_BUSSES][bus]] = solph.Flow( |
|
131
|
|
|
# # # fix=dict_asset[TIMESERIES], nominal_value=1 |
|
132
|
|
|
# # # ) |
|
133
|
|
|
# # # index += 1 |
|
134
|
|
|
# # else: |
|
135
|
|
|
# # inputs_noncritical = { |
|
136
|
|
|
# # kwargs[OEMOF_BUSSES][dict_asset[INFLOW_DIRECTION]]: solph.Flow( |
|
137
|
|
|
# # min=0, |
|
138
|
|
|
# # max=max_non_critical, |
|
139
|
|
|
# # nominal_value=non_critical_demand_peak, |
|
140
|
|
|
# # variable_costs=-1e-15, |
|
141
|
|
|
# # ) |
|
142
|
|
|
# # } |
|
143
|
|
|
# # inputs_critical = { |
|
144
|
|
|
# # kwargs[OEMOF_BUSSES][dict_asset[INFLOW_DIRECTION]]: solph.Flow( |
|
145
|
|
|
# # fix=critical_demand_ts, nominal_value=1 |
|
146
|
|
|
# # ) |
|
147
|
|
|
# # } |
|
148
|
|
|
# |
|
149
|
|
|
# non_critical_demand = Sink( |
|
150
|
|
|
# inputs={ |
|
151
|
|
|
# self.el_bus: Flow( |
|
152
|
|
|
# min=0, |
|
153
|
|
|
# max=max_non_critical, |
|
154
|
|
|
# nominal_value=non_critical_demand_peak, |
|
155
|
|
|
# variable_costs=-1e-15, |
|
156
|
|
|
# ) |
|
157
|
|
|
# }, |
|
158
|
|
|
# ) |
|
159
|
|
|
# critical_demand = solph.components.Sink( |
|
160
|
|
|
# label=reducable_demand_name(dict_asset[LABEL], critical=True), |
|
161
|
|
|
# inputs=inputs_critical, |
|
162
|
|
|
# ) |
|
163
|
|
|
# |
|
164
|
|
|
# # create and add demand sink and critical demand sink |
|
165
|
|
|
# |
|
166
|
|
|
# model.add(critical_demand) |
|
167
|
|
|
# model.add(non_critical_demand) |
|
168
|
|
|
# kwargs[OEMOF_SINK].update( |
|
169
|
|
|
# {reducable_demand_name(dict_asset[LABEL]): non_critical_demand} |
|
170
|
|
|
# ) |
|
171
|
|
|
# kwargs[OEMOF_SINK].update( |
|
172
|
|
|
# { |
|
173
|
|
|
# reducable_demand_name( |
|
174
|
|
|
# dict_asset[LABEL], critical=True |
|
175
|
|
|
# ): critical_demand |
|
176
|
|
|
# } |
|
177
|
|
|
# ) |
|
178
|
|
|
# logging.debug( |
|
179
|
|
|
# f"Added: Reducable Non-dispatchable sink {dict_asset[LABEL]} to bus {dict_asset[INFLOW_DIRECTION]}" |
|
180
|
|
|
# ) |
|
181
|
|
|
|