2.2 Moisture & Humidity
Water vapor is the most important variable constituent of the atmosphere. Its phase changes release and absorb latent heat, driving convection and weather systems.
Humidity Variables
Mixing Ratio (r)
$$r = \frac{m_v}{m_d} = \frac{\rho_v}{\rho_d}$$
Mass of water vapor per mass of dry air (g/kg)
Specific Humidity (q)
$$q = \frac{m_v}{m_v + m_d} = \frac{r}{1+r} \approx r$$
Mass of water vapor per total mass (g/kg)
Relative Humidity (RH)
$$RH = \frac{e}{e_s} \times 100\%$$
Ratio of actual to saturation vapor pressure
Clausius-Clapeyron Equation
$$\frac{de_s}{dT} = \frac{L_v e_s}{R_v T^2}$$
Rate of change of saturation vapor pressure with temperature
Integrated form (Tetens formula):
$$e_s(T) = 6.11 \exp\left(\frac{17.27 (T-273.15)}{T - 35.85}\right) \text{ hPa}$$
Saturation vapor pressure approximately doubles for every 10°C increase
Dew Point Temperature
Definition
Temperature to which air must be cooled at constant pressure to become saturated
Dew Point Depression
T - Td: larger values indicate drier air
Python: Humidity Calculations
#!/usr/bin/env python3
"""
moisture.py - Humidity and moisture calculations
Run: python3 moisture.py
Requires: pip install numpy matplotlib
"""
import numpy as np
import matplotlib.pyplot as plt
# Constants
R_d = 287.0 # J/(kg·K) - gas constant for dry air
R_v = 461.5 # J/(kg·K) - gas constant for water vapor
L_v = 2.5e6 # J/kg - latent heat of vaporization
epsilon = R_d / R_v # ≈ 0.622
def saturation_vapor_pressure(T_celsius):
"""Tetens formula for saturation vapor pressure (hPa)"""
return 6.11 * np.exp(17.27 * T_celsius / (T_celsius + 237.3))
def dew_point(e):
"""Dew point from vapor pressure (hPa) -> °C"""
return 237.3 * np.log(e / 6.11) / (17.27 - np.log(e / 6.11))
def mixing_ratio(e, p):
"""Mixing ratio from vapor pressure and total pressure (g/kg)"""
return 1000 * epsilon * e / (p - e)
# Temperature range
T = np.linspace(-40, 40, 100) # °C
e_s = saturation_vapor_pressure(T)
# Plot Clausius-Clapeyron curve
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# Saturation vapor pressure vs temperature
ax1 = axes[0, 0]
ax1.semilogy(T, e_s, 'b-', linewidth=2)
ax1.set_xlabel('Temperature (°C)', fontsize=12)
ax1.set_ylabel('Saturation Vapor Pressure (hPa)', fontsize=12)
ax1.set_title('Clausius-Clapeyron: Saturation Vapor Pressure', fontsize=14)
ax1.grid(True, alpha=0.3, which='both')
ax1.axhline(y=6.11, color='gray', linestyle='--', alpha=0.5)
ax1.annotate('e_s(0°C) = 6.11 hPa', (0, 6.11), xytext=(10, 10), fontsize=10)
# Saturation mixing ratio
ax2 = axes[0, 1]
p_surface = 1013.25 # hPa
r_s = mixing_ratio(e_s, p_surface)
ax2.plot(T, r_s, 'g-', linewidth=2)
ax2.set_xlabel('Temperature (°C)', fontsize=12)
ax2.set_ylabel('Saturation Mixing Ratio (g/kg)', fontsize=12)
ax2.set_title(f'Saturation Mixing Ratio (p = {p_surface} hPa)', fontsize=14)
ax2.grid(True, alpha=0.3)
# Relative humidity example
ax3 = axes[1, 0]
T_air = 25 # °C
e_s_25 = saturation_vapor_pressure(T_air)
RH_values = np.linspace(10, 100, 10)
e_values = RH_values / 100 * e_s_25
T_d_values = dew_point(e_values)
ax3.bar(RH_values, T_d_values, width=8, color='cyan', alpha=0.7, edgecolor='blue')
ax3.axhline(y=T_air, color='red', linestyle='--', label=f'Air Temperature = {T_air}°C')
ax3.set_xlabel('Relative Humidity (%)', fontsize=12)
ax3.set_ylabel('Dew Point (°C)', fontsize=12)
ax3.set_title('Dew Point vs Relative Humidity (T = 25°C)', fontsize=14)
ax3.legend()
ax3.grid(True, alpha=0.3)
# Water vapor increase with warming
ax4 = axes[1, 1]
T_base = np.array([10, 15, 20, 25, 30, 35])
e_s_base = saturation_vapor_pressure(T_base)
e_s_warm = saturation_vapor_pressure(T_base + 1) # 1°C warming
pct_increase = (e_s_warm - e_s_base) / e_s_base * 100
ax4.bar(T_base, pct_increase, width=3, color='orange', alpha=0.7, edgecolor='red')
ax4.axhline(y=7, color='red', linestyle='--', label='~7%/°C (Clausius-Clapeyron)')
ax4.set_xlabel('Temperature (°C)', fontsize=12)
ax4.set_ylabel('% Increase in e_s per 1°C', fontsize=12)
ax4.set_title('Water-Holding Capacity Increase', fontsize=14)
ax4.legend()
ax4.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('moisture.png', dpi=150, bbox_inches='tight')
plt.show()
# Example calculation
print("\nExample: T = 25°C, RH = 60%")
e_s_ex = saturation_vapor_pressure(25)
e_ex = 0.6 * e_s_ex
T_d_ex = dew_point(e_ex)
r_ex = mixing_ratio(e_ex, 1013.25)
print(f" Saturation vapor pressure: {e_s_ex:.2f} hPa")
print(f" Actual vapor pressure: {e_ex:.2f} hPa")
print(f" Dew point: {T_d_ex:.1f}°C")
print(f" Mixing ratio: {r_ex:.1f} g/kg")