Thermodynamics.jl
March 9, 2026 · View on GitHub
Thermodynamics.jl
The Thermodynamics.jl package implements the thermodynamic formulation of the CliMA Earth System Model (Yatunin et al., 2026). It provides a consistent framework for moist thermodynamics based on the Rankine-Kirchhoff approximations (Romps, 2021), and thermodynamic functions for moist air including all phases of water (vapor, liquid, and ice).
| Documentation | |
| Docs Build | |
| GHA CI | |
| Code Coverage | |
| Downloads |
Quick Start
Installation
using Pkg
Pkg.add("Thermodynamics")
Pkg.add("ClimaParams")
Basic Usage
Thermodynamics.jl provides a functional, stateless API. You import the package (TD) and pass a parameter set plus thermodynamic variables (e.g., density, internal energy, specific humidities) directly to functions.
import Thermodynamics as TD
# Use RootSolvers for the saturation adjustment method
import RootSolvers as RS
using ClimaParams
# 1. Create thermodynamic parameters
# (requires a definition of the parameter set, e.g. from ClimaParams)
params = TD.Parameters.ThermodynamicsParameters(Float64)
# 2. Define your thermodynamic variables
ρ = 1.1 # Density [kg/m³]
e_int = -36000.0 # Internal energy [J/kg, can be negative]
q_tot = 0.015 # Total specific humidity [kg/kg]
q_liq = 0.005 # Liquid specific humidity [kg/kg]
q_ice = 0.001 # Ice specific humidity [kg/kg]
# 3. Compute properties directly
T = TD.air_temperature(params, e_int, q_tot, q_liq, q_ice)
p = TD.air_pressure(params, T, ρ, q_tot, q_liq, q_ice)
Saturation Adjustment
To find the phase equilibrium temperature and phase partition from thermodynamic variables (e.g., given ρ, e_int, q_tot), use saturation_adjustment:
# Solve for phase equilibrium (T, q_liq, q_ice) given (ρ, e_int, q_tot)
# using SecantMethod
sol = TD.saturation_adjustment(
RS.SecantMethod, # Root-solving method
params, # Parameter set
TD.ρe(), # Formulation: Density & Internal Energy
ρ, e_int, q_tot, # Input variables
10, # Max iterations
1e-3 # Relative tolerance
)
println("Equilibrium T: ", sol.T)
println("Liquid q: ", sol.q_liq)
println("Ice q: ", sol.q_ice)
println("Converged: ", sol.converged)
Key Features
🌟 Comprehensive Thermodynamics
- Moist air thermodynamics including all water phases (vapor, liquid, ice).
- Stateless, functional API for flexibility and integration.
- Consistent formulation assuming a calorically perfect gas mixture.
⚡ High Performance
- Type-stable and GPU-compatible (CUDA.jl, AMDGPU.jl, etc.).
- AD-compatible (ForwardDiff.jl, etc.) for differentiable physics.
- Zero-allocation design for core functions.
🔧 Flexible Design
- Multiple formulations: Solve for phase equilibrium from
(ρ, e_int),(p, h),(p, θ_li), etc. - Extensible parameters: Easily adapt to different planetary atmospheres via
ClimaParams.
Core Design Principles
Functional & Stateless
Functions in Thermodynamics.jl are stateless. They take a ThermodynamicsParameters struct and the necessary thermodynamic variables (e.g., T, ρ, q...) as arguments. This design fits naturally into large-scale simulations (e.g., with ClimaAtmos.jl).
Working Fluid
The working fluid is moist air (dry air + water vapor + liquid water + ice, which may include precipitation). We treat it as a mixture of ideal gases and condensed phases, ensuring rigorous mass and energy conservation.
Consistent Formulation
All quantities are derived from the calorically perfect gas assumption with constant specific heat capacities. This provides a consistent, closed set of equations for saturation vapor pressures (the so-called Rankine-Kirchhoff approximation), latent heats, and other derived quantities.
Documentation
- Mathematical Formulation - Theoretical background.
- How-To Guide - Recipes and examples.
- API Reference - Detailed function documentation.
Integration with Climate Models
Thermodynamics.jl is the thermodynamic core for the CliMA ecosystem, including:
Getting Help
For questions, check the documentation or open an issue on GitHub.