Source code for tespy.components.heat_exchangers.parallel

# -*- coding: utf-8

"""Module of class ParallelFlowHeatExchanger.


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/heat_exchangers/parallel.py

SPDX-License-Identifier: MIT
"""
import math

from tespy.components.component import component_registry
from tespy.components.heat_exchangers.base import HeatExchanger


[docs] @component_registry class ParallelFlowHeatExchanger(HeatExchanger): r""" Class for parallel flow heat exchanger. .. image:: /api/_images/components/HeatExchanger.svg :alt: flowsheet of the parallelflowheatexchanger :align: center :class: only-light .. image:: /api/_images/components/HeatExchanger_darkmode.svg :alt: flowsheet of the parallelflowheatexchanger :align: center :class: only-dark Ports ----- - Fluid inlets: in1, in2 - Fluid outlets: out1, out2 Mandatory Equations ------------------- - mass flow equality constraint(s): :py:meth:`variable_equality_structure_matrix <tespy.components.component.Component.variable_equality_structure_matrix>` - fluid composition equality constraint(s): :py:meth:`variable_equality_structure_matrix <tespy.components.component.Component.variable_equality_structure_matrix>` - hot side to cold side heat transfer equation: :py:meth:`energy_balance_func <tespy.components.heat_exchangers.base.HeatExchanger.energy_balance_func>` Parameters ---------- char_warnings : bool Ignore warnings on default characteristics usage for this component. design : list List containing design parameters (stated as String). design_path : str Path to the components design case. dp1 : float, dict Hot side inlet to outlet absolute pressure change. Quantity: :code:`pressure_difference`. Equation: :py:meth:`dp_structure_matrix <tespy.components.component.Component.dp_structure_matrix>`. dp2 : float, dict Cold side inlet to outlet absolute pressure change. Quantity: :code:`pressure_difference`. Equation: :py:meth:`dp_structure_matrix <tespy.components.component.Component.dp_structure_matrix>`. kA : float, dict Deprecated, use :code:`UA` instead. Quantity: :code:`heat_transfer_coefficient`. kA_char : GroupedComponentCharacteristics Deprecated, use :code:`UA_char` instead. Elements: :code:`kA_char1`, :code:`kA_char2`. kA_char1 : tespy.tools.characteristics.CharLine, dict Deprecated, use :code:`UA_char1` instead. kA_char2 : tespy.tools.characteristics.CharLine, dict Deprecated, use :code:`UA_char2` instead. label : str The label of the component. lmtd : float, dict Effective logarithmic mean temperature difference |Q|/UA. Quantity: :code:`temperature_difference`. local_design : bool Treat this component in design mode in an offdesign calculation. local_offdesign : bool Treat this component in offdesign mode in a design calculation. offdesign : list List containing offdesign parameters (stated as String). pr1 : float, dict Hot side outlet to inlet pressure ratio. Quantity: :code:`ratio`. Equation: :py:meth:`pr_structure_matrix <tespy.components.component.Component.pr_structure_matrix>`. pr2 : float, dict Cold side outlet to inlet pressure ratio. Quantity: :code:`ratio`. Equation: :py:meth:`pr_structure_matrix <tespy.components.component.Component.pr_structure_matrix>`. printout : bool Include this component in the network's results printout. Q : float, dict Heat transfer from hot side. Quantity: :code:`heat`. Equation: :py:meth:`energy_balance_hot_func <tespy.components.heat_exchangers.base.HeatExchanger.energy_balance_hot_func>`. td_log : float, dict Deprecated, use :code:`lmtd` instead. Quantity: :code:`temperature_difference`. ttd_l : float, dict Terminal temperature difference at hot side outlet to cold side inlet. Quantity: :code:`temperature_difference`. Equation: :py:meth:`ttd_l_func <tespy.components.heat_exchangers.parallel.ParallelFlowHeatExchanger.ttd_l_func>`. ttd_u : float, dict Terminal temperature difference at hot side inlet to cold side outlet. Quantity: :code:`temperature_difference`. Equation: :py:meth:`ttd_u_func <tespy.components.heat_exchangers.parallel.ParallelFlowHeatExchanger.ttd_u_func>`. UA : float, dict Heat transfer coefficient considering terminal temperature differences. Quantity: :code:`heat_transfer_coefficient`. Equation: :py:meth:`UA_func <tespy.components.heat_exchangers.base.HeatExchanger.UA_func>`. UA_char : GroupedComponentCharacteristics Equation for heat transfer based on UA and modification factor. Elements: :code:`UA_char1`, :code:`UA_char2`. Equation: :py:meth:`UA_char_func <tespy.components.heat_exchangers.base.HeatExchanger.UA_char_func>`. UA_char1 : tespy.tools.characteristics.CharLine, dict Hot side UA modification lookup table for offdesign. UA_char2 : tespy.tools.characteristics.CharLine, dict Cold side UA modification lookup table for offdesign. zeta1 : float, dict Deprecated, use :code:`zeta1_d4` instead. zeta1_d4 : float, dict Hot side geometry-independent friction coefficient zeta/D^4 for pressure loss calculation. Equation: :py:meth:`zeta_d4_func <tespy.components.component.Component.zeta_d4_func>`. zeta2 : float, dict Deprecated, use :code:`zeta2_d4` instead. zeta2_d4 : float, dict Cold side geometry-independent friction coefficient zeta/D^4 for pressure loss calculation. Equation: :py:meth:`zeta_d4_func <tespy.components.component.Component.zeta_d4_func>`. Notes ----- .. note:: The :code:`ParallelFlowHeatExchanger` implements parallel flow of both streams, meaning the streams enter with a high temperature difference and then gradually reduce their temperature difference to each other. The initial temperature difference is the maximum temperature difference, the final temperature difference is the minimum temperature difference. Example ------- Water at 75 °C is used to heat up an air stream 2500 l/s from 10 °C to 35 °C. >>> from tespy.components import Sink, Source, ParallelFlowHeatExchanger >>> from tespy.connections import Connection >>> from tespy.networks import Network >>> nw = Network(iterinfo=False) >>> nw.units.set_defaults(**{ ... "pressure": "bar", "pressure_difference": "bar", ... "temperature": "degC", "enthalpy": "kJ/kg", ... "volumetric_flow": "l/s", "heat_transfer_coefficient": "kW/K" ... }) >>> feed_water = Source("Feed water inlet") >>> return_water = Sink("Water outlet") >>> air_inlet = Source("Fresh air inlet") >>> air_warm = Sink("Air outlet") >>> he = ParallelFlowHeatExchanger("heat exchanger") >>> c1 = Connection(feed_water, 'out1', he, 'in1') >>> c2 = Connection(he, 'out1', return_water, 'in1') >>> c3 = Connection(air_inlet, 'out1', he, 'in2') >>> c4 = Connection(he, 'out2', air_warm, 'in1') >>> nw.add_conns(c1, c2, c3, c4) We assume pressure losses of 10 mbar on the air side, and 100 mbar on the water side. Depending on our specifications we can calculate: - What is the temperature of the water leaving the heat exchanger, or - What is the required mass flow of water to heat up the air Let's first assume, that a final pinch :code:`ttd_u` of 7.5 K is desired, meaning, the water should leave the heat exchanger with a temperature higher than the air by 7.5 K. With that, we will get the water flow, and also the heat transfer coefficient :code:`kA` as a result. .. note:: Note, that for specification of initial or final pinch temperature differences, it is often important to start the calculation with a good initial guess. In this case, we know that the water will be in liquid state, therefore we can - either specify the outlet enthalpy initial guess to be liquid, - the state at the water outlet to be :code:`"l"`, - or use :code:`"INCOMP::Water"` as fluid, since this uses liquid phase only. >>> he.set_attr(dp1=0.1, dp2=0.01, ttd_u=7.5) >>> c1.set_attr(fluid={"INCOMP::Water": 1}, T=70, p=1.3) >>> c3.set_attr(fluid={"air": 1}, T=10, p=1.02, v=2500) >>> c4.set_attr(T=35) >>> nw.solve("design") >>> round(c1.v.val, 2) 0.7 >>> round(he.kA.val, 2) 3.13 Now, it might be interesting to see what happens under different operation conditions after we have designed the system. For that, we can assume that the heat transfer coefficient is constant. First we just fix the :code:`UA` value instead of the final pinch and then resolve again. >>> he.set_attr(design=["ttd_u"], offdesign=["UA"]) >>> design_state = nw.save(as_dict=True) >>> nw.solve("offdesign", design_path=design_state) >>> round(he.UA.val_SI / he.UA.design, 1) 1.0 Now, let's see what happens under different operating conditions. First we change the air volumetric flow, then we change the air temperature to check what happens to the outflow temperature of the water. >>> c3.set_attr(v=2000) >>> nw.solve("offdesign", design_path=design_state) >>> round(c2.T.val, 2) 38.69 >>> c3.set_attr(v=2500, T=8) >>> nw.solve("offdesign", design_path=design_state) >>> round(c2.T.val, 2) 44.0 """
[docs] def get_parameters(self): params = super().get_parameters() del params["ttd_min"] del params["eff_hot"] del params["eff_cold"] del params["eff_max"] return params
def _calc_ttd_u(self): return self.outl[0].T.val_SI - self.outl[1].T.val_SI def _calc_ttd_l(self): return self.inl[0].T.val_SI - self.inl[1].T.val_SI
[docs] def ttd_l_func(self): T_i1 = self.inl[0].calc_T() T_i2 = self.inl[1].calc_T() return self.ttd_l.val_SI - T_i1 + T_i2
[docs] def ttd_l_dependents(self): return [var for c in self.inl for var in [c.p, c.h]]
[docs] def ttd_u_func(self): T_o1 = self.outl[0].calc_T() T_o2 = self.outl[1].calc_T() return self.ttd_u.val_SI - T_o1 + T_o2
[docs] def ttd_u_dependents(self): return [var for c in self.outl for var in [c.p, c.h]]
[docs] def calculate_td_log(self): T_i1 = self.inl[0].calc_T() T_i2 = self.inl[1].calc_T() T_o1 = self.outl[0].calc_T() T_o2 = self.outl[1].calc_T() ttd_u = T_o1 - T_o2 ttd_l = T_i1 - T_i2 min_ttd = min(ttd_u, ttd_l) if min_ttd <= 0: return min_ttd if round(ttd_u, 6) == round(ttd_l, 6): return ttd_l return (ttd_l - ttd_u) / math.log(ttd_l / ttd_u)