Source code for component.heat_exchanger.hex_eNTU

# -*- coding: utf-8 -*-
"""
Created on Tue Jul 30 14:32:39 2024

@author: Basile
"""

from component.base_component import BaseComponent

from correlations.convection.pipe_htc import gnielinski_pipe_htc 
from correlations.heat_exchanger.e_NTU import e_NTU

from connector.mass_connector import MassConnector
from connector.work_connector import WorkConnector
from connector.heat_connector import HeatConnector

from CoolProp.CoolProp import PropsSI
import CoolProp.CoolProp as CP

[docs] class HexeNTU(BaseComponent): """ **Component**: Heat Exchanger **Model**: ε-NTU (Effectiveness - Number of Transfer Units) method. **Description**: This component models a heat exchanger using the ε-NTU method, a widely used approach for estimating heat transfer performance in steady-state conditions when outlet temperatures are not known a priori. It calculates heat transfer based on fluid properties, flow configuration, and geometry using thermal resistances and heat transfer correlations. The model is applicable to various geometries (e.g., pipe-type, plate-type) and requires fluid and geometric properties. The thermal effectiveness is computed via an external ε-NTU correlation, which supports multiple flow configurations (e.g., CounterFlow, ParallelFlow, CrossFlow). **Assumptions**: - Steady-state operation. - No heat loss to the environment. - No pressure drop considered (isenthalpic mixing assumed). - Thermophysical properties are evaluated at average temperatures. - No phase change within the exchanger. **Connectors**: su_H (MassConnector): Hot fluid inlet connector. su_C (MassConnector): Cold fluid inlet connector. ex_H (MassConnector): Hot fluid outlet connector. ex_C (MassConnector): Cold fluid outlet connector. Q_hex (HeatConnector): Connector for total heat transfer rate. **Parameters**: Flow_Type : Flow configuration of the fluid ('CounterFlow', 'CrossFlow', 'Shell&Tube', 'ParallelFlow') [-] A_htx: Total heat exchange area [m²] L_HTX: Length of the heat exchanger [m] V_HTX: Volume of the heat exchanger [m³] A_canal_H: Cross-sectional area of hot fluid channels [m²] A_canal_C: Cross-sectional area of cold fluid channels [m²] D_h: Hydraulic diameter [m] k_plate: Thermal conductivity of the separating plate [W/m.K] t_plate: Thickness of the separating plate [m] n_plates: Number of plates [-] co_pitch: Plate corrugation pitch [m] chevron_angle: Plate chevron angle [degrees] fouling: Fouling resistance [m².K/W] **Inputs**: T_su_H: Hot fluid inlet temperature [K] P_su_H: Hot fluid inlet pressure [Pa] h_su_H: Hot fluid inlet enthalpy [J/kg] fluid_H: Hot fluid identifier [-] m_dot_H: Hot fluid mass flow rate [kg/s] T_su_C: Cold fluid inlet temperature [K] P_su_C: Cold fluid inlet pressure [Pa] h_su_C: Cold fluid inlet enthalpy [J/kg] fluid_C: Cold fluid identifier [-] m_dot_C: Cold fluid mass flow rate [kg/s] **Outputs**: h_ex_H: Hot fluid outlet enthalpy [J/kg] P_ex_H: Hot fluid outlet pressure [Pa] h_ex_C: Cold fluid outlet enthalpy [J/kg] p_ex_C: Cold fluid outlet pressure [Pa] Q_dot: Heat transfer rate [W] """ def __init__(self): super().__init__() self.su_H = MassConnector() self.su_C = MassConnector() self.ex_H = MassConnector() self.ex_C = MassConnector() # Mass_connector self.Q_hex = HeatConnector() def get_required_inputs(self): # Return a list of required inputs return ['P_su_H', 'T_su_H', 'm_dot_H', 'fluid_H', 'P_su_C', 'T_su_C', 'm_dot_C', 'fluid_C'] def get_required_parameters(self): """ Returns the list of required parameters to describe the geometry and physical configuration """ return ['A_htx', 'L_HTX', 'V_HTX', 'Flow_Type', 'A_canal_h', 'A_canal_c', 'D_h', 'k_plate', 't_plate', 'n_plates', 'co_pitch', 'chevron_angle', 'fouling'] def solve(self): self.check_calculable() self.check_parametrized() self.AS_H = CP.AbstractState('HEOS', self.su_H.fluid) self.AS_C = CP.AbstractState('HEOS', self.su_C.fluid) if self.calculable and self.parametrized: # Detect Phase change # self.detect_phase_change() # Calcul de C_r # cp_h = PropsSI('C', 'H', self.su_hot.h, 'P', self.su_hot.p, self.su_hot.fluid) # cp_c = PropsSI('C', 'H', self.su_cold.h, 'P', self.su_cold.p, self.su_cold.fluid) self.AS_H.update(CP.HmassP_INPUTS, self.su_H.h, self.su_H.p) cp_h = self.AS_H.cpmass() self.AS_C.update(CP.HmassP_INPUTS, self.su_H.h, self.su_C.p) cp_c = self.AS_C.cpmass() C_h = cp_h*self.su_H.m_dot #Heat capacity rate C_c = cp_c*self.su_C.m_dot C_min = min(C_h, C_c) C_max = max(C_h, C_c) C_r = C_min/C_max # Heat capacity ratio # Calcul de NTU T_w = (self.su_H.T + self.su_C.T)/2 # --- Heat transfer coefficient estimation using Gnielinski correlation --- # mu_h, Pr_h, k_h = PropsSI(('V','PRANDTL','L'), 'H', self.su_hot.h, 'P', self.su_hot.p, self.su_hot.fluid) # mu_c, Pr_c, k_c = PropsSI(('V','PRANDTL','L'), 'H', self.su_cold.h, 'P', self.su_cold.p, self.su_cold.fluid) self.AS_H.update(CP.HmassP_INPUTS, self.su_H.h, self.su_H.p) mu_h = self.AS_H.viscosity() Pr_h = self.AS_H.Prandtl() k_h = self.AS_H.conductivity() self.AS_C.update(CP.HmassP_INPUTS, self.su_C.h, self.su_C.p) mu_c = self.AS_C.viscosity() Pr_c = self.AS_C.Prandtl() k_c = self.AS_C.conductivity() G_h = self.su_H.m_dot/self.params['A_canal_h'] G_c = self.su_C.m_dot/self.params['A_canal_c'] h_h = gnielinski_pipe_htc(mu_h, Pr_h, Pr_h, k_h, G_h, self.params['D_h'], self.params['L_HTX'])[0] h_c = gnielinski_pipe_htc(mu_c, Pr_c, Pr_c, k_c, G_c, self.params['D_h'], self.params['L_HTX'])[0] AU = (1/(self.params['A_htx']*h_h) + 1/(self.params['A_htx']*h_c) + self.params['t_plate']/(self.params['k_plate']*self.params['A_htx']) + self.params['fouling']/self.params['A_htx'])**(-1) NTU = AU/C_min # --- Calculate effectiveness from NTU correlation --- eps = e_NTU(NTU, C_r, self.params) # --- Estimate maximum heat transfer Q(ideal case with infinite area) --- # h_c_Th = PropsSI('H','T',self.su_hot.T,'P',self.su_cold.p,self.su_cold.fluid) # h_h_Tc = PropsSI('H','T',self.su_cold.T,'P',self.su_hot.p,self.su_hot.fluid) self.AS_C.update(CP.PT_INPUTS, self.su_C.p, self.su_H.T) h_c_Th = self.AS_C.hmass() self.AS_H.update(CP.PT_INPUTS, self.su_H.p, self.su_C.T) h_h_Tc = self.AS_H.hmass() # DH_pc_c = PropsSI('H','Q',1,'P',self.su_cold.p,self.su_cold.fluid) - PropsSI('H','Q',0,'P',self.su_cold.p,self.su_cold.fluid) self.AS_C.update(CP.PQ_INPUTS, self.su_C.p, 0) h_l_cold = self.AS_C.hmass() self.AS_C.update(CP.PQ_INPUTS, self.su_C.p, 1) h_v_cold = self.AS_C.hmass() DH_pc_c = h_v_cold - h_l_cold # Special case for incompressibles if "INCOMP" not in self.su_H.fluid: # DH_pc_h = PropsSI('H','Q',1,'P',self.su_hot.p,self.su_hot.fluid) - PropsSI('H','Q',0,'P',self.su_hot.p,self.su_hot.fluid) self.AS_H.update(CP.PQ_INPUTS, self.su_H.p, 0) h_l_hot = self.AS_H.hmass() self.AS_H.update(CP.PQ_INPUTS, self.su_H.p, 1) h_v_hot = self.AS_H.hmass() DH_pc_h = h_v_hot - h_l_hot else: DH_pc_h = 0 Qmax_c = self.su_C.m_dot*((h_c_Th - self.su_C.h)) Qmax_h = self.su_H.m_dot*((self.su_H.h - h_h_Tc)) Qmax = min(Qmax_c, Qmax_h) Q = eps*Qmax # Actual heat exchanged # --- Set exhaust states (new enthalpies) and link to connectors --- self.ex_H.set_properties(H = self.su_H.h - Q/self.su_H.m_dot, fluid = self.su_H.fluid, m_dot = self.su_H.m_dot, P = self.su_H.p) self.ex_C.set_properties(H = self.su_C.h + Q/self.su_C.m_dot, fluid = self.su_C.fluid, m_dot = self.su_C.m_dot, P = self.su_C.p) self.Q_hex.set_Q_dot(Q) self.defined = True else: if not self.calculable: print("Input of the component not completely known. Required inputs:") for input in self.get_required_inputs(): if input not in self.inputs: print(f" - {input}") if not self.parametrized: print("Parameters of the component not completely known. Required parameters:") for param in self.get_required_parameters(): if param not in self.params: print(f" - {param}") def print_results(self): if self.defined: print("=== Heat Exchanger Results ===") print(f" - H_ex: fluid={self.ex_H.fluid}, T={self.ex_H.T}, p={self.ex_H.p}, m_dot={self.ex_H.m_dot}") print(f" - C_ex: fluid={self.ex_C.fluid}, T={self.ex_C.T}, p={self.ex_C.p}, m_dot={self.ex_C.m_dot}") print(f" - Q_dot: {self.Q_hex.Q_dot}") else: print("Heat Exchanger component is not defined. Ensure it is solved first.")