Source code for tespy.components.turbomachinery.steam_turbine

# -*- coding: utf-8

"""Module of class SteamTurbine.


This file is part of project TESPy (github.com/oemof/tespy). It's copyrighted
by the contributors recorded in the version control history of the file,
available from its original location tespy/components/turbomachinery/steam_turbine.py

SPDX-License-Identifier: MIT
"""

from scipy.optimize import brentq

from tespy.components.component import component_registry
from tespy.components.turbomachinery.turbine import Turbine
from tespy.tools.data_containers import ComponentProperties as dc_cp
from tespy.tools.data_containers import GroupedComponentProperties as dc_gcp
from tespy.tools.fluid_properties import h_mix_pQ
from tespy.tools.fluid_properties import isentropic
from tespy.tools.fluid_properties.helpers import single_fluid
from tespy.tools.helpers import fluidalias_in_list
from tespy.tools.logger import logger


[docs] @component_registry class SteamTurbine(Turbine): r""" Class for steam turbines with wet expansion. **Mandatory Equations** - fluid: :py:meth:`tespy.components.component.Component.variable_equality_structure_matrix` - mass flow: :py:meth:`tespy.components.component.Component.variable_equality_structure_matrix` **Optional Equations** - :py:meth:`tespy.components.component.Component.dp_structure_matrix` - :py:meth:`tespy.components.component.Component.pr_structure_matrix` - :py:meth:`tespy.components.turbomachinery.base.Turbomachine.energy_balance_func` - :py:meth:`tespy.components.turbomachinery.steam_turbine.SteamTurbine.eta_s_wet_func` - :py:meth:`tespy.components.turbomachinery.turbine.Turbine.eta_s_func` - :py:meth:`tespy.components.turbomachinery.turbine.Turbine.eta_s_char_func` - :py:meth:`tespy.components.turbomachinery.turbine.Turbine.cone_func` Inlets/Outlets - in1 - out1 Optional outlets - power Image .. image:: /api/_images/Turbine.svg :alt: flowsheet of the turbine :align: center :class: only-light .. image:: /api/_images/Turbine_darkmode.svg :alt: flowsheet of the turbine :align: center :class: only-dark Parameters ---------- label : str The label of the component. design : list List containing design parameters (stated as String). offdesign : list List containing offdesign parameters (stated as String). design_path : str Path to the components design case. local_offdesign : boolean Treat this component in offdesign mode in a design calculation. local_design : boolean Treat this component in design mode in an offdesign calculation. char_warnings : boolean Ignore warnings on default characteristics usage for this component. printout : boolean Include this component in the network's results printout. P : float, dict Power, :math:`P/\text{W}` eta_s : float, dict Isentropic efficiency, :math:`\eta_s/1` eta_s_dry : float, dict Dry isentropic efficiency, :math:`\eta_s/1` alpha: float, dict Influence factor on wetness efficiency modifier, :math:`\alpha/1` pr : float, dict Outlet to inlet pressure ratio, :math:`pr/1` dp : float, dict Inlet to outlet pressure difference, :math:`dp/\text{p}_\text{unit}` Is specified in the Network's pressure unit eta_s_char : tespy.tools.characteristics.CharLine, dict Characteristic curve for isentropic efficiency, provide CharLine as function :code:`func`. cone : dict Apply Stodola's cone law (works in offdesign only). Example ------- A steam turbine expands 10 kg/s of superheated steam at 550 °C and 110 bar to 0,5 bar at the outlet. For example, it is possible to calulate the power output and vapour content at the outlet for a given isentropic efficiency. The :code:`SteamTurbine` class follows the implementation of the Baumann rule :cite:`Tanuma2017` >>> from tespy.components import Sink, Source, SteamTurbine >>> from tespy.connections import Connection >>> from tespy.networks import Network >>> nw = Network(iterinfo=False) >>> nw.units.set_defaults(**{ ... "pressure": "bar", "temperature": "degC", "enthalpy": "kJ/kg" ... }) >>> si = Sink('sink') >>> so = Source('source') >>> st = SteamTurbine('steam turbine') >>> inc = Connection(so, 'out1', st, 'in1') >>> outg = Connection(st, 'out1', si, 'in1') >>> nw.add_conns(inc, outg) In design conditions the isentropic efficiency is specified. >>> st.set_attr(eta_s=0.9) >>> inc.set_attr(fluid={'water': 1}, m=10, T=250, p=20) >>> outg.set_attr(p=0.1) >>> nw.solve('design') >>> round(st.P.val, 0) -7471296.0 >>> round(outg.x.val, 3) 0.821 To capture the effect of liquid drop-out on the isentropic efficiency, the dry turbine efficiency is specified >>> st.set_attr(eta_s=None) >>> st.set_attr(eta_s_dry=0.9, alpha=1.0) >>> nw.solve('design') >>> round(st.P.val, 0) -7009682.0 >>> round(outg.x.val, 3) 0.84 """
[docs] def get_parameters(self): params = super().get_parameters() params["alpha"] = dc_cp( min_val=0.4, max_val=2.5, quantity="ratio", description="influence factor for wetness efficiency modifier" ) params["eta_s_dry"] = dc_cp( min_val=0.0, max_val=1.0, quantity="efficiency", description="isentropic efficiency of dry expansion" ) params["eta_s_dry_group"] = dc_gcp( num_eq_sets=1, elements=["alpha", "eta_s_dry"], func=self.eta_s_wet_func, dependents=self.eta_s_dependents, # same depedents! description="method to apply Baumann rule" ) return params
def _preprocess(self, num_nw_vars): fluid = single_fluid(self.inl[0].fluid_data) if fluid is None: msg = "The SteamTurbine can only be used with pure fluids." logger.error(msg) raise ValueError(msg) if not fluidalias_in_list(fluid, ["water"]): msg = "The SteamTurbine is intended to be used with water only." logger.warning(msg) return super()._preprocess(num_nw_vars)
[docs] def eta_s_wet_func(self): r""" Equation for given dry isentropic efficiency of a turbine under wet expansion. Returns ------- residual : float Residual value of equation. .. math:: 0 = -\left( h_{out} - h_{in} \right) + \left( h_{out,s} - h_{in} \right) \cdot \eta_{s,e} \eta_{s,e} = \eta_{s,e}^{dry} \cdot \left( 1 - \alpha \cdot y_m \right) y_m = \frac{\left( 1-x_{in}\right)+ \left( 1-x_{out} \right)}{2} """ inl = self.inl[0] outl = self.outl[0] state = inl.calc_phase() if state == "tp": # two-phase or saturated vapour ym = 1 - (inl.calc_x() + outl.calc_x()) / 2 # average wetness return ( self.calc_eta_s() - self.eta_s_dry.val_SI * (1 - self.alpha.val_SI * ym) ) else: # superheated vapour if outl.calc_phase() == "g": return self.calc_eta_s() - self.eta_s_dry.val_SI dp = inl.p.val_SI - outl.p.val_SI # compute the pressure and enthalpy at which the expansion # enters the vapour dome def find_sat(frac): psat = inl.p.val_SI - frac * dp # calculate enthalpy under dry expansion to psat hout_isen = isentropic( inl.p.val_SI, inl.h.val_SI, psat, inl.fluid_data, inl.mixing_rule, T0=inl.T.val_SI ) hout = ( inl.h.val_SI - self.eta_s_dry.val_SI * (inl.h.val_SI - hout_isen) ) # calculate enthalpy of saturated vapour at psat hsat = h_mix_pQ(psat, 1, inl.fluid_data) return hout - hsat frac = brentq(find_sat, 1, 0) psat = inl.p.val_SI - frac * dp hsat = h_mix_pQ(psat, 1, inl.fluid_data) # calculate the isentropic efficiency for wet expansion ym = 1 - (1.0 + outl.calc_x()) / 2 # average wetness eta_s = self.eta_s_dry.val_SI * (1 - self.alpha.val_SI * ym) # calculate the final outlet enthalpy hout_isen = isentropic( psat, hsat, outl.p.val_SI, inl.fluid_data, inl.mixing_rule, T0=inl.T.val_SI ) hout = hsat - eta_s * (hsat - hout_isen) # return residual: outlet enthalpy = calculated outlet enthalpy return outl.h.val_SI - hout
[docs] def initialise_source(self, c, key): r""" Return a starting value for pressure and enthalpy at outlet. Parameters ---------- c : tespy.connections.connection.Connection Connection to perform initialisation on. key : str Fluid property to retrieve. Returns ------- val : float Starting value for pressure/enthalpy in SI units. """ if key == 'p': return super().initialise_source(c, key) elif key == 'h': fluid = single_fluid(c.fluid_data) if fluid is not None: return h_mix_pQ(c.p.val_SI, 0.9, c.fluid_data, c.mixing_rule)