Telluris Labs

Geospatial Software and Data Solutions

Surface fluxes & energy balance

Turbulent transfer of momentum, heat, moisture, and particles, the stability that governs it, and the surface energy budget that integrates every flux.

turbulent — Turbulent fluxes

Bulk-aerodynamic turbulent fluxes and the surface-layer quantities they need: air density, sensible and latent heat flux, transfer coefficients, shear stress, and resistance.

air_density

air_density(temp: 'float', pressure: 'float', unit: 'str' = 'C') -> 'float'

Density of dry air from temperature and pressure (ideal gas law).

Ideal gas law\rho=\dfrac{P}{R_d\,T}
>>> from atmoflux.turbulent import air_density
>>> round(air_density(15, 101.325), 4)
1.225

sensible_heat_flux

sensible_heat_flux(density: 'float', wind_speed: 'float', temp_air: 'float', temp_surface: 'float', transfer_coeff: 'float', unit: 'str' = 'C') -> 'float'

Bulk-aerodynamic sensible heat flux.

Bulk-aerodynamic formH=\rho\,c_p\,C_h\,U\,(T_s-T_a)
>>> from atmoflux.turbulent import sensible_heat_flux
>>> round(sensible_heat_flux(1.2, 3.0, 20.0, 25.0, 0.0013), 4)
23.517

latent_heat_flux

latent_heat_flux(density: 'float', wind_speed: 'float', q_air: 'float', q_surface: 'float', transfer_coeff: 'float') -> 'float'

Bulk-aerodynamic latent heat flux.

Bulk-aerodynamic formLE=\rho\,L_v\,C_e\,U\,(q_s-q_a)
>>> from atmoflux.turbulent import latent_heat_flux
>>> round(latent_heat_flux(1.2, 3.0, 0.008, 0.012, 0.0013), 4)
45.864

bulk_transfer_coefficient

bulk_transfer_coefficient(height: 'float', roughness: 'float', displacement: 'float' = 0.0, karman: 'float' = 0.4) -> 'float'

Neutral bulk transfer coefficient from surface-layer geometry.

Neutral transfer coefficientC=\dfrac{k^2}{\big[\ln((z-d)/z_0)\big]^2}
>>> from atmoflux.turbulent import bulk_transfer_coefficient
>>> round(bulk_transfer_coefficient(10.0, 0.03), 6)
0.004741

surface_shear_stress

surface_shear_stress(density: 'float', friction_velocity: 'float') -> 'float'

Surface shear stress (momentum flux) from friction velocity.

Surface shear stress\tau=\rho\,u_*^2
>>> from atmoflux.turbulent import surface_shear_stress
>>> round(surface_shear_stress(1.225, 0.3), 5)
0.11025

aerodynamic_resistance

aerodynamic_resistance(wind_speed: 'float', height: 'float', roughness: 'float', displacement: 'float' = 0.0, karman: 'float' = 0.4) -> 'float'

Neutral aerodynamic resistance to turbulent transfer.

Neutral aerodynamic resistancer_a=\dfrac{\big[\ln((z-d)/z_0)\big]^2}{k^2\,U}
>>> from atmoflux.turbulent import aerodynamic_resistance
>>> round(aerodynamic_resistance(3.0, 10.0, 0.03), 2)
70.3

stability — Surface-layer stability

Closed-form surface-layer stability diagnostics: bulk Richardson number, Monin–Obukhov length and stability parameter, the correction functions, and a stability class.

bulk_richardson_number

bulk_richardson_number(temp_lower: 'float', temp_upper: 'float', wind_upper: 'float', height_lower: 'float', height_upper: 'float', unit: 'str' = 'C') -> 'float'

Bulk Richardson number between two heights.

Bulk Richardson numberR_b=\dfrac{g\,\Delta\theta\,\Delta z}{T_\mathrm{mean}\,U^2}
>>> from atmoflux.stability import bulk_richardson_number
>>> round(bulk_richardson_number(15, 14, 5.0, 2.0, 10.0), 5)
-0.01091

obukhov_length

obukhov_length(friction_velocity: 'float', temp: 'float', sensible_heat_flux: 'float', density: 'float', unit: 'str' = 'C') -> 'float'

Monin-Obukhov length from friction velocity and sensible heat flux.

Monin–Obukhov lengthL=-\dfrac{\rho\,c_p\,T\,u_*^3}{k\,g\,H}
>>> from atmoflux.stability import obukhov_length
>>> round(obukhov_length(0.3, 20, 100.0, 1.2), 3)
-24.334

stability_parameter

stability_parameter(height: 'float', obukhov_length: 'float') -> 'float'

Monin-Obukhov stability parameter zeta = z / L.

Stability parameter\zeta=\dfrac{z}{L}
>>> from atmoflux.stability import stability_parameter
>>> round(stability_parameter(10.0, -50.0), 2)
-0.2

psi_momentum

psi_momentum(zeta: 'float') -> 'float'

Integrated stability correction function for momentum.

Businger–Dyer (momentum)\psi_m=\begin{cases}2\ln\dfrac{1+x}{2}+\ln\dfrac{1+x^2}{2}-2\arctan x+\dfrac{\pi}{2}, & \zeta<0\\[4pt]-5\zeta, & \zeta\ge 0\end{cases}\quad x=(1-16\zeta)^{1/4}
>>> from atmoflux.stability import psi_momentum
>>> psi_momentum(0.1)
-0.5
>>> round(psi_momentum(-0.1), 4)
0.2836

psi_heat

psi_heat(zeta: 'float') -> 'float'

Integrated stability correction function for heat.

Businger–Dyer (heat)\psi_h=\begin{cases}2\ln\dfrac{1+y}{2}, & \zeta<0\\[4pt]-5\zeta, & \zeta\ge 0\end{cases}\quad y=(1-16\zeta)^{1/2}
>>> from atmoflux.stability import psi_heat
>>> psi_heat(0.1)
-0.5
>>> round(psi_heat(-0.1), 4)
0.5343

stability_class

stability_class(richardson: 'float') -> 'str'

Qualitative stability class from a bulk Richardson number.

Threshold scheme\text{class}=\begin{cases}\text{unstable}, & R_b<-0.01\\ \text{neutral}, & |R_b|\le 0.01\\ \text{stable}, & R_b>0.01\end{cases}
>>> from atmoflux.stability import stability_class
>>> stability_class(-0.5)
'unstable'
>>> stability_class(0.0)
'neutral'
>>> stability_class(0.5)
'stable'

hydro — Evaporation & hydrology

Water fluxes: latent-heat-to-evaporation conversion and the Penman, Penman–Monteith, FAO-56, equilibrium, Priestley–Taylor, and Hargreaves methods.

latent_heat_to_evaporation

latent_heat_to_evaporation(latent_heat: 'float', density_water: 'float' = 1000.0) -> 'float'

Convert latent heat flux to an equivalent evaporation depth.

Latent-heat-to-evaporationE=\dfrac{LE}{L_v\,\rho_w}\times 1000\times 86400\ \ [\mathrm{mm/day}]
>>> from atmoflux.hydro import latent_heat_to_evaporation
>>> round(latent_heat_to_evaporation(100.0), 3)
3.527

penman_evaporation

penman_evaporation(net_radiation: 'float', ground_heat: 'float', temp: 'float', wind_2m: 'float', es: 'float', ea: 'float', pressure: 'float' = 101.325, unit: 'str' = 'C') -> 'float'

Open-water evaporation using the Penman combination equation.

Penman (1948)ET=\dfrac{\Delta(R_n-G)+\gamma\,E_a}{\lambda(\Delta+\gamma)},\quad E_a=6.43\,(1+0.536\,u_2)(e_s-e_a)
>>> from atmoflux.hydro import penman_evaporation
>>> round(penman_evaporation(15.0, 0.0, 25.0, 2.0, 3.169, 1.9, 101.3), 3)
6.326

penman_monteith

penman_monteith(net_radiation: 'float', ground_heat: 'float', temp: 'float', vpd: 'float', density: 'float', resistance_aero: 'float', resistance_surface: 'float', pressure: 'float' = 101.325, unit: 'str' = 'C') -> 'float'

Evaporation from the general Penman-Monteith equation.

Penman–Monteith (Monteith, 1965)\lambda E=\dfrac{\Delta\,A+\rho\,c_p\,D/r_a}{\Delta+\gamma\,(1+r_s/r_a)},\quad A=R_n-G
>>> from atmoflux.hydro import penman_monteith
>>> round(penman_monteith(150.0, 20.0, 25.0, 1.5, 1.2, 50.0, 70.0), 3)
6.133

potential_evapotranspiration

potential_evapotranspiration(net_radiation: 'float', ground_heat: 'float', temp: 'float', wind_2m: 'float', es: 'float', ea: 'float', pressure: 'float' = 101.325, unit: 'str' = 'C') -> 'float'

Reference evapotranspiration from the FAO-56 Penman-Monteith equation.

FAO-56 (Allen et al., 1998)ET_0=\dfrac{0.408\,\Delta(R_n-G)+\gamma\,\dfrac{900}{T+273}\,u_2(e_s-e_a)}{\Delta+\gamma\,(1+0.34\,u_2)}
>>> from atmoflux.hydro import potential_evapotranspiration
>>> round(potential_evapotranspiration(15.0, 0.0, 25.0, 2.0, 3.169, 1.9, 101.3), 3)
5.539

equilibrium_evaporation

equilibrium_evaporation(net_radiation: 'float', ground_heat: 'float', temp: 'float', pressure: 'float' = 101.325, unit: 'str' = 'C') -> 'float'

Equilibrium evaporation from available energy.

Equilibrium evaporationE_\mathrm{eq}=\dfrac{\Delta}{\Delta+\gamma}\cdot\dfrac{R_n-G}{\lambda}
>>> from atmoflux.hydro import equilibrium_evaporation
>>> round(equilibrium_evaporation(15.0, 0.0, 25.0), 3)
4.521

priestley_taylor

priestley_taylor(net_radiation: 'float', ground_heat: 'float', temp: 'float', alpha: 'float' = 1.26, pressure: 'float' = 101.325, unit: 'str' = 'C') -> 'float'

Priestley-Taylor evaporation.

Priestley & Taylor (1972)E_\mathrm{pt}=\alpha\,E_\mathrm{eq}
>>> from atmoflux.hydro import priestley_taylor
>>> round(priestley_taylor(15.0, 0.0, 25.0), 3)
5.697

hargreaves

hargreaves(temp_mean: 'float', temp_min: 'float', temp_max: 'float', extraterrestrial: 'float', unit: 'str' = 'C') -> 'float'

Hargreaves reference evapotranspiration.

Hargreaves–Samani (1985)ET_0=0.0023\,(T_\mathrm{mean}+17.8)\,\sqrt{T_\mathrm{max}-T_\mathrm{min}}\;\dfrac{R_a}{\lambda}
>>> from atmoflux.hydro import hargreaves
>>> round(hargreaves(25.0, 18.0, 32.0, 36.0), 3)
5.41

aerosols — Aerosols

Fluxes of particles and non-water trace gases: gravitational settling, resistance-model dry deposition, and surface emission.

settling_velocity

settling_velocity(diameter: 'float', particle_density: 'float', viscosity: 'float' = 1.789e-05, mean_free_path: 'float' = 6.63e-08) -> 'float'

Gravitational settling velocity of a spherical aerosol particle.

Stokes law with Cunningham slip\begin{aligned}C_c&=1+\dfrac{2\lambda}{d}\Big(1.257+0.4\,e^{-1.1\,d/(2\lambda)}\Big)\\ v_s&=\dfrac{(\rho_p-\rho_a)\,d^2\,g\,C_c}{18\,\mu}\end{aligned}
>>> from atmoflux.aerosols import settling_velocity
>>> round(settling_velocity(1e-6, 1000.0) * 1e6, 3)
35.486
>>> round(settling_velocity(10e-6, 1000.0) * 1e3, 3)
3.092

dry_deposition_velocity

dry_deposition_velocity(settling: 'float', resistance_aero: 'float', resistance_surface: 'float') -> 'float'

Dry deposition velocity from the resistance-in-series model.

Resistance-in-series modelv_d=v_s+\dfrac{1}{r_a+r_b+r_a r_b v_s}
>>> from atmoflux.aerosols import dry_deposition_velocity, settling_velocity
>>> vs = settling_velocity(10e-6, 1000.0)
>>> round(dry_deposition_velocity(vs, 50.0, 20.0) * 1000, 3)
16.774

emission_flux

emission_flux(concentration: 'float', transfer_velocity: 'float') -> 'float'

Surface emission flux from a transfer velocity and concentration.

Emission fluxF=v_t\,C
>>> from atmoflux.aerosols import emission_flux
>>> emission_flux(2e-6, 0.01)
2e-08

balance — Energy balance

Surface energy-budget diagnostics: closure residual, Bowen ratio, available energy, the closure ratio, ground-heat parameterization, and the EnergyBalance container.

surface_energy_residual

surface_energy_residual(net_radiation: 'float', sensible_heat: 'float', latent_heat: 'float', ground_heat: 'float' = 0.0) -> 'float'

Surface energy balance closure residual.

Energy-balance closure\mathrm{residual}=R_n-G-H-LE
>>> from atmoflux.balance import surface_energy_residual
>>> surface_energy_residual(400.0, 150.0, 200.0, 50.0)
0.0

bowen_ratio

bowen_ratio(sensible_heat: 'float', latent_heat: 'float') -> 'float'

Bowen ratio of sensible to latent heat flux.

Bowen ratio\beta=\dfrac{H}{LE}
>>> from atmoflux.balance import bowen_ratio
>>> round(bowen_ratio(150.0, 200.0), 3)
0.75

energy_balance

energy_balance(net_radiation: 'float', sensible_heat: 'float', latent_heat: 'float', ground_heat: 'float' = 0.0) -> 'EnergyBalance'

Assemble an EnergyBalance container from surface flux components.

>>> from atmoflux.balance import bowen_ratio, energy_balance
>>> eb = energy_balance(400.0, 150.0, 200.0, 50.0)
>>> eb.residual
0.0
>>> round(eb.bowen_ratio, 2)
0.75

available_energy

available_energy(net_radiation: 'float', ground_heat: 'float' = 0.0) -> 'float'

Available energy at the surface.

Available energyA=R_n-G
>>> from atmoflux.balance import available_energy
>>> available_energy(400.0, 50.0)
350.0

energy_balance_ratio

energy_balance_ratio(sensible_heat: 'float', latent_heat: 'float', net_radiation: 'float', ground_heat: 'float' = 0.0) -> 'float'

Energy balance closure ratio.

Energy-balance ratio\mathrm{EBR}=\dfrac{H+LE}{R_n-G}
>>> from atmoflux.balance import energy_balance_ratio
>>> round(energy_balance_ratio(150.0, 200.0, 400.0, 50.0), 3)
1.0

ground_heat_fraction

ground_heat_fraction(net_radiation: 'float', fraction: 'float' = 0.1) -> 'float'

Estimate ground heat flux as a fraction of net radiation.

Ground-heat fractionG=f\,R_n
>>> from atmoflux.balance import ground_heat_fraction
>>> ground_heat_fraction(400.0)
40.0