Skip to content

bet-lab/tmhp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

153 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Thermodynamic Models for Heat Pumps

A physics-based Python library for heat pump simulation

Refrigerant-agnostic · operating-condition-agnostic · first-principles from the cycle up

Python License Docs CoolProp

Documentation · Sister project: Energy-Exergy Analysis Engine


Overview

tmhp is a Python library of thermodynamic cycle models for air-source, ground-source, and water-source heat pumps. The models cover domestic hot water (DHW), space heating, and space cooling.

Every model solves the same closed refrigerant cycle from first principles at every time step — no manufacturer-specific curve fits, no per-unit recalibration. Swap the refrigerant, change the source side, or move the operating point, and the same code path produces a coherent answer.

In one line: a refrigerant-agnostic, condition-agnostic heat pump model — one library, many systems.


Why physics-based?

Most building-energy simulators (EnergyPlus, TRNSYS, and friends) model a heat pump as an empirical curve fit against the manufacturer's catalogue. That is cheap and accurate inside the calibration envelope, but it carries structural limits:

Curve-fit models This library
Tied to the operating range of the original test data Predictive across the full refrigerant envelope
Refrigerant is baked into the coefficients Any CoolProp-supported refrigerant, swappable at runtime
Refrigerant state is hidden Full thermodynamic state at every cycle node
Requires re-fitting for every new unit One model class, parameterized by geometry & components

You pay for it with a few extra parameters and a slightly more expensive time step. What you get in return is a model you can trust outside its calibration range — across refrigerants, operating envelopes, and system topologies that no single catalogue covers.


How it works

Cycle architecture: source → evaporator → compressor → condenser → expander, with a cycle-closure solver optimizing the evaporating-side approach temperature and compressor speed

Shared cycle architecture — bold blocks are reused across ASHPB, GSHPB, WSHPB, ASHP, and GSHP. Open the interactive version →



ASHPB system schematic

Reference ASHPB topology — outdoor unit, refrigerant loop, hot water tank, mixing valve.

Each time step solves a closed refrigerant cycle coupled to the surrounding system (tank, building, ground loop, …). The condenser duty is given; the evaporating temperature is the free variable, picked by minimizing compressor power. The cycle closes on a physical optimum, not on fitted coefficients.

Sub-model Method
Refrigerant state points CoolProp (REFPROP-grade equation of state)
Compressor work Isentropic + volumetric + mechanical efficiency
Condenser / evaporator ε-NTU (effectiveness-NTU) heat exchanger model
Outdoor unit fan ASHRAE 90.1-style variable-speed-drive (VSD) power curve + air-side ε-NTU
Ground heat exchanger g-function (ground thermal response) via pygfunction
PV / solar thermal pvlib-driven irradiance & power
Cycle closure Internal minimization → optimal evaporating temperature
Plotting backend dartwork-mpl — thin matplotlib utility layer

The same refrigerant cycle is reused across every system model. What varies between models is composed along three independent axes:

  • Environmental medium — air, ground, or water. Acts as the heat source in heating mode and the heat sink in cooling mode; the same loop, with the direction of heat flow reversed.
  • Demand side — what the system has to deliver: a domestic-hot-water tank, a space-heating load, or a space-cooling load.
  • Auxiliary subsystems — parallel energy contributors that augment (not replace) the cycle: solar thermal collectors (STC) preheat the tank, photovoltaics (PV) offset compressor and fan electricity, and an energy storage system (ESS) buffers surplus PV generation.

Each concrete model in the next section is a fixed combination of these three axes.


Installation

Requires Python ≥ 3.10 and the uv package manager.

git clone https://github.com/bet-lab/tmhp.git
cd tmhp
uv sync

That's it — uv sync reads pyproject.toml and resolves every dependency against the committed uv.lock.

Runtime dependencies pulled in automatically:

Optional dev / docs tooling lives behind PEP 735 dependency groups, so the runtime install stays lean:

uv sync --group dev      # ruff, mypy, pytest, pytest-cov
uv sync --group docs     # sphinx + shibuya theme + authoring / UX extensions

See the installation guide for the full per-group breakdown and the CI-equivalent --locked workflow.


Quick start

Steady-state operating point

from tmhp import AirSourceHeatPumpBoiler

# Build a model — the refrigerant is a constructor argument (default: R134a)
ashpb = AirSourceHeatPumpBoiler(ref="R32")

# Steady state: tank at 55 °C, ambient at 5 °C, target condenser duty 8 kW
result = ashpb.analyze_steady(
    T_tank_w=55.0,
    T0=5.0,
    Q_ref_cond=8_000.0,
)

print(f"COP (refrigerant) : {result['cop_ref [-]']:.2f}")
print(f"COP (system)      : {result['cop_sys [-]']:.2f}")
print(f"Heating capacity  : {result['Q_ref_cond [W]'] / 1e3:.2f} kW")
print(f"Compressor power  : {result['E_cmp [W]'] / 1e3:.2f} kW")
print(f"Evap sat. temp.   : {result['T_ref_evap_sat [°C]']:.1f} °C")
print(f"Cond sat. temp.   : {result['T_ref_cond_sat_v [°C]']:.1f} °C")

Swap the refrigerant by changing one argument — no recalibration, no manufacturer data:

ashpb_r290 = AirSourceHeatPumpBoiler(ref="R290")    # propane
ashpb_r744 = AirSourceHeatPumpBoiler(ref="R744")    # CO₂
ashpb_r410 = AirSourceHeatPumpBoiler(ref="R410A")

Time-stepping dynamic simulation

import numpy as np
from tmhp import AirSourceHeatPumpBoiler

ashpb = AirSourceHeatPumpBoiler(ref="R32")

simulation_period_sec = 24 * 3600
dt_s                  = 60
n_steps               = simulation_period_sec // dt_s

dhw_usage_schedule = np.zeros(n_steps)            # m³/s per step
T0_schedule        = np.full(n_steps, 5.0)        # outdoor °C per step

df = ashpb.analyze_dynamic(
    simulation_period_sec = simulation_period_sec,
    dt_s                  = dt_s,
    T_tank_w_init_C       = 50.0,
    dhw_usage_schedule    = dhw_usage_schedule,
    T0_schedule           = T0_schedule,
)

# df is a pandas DataFrame with the same keys as analyze_steady, per time step.

Models

Air-source heat pump boilers (ASHPB)
Class Description
AirSourceHeatPumpBoiler Core ASHPB — refrigerant cycle + storage tank
ASHPB_STC_preheat + Solar thermal collector preheat
ASHPB_STC_tank + STC with stratified tank
ASHPB_PV_ESS + PV + Energy Storage System
Ground-source heat pump boilers (GSHPB)
Class Description
GroundSourceHeatPumpBoiler Core GSHPB with g-function borehole model
GSHPB_STC_preheat + STC preheat
GSHPB_STC_tank + STC with stratified tank
GSHPB_PV_ESS + PV + Energy Storage System
Water-source heat pump boiler (WSHPB)
Class Description
WaterSourceHeatPumpBoiler Dynamic WSHPB model
Space-conditioning heat pumps
Class Description
AirSourceHeatPump ASHP — heating & cooling
GroundSourceHeatPump GSHP — heating & cooling
Supporting modules
Module Purpose
refrigerant.py CoolProp state-point helpers
thermodynamics.py Cycle analysis — COP, compression ratio, isentropic efficiency
heat_transfer.py ε-NTU heat exchanger calculations
hx_fan.py Air-side fan & heat-exchanger model
g_function.py Borehole g-function (pygfunction)
weather.py Outdoor air temperature & weather utilities
dhw.py Domestic hot water demand profiles
cop.py COP correlations
enex_functions.py Energy / exergy helpers
dynamic_context.py Per-step simulation state
subsystems.py Subsystem composition (STC / PV / UV)
simulation_summary.py Stdout summary tables
visualization.py Plotting facade
mollier_diagram.py T-h / P-h / T-s plots
uv_treatment.py UV treatment subsystem
calc_util.py Unit conversions
constants.py Physical constants

Validation

AirSourceHeatPumpBoiler has been benchmarked against the Samsung EHS Mono HT Quiet R32 14 kW unit (Technical Data Book PDF) across 15 operating points$T_{\mathrm{LWT}} \in {40, 50, 65}$ °C paired with outdoor air temperatures from −10 to 30 °C. The model tracks the catalogue COP to MAE 0.35 (MAPE 10.1 %) without any unit-specific calibration.

Parity plot: predicted vs target COP across 15 operating points

Per-point comparison (catalogue conditions and target values follow Table 1 of the KJACR 2026 paper; predicted values come from re-running the released code via scripts/validation/samsung_ehs_parity.py):

$\mathrm{ID}$ $T_{\mathrm{LWT}}~[^\circ\mathrm{C}]$ $T_0~[^\circ\mathrm{C}]$ ${Q}_{\mathrm{ref,cond}}~[\mathrm{kW}]$ $\mathrm{COP}_{\mathrm{target}}$ $\mathrm{COP}_{\mathrm{pred}}$ $\mathrm{AE}$ $\mathrm{APE}$
1 40 −10 13.45 2.30 2.37 0.07 3.0 %
2 40 2 12.42 3.04 3.83 0.79 25.8 %
3 40 12 14.65 5.07 4.67 0.40 7.9 %
4 40 20 15.69 6.48 5.65 0.83 12.8 %
5 40 30 16.98 7.68 7.43 0.25 3.2 %
6 50 −10 13.89 2.00 1.84 0.16 7.8 %
7 50 2 13.27 2.56 3.04 0.48 18.9 %
8 50 12 14.76 3.86 3.71 0.15 3.9 %
9 50 20 15.97 4.78 4.34 0.44 9.2 %
10 50 30 17.48 5.95 5.37 0.58 9.8 %
11 65 −10 13.97 1.73 1.42 0.31 17.7 %
12 65 2 13.71 2.04 2.37 0.33 16.1 %
13 65 12 16.38 2.84 2.73 0.11 3.7 %
14 65 20 17.48 3.34 3.17 0.17 5.1 %
15 65 30 18.84 4.04 3.79 0.25 6.1 %
Mean 0.35 10.1 %

Notation

  • TLWT — Leaving Water Temperature, the manufacturer's catalogue reference. The model's tank water temperature is set 2.5 K below TLWT for TLWT ≤ 60 °C and 5 K below for TLWT > 60 °C, per the paper's EWT/LWT offset.
  • T0 — outdoor (dead-state) air temperature.
  • Qref,cond — target condenser heat rate.
  • COP — system Coefficient of Performance, Qref,cond / (Ecmp + Efan).
  • AE — Absolute Error, |COPpred − COPtarget|.
  • APE — Absolute Percentage Error, (AE / COPtarget) × 100 %.
  • MAE / MAPE — mean AE / APE across the 15 points.

The parity plot and the table above are regenerated by scripts/validation/samsung_ehs_parity.py, so anyone can reproduce the comparison from source.

Scope. Only AirSourceHeatPumpBoiler has been quantitatively validated against catalogue data. The other system classes (GroundSourceHeatPumpBoiler, WaterSourceHeatPumpBoiler, AirSourceHeatPump, GroundSourceHeatPump, and the subsystem-augmented variants) share the same refrigerant-cycle core and pass smoke tests on representative operating points, but they have not yet been benchmarked against unit-specific data.

📄 Jo, H. & Choi, W. "Thermodynamic Modeling of Refrigerant Cycle in an Air-Source Heat Pump Boiler and Performance Validation", KJACR (2026, in press).

📘 Samsung Electronics, EHS Mono HT Quiet R32 Technical Data Book (2024) — PDF


Documentation

The full documentation — getting-started guide, concept pages, tutorials, API reference, and validation report — lives at https://bet-lab.github.io/tmhp/.

If you're new to the library, start with the getting-started guide for a three-step path from uv sync to your first dynamic simulation.


Project layout
tmhp/
├── src/tmhp/                # Importable package
│   ├── __init__.py                # Public re-exports
│   │
│   ├── air_source_heat_pump.py            # ASHP (space conditioning)
│   ├── air_source_heat_pump_boiler.py     # ASHPB core
│   ├── ashpb_stc_preheat.py
│   ├── ashpb_stc_tank.py
│   ├── ashpb_pv_ess.py
│   │
│   ├── ground_source_heat_pump.py         # GSHP (space conditioning)
│   ├── ground_source_heat_pump_boiler.py  # GSHPB core
│   ├── gshpb_stc_preheat.py
│   ├── gshpb_stc_tank.py
│   ├── gshpb_pv_ess.py
│   │
│   ├── water_source_heat_pump_boiler.py   # WSHPB core
│   │
│   ├── refrigerant.py             # CoolProp helpers
│   ├── thermodynamics.py          # Cycle analysis
│   ├── heat_transfer.py           # ε-NTU
│   ├── hx_fan.py                  # Air-side fan & heat-exchanger model
│   ├── g_function.py              # Borehole g-function
│   ├── weather.py
│   ├── dhw.py
│   ├── cop.py
│   ├── enex_functions.py
│   ├── dynamic_context.py
│   ├── subsystems.py
│   ├── simulation_summary.py
│   ├── visualization.py
│   ├── mollier_diagram.py
│   ├── uv_treatment.py
│   ├── calc_util.py
│   └── constants.py
│
├── docs/                          # Sphinx documentation
├── tests/                         # Unit / smoke tests
├── pyproject.toml
├── uv.lock
└── README.md

Cite

If you use this library in academic work, please cite the validation paper:

@article{Jo2026Thermodynamic,
  title   = {Thermodynamic Modeling of Refrigerant Cycle in an Air-Source
             Heat Pump Boiler and Performance Validation},
  author  = {Jo, Habin and Choi, Wonjun},
  journal = {Korean Journal of Air-Conditioning and Refrigeration Engineering},
  year    = {2026},
  note    = {in press}
}

Related work

  • Sister project: Energy-Exergy Analysis Engine — an energy / exergy analysis library developed in parallel by the same team. It consumes simulation output from tmhp (or any other source) and computes the second-law balance; the two projects ship as separate packages.

License

MIT License © 2025 betlab (Habin Jo, Wonjun Choi). See LICENSE for the full text.

Releases

No releases published

Packages

 
 
 

Contributors

Languages