Source code for oemof.solph.components.extraction_turbine_chp
# -*- coding: utf-8 -
"""
ExtractionTurbineCHP and associated individual constraints (blocks)
and groupings.
SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de>
SPDX-FileCopyrightText: Simon Hilpert
SPDX-FileCopyrightText: Cord Kaldemeyer
SPDX-FileCopyrightText: Patrik Schönfeldt
SPDX-FileCopyrightText: FranziPl
SPDX-FileCopyrightText: jnnr
SPDX-FileCopyrightText: Stephan Günther
SPDX-FileCopyrightText: FabianTU
SPDX-FileCopyrightText: Johannes Röder
SPDX-License-Identifier: MIT
"""
from pyomo.core.base.block import SimpleBlock
from pyomo.environ import BuildAction
from pyomo.environ import Constraint
from oemof.solph import network as solph_network
from oemof.solph.plumbing import sequence as solph_sequence
[docs]class ExtractionTurbineCHP(solph_network.Transformer):
r"""
A CHP with an extraction turbine in a linear model. For more options see
the :class:`~oemof.solph.components.GenericCHP` class.
One main output flow has to be defined and is tapped by the remaining flow.
The conversion factors have to be defined for the maximum tapped flow (
full CHP mode) and for no tapped flow (full condensing mode). Even though
it is possible to limit the variability of the tapped flow, so that the
full condensing mode will never be reached.
Parameters
----------
conversion_factors : dict
Dictionary containing conversion factors for conversion of inflow
to specified outflow. Keys are output bus objects.
The dictionary values can either be a scalar or a sequence with length
of time horizon for simulation.
conversion_factor_full_condensation : dict
The efficiency of the main flow if there is no tapped flow. Only one
key is allowed. Use one of the keys of the conversion factors. The key
indicates the main flow. The other output flow is the tapped flow.
Notes
-----
The following sets, variables, constraints and objective parts are created
* :py:class:`~oemof.solph.components.extraction_turbine_chp.ExtractionTurbineCHPBlock`
Examples
--------
>>> from oemof import solph
>>> bel = solph.Bus(label='electricityBus')
>>> bth = solph.Bus(label='heatBus')
>>> bgas = solph.Bus(label='commodityBus')
>>> et_chp = solph.components.ExtractionTurbineCHP(
... label='variable_chp_gas',
... inputs={bgas: solph.Flow(nominal_value=10e10)},
... outputs={bel: solph.Flow(), bth: solph.Flow()},
... conversion_factors={bel: 0.3, bth: 0.5},
... conversion_factor_full_condensation={bel: 0.5})
""" # noqa: E501
def __init__(self, conversion_factor_full_condensation, *args, **kwargs):
super().__init__(*args, **kwargs)
self.conversion_factor_full_condensation = {
k: solph_sequence(v)
for k, v in conversion_factor_full_condensation.items()
}
[docs]class ExtractionTurbineCHPBlock(SimpleBlock):
r"""Block for the linear relation of nodes with type
:class:`~oemof.solph.components.ExtractionTurbineCHP`
**The following two constraints are created:**
.. _ETCHP-equations:
.. math::
&
(1)\dot H_{Fuel}(t) =
\frac{P_{el}(t) + \dot Q_{th}(t) \cdot \beta(t)}
{\eta_{el,woExtr}(t)} \\
&
(2)P_{el}(t) \geq \dot Q_{th}(t) \cdot C_b =
\dot Q_{th}(t) \cdot
\frac{\eta_{el,maxExtr}(t)}
{\eta_{th,maxExtr}(t)}
where :math:`\beta` is defined as:
.. math::
\beta(t) = \frac{\eta_{el,woExtr}(t) -
\eta_{el,maxExtr}(t)}{\eta_{th,maxExtr}(t)}
where the first equation is the result of the relation between the input
flow and the two output flows, the second equation stems from how the two
output flows relate to each other, and the symbols used are defined as
follows (with Variables (V) and Parameters (P)):
========================= ============================================ ==== =========
symbol attribute type explanation
========================= ============================================ ==== =========
:math:`\dot H_{Fuel}` `flow[i, n, t]` V fuel input flow
:math:`P_{el}` `flow[n, main_output, t]` V electric power
:math:`\dot Q_{th}` `flow[n, tapped_output, t]` V thermal output
:math:`\beta` `main_flow_loss_index[n, t]` P power loss index
:math:`\eta_{el,woExtr}` `conversion_factor_full_condensation[n, t]` P electric efficiency
without heat extraction
:math:`\eta_{el,maxExtr}` `conversion_factors[main_output][n, t]` P electric efficiency
with max heat extraction
:math:`\eta_{th,maxExtr}` `conversion_factors[tapped_output][n, t]` P thermal efficiency with
maximal heat extraction
========================= ============================================ ==== =========
""" # noqa: E501
CONSTRAINT_GROUP = True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def _create(self, group=None):
"""Creates the linear constraint for the
:class:`oemof.solph.Transformer` block.
Parameters
----------
group : list
List of :class:`oemof.solph.ExtractionTurbineCHP` (trsf) objects
for which the linear relation of inputs and outputs is created
e.g. group = [trsf1, trsf2, trsf3, ...]. Note that the relation
is created for all existing relations of the inputs and all outputs
of the transformer. The components inside the list need to hold
all needed attributes.
"""
if group is None:
return None
m = self.parent_block()
for n in group:
n.inflow = list(n.inputs)[0]
n.main_flow = [
k for k, v in n.conversion_factor_full_condensation.items()
][0]
n.main_output = [o for o in n.outputs if n.main_flow == o][0]
n.tapped_output = [o for o in n.outputs if n.main_flow != o][0]
n.conversion_factor_full_condensation_sq = (
n.conversion_factor_full_condensation[n.main_output]
)
n.flow_relation_index = [
n.conversion_factors[n.main_output][t]
/ n.conversion_factors[n.tapped_output][t]
for t in m.TIMESTEPS
]
n.main_flow_loss_index = [
(
n.conversion_factor_full_condensation_sq[t]
- n.conversion_factors[n.main_output][t]
)
/ n.conversion_factors[n.tapped_output][t]
for t in m.TIMESTEPS
]
def _input_output_relation_rule(block):
"""Connection between input, main output and tapped output."""
for t in m.TIMESTEPS:
for g in group:
lhs = m.flow[g.inflow, g, t]
rhs = (
m.flow[g, g.main_output, t]
+ m.flow[g, g.tapped_output, t]
* g.main_flow_loss_index[t]
) / g.conversion_factor_full_condensation_sq[t]
block.input_output_relation.add((g, t), (lhs == rhs))
self.input_output_relation = Constraint(
group, m.TIMESTEPS, noruleinit=True
)
self.input_output_relation_build = BuildAction(
rule=_input_output_relation_rule
)
def _out_flow_relation_rule(block):
"""Relation between main and tapped output in full chp mode."""
for t in m.TIMESTEPS:
for g in group:
lhs = m.flow[g, g.main_output, t]
rhs = (
m.flow[g, g.tapped_output, t]
* g.flow_relation_index[t]
)
block.out_flow_relation.add((g, t), (lhs >= rhs))
self.out_flow_relation = Constraint(
group, m.TIMESTEPS, noruleinit=True
)
self.out_flow_relation_build = BuildAction(
rule=_out_flow_relation_rule
)