Thermodynamics

Thermodynamics.ThermodynamicsModule
Thermodynamics

Moist thermodynamic functions for atmospheric modeling, including air pressure, latent heats, saturation vapor pressures, and saturation specific humidities.

Parameter Sets

Many functions defined in this module rely on ClimaParams.jl. ClimaParams.jl defines several functions (e.g., many planet parameters). For example, to compute the mole-mass ratio of dry air and water vapor:

import ClimaParams as CP
import Thermodynamics.Parameters as TP
FT = Float64
param_set = TP.ThermodynamicsParameters(FT)
Rv_over_Rd = TP.Rv_over_Rd(param_set)

Because these parameters are widely used throughout this module, param_set is an argument for many Thermodynamics functions.

Saturation adjustment

One entry point is saturation_adjustment. It accepts:

  • method: A root-solving method type from RootSolvers.jl (e.g., RS.NewtonsMethod, RS.SecantMethod).
  • param_set: The thermodynamics parameter set.
  • formulation: The thermodynamic formulation (e.g., ρe(), ph()).
  • Thermodynamic state variables appropriate for the formulation.

Supported methods in RootSolvers.jl:

  • NewtonsMethod: Newton method with analytic gradients (recommended for ρe).
  • NewtonsMethodAD: Newton method with automatic differentiation.
  • SecantMethod: Secant method (derivative-free).
  • BrentsMethod: Brent's method (hybrid root-finding).

Thermodynamic functions

Many thermodynamic functions (e.g., air_temperature, air_pressure) are dispatched over the independent variables used to compute them. The available independent variable types (subtypes of IndepVars) are:

  • ρe: Density, internal energy, and specific humidities
  • pe: Pressure, internal energy, and specific humidities
  • ph: Pressure, enthalpy, and specific humidities
  • : Pressure, density, and specific humidities
  • pθ_li: Pressure, liquid-ice potential temperature, and specific humidities
  • ρθ_li: Density, liquid-ice potential temperature, and specific humidities
source

Thermodynamics Parameters

Thermodynamics.Parameters.ThermodynamicsParametersType
ThermodynamicsParameters

Parameters for Thermodynamics.jl.

Example

import ClimaParams as CP
import Thermodynamics.Parameters as TP

FT = Float64;
param_set = TP.ThermodynamicsParameters(FT)

# Alternatively:

toml_dict = CP.create_toml_dict(FT)
param_set = TP.ThermodynamicsParameters(toml_dict)
source

Types

Thermodynamic Functions

Air Properties

Thermodynamics.gas_constant_airFunction
gas_constant_air(param_set, q_tot=0, q_liq=0, q_ice=0)

The specific gas constant of moist air R_m.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • R_m: specific gas constant of moist air [J/(kg·K)]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression.

source
Thermodynamics.cp_mFunction
cp_m(param_set, q_tot=0, q_liq=0, q_ice=0)

The isobaric specific heat capacity of moist air cp_m.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • q_tot: total specific humidity of water [kg/kg]
  • q_liq: specific humidity of liquid [kg/kg]
  • q_ice: specific humidity of ice [kg/kg]

Returns

  • cp_m: isobaric specific heat capacity [J/(kg·K)]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The specific heat capacities are assumed to be constant (calorically perfect air).

source
Thermodynamics.cv_mFunction
cv_m(param_set, q_tot=0, q_liq=0, q_ice=0)

The isochoric specific heat capacity of moist air cv_m.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • cv_m: isochoric specific heat capacity [J/(kg·K)]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The specific heat capacities are assumed to be constant (calorically perfect air).

source
Thermodynamics.soundspeed_airFunction
soundspeed_air(param_set, T, q_tot=0, q_liq=0, q_ice=0)

The speed of sound in unstratified air.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • c: speed of sound [m/s]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The formula is c = √(γ R_m T) where γ = cp_m/cv_m.

source

Air Humidities

Thermodynamics.vapor_specific_humidityFunction
vapor_specific_humidity(q_tot=0, q_liq=0, q_ice=0)

The vapor specific humidity.

Arguments

  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • q_vap: vapor specific humidity [kg/kg]

If the specific humidities are not given, the result is zero. The formula is q_vap = q_tot - q_liq - q_ice.

Note: callers must ensure q_liq + q_ice ≤ q_tot; no clamping is applied.

source
Thermodynamics.condensate_specific_humidityFunction
condensate_specific_humidity(q_liq=0, q_ice=0)

The condensate specific humidity.

Arguments

  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • q_cond: condensate specific humidity [kg/kg]

If the specific humidities are not given, the result is zero. The formula is q_cond = q_liq + q_ice.

source
Thermodynamics.vol_vapor_mixing_ratioFunction
vol_vapor_mixing_ratio(param_set, q_tot=0, q_liq=0, q_ice=0)

The molar (volume) mixing ratio of water vapor.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • r_v: molar mixing ratio of water vapor [mol/mol]

If the specific humidities are not given, the result is zero.

source
Thermodynamics.partial_pressure_dryFunction
partial_pressure_dry(param_set, p, q_tot=0, q_liq=0, q_ice=0)

The partial pressure of dry air.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • p: air pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • p_d: partial pressure of dry air [Pa]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this equals the total pressure.

source
Thermodynamics.partial_pressure_vaporFunction
partial_pressure_vapor(param_set, p, q_tot=0, q_liq=0, q_ice=0)

The partial pressure of water vapor.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • p: air pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • p_v: partial pressure of water vapor [Pa]

If the specific humidities are not given, the partial pressure is zero.

source
Thermodynamics.vapor_pressure_deficitFunction
vapor_pressure_deficit(param_set, T, p, q_tot, q_liq, q_ice, phase::Phase)

The vapor pressure deficit (saturation vapor pressure minus actual vapor pressure, truncated to be non-negative) over a specific phase (Liquid or Ice).

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: air temperature [K]
  • p: air pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]
  • phase: phase to compute saturation over (Liquid() or Ice())

Returns

  • VPD: vapor pressure deficit [Pa]
source
vapor_pressure_deficit(param_set, T, p, q_tot=0, q_liq=0, q_ice=0)

The vapor pressure deficit (saturation vapor pressure minus actual vapor pressure, truncated to be non-negative) over liquid water for temperatures above freezing and over ice for temperatures below freezing.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: air temperature [K]
  • p: air pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • VPD: vapor pressure deficit [Pa]

If the specific humidities are not given, the result is the saturation vapor pressure.

source
Thermodynamics.relative_humidityFunction
relative_humidity(param_set, T, p, q_tot=0, q_liq=0, q_ice=0)

The relative humidity (clipped between 0 and 1).

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • p: pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • RH: relative humidity [dimensionless], 0 ≤ RH ≤ 1

If q_liq and q_ice are zero (or not given), the relative humidity is computed relative to saturation over ice below freezing and over liquid above freezing. If condensate is present, the relative humidity is computed relative to saturation over a mixture of liquid and ice, with the liquid fraction given by the ratio q_liq / (q_liq + q_ice).

Note: relative_humidity uses saturation_vapor_pressure(param_set, T, q_liq, q_ice). In particular, for q_liq == q_ice == 0 it includes a small smooth transition around freezing (via liquid_fraction(param_set, T, q_liq, q_ice)).

source
Thermodynamics.condensate_partitionFunction
condensate_partition(param_set, T, ρ, q_tot)

Compute the equilibrium liquid and ice specific humidities from the condensate in thermodynamic equilibrium, returning a tuple (q_liq, q_ice).

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]

Returns

  • (q_liq, q_ice): tuple of liquid and ice specific humidities [kg/kg]

The condensate is partitioned into liquid and ice using the temperature-dependent liquid fraction (see liquid_fraction) and the saturation excess (see saturation_excess).

source
Thermodynamics.has_condensateFunction
has_condensate(q_c)

Bool indicating if condensate exists, i.e., q_c > eps.

We use a threshold of eps rather than 0 to avoid division by zero in functions such as liquid_fraction and to robustly handle numerical noise.

source
Thermodynamics.liquid_fractionFunction
liquid_fraction(param_set, T, q_liq, q_ice)

The fraction of condensate that is liquid.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • λ: liquid fraction [dimensionless], 0 ≤ λ ≤ 1

The liquid fraction is computed from q_liq and q_ice. If q_liq + q_ice exceeds a small threshold (see has_condensate), q_liq / (q_liq + q_ice) is returned. If there is effectively no condensate, a smooth temperature-dependent partitioning is used (linear ramp from 0 to 1 over ±0.1 K around freezing).

source
Thermodynamics.liquid_fraction_rampFunction
liquid_fraction_ramp(param_set, T)

The liquid fraction computed from temperature using a power law interpolation between T_icenuc and T_freeze.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]

Returns

  • λ: liquid fraction [dimensionless], 0 ≤ λ ≤ 1

Edge cases:

  • For T > T_freeze, this returns 1; for T ≤ T_icenuc, it returns 0.

Reference

Kaul et al. (2015), "Sensitivities in large-eddy simulations of mixed-phase Arctic stratocumulus clouds using a simple microphysics approach," Monthly Weather Review, 143, 4393-4421, doi:10.1175/MWR-D-14-00319.1.

source
Thermodynamics.specific_humidity_to_mixing_ratioFunction
specific_humidity_to_mixing_ratio(q, q_tot)

Converts specific humidity to mixing ratio (total basis).

Arguments

  • q: specific humidity of interest [kg/kg]
  • q_tot: total specific humidity [kg/kg]

Returns

  • r: mixing ratio [kg/kg]

Note that this function is singular when q_tot = 1. The formula is r = q / (1 - q_tot).

source

Air Energies

Thermodynamics.internal_energyFunction
internal_energy(param_set, T, q_tot=0, q_liq=0, q_ice=0)

The internal energy per unit mass.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • e_int: specific internal energy [J/kg]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The internal energy is computed as a mass-weighted sum of the internal energies of each component (dry air, vapor, liquid, ice), referenced to T_0.

source
Thermodynamics.enthalpyFunction
enthalpy(e_int, R_m, T)

The specific enthalpy.

Arguments

  • e_int: internal specific energy [J/kg]
  • R_m: gas constant of moist air [J/(kg·K)], see gas_constant_air
  • T: air temperature [K]

Returns

  • h: specific enthalpy [J/kg]

The enthalpy is computed as h = e_int + R_m T, which follows from h = e_int + p v with the ideal gas law p v = R_m T (specific volume v = 1/ρ).

source
enthalpy(param_set, T, q_tot=0, q_liq=0, q_ice=0)

The specific enthalpy.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • h: specific enthalpy [J/kg]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The enthalpy is computed as a mass-weighted sum of the enthalpies of each component (dry air, vapor, liquid, ice).

source
Thermodynamics.enthalpy_dryFunction
enthalpy_dry(param_set, T)

The specific enthalpy of dry air.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]

Returns

  • h_d: specific enthalpy of dry air [J/kg]
source
Thermodynamics.enthalpy_vaporFunction
enthalpy_vapor(param_set, T)

The specific enthalpy of water vapor.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]

Returns

  • h_v: specific enthalpy of water vapor [J/kg]
source
Thermodynamics.enthalpy_liquidFunction
enthalpy_liquid(param_set, T)

The specific enthalpy of liquid.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]

Returns

  • h_l: specific enthalpy of liquid [J/kg]

The specific enthalpy of liquid is equal to the internal energy of liquid because the specific volume of condensed water is neglected (i.e., p v_l ≈ 0).

source
Thermodynamics.enthalpy_iceFunction
enthalpy_ice(param_set, T)

The specific enthalpy of ice.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]

Returns

  • h_i: specific enthalpy of ice [J/kg]

The specific enthalpy of ice is equal to the internal energy of ice because the specific volume of condensed water is neglected (i.e., p v_i ≈ 0).

source
Thermodynamics.total_energyFunction
total_energy(param_set, e_kin, e_pot, T, q_tot=0, q_liq=0, q_ice=0)

The total energy per unit mass.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • e_kin: kinetic energy per unit mass [J/kg]
  • e_pot: gravitational potential energy (geopotential)per unit mass [J/kg]
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • e_tot: total specific energy [J/kg]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The total energy is e_tot = e_int + e_kin + e_pot.

source
Thermodynamics.total_enthalpyFunction
total_enthalpy(param_set, e_tot, T, q_tot=0, q_liq=0, q_ice=0)

The total enthalpy per unit mass, h_tot = e_tot + R_m T.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • e_tot: total specific energy [J/kg], see total_energy
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • h_tot: total specific enthalpy [J/kg]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression.

source
Thermodynamics.dry_static_energyFunction
dry_static_energy(param_set, T, e_pot)

The dry static energy.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • e_pot: gravitational potential energy per unit mass (geopotential) [J/kg]

Returns

  • s_d: dry static energy [J/kg]

The dry static energy is the sum of the dry enthalpy and geopotential: s_d = h_d + e_pot.

source
Thermodynamics.vapor_static_energyFunction
vapor_static_energy(param_set, T, e_pot)

The static energy (sensible heat only) of water vapor.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • e_pot: gravitational potential energy per unit mass (geopotential) [J/kg]

Returns

  • s_v: vapor static energy [J/kg]

The formula is s_v = cp_v * (T - T_0) + e_pot, where T_0 is the reference temperature.

source
Thermodynamics.moist_static_energyFunction
moist_static_energy(param_set, T, e_pot, q_tot=0, q_liq=0, q_ice=0)

The moist static energy.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • e_pot: gravitational potential energy per unit mass (geopotential) [J/kg]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • s_m: moist static energy [J/kg]

If the specific humidities are not given, the result is for dry air. The moist static energy is the sum of the moist enthalpy and geopotential: s_m = h + e_pot, where h is computed from enthalpy.

source
Thermodynamics.virtual_dry_static_energyFunction
virtual_dry_static_energy(param_set, T, e_pot, q_tot=0, q_liq=0, q_ice=0)

The virtual dry static energy.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • e_pot: gravitational potential energy per unit mass (geopotential) [J/kg]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • s_vd: virtual dry static energy [J/kg]

If the specific humidities are not given, the result is for dry air. The virtual dry static energy is s_vd = cp_d * (T_virt - T_0) + e_pot, where T_virt is the virtual temperature (see virtual_temperature) and T_0 is the reference temperature.

source
Thermodynamics.latent_heat_fusionFunction
latent_heat_fusion(param_set, T)

The specific latent heat of fusion L_f.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]

Returns

  • L_f: latent heat of fusion [J/kg]

Because the specific heats are assumed constant, the latent heats are linear functions of temperature by Kirchhoff's law.

source
Thermodynamics.latent_heat_sublimFunction
latent_heat_sublim(param_set, T)

The specific latent heat of sublimation L_s.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]

Returns

  • L_s: latent heat of sublimation [J/kg]

Because the specific heats are assumed constant, the latent heats are linear functions of temperature by Kirchhoff's law.

source
Thermodynamics.latent_heat_vaporFunction
latent_heat_vapor(param_set, T)

The specific latent heat of vaporization L_v.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]

Returns

  • L_v: latent heat of vaporization [J/kg]

Because the specific heats are assumed constant, the latent heats are linear functions of temperature by Kirchhoff's law.

source
Thermodynamics.latent_heat_mixedFunction
latent_heat_mixed(param_set, T, λ)

The specific latent heat of a mixed phase, weighted by the liquid fraction λ.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: air temperature [K]
  • λ: liquid fraction [dimensionless], 0 ≤ λ ≤ 1

Returns

  • L: latent heat of the mixed phase [J/kg]

Computed as L = λ * L_v(T) + (1 - λ) * L_s(T).

source
Thermodynamics.latent_heatFunction
latent_heat(param_set, T)
latent_heat(param_set, T, q_liq, q_ice)

The specific latent heat of phase change for a mixed-phase condensate.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • q_liq: (optional) liquid specific humidity [kg/kg]
  • q_ice: (optional) ice specific humidity [kg/kg]

Returns

  • L: latent heat [J/kg]

If q_liq and q_ice are provided, the liquid fraction is computed from these (see liquid_fraction). If there is no condensate, a temperature-dependent partitioning similar to liquid_fraction_ramp is used.

If q_liq and q_ice are not provided, the liquid fraction is computed from a temperature-dependent parameterization liquid_fraction_ramp.

See also latent_heat_mixed for the underlying computation.

source
Thermodynamics.humidity_weighted_latent_heatFunction
humidity_weighted_latent_heat(param_set, q_liq=0, q_ice=0)

Specific-humidity weighted sum of latent heats of liquid and ice evaluated at reference temperature T_0.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • L_q: humidity-weighted latent heat [J/kg]

Computed as L_q = LH_v0 * q_liq + LH_s0 * q_ice. If q_liq and q_ice are not provided, this returns zero. Used in liquid-ice potential temperature computations.

source

Air Temperatures

Thermodynamics.air_temperatureFunction
air_temperature(param_set, e_int, q_tot=0, q_liq=0, q_ice=0)

The air temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • e_int: specific internal energy of moist air [J/kg]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • T: air temperature [K]

If the specific humidities are not given, the result is for dry air. This method inverts internal_energy by solving for T given e_int.

source
air_temperature(param_set, ::ph, h, q_tot=0, q_liq=0, q_ice=0)

The air temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • h: specific enthalpy of moist air [J/kg]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • T: air temperature [K]

If the specific humidities are not given, the result is for dry air. This method inverts enthalpy by solving for T given h.

source
air_temperature(param_set, ::pρ, p, ρ, q_tot=0, q_liq=0, q_ice=0)

The air temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • p: air pressure [Pa]
  • ρ: air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • T: air temperature [K]

If the specific humidities are not given, the result is for dry air. This directly applies the ideal gas law: T = p / (R_m ρ).

source
air_temperature(
    param_set,
    ::pθ_li,
    p,
    θ_li,
    q_tot=0,
    q_liq=0,
    q_ice=0
)

The air temperature obtained by inverting the liquid-ice potential temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • p: pressure [Pa]
  • θ_li: liquid-ice potential temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • T: air temperature [K]

If the specific humidities are not given, θ_li is assumed to be the dry-air potential temperature. This inverts liquid_ice_pottemp_given_pressure by solving for T.

source
air_temperature(param_set, ::ρθ_li, ρ, θ_li, q_tot=0, q_liq=0, q_ice=0)

The air temperature obtained by inverting the liquid-ice potential temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • ρ: (moist-)air density [kg/m³]
  • θ_li: liquid-ice potential temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • T: air temperature [K]

If the specific humidities are not given, the results are for dry air.

Method

This function uses a second-order Taylor expansion to avoid an iterative inversion. The unsaturated temperature T_unsat is first computed assuming the ideal gas law with potential temperature, then latent heat corrections are applied.

source
air_temperature(param_set, ::DryAdiabaticProcess, p, θ)

The air temperature for an isentropic process.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • p: pressure [Pa]
  • θ: potential temperature [K]

Returns

  • T: air temperature [K]

The temperature is computed using the definition of the dry potential temperature: T = θ * (p/p₀)^κ_d, where p₀ is the reference pressure and κ_d = R_d/cp_d.

source
Thermodynamics.potential_temperatureFunction
potential_temperature(param_set, T, ρ, q_tot=0, q_liq=0, q_ice=0)

The potential temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • θ: potential temperature [K]

If the specific humidities are not given, the result is for dry air.

Note: if any of q_tot, q_liq, or q_ice are nonzero, the Exner function uses the moist exponent R_m/cp_m (reducing to the dry exponent R_d/cp_d in the dry limit).

source
Thermodynamics.potential_temperature_given_pressureFunction
potential_temperature_given_pressure(param_set, T, p, q_tot=0, q_liq=0, q_ice=0)

The potential temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • p: pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • θ: potential temperature [K]

If the specific humidities are not given, the result is for dry air.

Note: if any of q_tot, q_liq, or q_ice are nonzero, the Exner function uses the moist exponent R_m/cp_m (reducing to the dry exponent R_d/cp_d in the dry limit).

source
Thermodynamics.liquid_ice_pottempFunction
liquid_ice_pottemp(param_set, T, ρ, q_tot=0, q_liq=0, q_ice=0)

The liquid-ice potential temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • θ_li: liquid-ice potential temperature [K]

If the specific humidities are not given, the result is for dry air.

Reference

Betts (1973), "Non-precipitating cumulus convection and its parameterization," Quarterly Journal of the Royal Meteorological Society, 99, 178-196, doi:10.1002/qj.49709941915.

source
Thermodynamics.liquid_ice_pottemp_given_pressureFunction
liquid_ice_pottemp_given_pressure(param_set, T, p, q_tot=0, q_liq=0, q_ice=0)

The liquid-ice potential temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • p: pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • θ_li: liquid-ice potential temperature [K]

If the specific humidities are not given, the result is for dry air. The latent heats of phase transitions are approximated as constants.

Reference

Betts (1973), "Non-precipitating cumulus convection and its parameterization," Quarterly Journal of the Royal Meteorological Society, 99, 178-196, doi:10.1002/qj.49709941915.

source
Thermodynamics.virtual_pottempFunction
virtual_pottemp(param_set, T, ρ, q_tot=0, q_liq=0, q_ice=0)

The virtual potential temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • θ_v: virtual potential temperature [K]

If the specific humidities are not given, the result is for dry air. The virtual potential temperature is defined as θ_v = θ * R_m / R_d.

source
Thermodynamics.virtual_temperatureFunction
virtual_temperature(param_set, T, q_tot=0, q_liq=0, q_ice=0)

The virtual temperature.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • T_v: virtual temperature [K]

If the specific humidities are not given, the result is for dry air. The virtual temperature is defined such that dry air at T_v has the same density as moist air at T, i.e., T_v = T (R_m / R_d).

source

Air Pressure and Density

Thermodynamics.air_pressureFunction
air_pressure(param_set, T, ρ, q_tot=0, q_liq=0, q_ice=0)

The air pressure from the equation of state (ideal gas law).

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: air temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • p: air pressure [Pa]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The formula is p = ρ R_m T where R_m is the gas constant of moist air (see gas_constant_air).

source
air_pressure(param_set, ::DryAdiabaticProcess, T, T∞, p∞)

The air pressure for an isentropic process.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: current temperature [K]
  • T∞: reference temperature [K]
  • p∞: reference pressure [Pa]

Returns

  • p: air pressure [Pa]

The pressure is computed using the isentropic relation: p = p∞ * (T/T∞)^(1/κ_d), where κ_d = R_d/cp_d is the ratio of the gas constant to the isobaric specific heat constant of dry air.

source
Thermodynamics.air_densityFunction
air_density(param_set, T, p, q_tot=0, q_liq=0, q_ice=0)

The (moist-)air density from the equation of state (ideal gas law).

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: air temperature [K]
  • p: pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • ρ: (moist-)air density [kg/m³]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The formula is ρ = p / (R_m T) where R_m is the gas constant of moist air (see gas_constant_air).

source
Thermodynamics.exnerFunction
exner(param_set, T, ρ, q_tot=0, q_liq=0, q_ice=0)

The Exner function Π = (p/p₀)^(R_m/cp_m).

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • T: temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • Π: Exner function [dimensionless]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The pressure is computed internally from the equation of state (see air_pressure).

source
Thermodynamics.exner_given_pressureFunction
exner_given_pressure(param_set, p, q_tot=0, q_liq=0, q_ice=0)

The Exner function Π = (p/p₀)^(R_m/cp_m), where p₀ is the reference pressure.

Arguments

  • param_set: thermodynamics parameter set, see the Thermodynamics for more details
  • p: pressure [Pa]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • Π: Exner function [dimensionless]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The reference pressure p₀ is p_ref_theta from the parameter set.

source
Thermodynamics.air_pressure_given_θFunction
air_pressure_given_θ(param_set, ::DryAdiabaticProcess, θ, Φ)

The air pressure for an isentropic process.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • θ: potential temperature [K]
  • Φ: gravitational potential [J/kg]

Returns

  • p: air pressure [Pa]

The pressure is computed using the hydrostatic balance and the definition of potential temperature for an isentropic process: p = p₀ * (1 - Φ/(θ * cp_d))^(1/κ_d), where p₀ is the reference pressure, cp_d is the isobaric specific heat capacity of dry air, and κ_d = R_d/cp_d.

source

Air Saturation Functions

Thermodynamics.saturation_vapor_pressureFunction
saturation_vapor_pressure(param_set, T, ::Liquid)
saturation_vapor_pressure(param_set, T, ::Ice)

The saturation vapor pressure over a plane surface of condensate.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • Liquid() or Ice() to dispatch over the condensate type

Returns

  • p_v^*: saturation vapor pressure [Pa]

The saturation vapor pressure is computed by integration of the Clausius-Clapeyron relation, assuming constant specific heat capacities in the so-called Rankine-Kirchhoff approximation.

source
saturation_vapor_pressure(param_set, T)
saturation_vapor_pressure(param_set, T, q_liq, q_ice)

The saturation vapor pressure over liquid, ice, or a mixture of liquid and ice.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • q_liq: (optional) liquid specific humidity [kg/kg]
  • q_ice: (optional) ice specific humidity [kg/kg]

Returns

  • p_v^*: saturation vapor pressure [Pa]

Important: two different liquid fraction parameterizations are used

The two-argument form saturation_vapor_pressure(param_set, T) uses liquid_fraction_ramp, a power-law interpolation between T_icenuc and T_freeze.

The four-argument form saturation_vapor_pressure(param_set, T, q_liq, q_ice) uses liquid_fraction, which returns q_liq / (q_liq + q_ice) when condensate is present, or a ±0.1 K linear ramp around T_freeze when there is no condensate.

As a result, saturation_vapor_pressure(param_set, T, 0, 0) and saturation_vapor_pressure(param_set, T) give the same value at T_freeze (both λ=1) but can differ away from freezing. Use the two-argument form when no condensate information is available; use the four-argument form when condensate fractions are known.

source
Thermodynamics.q_vap_saturationFunction
q_vap_saturation(param_set, T, ρ)
q_vap_saturation(param_set, T, ρ, q_liq, q_ice)

The saturation specific humidity.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • ρ: air density [kg/m³]
  • (optional) q_liq: liquid specific humidity [kg/kg]
  • (optional) q_ice: ice specific humidity [kg/kg]

Returns

  • q_v^*: saturation specific humidity [kg/kg]

If q_liq and q_ice are provided, the saturation specific humidity is that over a mixture of liquid and ice, computed in a thermodynamically consistent way from the weighted sum of the latent heats of the respective phase transitions. That is, the saturation vapor pressure and from it the saturation specific humidity are computed from a weighted mean of the latent heats of vaporization and sublimation, with the weights given by the liquid fraction (see liquid_fraction). If q_liq and q_ice are 0, the saturation specific humidity is that over liquid above freezing and over ice below freezing.

Otherwise, the fraction of liquid is given by the temperature dependent liquid_fraction_ramp(param_set, T).

Reference

Pressel et al. (2015), "Numerics and subgrid-scale modeling in large eddy simulations of stratocumulus clouds," Journal of Advances in Modeling Earth Systems, 7(3), 1199-1220, doi:10.1002/2014MS000376.

source
q_vap_saturation(param_set, T, ρ, phase::Phase)

The saturation specific humidity.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • phase: the phase to compute saturation over (either Liquid() or Ice())

Returns

  • q_v^*: saturation specific humidity [kg/kg]
source
Thermodynamics.∂q_vap_sat_∂TFunction
∂q_vap_sat_∂T(param_set, T, ρ)
∂q_vap_sat_∂T(param_set, T, ρ, q_liq, q_ice)
∂q_vap_sat_∂T(param_set, T, ρ, phase::Phase)

Derivative of saturation vapor specific humidity with respect to temperature.

Arguments

  • param_set: Parameter set.
  • T: Temperature [K].
  • ρ: Density [kg/m³].
  • q_liq: (Optional) Liquid specific humidity [kg/kg].
  • q_ice: (Optional) Ice specific humidity [kg/kg].
  • phase: (Optional) Phase (Liquid() or Ice()).

Returns

  • ∂q_vap_sat / ∂T: Derivative of saturation specific humidity with respect to temperature [kg/kg/K].

Computed as

\[\frac{\partial q_v^*}{\partial T} = q_v^* \left( \frac{L}{R_v T^2} - \frac{1}{T} \right),\]

which follows from the definition of saturation specific humidity and the ideal gas law,

\[q_v^* = \frac{p_v^*}{\rho R_v T},\]

(where $q_v^*$ is q_vap_sat and $p_v^*$ is saturation vapor pressure) and the Clausius-Clapeyron relation

\[\frac{\partial \ln p_v^*}{\partial T} = \frac{L}{R_v T^2}\]

by differentiation with respect to $T$ while holding $\rho$ constant.

If q_liq and q_ice are provided, the saturation specific humidity derivative is computed assuming a phase mixture defined by the liquid fraction (see liquid_fraction).

If phase is provided, the derivative is computed for saturation over that specific phase.

If neither are provided, the saturation specific humidity derivative is computed assuming phase equilibrium, where the liquid fraction is determined by a temperature-dependent parameterization (see liquid_fraction_ramp).

source
Thermodynamics.supersaturationFunction
supersaturation(param_set, q_vap, ρ, T[, phase::Phase = Liquid()])

The supersaturation over water or ice.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • q_vap: vapor specific humidity [kg/kg]
  • ρ: air density [kg/m³]
  • T: air temperature [K]
  • phase: (optional) liquid or ice phase to dispatch over (default: Liquid())

Returns

  • S: supersaturation [dimensionless], defined as p_v/p_v^* - 1
source
supersaturation(param_set, q_vap, ρ, T, p_v_sat)

The supersaturation given the saturation vapor pressure.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • q_vap: vapor specific humidity [kg/kg]
  • ρ: air density [kg/m³]
  • T: temperature [K]
  • p_v_sat: saturation vapor pressure [Pa]

Returns

  • S: supersaturation [dimensionless], defined as p_v/p_v_sat - 1
source
Thermodynamics.saturation_excessFunction
saturation_excess(param_set, T, ρ, q_tot)
saturation_excess(param_set, T, ρ, q_tot, q_liq, q_ice)

The saturation excess in equilibrium.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]
  • (optional) q_liq: liquid specific humidity [kg/kg]
  • (optional) q_ice: ice specific humidity [kg/kg]

Returns

  • q_ex: saturation excess [kg/kg]

The saturation excess is the difference between the total specific humidity q_tot and the saturation specific humidity in equilibrium, and it is defined to be nonzero only if this difference is positive: q_ex = max(0, q_tot - q_v^*).

source
saturation_excess(param_set, T, ρ, q_tot, p_vap_sat)

The saturation excess given the saturation vapor pressure.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: temperature [K]
  • ρ: air density [kg/m³]
  • q_tot: total specific humidity [kg/kg]
  • p_vap_sat: saturation vapor pressure [Pa]

Returns

  • q_ex: saturation excess [kg/kg]

The saturation excess is the difference between the total specific humidity q_tot and the saturation specific humidity, and it is defined to be nonzero only if this difference is positive: q_ex = max(0, q_tot - q_v^*).

source
Thermodynamics.q_vap_from_RHFunction
q_vap_from_RH(param_set, p, T, RH, phase)

Compute the vapor specific humidity from the relative humidity.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • p: pressure [Pa]
  • T: temperature [K]
  • RH: relative humidity [dimensionless], 0 ≤ RH ≤ 1
  • phase: the phase to compute saturation over (either Liquid() or Ice())

Returns

  • q_vap: vapor specific humidity [kg/kg]

Note: this function assumes all water is in vapor form (no liquid or ice condensate).

source
Thermodynamics.q_vap_from_p_vapFunction
q_vap_from_p_vap(param_set, T, ρ, p_v)

Compute the vapor specific humidity from the vapor partial pressure.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • T: air temperature [K]
  • ρ: (moist-)air density [kg/m³]
  • p_v: partial pressure of water vapor [Pa]

Returns

  • q_vap: vapor specific humidity [kg/kg]
source
Thermodynamics.q_vap_saturation_from_pressureFunction
q_vap_saturation_from_pressure(param_set, q_tot, p, T)
q_vap_saturation_from_pressure(param_set, q_tot, p, T, q_liq, q_ice)

The saturation specific humidity.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • q_tot: total water specific humidity [kg/kg]
  • p: air pressure [Pa]
  • T: air temperature [K]
  • (optional) q_liq: liquid specific humidity [kg/kg]
  • (optional) q_ice: ice specific humidity [kg/kg]

Returns

  • q_v^*: saturation specific humidity [kg/kg]

If q_liq and q_ice are provided, the saturation vapor pressure is computed from a weighted mean of the latent heats of vaporization and sublimation, with the weights given by the liquid fraction (see liquid_fraction). If q_liq and q_ice are 0, the saturation vapor pressure is that over liquid above freezing and over ice below freezing.

Otherwise, the liquid fraction is computed from a temperature dependent parameterization liquid_fraction_ramp(param_set, T).

The saturation specific humidity is computed as: $q_v^* = (R_d / R_v) * (1 - q_{tot}) * p_v^* / (p - p_v^*)$ where p_v^* is the saturation vapor pressure.

Edge case: this expression assumes p > p_v^*(T); if p ≤ p_v^*(T) the denominator changes sign.

source

Saturation Adjustment

Thermodynamics.saturation_adjustmentFunction
saturation_adjustment(
    ::Type{M},  # RS.RootSolvingMethod type
    param_set,
    ::ρe,
    ρ::Real,
    e_int::Real,
    q_tot::Real,
    maxiter::Int,
    tol,
    [T_guess::Union{Nothing, Real} = nothing],
    [forced_fixed_iters::Bool = false]
)

Compute the saturation equilibrium temperature T and phase partition (q_liq, q_ice) given density ρ, internal energy e_int, and total specific humidity q_tot.

Arguments

  • M: Root-solving method type from RS.jl. Use RS.NewtonsMethod, RS.SecantMethod, RS.BrentsMethod, or RS.NewtonsMethodAD.
  • param_set: Thermodynamics parameter set, see Thermodynamics.
  • ρ: Density of moist air [kg/m³].
  • e_int: Specific internal energy [J/kg].
  • q_tot: Total specific humidity [kg/kg].
  • maxiter: Maximum iterations for the solver [dimensionless integer].
  • tol: Relative tolerance for the temperature solution (or a RS.RelativeSolutionTolerance).
  • T_guess: Optional initial guess for the temperature [K]. Defaults to nothing.
  • forced_fixed_iters: Optional boolean to force a fixed number of iterations (maxiter) without checking for convergence. Useful for GPU optimization to avoid branch divergence. When true, T_guess and tol are ignored. Defaults to false.

Returns

  • NamedTuple (; T, q_liq, q_ice, converged):
    • T: Temperature [K]
    • q_liq: Liquid specific humidity [kg/kg]
    • q_ice: Ice specific humidity [kg/kg]
    • converged: Boolean flag indicating if the solver converged

Notes

  • This function solves for T such that e_int = internal_energy_sat(param_set, T, ρ, q_tot) using root-finding, then computes (q_liq, q_ice) from condensate_partition.
  • NewtonsMethod is recommended for all formulations (analytic derivatives available).
  • GPU broadcasting: Pass forced_fixed_iters as a positional Bool.
source
saturation_adjustment(
    ::Type{M},  # RS.RootSolvingMethod type
    param_set,
    ::pe,
    p::Real,
    e_int::Real,
    q_tot::Real,
    maxiter::Int,
    tol,
    [T_guess::Union{Nothing, Real} = nothing],
    [forced_fixed_iters::Bool = false]
)

Compute the saturation equilibrium temperature T and phase partition (q_liq, q_ice) given pressure p, specific internal energy e_int, and total specific humidity q_tot.

Arguments

  • M: Root-solving method type from RootSolvers.jl. Supported types: RS.SecantMethod, RS.BrentsMethod, RS.NewtonsMethod, RS.NewtonsMethodAD.
  • param_set: Thermodynamics parameter set, see Thermodynamics.
  • p: Pressure of moist air [Pa].
  • e_int: Specific internal energy [J/kg].
  • q_tot: Total specific humidity [kg/kg].
  • maxiter: Maximum iterations for the solver [dimensionless integer].
  • tol: Relative tolerance for the temperature solution (or a RS.RelativeSolutionTolerance).
  • T_guess: Optional initial guess for the temperature [K]. Defaults to nothing.
  • forced_fixed_iters: Optional boolean to force a fixed number of iterations (maxiter) without checking for convergence. Useful for GPU optimization to avoid branch divergence. When true, T_guess and tol are ignored. Defaults to false.

Returns

  • NamedTuple (; T, q_liq, q_ice, converged):
    • T: Temperature [K]
    • q_liq: Liquid specific humidity [kg/kg]
    • q_ice: Ice specific humidity [kg/kg]
    • converged: Boolean flag indicating if the solver converged

Notes

  • GPU broadcasting: Pass forced_fixed_iters as a positional Bool.
source
saturation_adjustment(
    ::Type{M},  # RS.RootSolvingMethod type
    param_set,
    ::ph,
    p::Real,
    h::Real,
    q_tot::Real,
    maxiter::Int,
    tol,
    [T_guess::Union{Nothing, Real} = nothing],
    [forced_fixed_iters::Bool = false]
)

Compute the saturation equilibrium temperature T and phase partition (q_liq, q_ice) given pressure p, specific enthalpy h, and total specific humidity q_tot.

Returns a NamedTuple (; T, q_liq, q_ice, converged).

Arguments

  • M: Root-solving method type from RootSolvers.jl. Supported types: RS.SecantMethod, RS.BrentsMethod, RS.NewtonsMethod, RS.NewtonsMethodAD.
  • param_set: Thermodynamics parameter set, see Thermodynamics.
  • p: Pressure of moist air [Pa].
  • h: Specific enthalpy [J/kg].
  • q_tot: Total specific humidity [kg/kg].
  • maxiter: Maximum iterations for the solver [dimensionless integer].
  • tol: Relative tolerance for the temperature solution (or a RS.RelativeSolutionTolerance).
  • T_guess: Optional initial guess for the temperature [K]. Defaults to nothing.
  • forced_fixed_iters: Optional boolean to force a fixed number of iterations (maxiter) without checking for convergence. Useful for GPU optimization to avoid branch divergence. When true, T_guess and tol are ignored. Defaults to false.

Returns

  • NamedTuple (; T, q_liq, q_ice, converged):
    • T: Temperature [K]
    • q_liq: Liquid specific humidity [kg/kg]
    • q_ice: Ice specific humidity [kg/kg]
    • converged: Boolean flag indicating if the solver converged

Notes

  • GPU broadcasting: Pass forced_fixed_iters as a positional Bool.
source
saturation_adjustment(
    ::Type{M},  # RS.RootSolvingMethod type
    param_set,
    ::pθ_li,
    p::Real,
    θ_li::Real,
    q_tot::Real,
    maxiter::Int,
    tol,
    [T_guess::Union{Nothing, Real} = nothing],
    [forced_fixed_iters::Bool = false]
)

Compute the saturation equilibrium temperature T and phase partition (q_liq, q_ice) given pressure p, liquid-ice potential temperature θ_li, and total specific humidity q_tot.

Arguments

  • M: Root-solving method type from RootSolvers.jl. Supported types: RS.SecantMethod, RS.BrentsMethod, RS.NewtonsMethod, RS.NewtonsMethodAD.
  • param_set: Thermodynamics parameter set, see Thermodynamics.
  • p: Pressure of moist air [Pa].
  • θ_li: Liquid-ice potential temperature [K].
  • q_tot: Total specific humidity [kg/kg].
  • maxiter: Maximum iterations for the solver [dimensionless integer].
  • tol: Relative tolerance for the temperature solution (or a RS.RelativeSolutionTolerance).
  • T_guess: Optional initial guess for the temperature [K]. Defaults to nothing.
  • forced_fixed_iters: Optional boolean to force a fixed number of iterations (maxiter) without checking for convergence. Useful for GPU optimization to avoid branch divergence. When true, T_guess and tol are ignored. Defaults to false.

Returns

  • NamedTuple (; T, q_liq, q_ice, converged):
    • T: Temperature [K]
    • q_liq: Liquid specific humidity [kg/kg]
    • q_ice: Ice specific humidity [kg/kg]
    • converged: Boolean flag indicating if the solver converged

Notes

  • GPU broadcasting: Pass forced_fixed_iters as a positional Bool.
source
saturation_adjustment(
    ::Type{M},  # RS.RootSolvingMethod type
    param_set,
    ::ρθ_li,
    ρ::Real,
    θ_li::Real,
    q_tot::Real,
    maxiter::Int,
    tol,
    [T_guess::Union{Nothing, Real} = nothing],
    [forced_fixed_iters::Bool = false]
)

Compute the saturation equilibrium temperature T and phase partition (q_liq, q_ice) given density ρ, liquid-ice potential temperature θ_li, and total specific humidity q_tot.

Arguments

  • M: Root-solving method type from RootSolvers.jl. Supported types: RS.SecantMethod, RS.BrentsMethod, RS.NewtonsMethod, RS.NewtonsMethodAD.
  • param_set: Thermodynamics parameter set, see Thermodynamics.
  • ρ: Density of moist air [kg/m³].
  • θ_li: Liquid-ice potential temperature [K].
  • q_tot: Total specific humidity [kg/kg].
  • maxiter: Maximum iterations for the solver [dimensionless integer].
  • tol: Relative tolerance for the temperature solution (or a RS.RelativeSolutionTolerance).
  • T_guess: Optional initial guess for the temperature [K]. Defaults to nothing.
  • forced_fixed_iters: Optional boolean to force a fixed number of iterations (maxiter) without checking for convergence. Useful for GPU optimization to avoid branch divergence. When true, T_guess and tol are ignored. Defaults to false.

Returns

  • NamedTuple (; T, q_liq, q_ice, converged):
    • T: Temperature [K]
    • q_liq: Liquid specific humidity [kg/kg]
    • q_ice: Ice specific humidity [kg/kg]
    • converged: Boolean flag indicating if the solver converged

Notes

  • GPU broadcasting: Pass forced_fixed_iters as a positional Bool.
source
saturation_adjustment(
    ::Type{M},  # RS.RootSolvingMethod type
    param_set,
    ::pρ,
    p::Real,
    ρ::Real,
    q_tot::Real,
    maxiter::Int,
    tol,
    [T_guess::Union{Nothing, Real} = nothing],
    [forced_fixed_iters::Bool = false]
)

Compute the saturation equilibrium temperature T and phase partition (q_liq, q_ice) given pressure p, density ρ, and total specific humidity q_tot.

Arguments

  • M: Root-solving method type from RootSolvers.jl. Supported types: RS.SecantMethod, RS.BrentsMethod, RS.NewtonsMethod, RS.NewtonsMethodAD.
  • param_set: Thermodynamics parameter set, see Thermodynamics.
  • p: Pressure of moist air [Pa].
  • ρ: Density of moist air [kg/m³].
  • q_tot: Total specific humidity [kg/kg].
  • maxiter: Maximum iterations for the solver [dimensionless integer].
  • tol: Relative tolerance for the temperature solution (or a RS.RelativeSolutionTolerance).
  • T_guess: Optional initial guess for the temperature [K]. Defaults to nothing.
  • forced_fixed_iters: Optional boolean to force a fixed number of iterations (maxiter) without checking for convergence. Useful for GPU optimization to avoid branch divergence. When true, T_guess and tol are ignored. Defaults to false.

Returns

  • NamedTuple (; T, q_liq, q_ice, converged):
    • T: Temperature [K]
    • q_liq: Liquid specific humidity [kg/kg]
    • q_ice: Ice specific humidity [kg/kg]
    • converged: Boolean flag indicating if the solver converged

Notes

  • GPU broadcasting: Pass forced_fixed_iters as a positional Bool.
source
saturation_adjustment(
    param_set,
    ::ρe,
    ρ,
    e_int,
    q_tot;
    maxiter::Int = 2,
)

Convenience method for ρe formulation with reasonable GPU-optimized defaults.

Uses RS.NewtonsMethod with forced_fixed_iters=true and maxiter=2 for fast, branch-free execution on GPUs. For typical atmospheric conditions (T < 320 K), this achieves better than 0.1 K accuracy.

For more control over solver parameters, use the full signature with explicit method type.

Returns

  • NamedTuple (; T, q_liq, q_ice) — note: converged is not included; fixed iterations always succeed by construction.
source
saturation_adjustment(
    param_set,
    ::pe,
    p,
    e_int,
    q_tot;
    maxiter::Int = 2,
)

Convenience method for pe formulation with reasonable GPU-optimized defaults.

Uses RS.NewtonsMethod with forced_fixed_iters=true and maxiter=2 for fast, branch-free execution on GPUs. For typical atmospheric conditions (T < 320 K), this achieves better than 0.1 K accuracy.

For more control over solver parameters, use the full signature with explicit method type.

Returns

  • NamedTuple (; T, q_liq, q_ice) — note: converged is not included; fixed iterations always succeed by construction.
source
saturation_adjustment(
    param_set,
    ::ph,
    p,
    h,
    q_tot;
    maxiter::Int = 2,
)

Convenience method for ph formulation with reasonable GPU-optimized defaults.

Uses RS.NewtonsMethod with forced_fixed_iters=true and maxiter=2 for fast, branch-free execution on GPUs. For typical atmospheric conditions (T < 320 K), this achieves better than 0.1 K accuracy.

For more control over solver parameters, use the full signature with explicit method type.

Returns

  • NamedTuple (; T, q_liq, q_ice) — note: converged is not included; fixed iterations always succeed by construction.
source
saturation_adjustment(
    param_set,
    ::pθ_li,
    p,
    θ_li,
    q_tot;
    maxiter::Int = 2,
)

Convenience method for pθ_li formulation with reasonable GPU-optimized defaults.

Uses RS.NewtonsMethod with forced_fixed_iters=true and maxiter=2 for fast, branch-free execution on GPUs. For typical atmospheric conditions (T < 320 K), this achieves better than 0.1 K accuracy.

For more control over solver parameters, use the full signature with explicit method type.

Returns

  • NamedTuple (; T, q_liq, q_ice) — note: converged is not included; fixed iterations always succeed by construction.
source
saturation_adjustment(
    param_set,
    ::ρθ_li,
    ρ,
    θ_li,
    q_tot;
    maxiter::Int = 2,
)

Convenience method for ρθ_li formulation with reasonable GPU-optimized defaults.

Uses RS.NewtonsMethod with forced_fixed_iters=true and maxiter=2 for fast, branch-free execution on GPUs. For typical atmospheric conditions (T < 320 K), this achieves better than 0.1 K accuracy.

For more control over solver parameters, use the full signature with explicit method type.

Returns

  • NamedTuple (; T, q_liq, q_ice) — note: converged is not included; fixed iterations always succeed by construction.
source
saturation_adjustment(
    param_set,
    ::pρ,
    p,
    ρ,
    q_tot;
    maxiter::Int = 2,
)

Convenience method for formulation with reasonable GPU-optimized defaults.

Uses RS.NewtonsMethod with forced_fixed_iters=true and maxiter=2 for fast, branch-free execution on GPUs. For typical atmospheric conditions (T < 320 K), this achieves better than 0.1 K accuracy.

For more control over solver parameters, use the full signature with explicit method type.

Returns

  • NamedTuple (; T, q_liq, q_ice) — note: converged is not included; fixed iterations always succeed by construction.
source
Thermodynamics.∂e_int_∂T_sat_ρFunction
∂e_int_∂T_sat_ρ(param_set, T, ρ, q_tot)

Derivative of internal_energy_sat with respect to temperature at fixed density.

Uses ∂q_vap_sat/∂T|_ρ from Clausius-Clapeyron, which includes the -1/T term from the density dependence of saturation vapor pressure.

source
Thermodynamics.∂e_int_∂T_sat_pFunction
∂e_int_∂T_sat_p(param_set, T, p, q_tot)

Derivative of internal_energy_sat with respect to temperature at fixed pressure.

Uses ∂q_vap_sat/∂T|_p = q_vap_sat * L / (R_v T²) (Clausius-Clapeyron at constant pressure), which differs from the constant-density form used in ∂e_int_∂T_sat_ρ by an additional q_vap_sat / T term.

source
Thermodynamics.∂θ_li_∂T_sat_ρFunction
∂θ_li_∂T_sat_ρ(param_set, T, ρ, q_tot)

Derivative of liquid_ice_pottemp (at saturation equilibrium) with respect to temperature at fixed density.

Structured like ∂θ_li_∂T_sat_p, but accounts for p = ρ R_m T varying with T. This introduces two corrections to ∂θ/∂T:

  • an extra -α/T from ∂ln(p)/∂T|_ρ = 1/T + ∂R_m/∂T / R_m, and
  • an extra -∂R_m/∂T / cp_m from the same.

The ∂q_vap_sat/∂T also differs: at fixed ρ it carries an extra -q_vap_sat / T relative to the fixed-p Clausius–Clapeyron form.

source
Thermodynamics.∂θ_li_∂T_sat_pFunction
∂θ_li_∂T_sat_p(param_set, T, p, q_tot)

Derivative of liquid_ice_pottemp_given_pressure (at saturation equilibrium) with respect to temperature at fixed pressure.

Uses the product rule on θ_li = θ * (1 - L_c / (cp_m T)), differentiating each factor through the T-dependent phase partition.

source
Thermodynamics.∂p_∂T_sat_ρFunction
∂p_∂T_sat_ρ(param_set, T, ρ, q_tot)

Derivative of air_pressure (at saturation equilibrium) with respect to temperature at fixed density.

From p = ρ R_m T and ∂R_m/∂T = R_v · ∂q_vap_sat/∂T:

∂p/∂T|_ρ = ρ · (R_m + T · ∂R_m/∂T)

Unsaturated: R_m is constant, so ∂p/∂T = ρ R_m.

source
Thermodynamics.∂h_∂T_sat_pFunction
∂h_∂T_sat_p(param_set, T, p, q_tot)

Derivative of enthalpy_sat with respect to temperature at fixed pressure.

Structured identically to ∂e_int_∂T_sat_p but with component enthalpies (cp_m instead of cv_m, enthalpy_vapor instead of internal_energy_vapor, etc.).

source

Air Entropies

Thermodynamics.entropyFunction
entropy(param_set, p, T, q_tot=0, q_liq=0, q_ice=0)

The specific entropy in thermodynamic equilibrium.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • p: pressure [Pa]
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • s: specific entropy [J/(kg·K)]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), this reduces to the dry-air expression. The entropy is computed as a mass-weighted sum of the entropies of each component (dry air, vapor, liquid, ice).

Reference

Pressel et al. (2015), "Numerics and subgrid-scale modeling in large eddy simulations of stratocumulus clouds," Journal of Advances in Modeling Earth Systems, 7(3), 1199-1220, doi:10.1002/2015MS000496. (Their Eqs. (29)-(33))

source
Thermodynamics.entropy_dryFunction
entropy_dry(param_set, p, T, q_tot=0, q_liq=0, q_ice=0)

The specific entropy of dry air at its partial pressure.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • p: total air pressure [Pa]
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • s_d: specific entropy of dry air [J/(kg·K)]

In the dry limit (q_tot = q_liq = q_ice = 0, the default), the dry-air partial pressure equals the total pressure. Note: entropy_dry diverges logarithmically as q_tot → 1 (since p_d → 0). See also the analogous warning in entropy_vapor.

source
Thermodynamics.entropy_vaporFunction
entropy_vapor(param_set, p, T, q_tot=0, q_liq=0, q_ice=0)

The specific entropy of water vapor at its partial pressure.

Arguments

  • param_set: thermodynamics parameter set, see Thermodynamics
  • p: total air pressure [Pa]
  • T: temperature [K]
  • q_tot: total specific humidity [kg/kg]
  • q_liq: liquid specific humidity [kg/kg]
  • q_ice: ice specific humidity [kg/kg]

Returns

  • s_v: specific entropy of water vapor [J/(kg·K)]

Note: the entropy of water vapor diverges logarithmically as q_tot → 0 (since p_v → 0). The analogous divergence occurs in entropy_dry as q_tot → 1 (since p_d → 0). A small numerical regularization ϵ_numerics(FT) is added to the pressure before taking the logarithm to avoid floating-point exceptions, but results should not be trusted in these limits.

source

Temperature Profiles

Thermodynamics.TemperatureProfiles.TemperatureProfileType
TemperatureProfile

Abstract type for temperature or virtual temperature reference profiles that can be used in atmosphere models.

Instances of this type are required to be callable objects with the following signature

T,p = (::TemperatureProfile)(param_set::APS, z::FT) where {FT}

where T is the temperature or virtual temperature (K), and p is the pressure (Pa).

source
Thermodynamics.TemperatureProfiles.DecayingTemperatureProfileType
DecayingTemperatureProfile{FT} <: TemperatureProfile{FT}

Virtual temperature profile that decays smoothly with height z from T_virt_surf to T_min_ref over height scale H_t (default: density scale height with T_virt_surf).

\[T_{\text{v}}(z) = \max(T_{\text{v, sfc}} − (T_{\text{v, sfc}} - T_{\text{v, min}}) \tanh(z/H_{\text{t}}), T_{\text{v, min}})\]

Fields

  • T_virt_surf: Virtual temperature at surface (K)
  • T_min_ref: Minimum virtual temperature at the top of the atmosphere (K)
  • H_t: Height scale over which virtual temperature drops (m)
source
Thermodynamics.TemperatureProfiles.DryAdiabaticProfileType
DryAdiabaticProfile{FT} <: TemperatureProfile{FT}

Temperature profile with uniform potential temperature θ up to the height where a minimum temperature is reached.

Fields

  • T_surface: Surface temperature (K)
  • T_min_ref: Minimum temperature (K)
source

Data Collection

Thermodynamics.DataCollectionModule
DataCollection

This module is designed to help judge the accuracy and performance for a particular formulation, tolerance, and or solver configuration, by providing tools to collect various statistics when saturation_adjustment is called.

Example:

import Thermodynamics as TD
import RootSolvers as RS

function do_work()
    # Calls TD.saturation_adjustment()..., possibly many times
end

TD.solution_type() = RS.VerboseSolution()
do_work()
TD.DataCollection.print_summary()
Warn

This data collection was designed for unthreaded single processor runs, and may not work correctly for threaded / multi-processor runs.

source