Heat Exchanger - Moving Boundary Charge Sensitive Model

Model description

The model implemented is based on the moving boundary approach as described in [1]. This model can be used for the following geometris of heat exchangers: plate, tube and fins, shell and tube, and PCHE. An example of use for each geometry is provided in the examples section.

Class description

class component.heat_exchanger.hex_MB_charge_sensitive.HexMBChargeSensitive(HTX_Type)[source]

Component: Heat Exchanger

Model: The model is based on the the work of Ian Bell “A generalized moving-boundary algorithm to predict the heat transfer

rate of counterflow heat exchangers for any phase configuration”.

Descritpion:

It is a moving-boundary model allowing for the precise estimation of its performance, pressure drops and fluid charges inside it (using a void fraction correlation for two-phase flow conditions). For now, the method has been adapted for many geometries : - Brazed-Plate heat exchangers - Shell-and-Tube heat exchangers - Cross-CounterFlow tube and fin heat exchangers

The precision of the model and the geometry dependent charge estimation requires to know the geometry. The required parameters are adapted to the used heat transfer and pressure drop correlations that can be chosen from the ones implemented.

Assumptions:

  • Steady-state operation.

  • Pressure drop proportional to the heat transfer area for each discretization.

  • Volume used for the charge computation are also assumed proportional to the heat transfer area for each discretization.

  • No loss to the ambient is considered.

Connectors:

su_H (MassConnector): Mass connector for the hot suction side. su_C (MassConnector): Mass connector for the cold suction side.

ex_H (MassConnector): Mass connector for the hot exhaust side. ex_C (MassConnector): Mass connector for the cold exhaust side.

Q_dot (HeatConnector): Heat connector for the heat transfer between the fluids

Parameters:

Parameters can be differentiated between geometrical parameters and simulation parameters.

Simulation required parameters are:

Flow_Type : Flow configuration of the fluid (‘CounterFlow’, ‘CrossFlow’, ‘Shell&Tube’, ‘ParallelFlow’) [-]

htc_type : Heat Transfer coefficient type (‘User-Defined’ or ‘Correlation’) [-]. If the ‘User-Defined’ option is chosen, values for the different heat transfer coefficients can be manually passed by the user for different state conditions: ‘Liquid’, ‘Vapor’, ‘Two-Phase’, ‘Vapor-wet’, ‘Dryout’, ‘Transcritical’. If the ‘Correlation’ option is chosen, then the names of implemented correlations shall be passed. For 1 phase heat transfer, 2 phases heat transfer and for pressure drops.

n_disc : number of heat exchanger discretizations [-]

Geometry required parameters depend on the type of heat exchanger and on especially the used correlations. More information can be found in the documentation of the correlations themselves.

Inputs:

P_su_H: Hot suction side pressure. [Pa]

h_su_H: Hot suction side enthalpy. [J/kg]

fluid_H: Hot suction side fluid. [-]

m_dot_H: Hot suction side mass flowrate. [kg/s]

P_su_C: Cold suction side pressure. [Pa]

h_su_C: Cold suction side enthalpy. [J/kg]

fluid_C: Cold suction side fluid. [-]

m_dot_C: Cold suction side mass flowrate. [kg/s]

Ouputs:

h_ex_H: Hot exhaust side specific enthalpy. [J/kg]

P_ex_H: Hot exhaust side pressure. [Pa]

h_ex_C: Cold exhaust side specific enthalpy. [J/kg]

P_ex_C: Cold exhaust side pressure. [Pa]

Q: Heat transfer rate [W]

M_H : Hot fluid charge [kg]

M_C : Cold fluid charge [kg]

Example of use

Plate heat exchanger:

"""
Supplemental code for paper:
I. Bell et al., "A Generalized Moving-Boundary Algorithm to Predict the Heat Transfer Rate of 
Counterflow Heat Exchangers for any Phase Configuration", Applied Thermal Engineering, 2014
"""

"""
Modification w/r to previous version:
    - Putting some order in the Objective Function "for" loops. Sparing some
    lines of code.
    - x_di_c correct calculation.
"""

# # from __future__ import division, print_function
# import __init__

from labothappy.toolbox.geometries.heat_exchanger.geometry_plate_hx_swep import PlateGeomSWEP
from labothappy.component.heat_exchanger.hex_MB_charge_sensitive import HexMBChargeSensitive

#%%

# import time
# start_time = time.time()   

# "------------ Plate HX -------------------------------------------------------------------------------------------------"

"HTX Instanciation"

HX = HexMBChargeSensitive('Plate')

# "Setting inputs"

# # ---------------------------------------------------------------------------------------------------------

# # Condenser Case
# HX.set_inputs(
#     # First fluid
#     Hsu_fluid = 'Cyclopentane',
#     Hsu_T = 139 + 273.15, # K
#     Hsu_p = 0.77*1e5, # Pa
#     Hsu_m_dot = 0.014, # kg/s

#     # Second fluid
#     Csu_fluid = 'Water',
#     Csu_T = 12 + 273.15, # K
#     Csu_p = 5*1e5, # Pa
#     Csu_m_dot = 0.2, # kg/s  # Make sure to include fluid information
# )

# "Geometry Loading"

# HX_geom = PlateGeomSWEP()
# HX_geom.set_parameters("B20Hx24/1P") 

# Corr_H = {"1P" : "Gnielinski", "2P" : "Han_cond_BPHEX"}
# Corr_C = {"1P" : "Gnielinski", "2P" : "Han_Boiling_BPHEX_HTC"}

# ---------------------------------------------------------------------------------------------------------

# # Evaporator Case
HX.set_inputs(
    # First fluid
    fluid_H = 'INCOMP::T66',
    T_su_H = 243 + 273.15, # K
    P_su_H = 5*1e5, # Pa
    m_dot_H = 0.4, # kg/s

    # Second fluid
    fluid_C = 'Cyclopentane',
    T_su_C = 41 + 273.15, # K
    P_su_C = 31.5*1e5, # Pa
    m_dot_C = 0.014, # kg/s  # Make sure to include fluid information
)

"Geometry Loading"

HX_geom = PlateGeomSWEP()
HX_geom.set_parameters("B20Hx24/1P")

Corr_H = {"1P" : "Gnielinski", "2P" : "Han_cond_BPHEX"}
Corr_C = {"1P" : "Gnielinski", "2P" : "Boiling_curve"}

Corr_H_DP = {"1P" : "Gnielinski_DP", "2P" : "Choi_DP"}
Corr_C_DP = {"1P" : "Gnielinski_DP", "2P" : "Choi_DP"}

# ---------------------------------------------------------------------------------------------------------

# # Desuperheater Case
# HX.set_inputs(
#     # First fluid
#     Hsu_fluid = 'Cyclopentane',
#     Hsu_T = 205 + 273.15, # K
#     Hsu_p = 1*1e5, # Pa
#     Hsu_m_dot = 0.014, # kg/s

#     # Second fluid
#     Csu_fluid = 'Water',
#     Csu_T = 12 + 273.15, # K
#     Csu_p = 4*1e5, # Pa
#     Csu_m_dot = 0.2, # kg/s  # Make sure to include fluid information
# )

# "Geometry Loading"

# HX_geom = PlateGeomSWEP()
# HX_geom.set_parameters("B35TM0x10/1P") 

# Corr_H = {"1P" : "Gnielinski", "2P" : "Han_cond_BPHEX"}
# Corr_C = {"1P" : "Gnielinski", "2P" : "Han_Boiling_BPHEX_HTC"}

# ---------------------------------------------------------------------------------------------------------

# Condenser Case
# HX.set_inputs(
#     # First fluid
#     Hsu_fluid = 'R1233zd(E)',
#     Hsu_T = 334.3838266524477, # K
#     Hsu_p = 2*1e5, # Pa
#     Hsu_m_dot = 0.41973076344816307, # kg/s

#     # Second fluid
#     Csu_fluid = 'Water',
#     Csu_T = 15 + 273.15, # K
#     Csu_p = 2*1e5, # Pa
#     Csu_m_dot = 2.6, # kg/s  # Make sure to include fluid information
# )

# {'Hsu_fluid': 'R1233zd(E)',
#  'Csu_T': 288.15,
#  'Csu_p': 200000.0,
#  'Csu_fluid': 'Water',
#  'Csu_m_dot': 2.6,
#  'Hsu_T': 334.3838266524477,
#  'Hsu_p': 200000.0,
#  'Hsu_m_dot': 0.41973076344816307}

# Corr_H = {"1P" : "martin_holger_plate_HTC", "2P" : "Han_cond_BPHEX"}
# Corr_C = {"1P" : "water_plate_HTC", "2P" : "Han_Boiling_BPHEX_HTC"}

# Condenser
# condenser_geom = PlateGeomSWEP()
# condenser_geom.set_parameters("P200THx140/1P_Condenser")

# HX.set_parameters(
#     # Set the geometry of the condenser
#     A_c=condenser_geom.A_c, A_h=condenser_geom.A_h, h=condenser_geom.h, l=condenser_geom.l, l_v=condenser_geom.l_v, w_v=condenser_geom.w_v,
#     C_CS=condenser_geom.C_CS, C_Dh=condenser_geom.C_Dh, C_V_tot=condenser_geom.C_V_tot, C_canal_t=condenser_geom.C_canal_t, C_n_canals=condenser_geom.C_n_canals,
#     H_CS=condenser_geom.H_CS, H_Dh=condenser_geom.H_Dh, H_V_tot=condenser_geom.H_V_tot, H_canal_t=condenser_geom.H_canal_t, H_n_canals=condenser_geom.H_n_canals,
#     casing_t=condenser_geom.casing_t, chevron_angle=condenser_geom.chevron_angle, fooling=condenser_geom.fooling,
#     n_plates=condenser_geom.n_plates, plate_cond=condenser_geom.plate_cond, plate_pitch_co=condenser_geom.plate_pitch_co, t_plates=condenser_geom.t_plates, w=condenser_geom.w,
#     amplitude=condenser_geom.amplitude, phi=condenser_geom.phi, Flow_Type='CounterFlow', H_DP_ON=True, C_DP_ON=True, n_disc=50)

# HX.set_DP(DP_type="User-Defined", UD_H_DP = 20*1e3, UD_C_DP = 50*1e3)

# Set the heat transfer coefficients correlations of the condenser           
# HX.set_htc(htc_type = 'Correlation', Corr_H = Corr_H, Corr_C = Corr_C)

# ---------------------------------------------------------------------------------------------------------

"Parameters Setting"

HX.set_parameters(
    A_c = HX_geom.A_c, A_h = HX_geom.A_h, h = HX_geom.h, l = HX_geom.l, l_v = HX_geom.l_v, # 5
    C_CS = HX_geom.C_CS, C_Dh = HX_geom.C_Dh, C_V_tot = HX_geom.C_V_tot, C_canal_t = HX_geom.C_canal_t, C_n_canals = HX_geom.C_n_canals, # 10
    H_CS = HX_geom.H_CS, H_Dh = HX_geom.H_Dh, H_V_tot = HX_geom.H_V_tot, H_canal_t = HX_geom.H_canal_t, H_n_canals = HX_geom.H_n_canals, # 15
    casing_t = HX_geom.casing_t, chevron_angle = HX_geom.chevron_angle, fooling = HX_geom.fooling, # 18
    n_plates = HX_geom.n_plates, plate_cond = HX_geom.plate_cond, plate_pitch_co = HX_geom.plate_pitch_co, t_plates = HX_geom.t_plates, w = HX_geom.w, # 23
    
    Flow_Type = 'CounterFlow', H_DP_ON = True, C_DP_ON = True, n_disc = 50) # 27

# UD_H_HTC = {'Liquid':100,
#             'Vapor' : 100,
#             'Two-Phase' : 1000,
#             'Vapor-wet' : 100,
#             'Dryout' : 1000,
#             'Transcritical' : 200}

# UD_C_HTC = {'Liquid':100,
#             'Vapor' : 100,
#             'Two-Phase' : 1000,
#             'Vapor-wet' : 100,
#             'Dryout' : 10000,
#             'Transcritical' : 200}

HX.set_htc(htc_type = 'Correlation', Corr_H = Corr_H, Corr_C = Corr_C) # 'User-Defined' or 'Correlation' # 28

# HX.set_DP() # equivalent to HX.set_DP(DP_type = None)
# HX.set_DP(DP_type="User-Defined", UD_C_DP = 10000, UD_H_DP = 10000) # Fixed User-Defined values, equally distributed over discretizations
# HX.set_DP(DP_type="Correlation_Global", Corr_C=Corr_C_DP, Corr_H=Corr_H_DP)
HX.set_DP(DP_type="Correlation_Disc", Corr_C=Corr_C_DP, Corr_H=Corr_H_DP)

"Solve the component"
HX.solve()
HX.plot_cells()

Tube and fins heat exchanger:

"""
Supplemental code for paper:
I. Bell et al., "A Generalized Moving-Boundary Algorithm to Predict the Heat Transfer Rate of 
Counterflow Heat Exchangers for any Phase Configuration", Applied Thermal Engineering, 2014
"""

"""
Modification w/r to previous version:
    - Putting some order in the Objective Function "for" loops. Sparing some
    lines of code.
    - x_di_c correct calculation.
"""

# from __future__ import division, print_function
import __init__
from labothappy.component.heat_exchanger.hex_MB_charge_sensitive import HexMBChargeSensitive

#%%

import time
start_time = time.time()   

"--------- Tube and Fins HTX ------------------------------------------------------------------------------------------"

"HTX Instanciation"

HX = HexMBChargeSensitive('Tube&Fins')

# "Setting inputs"

# -------------------------------------------------------------------------------------------------------------

# # DECAGONE Recuperator HTX case

HX.set_inputs(
    # First fluid
    fluid_H = 'Cyclopentane',
    T_su_H = 133.8 + 273.15, # K
    P_su_H = 0.8*1e5, # Pa
    m_dot_H = 13.76, # kg/s

    # Second fluid
    fluid_C = 'Cyclopentane',
    T_su_C = 35.1 + 273.15, # K
    P_su_C = 31.5*1e5, # Pa
    m_dot_C = 13.76, # kg/s  # Make sure to include fluid information
)

"Correlation Loading"

# Corr_H = {"1P" : "Tube_And_Fins", "2P" : "ext_tube_film_condens"}
Corr_H = {"1P" : "Tube_And_Fins", "2P" : "Tube_And_Fins"}
Corr_C = {"1P" : "Gnielinski", "2P" : "Boiling_curve"}

Corr_H_DP = {"1P" : "Tube_And_Fins_DP", "2P" : "Tube_And_Fins_DP"}
Corr_C_DP = {"1P" : "Gnielinski_DP", "2P" : "Choi_DP"}

# -------------------------------------------------------------------------------------------------------------

# DECAGONE ACC HTX case

# HX.set_inputs(
#     # First fluid
#     fluid_H = 'Cyclopentane',
#     T_su_H = 53.6 + 273.15, # K
#     P_su_H = 0.7*1e5, # Pa
#     m_dot_H = 13.8/2, # kg/s

#     # Second fluid
#     Csu_fluid = 'Air',
#     Csu_T = 12 + 273.15, # K
#     Csu_p = 1.05*1e5, # Pa
#     Csu_m_dot = 158.5, # kg/s  # Make sure to include fluid information
# )

# "Geometry Loading"

# HX_geom = TubeAndFinsGeom()
# HX_geom.set_parameters("DECAGONE_ACC") 

# Fin_Side = 'C'

# "Correlation Loading"

# Corr_H = {"1P" : "Gnielinski", "2P" : "Horizontal_Tube_Internal_Condensation"}
# Corr_C = {"1P" : "Tube_And_Fins", "2P" : "Boiling_curve"}

# -------------------------------------------------------------------------------------------------------------

"Parameters Setting"

params = {
        'A_flow' : 3.36, # [m2]    
        'fouling' : 0.9, # [(m^2*K)/W]
        'Fin_OD' : 0.0350625, # [m]
        'Fin_per_m' : 400, # [-]
        'Fin_t' : 0.00025, # [m]
        'k_fin' : 50, # [W/(m*K)] : Steel
        'Fin_type' : "Square", # [-]
        'Finned_tube_flag' : 1, # [-]
        'h' : 1.6, # [m]
        'Tube_pass' : 6, # [-]
        'n_rows' : 4, # [-]
        'n_series' : 1, # [-]
        'n_parallel' : 1, # [-]
        'pitch_ratio' : 2.125, # [-]
        'tube_arrang' : "Staggered", # [-]
        'Tube_cond' : 50, # [(m^2*K)/W]
        'Tube_L' : 4.5, # [m]
        'Tube_OD' : 0.0165, # [m]        
        'Tube_t' : 0.0015, # [m]        
        'n_tubes' : 480, # [-]
        'w' : 0.787, # [m]
        
        'Fin_Side' : 'H'
        }

HX.set_parameters(
    A_flow = params['A_flow'], Fin_OD = params['Fin_OD'], Fin_per_m = params['Fin_per_m'], Fin_t = params['Fin_t'], Fin_type = params['Fin_type'], # 10
    Finned_tube_flag = params['Tube_t'], Tube_L = params['Tube_L'], Tube_OD = params['Tube_OD'], # 15
    Tube_cond = params['Tube_cond'], Tube_t = params['Tube_t'], fouling = params['fouling'], h = params['h'], k_fin = params['k_fin'], # 20
    Tube_pass = params['Tube_pass'], n_rows = params['n_rows'], n_series = params['n_series'], n_tubes = params['n_tubes'], pitch_ratio = params['pitch_ratio'], tube_arrang = params['tube_arrang'], w = params['w'], # 30

    Fin_Side = params['Fin_Side'], # 28

    Flow_Type = 'CrossFlow', n_disc = 50) # 32

# User defined values

# UD_H_HTC = {'Liquid':29,
#             'Vapor' : 29,
#             'Two-Phase' : 29,
#             'Vapor-wet' : 29,
#             'Dryout' : 29,
#             'Transcritical' : 29}

# UD_C_HTC = {'Liquid':10000,
#             'Vapor' : 10000,
#             'Two-Phase' : 10000,
#             'Vapor-wet' : 10000,
#             'Dryout' : 10000,
#             'Transcritical' : 10000}

# HX.set_HTC(htc_type = 'User-Defined', UD_H_HTC = UD_H_HTC, UD_C_HTC = UD_C_HTC) # 'User-Defined' or 'Correlation'
HX.set_htc(htc_type = 'Correlation', Corr_H = Corr_H, Corr_C = Corr_C) # 

# HX.set_DP() # equivalent to HX.set_DP(DP_type = None)
# HX.set_DP(DP_type="User-Defined", UD_C_DP = 10000, UD_H_DP = 10000) # Fixed User-Defined values, equally distributed over discretizations
HX.set_DP(DP_type="Correlation_Global", Corr_C=Corr_C_DP, Corr_H=Corr_H_DP)
# HX.set_DP(DP_type="Correlation_Disc", Corr_C=Corr_C_DP, Corr_H=Corr_H_DP)

"Solve the component"
HX.solve()
HX.plot_cells()

Shell and tube heat exchanger:

"""
Supplemental code for paper:
I. Bell et al., "A Generalized Moving-Boundary Algorithm to Predict the Heat Transfer Rate of 
Counterflow Heat Exchangers for any Phase Configuration", Applied Thermal Engineering, 2014
"""

"""
Modification w/r to previous version:
    - Putting some order in the Objective Function "for" loops. Sparing some
    lines of code.
    - x_di_c correct calculation.
"""

# from __future__ import division, print_function

import __init__
from labothappy.component.heat_exchanger.hex_MB_charge_sensitive import HexMBChargeSensitive

# from toolbox.geometries.heat_exchanger.geometry_shell_and_tube_hx import ShellAndTubeGeom
from CoolProp.CoolProp import PropsSI    
from labothappy.correlations.heat_exchanger.STHE_cost_estimation import HeatExchangerCost, total_STHE_cost
from labothappy.toolbox.plots.plot_MB_STHE import plot_MB_STHE

#%%

import time
start_time = time.time()

"------------ Shell and Tube HTX ------------------------------------------------------------------------------------------"

"HTX Instanciation"

save_plot = 0
save_geom = 0
save_LMTD = 0
case_study = 'Methanol'

import numpy as np

def rmse(x, y):
    x = np.asarray(x)
    y = np.asarray(y)
    return np.sqrt(np.mean((x - y)**2))

n_disc_low = 30
n_disc_high = 30

n_disc_vec = np.linspace(n_disc_low,n_disc_high,n_disc_high - n_disc_low + 1)

# n_disc_vec = np.array([2, 5, 10, 30, 50])

# Q_dot = F*AU*LMTD

Q_vec = []
DP_h_vec = []
DP_c_vec = []
rmse_vec = []
w_vec = []
res_vec = []
n_it_vec = []
LMTD_vec = [[] for _ in range(len(n_disc_vec))]
w_vec    = [[] for _ in range(len(n_disc_vec))]
LMTD_val = []


for i in range(len(n_disc_vec)):
    
    n_disc = n_disc_vec[i]
    
    # # -------------------------------------------------------------------------------------------------------------
    # # Methanol Sensible HT Case
    
    HX = HexMBChargeSensitive('Shell&Tube')
    
    if case_study == 'Methanol':

        HX.set_inputs(
            # First fluid
            fluid_H = 'Methanol',
            T_su_H = 95 + 273.15, # K
            P_su_H = 10e5, # Pa
            m_dot_H = 27.8, # kg/s
        
            # Second fluid
            fluid_C = 'Water',
            T_su_C = 25 + 273.15, # K
            P_su_C = 5*1e5, # Pa
            m_dot_C = 68.9, # kg/s  # Make sure to include fluid information
        )
        
        "Geometry Loading"
        
        params = {'n_series': 1,
                  'n_parallel': 1,
                  'foul_t': 0.0002,
                  'foul_s': 0.00033,
                  'tube_cond': 50,
                  'Shell_Side': 'H',
                  'Flow_Type': 'Shell&Tube',
                  'n_disc': int(n_disc),
                  'Shell_ID': 0.83,
                  'Tube_L': 3.379,
                  'Tube_OD': 0.016,
                  'Tube_t': 0.016*0.1,
                  'central_spacing': 0.5,
                  'Tube_pass': 2,
                  'n_tubes': 1567,
                  'pitch_ratio': 1.25,
                  'tube_layout': 60,
                  'Baffle_cut': 25}
        
        HX.set_parameters(
            Baffle_cut = params['Baffle_cut'], Shell_ID = params['Shell_ID'], Tube_L = params['Tube_L'], 
            Tube_OD = params['Tube_OD'], Tube_pass = params['Tube_pass'], Tube_t = params['Tube_t'],
            central_spacing = params['central_spacing'], foul_s = params['foul_s'],
            foul_t = params['foul_t'], n_series = params['n_series'], n_parallel = params['n_parallel'], n_tubes = params['n_tubes'], 
            pitch_ratio = params['pitch_ratio'], tube_cond = params['tube_cond'], tube_layout = params['tube_layout'],
        
            Shell_Side = params['Shell_Side'],
        
            Flow_Type = params['Flow_Type'], n_disc = params['n_disc'])
        
        # "Correlation Loading"
        
        Corr_C = {"1P" : "Gnielinski", "2P" : "Flow_boiling"}
        Corr_H = {"1P" : "Shell_Kern_HTC", "2P" : "Shell_Kern_HTC"}
        
        Corr_H_DP = {"1P" : "Shell_Kern_DP", "2P" : "Shell_Kern_DP"}
        Corr_C_DP = {"1P" : "Gnielinski_DP", "2P" : "Choi_DP"}
    # -------------------------------------------------------------------------------------------------------------
    
    # Sizing code example case
    # R134a evaporator case
    
    if case_study == 'R134a':
        
        HX.set_inputs(
                      # Hot Fluid
                      T_su_H = 273.15 + 26, # K
                      P_su_H = 2*1e5, # 51.75*1e3, # Pa
                      m_dot_H = 5.35, # kg/s
                      fluid_H = 'Water',
                      
                      # Cold Fluid
                      h_su_C = PropsSI('H','T', 273.15+7,'Q',0,'R134a')+1, # kJ/kg
                      P_su_C = PropsSI('P','T', 273.15+7,'Q',0,'R134a'), # 51.75*1e3, # Pa
                      m_dot_C = 1.62, # kg/s
                      fluid_C = 'R134a'
                      )
        
        "Geometry Loading"

        params = {'n_series': 1,
                  'n_parallel': 1,
                  'foul_t': 0.000176,
                  'foul_s': 0.000176,
                  'tube_cond': 50,
                  'Shell_Side': 'H',
                  'Flow_Type': 'Shell&Tube',
                  'n_disc': int(n_disc),
                  'Shell_ID': 0.173,
                  'Tube_L': 4.18,
                  'Tube_OD': 0.01,
                  'Tube_t': 0.001,
                  'central_spacing': 0.381,
                  'Tube_pass': 2,
                  'n_tubes': 230,
                  'pitch_ratio': 1.25,
                  'tube_layout': 60,
                  'Baffle_cut': 25}        
        
        HX.set_parameters(
            Baffle_cut = params['Baffle_cut'], Shell_ID = params['Shell_ID'], Tube_L = params['Tube_L'], 
            Tube_OD = params['Tube_OD'], Tube_pass = params['Tube_pass'], Tube_t = params['Tube_t'],
            central_spacing = params['central_spacing'], foul_s = params['foul_s'],
            foul_t = params['foul_t'], n_series = params['n_series'], n_parallel = params['n_parallel'], n_tubes = params['n_tubes'], 
            pitch_ratio = params['pitch_ratio'], tube_cond = params['tube_cond'], tube_layout = params['tube_layout'],
        
            Shell_Side = params['Shell_Side'],
        
            Flow_Type = params['Flow_Type'], n_disc = params['n_disc'])
        
        # "Correlation Loading"
        
        Corr_C = {"1P" : "Gnielinski", "2P" : "Flow_boiling"}
        # Corr_C = {"1P" : "Gnielinski", "2P" : "Flow_boiling_gungor_winterton"}
        Corr_H = {"1P" : "Shell_Kern_HTC", "2P" : "Shell_Kern_HTC"}
        
        Corr_H_DP = {"1P" : "Shell_Kern_DP", "2P" : "Shell_Kern_DP"}
        Corr_C_DP = {"1P" : "Gnielinski_DP", "2P" : "Muller_Steinhagen_Heck_DP"}
    
    if case_study == 'R134a_cond':
                
        HX.set_inputs(
                      # Hot Fluid
                      T_su_C = 273.15 + 12, # K
                      P_su_C = 2*1e5, # 51.75*1e3, # Pa
                      m_dot_C = 20, # kg/s
                      fluid_C = 'Water',
                      
                      # Cold Fluid
                      h_su_H = PropsSI('H','T', 273.15+30,'Q',1,'R134a')-1, # kJ/kg
                      P_su_H = PropsSI('P','T', 273.15+30,'Q',1,'R134a'), # 51.75*1e3, # Pa
                      m_dot_H = 5.78, # kg/s
                      fluid_H = 'R134a'
                      )
        
        "Geometry Loading"
        
        params = {'n_series': 1,
                  'n_parallel': 1,
                  'foul_t': 0.0,
                  'foul_s': 0.0,
                  'tube_cond': 50,
                  'Shell_Side': 'C',
                  'Flow_Type': 'Shell&Tube',
                  'n_disc': int(n_disc),
                  'Shell_ID': 0.4,
                  'Tube_L': 5.348,
                  'Tube_OD': 0.01958,
                  'Tube_t': 0.002,
                  'central_spacing': 0.59,
                  'Tube_pass': 2,
                  'n_tubes': 194,
                  'pitch_ratio': 1.25,
                  'tube_layout': 60,
                  'Baffle_cut': 20}
        
        HX.set_parameters(
            Baffle_cut = params['Baffle_cut'], Shell_ID = params['Shell_ID'], Tube_L = params['Tube_L'], 
            Tube_OD = params['Tube_OD'], Tube_pass = params['Tube_pass'], Tube_t = params['Tube_t'],
            central_spacing = params['central_spacing'], foul_s = params['foul_s'],
            foul_t = params['foul_t'], n_series = params['n_series'], n_parallel = params['n_parallel'], n_tubes = params['n_tubes'], 
            pitch_ratio = params['pitch_ratio'], tube_cond = params['tube_cond'], tube_layout = params['tube_layout'],
        
            Shell_Side = params['Shell_Side'],
        
            Flow_Type = params['Flow_Type'], n_disc = params['n_disc'])
        
        # "Correlation Loading"
        
        Corr_H = {"1P" : "Gnielinski", "2P" : "Thome_Condensation"}
        # Corr_C = {"1P" : "Gnielinski", "2P" : "Flow_boiling_gungor_winterton"}
        Corr_C = {"1P" : "Shell_Kern_HTC", "2P" : "Shell_Kern_HTC"}
        
        Corr_C_DP = {"1P" : "Shell_Kern_DP", "2P" : "Shell_Kern_DP"}
        Corr_H_DP = {"1P" : "Gnielinski_DP", "2P" : "Choi_DP"}
    
    if case_study == 'R32':
        
        HX.set_inputs(
                      # Hot Fluid
                      T_su_H = 273.15 + 30, # K
                      P_su_H = 2*1e5, # 51.75*1e3, # Pa
                      m_dot_H = 36.3, # kg/s
                      fluid_H = 'Water',
                      
                      # Cold Fluid
                      h_su_C = PropsSI('H','T', 273.15+6,'Q',0,'R32')+1, # kJ/kg
                      P_su_C = PropsSI('P','T', 273.15+6,'Q',0,'R32'), # 51.75*1e3, # Pa
                      m_dot_C = 3.2716, # kg/s
                      fluid_C = 'R32'
                      )
        
        "Geometry Loading"
        
        params = {'n_series': 1,
                  'n_parallel': 1,
                  'foul_t': 0.000176,
                  'foul_s': 0.000176,
                  'tube_cond': 50,
                  'Shell_Side': 'H',
                  'Flow_Type': 'Shell&Tube',
                  'n_disc': int(n_disc),
                  'Shell_ID': 0.41353,
                  'Tube_L': 5.48864,
                  'Tube_OD': 0.02128,
                  'Tube_t': 0.002128,
                  'central_spacing': 0.94,
                  'Tube_pass': 2,
                  'n_tubes': 140,
                  'pitch_ratio': 1.25,
                  'tube_layout': 0,
                  'Baffle_cut': 25}
        
        HX.set_parameters(
            Baffle_cut = params['Baffle_cut'], Shell_ID = params['Shell_ID'], Tube_L = params['Tube_L'], 
            Tube_OD = params['Tube_OD'], Tube_pass = params['Tube_pass'], Tube_t = params['Tube_t'],
            central_spacing = params['central_spacing'], foul_s = params['foul_s'],
            foul_t = params['foul_t'], n_series = params['n_series'], n_parallel = params['n_parallel'], n_tubes = params['n_tubes'], 
            pitch_ratio = params['pitch_ratio'], tube_cond = params['tube_cond'], tube_layout = params['tube_layout'],
        
            Shell_Side = params['Shell_Side'],
        
            Flow_Type = params['Flow_Type'], n_disc = params['n_disc'])
        
        # "Correlation Loading"
        
        Corr_C = {"1P" : "Gnielinski", "2P" : "choi_boiling"}
        Corr_H = {"1P" : "Shell_Kern_HTC", "2P" : "Shell_Kern_HTC"}
        
        Corr_H_DP = {"1P" : "Shell_Kern_DP", "2P" : "Shell_Kern_DP"}
        Corr_C_DP = {"1P" : "Gnielinski_DP", "2P" : "Muller_Steinhagen_Heck_DP"}
    
    # -------------------------------------------------------------------------------------------------------------
    
    if case_study == 'CO2_GasCooler_1':

        # Sizing code example case
        # CO2 GasCooler Case
        
        HX.set_inputs(
                      # Hot Fluid
                      T_su_H = 273.15 + 100, # K
                      P_su_H = 100*1e5, # Pa
                      m_dot_H = 100, # kg/s
                      fluid_H = 'CO2',
                      
                      # Cold Fluid
                      T_su_C = 273.15 + 20, # K
                      P_su_C = 5*1e5, # Pa
                      m_dot_C = 47.82, # kg/s
                      fluid_C = 'Water'
                      )
        
        "Geometry Loading"
        
        params = {'n_series': 1,
                  'n_parallel': 1,
                'foul_t': 0,
                'foul_s': 0,
                'tube_cond': 50,
                'Shell_Side': 'C',
                'Flow_Type': 'Shell&Tube',
                'n_disc': 30,
                'Shell_ID': 1.43,
                'Tube_L': 9.21,
                'Tube_OD': 0.02,
                'Tube_t': 0.003,
                'central_spacing': 0.5*1.43,
                'Tube_pass': 1,
                'n_tubes': 1480,
                'pitch_ratio': 1.5,
                'tube_layout': 45,
                'Baffle_cut': 25}
        
        HX.set_parameters(
            Baffle_cut = params['Baffle_cut'], Shell_ID = params['Shell_ID'], Tube_L = params['Tube_L'], 
            Tube_OD = params['Tube_OD'], Tube_pass = params['Tube_pass'], Tube_t = params['Tube_t'],
            central_spacing = params['central_spacing'], foul_s = params['foul_s'],
            foul_t = params['foul_t'], n_series = params['n_series'], n_parallel = params['n_parallel'], n_tubes = params['n_tubes'], 
            pitch_ratio = params['pitch_ratio'], tube_cond = params['tube_cond'], tube_layout = params['tube_layout'],
        
            Shell_Side = params['Shell_Side'],
        
            Flow_Type = params['Flow_Type'], n_disc = params['n_disc'])
        
        # "Correlation Loading"
        
        Corr_H = {"1P" : "Gnielinski", "2P" : "Flow_boiling", "SC" : "Liu_sCO2"}
        Corr_C = {"1P" : "Shell_Kern_HTC", "2P" : "Shell_Kern_HTC"}
        
        Corr_C_DP = {"1P" : "Shell_Kern_DP", "2P" : "Shell_Kern_DP"}
        Corr_H_DP = {"1P" : "Gnielinski_DP", "2P" : "Muller_Steinhagen_Heck_DP", "SC" : "Cheng_CO2_DP"} 
    
    # -------------------------------------------------------------------------------------------------------------
    
    if case_study == 'CO2_GasCooler_2':
    
        HX.set_inputs(
                      # Hot Fluid
                      T_su_H = 273.15 + 105.4, # K
                      P_su_H = 90*1e5, # 51.75*1e3, # Pa
                      m_dot_H = 1590.82/4, # kg/s
                      fluid_H = 'CO2',
                      
                      # Cold Fluid
                      T_su_C = 273.15 + 25, # K
                      P_su_C = 5*1e5, # 51.75*1e3, # Pa
                      m_dot_C = 980/4, # kg/s
                      fluid_C = 'Water'
                      )
        
        params = {'htc_type': 'Correlation',
                  'Baffle_cut': 26.726000000000003,
                  'Shell_ID': 1.6764,
                  'Tube_L': 14.84,
                  'Tube_OD': 0.009524999999999999,
                  'Tube_pass': 1,
                  'Tube_t': 0.0005587999999999999,
                  'central_spacing': 0.742,
                  'foul_s': 0,
                  'foul_t': 0,
                  'n_series': 1,
                  'n_parallel': 1,
                  'n_tubes': 15638,
                  'pitch_ratio': 1.33,
                  'tube_cond': 50,
                  'tube_layout': 60,
                  'Shell_Side': 'C',
                  'Flow_Type': 'Shell&Tube',
                  'n_disc': 1}
        
        HX.set_parameters(
            Baffle_cut = params['Baffle_cut'], Shell_ID = params['Shell_ID'], Tube_L = params['Tube_L'], 
            Tube_OD = params['Tube_OD'], Tube_pass = params['Tube_pass'], Tube_t = params['Tube_t'],
            central_spacing = params['central_spacing'], foul_s = params['foul_s'],
            foul_t = params['foul_t'], n_series = params['n_series'], n_parallel = params['n_parallel'], n_tubes = params['n_tubes'], 
            pitch_ratio = params['pitch_ratio'], tube_cond = params['tube_cond'], tube_layout = params['tube_layout'],
        
            Shell_Side = params['Shell_Side'],
        
            Flow_Type = params['Flow_Type'], n_disc = params['n_disc'])
        
        # "Correlation Loading"
        
        Corr_H = {"1P" : "Gnielinski", "2P" : "Flow_boiling", "SC" : "Liu_sCO2"}
        Corr_C = {"1P" : "Shell_Kern_HTC", "2P" : "Shell_Kern_HTC"}
        
        Corr_C_DP = {"1P" : "Shell_Kern_DP", "2P" : "Shell_Kern_DP"}
        Corr_H_DP = {"1P" : "Gnielinski_DP", "2P" : "Muller_Steinhagen_Heck_DP", "SC" : "Cheng_CO2_DP"} 
    
    # # -------------------------------------------------------------------------------------------------------------
    
    if case_study == 'CO2_CD':

        # Sizing code example case
        # CO2 Condenser Case
        
        HX.set_inputs(
                      # Hot Fluid
                      T_su_H = 273.15 + 20, # K
                      P_su_H = 5087147.357957976, # 51.75*1e3, # Pa
                      m_dot_H = 30, # kg/s
                      fluid_H = 'CO2',
                      
                      # Cold Fluid
                      T_su_C = 273.15 + 3, # K
                      P_su_C = 5*1e5, # 51.75*1e3, # Pa
                      m_dot_C = 100, # kg/s
                      fluid_C = 'Water'
                      )
        
        "Geometry Loading"
        
        params = {'n_series': 1,
                  'n_parallel' : 2,
                  'foul_t': 0,
                  'foul_s': 0,
                  'tube_cond': 50,
                  'Shell_Side': 'C',
                  'Flow_Type': 'Shell&Tube',
                  'n_disc': int(n_disc),
                  'Shell_ID': 1.43,
                  'Tube_L': 9.21,
                  'Tube_OD': 0.02,
                  'Tube_t': 0.003,
                  'central_spacing': 1.43,
                  'Tube_pass': 2,
                  'n_tubes': 1480,
                  'pitch_ratio': 1.5,
                  'tube_layout': 45,
                  'Baffle_cut': 25}
        
        HX.set_parameters(
            Baffle_cut = params['Baffle_cut'], Shell_ID = params['Shell_ID'], Tube_L = params['Tube_L'], 
            Tube_OD = params['Tube_OD'], Tube_pass = params['Tube_pass'], Tube_t = params['Tube_t'],
            central_spacing = params['central_spacing'], foul_s = params['foul_s'],
            foul_t = params['foul_t'], n_series = params['n_series'], n_parallel = params['n_parallel'], n_tubes = params['n_tubes'], 
            pitch_ratio = params['pitch_ratio'], tube_cond = params['tube_cond'], tube_layout = params['tube_layout'],
        
            Shell_Side = params['Shell_Side'],
        
            Flow_Type = params['Flow_Type'], n_disc = params['n_disc'])
        
        # "Correlation Loading"
        
        Corr_H = {"SC" : "Gnielinski", "1P" : "Gnielinski", "2P" : "Thome_Condensation"}
        Corr_C = {"SC" : "Shell_Kern_HTC", "1P" : "Shell_Kern_HTC", "2P" : "Shell_Kern_HTC"}
        
        Corr_H_DP = {"SC" : "Gnielinski_DP", "1P" : "Gnielinski_DP", "2P" : "Choi_DP"}
        Corr_C_DP = {"SC" : "Shell_Kern_DP", "1P" : "Shell_Kern_DP", "2P" : "Shell_Kern_DP"}
            
    # # -------------------------------------------------------------------------------------------------------------
    
    # "User-Defined Heat Transfer Coefficients Setting"
    
    # UD_H_HTC = {'Liquid': 1500,
    #             'Vapor' : 100,
    #             'Two-Phase' : 1000,
    #             'Vapor-wet' : 100,
    #             'Dryout' : 1000,
    #             'Transcritical' : 1500}
    
    # UD_C_HTC = {'Liquid': 1350,
    #             'Vapor' : 100,
    #             'Two-Phase' : 1000,
    #             'Vapor-wet' : 100,
    #             'Dryout' : 10000,
    #             'Transcritical' : 1350}
    
    # HX.set_htc(htc_type = 'User-Defined', UD_H_HTC = UD_H_HTC, UD_C_HTC = UD_C_HTC) # 'User-Defined' or 'Correlation'
    
    # # -------------------------------------------------------------------------------------------------------------
    
    # HEAT TRANSFER COEFFICIENT SETTING
    
    HX.set_htc(htc_type = 'Correlation', Corr_H = Corr_H, Corr_C = Corr_C) # 'User-Defined' or 'Correlation' # 31
    
    # PRESSURE DROP SETTING
    
    # HX.set_DP() # equivalent to HX.set_DP(DP_type = None)
    # HX.set_DP(DP_type="User-Defined", UD_C_DP = 10000, UD_H_DP = 10000) # Fixed User-Defined values, equally distributed over discretizations
    # HX.set_DP(DP_type="Correlation_Global", Corr_C=Corr_C_DP, Corr_H=Corr_H_DP)
    HX.set_DP(DP_type="Correlation_Disc", Corr_C=Corr_C_DP, Corr_H=Corr_H_DP)
    
    "Solve the component"

    HX.solve()  # the function you want to profile
    
    res_vec.append(HX.residual)
    
    Q_vec.append(HX.Q)
    DP_h_vec.append(HX.DP_h)
    DP_c_vec.append(HX.DP_c)
    
    LMTD_val.append(sum(HX.LMTD*HX.w)/sum(HX.w))
    
    LMTD_vec[i] = np.array(HX.LMTD)
    w_vec[i] = np.cumsum(HX.w)
    
    # first two physical points
    w1, w2 = w_vec[i][0], w_vec[i][min(len(w_vec[i]) - 1, 1)]
    L1, L2 = LMTD_vec[i][0], LMTD_vec[i][min(len(w_vec[i]) - 1, 1)]
    
    # linear extrapolation to w = 0
    if w2 != w1 and len(w_vec[i]) > 2:
        p = 0.2  # small curvature
        L0 = HX.ex_H.T - (HX.ex_C.T + HX.su_C.T)/2 
    else: 
        L0 = L1
    
    # insert at beginning
    w_vec[i] = np.insert(w_vec[i], 0, 0.0)
    LMTD_vec[i] = np.insert(LMTD_vec[i], 0, L0)
        
#%%

# if case_study == 'Methanol':

#     import numpy as np
#     import matplotlib.pyplot as plt
    
#     x = n_disc_vec
    
#     Q_vec   = np.array(Q_vec)
#     DP_h_vec = np.array(DP_h_vec)
#     DP_c_vec = np.array(DP_c_vec)
    
#     fig, (ax1, ax2) = plt.subplots(
#         nrows=2,
#         ncols=1,
#         sharex=True,
#         figsize=(6, 6)
#     )
    
#     # ─────────────────────────────────────────────
#     # Top subplot: Heat transfer rate
#     # ─────────────────────────────────────────────
#     ax1.plot(x, Q_vec * 1e-3, color='darkorange', label='Simulated')
#     ax1.set_ylabel("Heat transfer rate [kW]", color='darkorange', fontsize = 14)
#     ax1.tick_params(axis='y', colors='darkorange')
#     ax1.set_ylim([4100, 4500])
    
#     # Horizontal reference line
#     ax1.axhline(y=4340, color='black', linestyle='-', label='Reference')
#     ax1.legend(loc='upper right', fontsize = 11)
    
#     ax1.grid(True)
    
#     # ─────────────────────────────────────────────
#     # Bottom subplot: Pressure drops
#     # ─────────────────────────────────────────────
#     ax2.plot(x, DP_h_vec * 1e-3, color='blue', linestyle='-',  label='DP shell side')
#     ax2.plot(x, DP_c_vec * 1e-3, color='blue', linestyle='--', label='DP tube side')
    
#     ax2.set_xlabel("Discretization number [-]", fontsize = 14)
#     ax2.set_ylabel("Pressure drops [kPa]", color='blue', fontsize = 14)
#     ax2.tick_params(axis='y', colors='blue')
#     ax2.set_ylim([0, 20])
    
#     # Horizontal reference lines
#     ax2.axhline(y=13.267,  color='black', linestyle='-', label='Reference shell side')
#     ax2.axhline(y=4.298, color='black', linestyle='--', label='Reference tube side')
    
#     ax2.legend(fontsize = 11)
#     ax2.grid(True)
    
#     plt.tight_layout()
    
#     if save_plot:
#         # Save as SVG
#         output_path = r"C:\Users\Basile\Desktop\Travail\Thèse\Ecriture\Article S&T\Images\HX model\Caputo_disc.svg"
#         plt.savefig(output_path, format="svg", bbox_inches="tight")
    
#     plt.show()
    
#     # w_cum = np.cumsum(HX.w)
#     # plt.plot(w_cum, HX.LMTD)
    
#     # plt.show()

#     for j in range(len(w_vec)):
#         n_disc = len(w_vec[j])
#         plt.plot(w_vec[j]/w_vec[j][-1], LMTD_vec[j], label = f"{n_disc - 1} disc")

#     plt.ylabel('Cell LMTD [K]', fontsize = 16)
#     plt.xlabel('Position in the heat exchanger [-]', fontsize = 16)
    
#     plt.ylim(0, 80)

#     plt.legend(loc='upper left')
#     plt.axvline(0.5, color='k', linestyle=':', linewidth=2)
    
#     plt.annotate(
#         "  Forward \n tube pass",
#         xy=(0.975, 14),          # point inside the rectangle (arrow tip)
#         xytext=(0.22, 70),        # text position
#         color='black',
#         fontsize=13,
#     )
    
#     plt.annotate(
#         "  Reverse \n tube pass",
#         xy=(0.975, 14),          # point inside the rectangle (arrow tip)
#         xytext=(0.65, 70),        # text position
#         color='black',
#         fontsize=13,
#     )
    
#     plt.grid()
    
#     if save_LMTD:
#         # Save as SVG
#         output_path = r"C:\Users\Basile\Desktop\Travail\Thèse\Ecriture\Article S&T\Images\HX model\Caputo_LMTD.svg"
#         plt.savefig(output_path, format="svg", bbox_inches="tight")
    
#     plt.show()
    
#     if save_geom:
#         save_path = r"C:\Users\Basile\Desktop\Travail\Thèse\Ecriture\Article S&T\Images\HX model\Caputo_HTC.svg"
#     else:
#         save_path = None

#     plot_MB_STHE(HX, props='htc', legend_range=[0,4500], save_path = save_path)

#     plt.plot(n_disc_vec, LMTD_val)
#     plt.show()

# if case_study == 'R134a':
    
#     import numpy as np
#     import matplotlib.pyplot as plt
    
#     x = n_disc_vec
    
#     Q_vec   = np.array(Q_vec)
#     DP_h_vec = np.array(DP_h_vec)
#     DP_c_vec = np.array(DP_c_vec)
    
#     fig, (ax1, ax2) = plt.subplots(
#         nrows=2,
#         ncols=1,
#         sharex=True,
#         figsize=(6, 6)
#     )
    
#     # ─────────────────────────────────────────────
#     # Top subplot: Heat transfer rate
#     # ─────────────────────────────────────────────
#     ax1.axhline(y=313, color='black', linestyle='-', label='Reference', alpha = 1)

#     ax1.plot(x, Q_vec * 1e-3, color='darkorange', label='Simulated')
#     ax1.set_ylabel("Heat transfer rate [kW]", color='darkorange', fontsize = 14)
#     ax1.tick_params(axis='y', colors='darkorange')
#     ax1.set_ylim([300, 330])
    
#     # Horizontal reference line
#     ax1.legend(loc='upper right', fontsize = 11)
    
#     ax1.grid(True)
    
#     # ─────────────────────────────────────────────
#     # Bottom subplot: Pressure drops
#     # ─────────────────────────────────────────────
#     ax2.plot(x, DP_h_vec * 1e-3, color='blue', linestyle='-',  label='DP shell side')
#     ax2.plot(x, DP_c_vec * 1e-3, color='blue', linestyle='--', label='DP tube side')
    
#     ax2.set_xlabel("Discretization number [-]", fontsize = 14)
#     ax2.set_ylabel("Pressure drops [kPa]", color='blue', fontsize = 14)
#     ax2.tick_params(axis='y', colors='blue')
#     ax2.set_ylim([0, 45])
    
#     # Horizontal reference lines
#     ax2.axhline(y=8.235,  color='black', linestyle='-', label='Reference shell side')
#     ax2.axhline(y=21.755, color='black', linestyle='--', label='Reference tube side')
    
#     ax2.legend(fontsize = 11)
#     ax2.grid(True)
    
#     plt.tight_layout()
    
#     if save_plot:
#         # Save as SVG
#         output_path = r"C:\Users\Basile\Desktop\Travail\Thèse\Ecriture\Article S&T\Images\HX model\Turgut_disc.svg"
#         plt.savefig(output_path, format="svg", bbox_inches="tight")
    
#     plt.show()
    
#     for j in range(len(w_vec)):
#         n_disc = len(w_vec[j])
#         plt.plot(w_vec[j]/w_vec[j][-1], LMTD_vec[j], label = f"{n_disc - 1} disc")

#     plt.ylabel('Cell LMTD [K]', fontsize = 16)
#     plt.xlabel('Position in the heat exchanger [-]', fontsize = 16)
    
#     plt.ylim(0, 30)
#     plt.legend(loc='upper left')
#     plt.axvline(0.5, color='k', linestyle=':', linewidth=2)
    
#     import matplotlib.patches as patches
    
#     rect = patches.Rectangle(
#         (0.98, 4),      # (x, y) lower-left corner
#         1.0 - 0.98,     # width
#         14 - 4,         # height
#         facecolor='red',
#         alpha=0.25,
#         edgecolor='none'
#     )
    
#     plt.gca().add_patch(rect)
    
#     plt.annotate(
#         "Superheated \n     region",
#         xy=(0.975, 14),          # point inside the rectangle (arrow tip)
#         xytext=(0.7, 18),        # text position
#         color='red',
#         fontsize=13,
#         ha='left',               # ← left-aligned text
#         arrowprops=dict(
#             arrowstyle='->',
#             color='red',
#             linewidth=2
#         )
#     )
    
#     plt.annotate(
#         "  Forward \n tube pass",
#         xy=(0.975, 14),          # point inside the rectangle (arrow tip)
#         xytext=(0.22, 26),        # text position
#         color='black',
#         fontsize=13,
#     )
    
#     plt.annotate(
#         "  Reverse \n tube pass",
#         xy=(0.975, 14),          # point inside the rectangle (arrow tip)
#         xytext=(0.65, 26),        # text position
#         color='black',
#         fontsize=13,
#     )
    
#     plt.grid()
    
#     if save_LMTD:
#         # Save as SVG
#         output_path = r"C:\Users\Basile\Desktop\Travail\Thèse\Ecriture\Article S&T\Images\HX model\Turgut_LMTD.svg"
#         plt.savefig(output_path, format="svg", bbox_inches="tight")
    
#     plt.show()

#     if save_geom:
#         save_path = r"C:\Users\Basile\Desktop\Travail\Thèse\Ecriture\Article S&T\Images\HX model\Turgut_HTC.svg"
#     else:
#         save_path = None

#     plot_MB_STHE(HX, props='htc', legend_range=[0,4500], save_path = save_path)

#     plt.plot(n_disc_vec, LMTD_val)
#     plt.show()

#     w_cum = np.cumsum(HX.w)
#     plt.plot(w_cum, HX.LMTD)
    
#     plt.show()

PCHE heat exchanger:

"""
Supplemental code for paper:
I. Bell et al., "A Generalized Moving-Boundary Algorithm to Predict the Heat Transfer Rate of 
Counterflow Heat Exchangers for any Phase Configuration", Applied Thermal Engineering, 2014
"""

"""
Modification w/r to previous version:
    - Putting some order in the Objective Function "for" loops. Sparing some
    lines of code.
    - x_di_c correct calculation.
"""

from labothappy.component.heat_exchanger.hex_MB_charge_sensitive import HexMBChargeSensitive

#%%

# import time
# start_time = time.time()

# "------------ Plate HX -------------------------------------------------------------------------------------------------"

"HTX Instanciation"

HX = HexMBChargeSensitive('PCHE')

test_case = "test_CO2"

# # "Setting inputs"

# # # ---------------------------------------------------------------------------------------------------------

# Case from:  
# Numerical modelling and transient analysis of a printed circuit heat exchanger 
# used as recuperator for supercritical CO2 heat to power conversion systems

if test_case == "test_CO2":
    HX.set_inputs(
        # First fluid
        fluid_H = 'CO2',
        T_su_H = 249 + 273.15, # K
        P_su_H = 96.4*1e5, # Pa
        m_dot_H = 5.35, # kg/s
    
        # Second fluid
        fluid_C = 'CO2',
        T_su_C = 52.77 + 273.15, # K
        P_su_C = 165.4*1e5, # Pa
        m_dot_C = 5.35, # kg/s  # Make sure to include fluid information
    )
    
    "Geometry Loading"
    params = {'alpha': 40, # Channel zigzag angle
              'D_c': 2*1e-3, # Channel diameter
              'C_V_tot' : 1, 
              'H_V_tot' : 1, 
              'k_cond': 60, # plate conductivity
              'L_c': 1.5, # channel length
              'N_c': 112, # n channels per plate
              'N_p': 256, # n plates
              'R_p': 1, # n_hot_channel_row / n_cold_channel_row
              't_2': 0.63*1e-3, # Horizontal pitch
              't_3': 1*1e-3, # Plate thickness
              'type_channel' : 'Zigzag'} 
    
    Corr_H = {"SC" : "Gnielinski", "1P" : "Gnielinski"}
    Corr_C = {"SC" : "Gnielinski", "1P" : "Gnielinski"}

    Corr_H_DP = {"SC" : "Darcy_Weisbach", "1P" : "Darcy_Weisbach"}
    Corr_C_DP = {"SC" : "Darcy_Weisbach", "1P" : "Darcy_Weisbach"}  

    # ---------------------------------------------------------------------------------------------------------
    # "Parameters Setting"
    
    HX.set_parameters(
        alpha = params['alpha'], C_V_tot = params['C_V_tot'], H_V_tot = params['H_V_tot'], D_c = params['D_c'], k_cond = params['k_cond'], L_c = params['L_c'], 
        N_c = params['N_c'], N_p = params['N_p'], R_p = params['R_p'], t_2 = params['t_2'], t_3 = params['t_3'], type_channel = params['type_channel'],
        
        Flow_Type = 'CounterFlow', H_DP_ON = True, C_DP_ON = True, n_disc = 50) # 27

if test_case == "TCO2_recup":

    HX.set_inputs(
        # First fluid
        fluid_H = 'CO2',
        T_su_H = 321.88, # K
        P_su_H = 5742510, # Pa
        m_dot_H = 415.93, # kg/s
    
        # Second fluid
        fluid_C = 'CO2',
        T_su_C = 305.61, # K
        P_su_C = 14153425, # Pa
        m_dot_C = 415.93, # kg/s  # Make sure to include fluid information
    )
    
    "Geometry Loading"
    params = {'alpha': 32.62, # Channel zigzag angle
              'D_c': 2.42*1e-3, # Channel diameter
              'C_V_tot' : 1, 
              'H_V_tot' : 1, 
              'k_cond': 60, # plate conductivity
              'L_c': 0.7432303013776589, # channel length
              'N_c': 736, # n channels per plate
              'N_p': 563, # n plates
              'R_p': 1, # n_hot_channel_row / n_cold_channel_row
              't_2': 0.0012282802564224898, # Horizontal pitch
              't_3': 0.0009428803890487963, # Plate_thickness
              'type_channel' : 'Zigzag'} 

    Corr_H = {"1P" : "Gnielinski", "SC" : "Gnielinski"}
    Corr_C = {"1P" : "Gnielinski", "SC" : "Gnielinski"}
    
    # H_DP = "Gnielinski_DP"
    # C_DP = "Gnielinski_DP"    
    
    H_DP = {"SC" : "Darcy_Weisbach", "1P" : "Darcy_Weisbach"}
    C_DP = {"SC" : "Darcy_Weisbach", "1P" : "Darcy_Weisbach"}  
    
    # ---------------------------------------------------------------------------------------------------------
    # "Parameters Setting"
    
    HX.set_parameters(
        alpha = params['alpha'], C_V_tot = params['C_V_tot'], H_V_tot = params['H_V_tot'], D_c = params['D_c'], k_cond = params['k_cond'], L_c = params['L_c'], 
        N_c = params['N_c'], N_p = params['N_p'], R_p = params['R_p'], t_2 = params['t_2'], t_3 = params['t_3'],
        
        Flow_Type = 'CounterFlow', H_DP_ON = True, C_DP_ON = True, n_disc = 50) # 27
    
# UD_H_HTC = {'Liquid':100,
#             'Vapor' : 100,
#             'Two-Phase' : 1000,
#             'Vapor-wet' : 100,
#             'Dryout' : 1000,
#             'Transcritical' : 200}

# UD_C_HTC = {'Liquid':100,
#             'Vapor' : 100,
#             'Two-Phase' : 1000,
#             'Vapor-wet' : 100,
#             'Dryout' : 10000,
#             'Transcritical' : 200}

HX.set_htc(htc_type = 'Correlation', Corr_H = Corr_H, Corr_C = Corr_C) # 'User-Defined' or 'Correlation' # 28
# HX.set_htc(htc_type = 'User-Defined', UD_H_HTC = UD_H_HTC, UD_C_HTC = UD_C_HTC) # 'User-Defined' or 'Correlation'

# HX.set_DP() # equivalent to HX.set_DP(DP_type = None)
# HX.set_DP(DP_type="User-Defined", UD_C_DP = 10000, UD_H_DP = 10000) # Fixed User-Defined values, equally distributed over discretizations
# HX.set_DP(DP_type="Correlation_Global", Corr_C=Corr_C_DP, Corr_H=Corr_H_DP)
HX.set_DP(DP_type="Correlation_Disc", Corr_C=Corr_C_DP, Corr_H=Corr_H_DP)

# "Solve the component"
HX.solve()
# HX.plot_cells()

References

[1] I. H. Bell et al., ‘A generalized moving-boundary algorithm to predict the heat transfer rate of counterflow heat exchangers for any phase configuration’, Applied Thermal Engineering, vol. 79, pp. 192–201, Mar. 2015, doi: 10.1016/j.applthermaleng.2014.12.028.