Source code for tespy.components.nodes.splitter

# -*- coding: utf-8

"""Module of class Splitter.


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/nodes/splitter.py

SPDX-License-Identifier: MIT
"""

import numpy as np

from tespy.components.nodes.base import NodeBase
from tespy.tools.data_containers import DataContainerSimple as dc_simple
from tespy.tools.document_models import generate_latex_eq


[docs]class Splitter(NodeBase): r""" Split up a mass flow in parts of identical enthalpy and fluid composition. **Mandatory Equations** - :py:meth:`tespy.components.nodes.base.NodeBase.mass_flow_func` - :py:meth:`tespy.components.nodes.base.NodeBase.pressure_equality_func` - :py:meth:`tespy.components.nodes.splitter.Splitter.fluid_func` - :py:meth:`tespy.components.nodes.splitter.Splitter.energy_balance_func` Inlets/Outlets - in1 - specify number of outlets with :code:`num_out` (default value: 2) Image .. image:: /api/_images/Splitter.svg :alt: flowsheet of the splitter :align: center :class: only-light .. image:: /api/_images/Splitter_darkmode.svg :alt: flowsheet of the splitter :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. num_out : float, dict Number of outlets for this component, default value: 2. Example ------- A splitter is used to split up a single mass flow into a specified number of different parts at identical pressure, enthalpy and fluid composition. >>> from tespy.components import Sink, Source, Splitter >>> from tespy.connections import Connection >>> from tespy.networks import Network >>> import shutil >>> import numpy as np >>> fluid_list = ['O2', 'N2'] >>> nw = Network(fluids=fluid_list, p_unit='bar', T_unit='C', ... iterinfo=False) >>> so = Source('source') >>> si1 = Sink('sink1') >>> si2 = Sink('sink2') >>> si3 = Sink('sink3') >>> s = Splitter('splitter', num_out=3) >>> s.component() 'splitter' >>> inc = Connection(so, 'out1', s, 'in1') >>> outg1 = Connection(s, 'out1', si1, 'in1') >>> outg2 = Connection(s, 'out2', si2, 'in1') >>> outg3 = Connection(s, 'out3', si3, 'in1') >>> nw.add_conns(inc, outg1, outg2, outg3) An Air (simplified) mass flow is split up into three mass flows. The total incoming mass flow is 5 kg/s, 3 kg/s and 1 kg/s respectively are leaving the splitter into the first two outlets. The residual mass flow will drain in the last outlet. Temperature and fluid composition will not change. >>> inc.set_attr(fluid={'O2': 0.23, 'N2': 0.77}, p=1, T=20, m=5) >>> outg1.set_attr(m=3) >>> outg2.set_attr(m=1) >>> nw.solve('design') >>> round(outg3.m.val_SI, 1) 1.0 >>> round(inc.T.val, 1) 20.0 >>> round(outg3.T.val, 1) 20.0 """
[docs] @staticmethod def component(): return 'splitter'
[docs] @staticmethod def get_variables(): return {'num_out': dc_simple()}
[docs] def get_mandatory_constraints(self): return { 'mass_flow_constraints': { 'func': self.mass_flow_func, 'deriv': self.mass_flow_deriv, 'constant_deriv': True, 'latex': self.mass_flow_func_doc, 'num_eq': 1}, 'fluid_constraints': { 'func': self.fluid_func, 'deriv': self.fluid_deriv, 'constant_deriv': True, 'latex': self.fluid_func_doc, 'num_eq': self.num_o * self.num_nw_fluids}, 'energy_balance_constraints': { 'func': self.energy_balance_func, 'deriv': self.energy_balance_deriv, 'constant_deriv': True, 'latex': self.energy_balance_func_doc, 'num_eq': self.num_o}, 'pressure_constraints': { 'func': self.pressure_equality_func, 'deriv': self.pressure_equality_deriv, 'constant_deriv': True, 'latex': self.pressure_equality_func_doc, 'num_eq': self.num_i + self.num_o - 1} }
[docs] @staticmethod def inlets(): return ['in1']
[docs] def outlets(self): if self.num_out.is_set: return ['out' + str(i + 1) for i in range(self.num_out.val)] else: self.set_attr(num_out=2) return self.outlets()
[docs] def fluid_func(self): r""" Calculate the vector of residual values for fluid balance equations. Returns ------- residual : list Vector of residual values for component's fluid balance. .. math:: 0 = x_{fl,in} - x_{fl,out,j} \; \forall fl \in \text{network fluids,} \; \forall j \in \text{outlets} """ residual = [] for o in self.outl: for fluid, x in self.inl[0].fluid.val.items(): residual += [x - o.fluid.val[fluid]] return residual
[docs] def fluid_func_doc(self, label): r""" Calculate the vector of residual values for fluid balance equations. Parameters ---------- label : str Label for equation. Returns ------- latex : str LaTeX code of equations applied. """ latex = ( r'0 = x_{fl\mathrm{,in}} - x_{fl\mathrm{,out,}j}' r'\; \forall fl \in \text{network fluids,} \; \forall j \in' r'\text{outlets}' ) return generate_latex_eq(self, latex, label)
[docs] def fluid_deriv(self): r""" Calculate partial derivatives for all fluid balance equations. Returns ------- deriv : list Matrix with partial derivatives for the fluid equations. """ deriv = np.zeros((self.num_nw_fluids * self.num_o, 1 + self.num_o, self.num_nw_vars)) k = 0 for o in self.outl: i = 0 for fluid in self.nw_fluids: deriv[i + k * self.num_nw_fluids, 0, i + 3] = 1 deriv[i + k * self.num_nw_fluids, k + 1, i + 3] = -1 i += 1 k += 1 return deriv
[docs] def energy_balance_func(self): r""" Calculate energy balance. Returns ------- residual : list Residual value of energy balance. .. math:: 0 = h_{in} - h_{out,j} \; \forall j \in \mathrm{outlets}\\ """ residual = [] for o in self.outl: residual += [self.inl[0].h.val_SI - o.h.val_SI] return residual
[docs] def energy_balance_func_doc(self, label): r""" Calculate energy balance. Parameters ---------- label : str Label for equation. """ latex = r'0=h_{in}-h_{\mathrm{out,}j}\;\forall j \in\text{outlets}' return generate_latex_eq(self, latex, label)
[docs] def energy_balance_deriv(self): r""" Calculate partial derivatives for energy balance equation. Returns ------- deriv : list Matrix of partial derivatives. """ deriv = np.zeros((self.num_o, 1 + self.num_o, self.num_nw_vars)) k = 0 for o in self.outl: deriv[k, 0, 2] = 1 deriv[k, k + 1, 2] = -1 k += 1 return deriv
[docs] def propagate_fluid_to_target(self, inconn, start): r""" Propagate the fluids towards connection's target in recursion. Parameters ---------- inconn : tespy.connections.connection.Connection Connection to initialise. start : tespy.components.component.Component This component is the fluid propagation starting point. The starting component is saved to prevent infinite looping. """ for outconn in self.outl: for fluid, x in inconn.fluid.val.items(): if (outconn.fluid.val_set[fluid] is False and outconn.good_starting_values is False): outconn.fluid.val[fluid] = x outconn.target.propagate_fluid_to_target(outconn, start)
[docs] def propagate_fluid_to_source(self, outconn, start): r""" Propagate the fluids towards connection's source in recursion. Parameters ---------- outconn : tespy.connections.connection.Connection Connection to initialise. start : tespy.components.component.Component This component is the fluid propagation starting point. The starting component is saved to prevent infinite looping. """ inconn = self.inl[0] for fluid, x in outconn.fluid.val.items(): if (inconn.fluid.val_set[fluid] is False and inconn.good_starting_values is False): inconn.fluid.val[fluid] = x inconn.source.propagate_fluid_to_source(inconn, start)