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")