Heat Exchanger - Nouman090/ThermoSim GitHub Wiki

A heat exchanger transfers thermal energy between two fluid streams (hot and cold sides). The package supports multiple HEX types with pinch-point constraints, effectiveness methods, and detailed temperature profile analysis.

HEX Types

Type Description
double_pipe Counter-flow or parallel-flow with both sides fully modeled
Condenser Hot side condenses (phase change); cold side may be single-phase
Evaporator Cold side evaporates (phase change); hot side may be single-phase
SimpleHEX Single-side only (external heat source/sink); no pinch analysis

Physics

Energy balance:

Q = แน_hot ร— (H_hot,in - H_hot,out) = แน_cold ร— (H_cold,out - H_cold,in)

Pinch-point constraint (PPT):

ฮ”T_min โ‰ฅ PPT   (minimum temperature difference)

UA and LMTD:

Q = UA ร— LMTD
LMTD = (ฮ”Tโ‚ - ฮ”Tโ‚‚) / ln(ฮ”Tโ‚ / ฮ”Tโ‚‚)

Exergy destruction:

Ex_D = (Ex_hot,in + Ex_cold,in) - (Ex_hot,out + Ex_cold,out)

Syntax

HeatExchanger(Model, ID, PPT, HEX_type, HeatAdded,
              Hot_In_state, Hot_Out_state,
              Cold_In_state, Cold_Out_state,
              UA=None, effectiveness=None, Q=None,
              div_N=200, PPT_graph=False, Calculate=False)
Parameter Type Default Description
Model ThermodynamicModel โ€” The model object
ID str โ€” Unique component name
PPT float โ€” Pinch-point temperature (K)
HEX_type str โ€” 'double_pipe', 'Condenser', 'Evaporator', 'SimpleHEX'
HeatAdded bool/None โ€” True = adds heat to cycle, False = rejects heat, None = internal
Hot_In_state str โ€” Hot inlet state point name
Hot_Out_state str โ€” Hot outlet state point name
Cold_In_state str โ€” Cold inlet state point name
Cold_Out_state str โ€” Cold outlet state point name
UA float None Overall heat transfer coefficient ร— Area [W/K]
effectiveness float None Heat exchanger effectiveness (0โ€“1)
Q float None Heat duty [W] (for SimpleHEX)
div_N int 200 Number of discretization segments for pinch analysis
PPT_graph bool False Show pinch-point diagram during calculation
Calculate bool False Solve immediately if True

Output Attributes

Attribute Type Unit Description
.Q float W Heat transferred
.UA float W/K Overall heat transfer coefficient
.Hot_to_Cold float โ€” Enthalpy ratio
.Hot_Mass_flowrate float kg/s Hot side mass flow
.Cold_Mass_flowrate float kg/s Cold side mass flow
.Ex_D float/str W Exergy destruction
.Solution_Status bool โ€” True if solved

HEX Types

Type Description Use Case
'SimpleHEX' Only one side modelled Boiler, condenser (external source/sink)
'double_pipe' Both sides modelled, single phase Recuperator, preheater
'Condenser' Phase change on hot side Steam condenser
'Evaporator' Phase change on cold side ORC evaporator

HeatAdded Parameter

Value Meaning Effect on Model Summary
True This HEX adds heat TO the cycle Counted as Q_in
False This HEX rejects heat FROM the cycle Counted as Q_out
None Internal heat exchange (recuperator) Not counted in Q_in or Q_out

Case 1: SimpleHEX โ€” Cold Side Heating (Boiler)

Only the cold side (cycle fluid) is modelled. No hot fluid needed.

from ThermoSim import ThermodynamicModel, HeatExchanger

Model = ThermodynamicModel()
Model.set_dead_state()

Model.add_point('water', 'ci', P=8e6, T=350, Mass_flowrate=1)
Model.add_point('water', 'co', P=8e6)

# Known Q: calculate outlet
HeatExchanger(Model, 'Boiler', PPT=5, HEX_type='SimpleHEX',
              HeatAdded=True,
              Hot_In_state=None, Hot_Out_state=None,
              Cold_In_state='ci', Cold_Out_state='co',
              Q=2500e3,
              Calculate=True)

Case 2: SimpleHEX โ€” Hot Side Cooling (Condenser)

Only the hot side is modelled.

Model.add_point('water', 'hi', P=0.008e6, H=2300000, Mass_flowrate=1)
Model.add_point('water', 'ho', P=0.008e6, Q=0)

HeatExchanger(Model, 'Condenser', PPT=5, HEX_type='SimpleHEX',
              HeatAdded=False,
              Hot_In_state='hi', Hot_Out_state='ho',
              Cold_In_state=None, Cold_Out_state=None,
              Calculate=True)

print(f"Heat rejected: {Model.Component['Condenser'].Q:.0f} W")

Case 3: SimpleHEX โ€” Compute Q from Known Inlet and Outlet

Model.add_point('water', 'ci', P=8e6, T=350,    Mass_flowrate=1)
Model.add_point('water', 'co', P=8e6, T=753.15)

HeatExchanger(Model, 'Boiler', PPT=5, HEX_type='SimpleHEX',
              HeatAdded=True,
              Hot_In_state=None, Hot_Out_state=None,
              Cold_In_state='ci', Cold_Out_state='co',
              Calculate=True)
# Q is calculated automatically

Case 4: SimpleHEX โ€” Known Q, Find Inlet

Model.add_point('water', 'ci', P=8e6, Mass_flowrate=1)   # H unknown
Model.add_point('water', 'co', P=8e6, T=753.15)

HeatExchanger(Model, 'Boiler', PPT=5, HEX_type='SimpleHEX',
              HeatAdded=True,
              Hot_In_state=None, Hot_Out_state=None,
              Cold_In_state='ci', Cold_Out_state='co',
              Q=2500e3,
              Calculate=True)
# Cold inlet H and T are calculated

Case 5: Double Pipe โ€” Both Sides Known, Find Mass Flow

When both hot and cold inlet/outlet enthalpies are known but one mass flow is unknown.

Model.add_point('water',  'hi', P=1e6, T=500, Mass_flowrate=2)
Model.add_point('water',  'ho', P=1e6, T=350)
Model.add_point('R245fa', 'ci', P=5e5, T=300)
Model.add_point('R245fa', 'co', P=5e5)

HeatExchanger(Model, 'Recup', PPT=5, HEX_type='double_pipe',
              HeatAdded=None,
              Hot_In_state='hi', Hot_Out_state='ho',
              Cold_In_state='ci', Cold_Out_state='co',
              Calculate=True)

print(f"Cold mass flow: {Model.Component['Recup'].Cold_Mass_flowrate:.3f} kg/s")

Case 6: Double Pipe โ€” Both Mass Flows Known, Cold Outlet Unknown

Model.add_point('water',  'hi', P=1e6, T=500, Mass_flowrate=2)
Model.add_point('water',  'ho', P=1e6, T=350)
Model.add_point('R245fa', 'ci', P=5e5, T=300, Mass_flowrate=3)
Model.add_point('R245fa', 'co', P=5e5)       # H unknown

HeatExchanger(Model, 'HEX1', PPT=5, HEX_type='double_pipe',
              HeatAdded=None,
              Hot_In_state='hi', Hot_Out_state='ho',
              Cold_In_state='ci', Cold_Out_state='co',
              Calculate=True)

Case 7: Double Pipe โ€” PPT-Based Solving (No Mass Flow)

When one mass flow is unknown AND one outlet is unknown, the solver uses the pinch point temperature difference to find the missing state.

Model.add_point('water',  'hi', P=1e6, T=500)   # no mass flow
Model.add_point('water',  'ho', P=1e6, T=350)
Model.add_point('R245fa', 'ci', P=5e5, T=300)
Model.add_point('R245fa', 'co', P=5e5)

HeatExchanger(Model, 'HEX1', PPT=10, HEX_type='double_pipe',
              HeatAdded=None,
              Hot_In_state='hi', Hot_Out_state='ho',
              Cold_In_state='ci', Cold_Out_state='co',
              PPT_graph=True,
              Calculate=True)

Case 8: Evaporator with Phase Change

Model.add_point('water',  'hi', P=1e6, T=500)
Model.add_point('water',  'ho', P=1e6, T=350)
Model.add_point('R245fa', 'ci', P=5e5, Q=0)   # saturated liquid in
Model.add_point('R245fa', 'co', P=5e5)         # superheated out

HeatExchanger(Model, 'Evap', PPT=10, HEX_type='Evaporator',
              HeatAdded=True,
              Hot_In_state='hi', Hot_Out_state='ho',
              Cold_In_state='ci', Cold_Out_state='co',
              PPT_graph=True,
              Calculate=True)

Case 9: Condenser with Phase Change

Model.add_point('R245fa', 'hi', P=5e5, T=400)              # superheated in
Model.add_point('R245fa', 'ho', P=5e5)                      # subcooled out
Model.add_point('water',  'ci', P=1e5, T=293.15, Mass_flowrate=10)
Model.add_point('water',  'co', P=1e5)

HeatExchanger(Model, 'Cond', PPT=5, HEX_type='Condenser',
              HeatAdded=False,
              Hot_In_state='hi', Hot_Out_state='ho',
              Cold_In_state='ci', Cold_Out_state='co',
              PPT_graph=True,
              Calculate=True)

Case 10: Effectiveness-NTU Method

Model.add_point('Air', 'hi', P=1e5, T=800, Mass_flowrate=1)
Model.add_point('Air', 'ho', P=1e5)
Model.add_point('Air', 'ci', P=1e5, T=350, Mass_flowrate=1.2)
Model.add_point('Air', 'co', P=1e5)

HeatExchanger(Model, 'Recup', PPT=5, HEX_type='double_pipe',
              HeatAdded=None,
              Hot_In_state='hi', Hot_Out_state='ho',
              Cold_In_state='ci', Cold_Out_state='co',
              effectiveness=0.85,
              Calculate=True)

Complete Example

from Thermosim import ThermodynamicModel, HeatExchanger

Model = ThermodynamicModel()
Model.set_dead_state()

# Hot side
Model.add_point('water', 'H_in',  P=2e5, T=363.15, Mass_flowrate=0.5)
Model.add_point('water', 'H_out', P=2e5)

# Cold side
Model.add_point('water', 'C_in',  P=1.5e5, T=293.15, Mass_flowrate=0.3)
Model.add_point('water', 'C_out', P=1.5e5)

# Create heat exchanger
HeatExchanger(Model, 'Recuperator', PPT=5, HEX_type='double_pipe',
              HeatAdded=None,
              Hot_In_state='H_in', Hot_Out_state='H_out',
              Cold_In_state='C_in', Cold_Out_state='C_out',
              Calculate=True)

# Results
hex = Model.Component['Recuperator']
print(f"Heat transferred:   {hex.Q/1e3:.2f} kW")
print(f"UA value:           {hex.UA:.2f} W/K")
print(f"Exergy destruction: {hex.Ex_D/1e3:.2f} kW")
print(f"Hot outlet:         {Model.Point['H_out'].T - 273.15:.2f} ยฐC")
print(f"Cold outlet:        {Model.Point['C_out'].T - 273.15:.2f} ยฐC")