Telluris Labs

Geospatial Software and Data Solutions

Atmospheric state

The measured and derived state of the near-surface atmosphere and its vertical structure.

temperature — Temperature

Unit conversion and temperature-derived quantities — dew point, potential and virtual temperature, lapse rates, wet-bulb temperature, and skin temperature from longwave.

convert_temperature

convert_temperature(temp: 'float', input_unit: 'str', output_unit: 'str') -> 'float'

Convert temperature between Celsius, Fahrenheit, and Kelvin.

>>> from atmoflux.temperature import convert_temperature
>>> convert_temperature(100, "C", "F")
212.0
>>> convert_temperature(273.15, "K", "C")
0.0
>>> a, b, c = 80, "F", "C"
>>> temp = convert_temperature(a, b, c)
>>> f"{a}°{b} is equal to {round(temp, 2)}°{c}."
80°F is equal to 26.67°C.

dewpoint_temperature

dewpoint_temperature(temp: 'float', rh: 'float', unit: 'str' = 'C') -> 'float'

Calculate dew point temperature from temperature and relative humidity.

Magnus–Tetens approximationT_d=\dfrac{b\,\alpha}{a-\alpha},\quad \alpha=\ln\!\dfrac{RH}{100}+\dfrac{aT}{b+T}\quad(a=17.27,\ b=237.3)
>>> from atmoflux.temperature import dewpoint_temperature
>>> round(dewpoint_temperature(30, 50), 2)
18.44
>>> round(dewpoint_temperature(86, 50, unit="F"), 2)
65.19

dewpoint_from_avp

dewpoint_from_avp(avp: 'float', unit: 'str' = 'C') -> 'float'

Calculate dew point temperature from actual vapor pressure.

Inverse Magnus formT_d=\dfrac{237.3\,\alpha}{17.27-\alpha},\quad \alpha=\ln\!\dfrac{e}{0.6108}
>>> from atmoflux.temperature import dewpoint_from_avp
>>> round(dewpoint_from_avp(2.338), 2)
20.0

potential_temperature

potential_temperature(temp: 'float', pressure: 'float', reference_pressure: 'float' = 101.325, unit: 'str' = 'K') -> 'float'

Calculate potential temperature of dry air.

Poisson's equation\theta=T\left(\dfrac{P_0}{P}\right)^{R_d/c_p}
>>> from atmoflux.temperature import potential_temperature
>>> round(potential_temperature(273.15, 80.0), 2)
292.22
>>> round(potential_temperature(0.0, 80.0, unit="C"), 2)
19.07

virtual_temperature

virtual_temperature(temp: 'float', mixing_ratio: 'float', unit: 'str' = 'K') -> 'float'

Calculate virtual temperature of moist air.

Virtual temperatureT_v=T\,(1+0.61\,w)
>>> from atmoflux.temperature import virtual_temperature
>>> round(virtual_temperature(300.0, 0.01), 3)
301.83

lapse_rate

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

Calculate the environmental lapse rate between two heights.

Environmental lapse rate\Gamma=-\dfrac{T_\mathrm{upper}-T_\mathrm{lower}}{z_\mathrm{upper}-z_\mathrm{lower}}
>>> from atmoflux.temperature import lapse_rate
>>> round(lapse_rate(15.0, 8.5, 0.0, 1000.0) * 1000, 1)
6.5

surface_temperature_from_lw

surface_temperature_from_lw(lw_up: 'float', emissivity: 'float' = 1.0, unit: 'str' = 'K') -> 'float'

Retrieve surface temperature from upwelling longwave radiation.

Inverse Stefan–Boltzmann lawT_s=\left(\dfrac{L_\uparrow}{\varepsilon\,\sigma}\right)^{1/4}
>>> from atmoflux.temperature import surface_temperature_from_lw
>>> round(surface_temperature_from_lw(390.0), 2)
287.98
>>> round(surface_temperature_from_lw(390.0, unit="C"), 2)
14.83

wet_bulb_temperature

wet_bulb_temperature(temp: 'float', rh: 'float', unit: 'str' = 'C') -> 'float'

Wet-bulb temperature using Stull's empirical approximation.

Stull (2011)\begin{aligned}T_w=\;&T\arctan\!\big(0.151977\sqrt{RH+8.313659}\big)+\arctan(T+RH)\\&-\arctan(RH-1.676331)+0.00391838\,RH^{1.5}\arctan(0.023101\,RH)\\&-4.686035\end{aligned}
>>> from atmoflux.temperature import wet_bulb_temperature
>>> round(wet_bulb_temperature(25, 50), 2)
18.0

equivalent_potential_temperature

equivalent_potential_temperature(temp: 'float', mixing_ratio: 'float', pressure: 'float', unit: 'str' = 'K') -> 'float'

Approximate equivalent potential temperature of moist air.

Bolton-style approximation\theta_e=\theta\,\exp\!\left(\dfrac{L_v\,w}{c_p\,T}\right)
>>> from atmoflux.temperature import equivalent_potential_temperature
>>> round(equivalent_potential_temperature(290.0, 0.01, 90.0), 2)
326.29

moist_adiabatic_lapse_rate

moist_adiabatic_lapse_rate(temp: 'float', mixing_ratio: 'float', unit: 'str' = 'C') -> 'float'

Saturated (moist) adiabatic lapse rate.

Saturated adiabatic lapse rate\Gamma_m=g\,\dfrac{1+\dfrac{L_v w}{R_d T}}{c_p+\dfrac{L_v^2 w}{R_v T^2}}
>>> from atmoflux.temperature import moist_adiabatic_lapse_rate
>>> round(moist_adiabatic_lapse_rate(20, 0.015) * 1000, 3)
4.302

humidity — Humidity & moisture

Atmospheric moisture: saturation and actual vapor pressure, the saturation-curve slope, humidity measures, vapor pressure deficit, and precipitable water.

saturation_vp

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

Saturation vapor pressure of water (kPa) using the Tetens formula.

Tetens (1930)e_s=0.6108\,\exp\!\left(\dfrac{17.27\,T}{T+237.3}\right)
>>> from atmoflux.humidity import saturation_vp
>>> round(saturation_vp(20), 4)
2.3382

actual_vp

actual_vp(dewpoint: 'float', unit: 'str' = 'C') -> 'float'

Actual vapor pressure of water (kPa) from dew point using the Tetens formula.

Tetens (1930), at the dew pointe=0.6108\,\exp\!\left(\dfrac{17.27\,T_d}{T_d+237.3}\right)
>>> from atmoflux.humidity import actual_vp
>>> round(actual_vp(10), 4)
1.2279

saturation_vp_slope

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

Slope of the saturation vapor pressure curve (kPa/°C).

Slope of the Tetens curve\Delta=\dfrac{4098\,e_s(T)}{(T+237.3)^2}
>>> from atmoflux.humidity import saturation_vp_slope
>>> round(saturation_vp_slope(20), 4)
0.1447

relative_humidity

relative_humidity(temp: 'float', dewpoint: 'float', unit: 'str' = 'C') -> 'float'

Relative humidity (%) from temperature and dew point.

Relative humidityRH=100\,\dfrac{e(T_d)}{e_s(T)}
>>> from atmoflux.humidity import relative_humidity
>>> round(relative_humidity(20, 10), 1)
52.5

specific_humidity

specific_humidity(vapor_pressure: 'float', pressure: 'float') -> 'float'

Specific humidity (kg/kg) from vapor pressure and total pressure.

Specific humidityq=\dfrac{\epsilon\,e}{P-(1-\epsilon)\,e}
>>> from atmoflux.humidity import specific_humidity
>>> round(specific_humidity(1.2279, 101.325), 5)
0.00757

mixing_ratio

mixing_ratio(vapor_pressure: 'float', pressure: 'float') -> 'float'

Mixing ratio (kg/kg) from vapor pressure and total pressure.

Mixing ratiow=\dfrac{\epsilon\,e}{P-e}
>>> from atmoflux.humidity import mixing_ratio
>>> round(mixing_ratio(1.2279, 101.325), 5)
0.00763

vapor_pressure_deficit

vapor_pressure_deficit(temp: 'float', rh: 'float', unit: 'str' = 'C') -> 'float'

Vapor pressure deficit (kPa) from temperature and relative humidity.

Vapor pressure deficit\mathrm{VPD}=e_s(T)\left(1-\dfrac{RH}{100}\right)
>>> from atmoflux.humidity import vapor_pressure_deficit
>>> round(vapor_pressure_deficit(25, 60), 4)
1.2671

absolute_humidity

absolute_humidity(vapor_pressure: 'float', temp: 'float', unit: 'str' = 'C') -> 'float'

Absolute humidity (kg/m³) from vapor pressure and temperature.

Absolute humidity (ideal gas)\rho_v=\dfrac{e}{R_v\,T}
>>> from atmoflux.humidity import absolute_humidity
>>> round(absolute_humidity(1.2279, 20), 5)
0.00908

saturation_vp_ice

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

Saturation vapor pressure over ice (kPa) using the Tetens ice formula.

Tetens (1930), ice forme_{s,\mathrm{ice}}=0.61078\,\exp\!\left(\dfrac{21.875\,T}{T+265.5}\right)
>>> from atmoflux.humidity import saturation_vp_ice
>>> round(saturation_vp_ice(-10), 4)
0.2595

specific_humidity_from_dewpoint

specific_humidity_from_dewpoint(dewpoint: 'float', pressure: 'float', unit: 'str' = 'C') -> 'float'

Specific humidity (kg/kg) from dew point and total pressure.

Specific humidityq=\dfrac{\epsilon\,e}{P-(1-\epsilon)\,e},\quad e=e(T_d)
>>> from atmoflux.humidity import specific_humidity_from_dewpoint
>>> round(specific_humidity_from_dewpoint(10, 101.325), 5)
0.00757

relative_humidity_from_specific_humidity

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

Relative humidity (%) from specific humidity, temperature, and pressure.

Relative humiditye=\dfrac{qP}{\epsilon+(1-\epsilon)q},\qquad RH=100\,\dfrac{e}{e_s(T)}
>>> from atmoflux.humidity import relative_humidity_from_specific_humidity
>>> round(relative_humidity_from_specific_humidity(0.00757, 20, 101.325), 1)
52.5

precipitable_water

precipitable_water(specific_humidity: 'float', pressure: 'float') -> 'float'

Column precipitable water from layer-mean specific humidity.

Precipitable water\mathrm{PW}=\dfrac{q\,P}{\rho_w\,g}
>>> from atmoflux.humidity import precipitable_water
>>> round(precipitable_water(0.01, 101.325), 2)
103.32

wind — Wind

Wind speed and direction from components, logarithmic and power-law height adjustment, friction velocity, shear, power density, and canopy-based roughness.

convert_wind_speed

convert_wind_speed(speed: 'float', from_unit: 'str', to_unit: 'str') -> 'float'

Convert wind speed between m/s, mph, km/h, and knots.

>>> from atmoflux.wind import convert_wind_speed
>>> round(convert_wind_speed(10, "m/s", "km/h"), 1)
36.0
>>> round(convert_wind_speed(20, "mph", "m/s"), 4)
8.9408

wind_speed

wind_speed(u: 'float', v: 'float') -> 'float'

Wind speed magnitude from zonal and meridional components.

Wind speedU=\sqrt{u^2+v^2}
>>> from atmoflux.wind import wind_speed
>>> wind_speed(3.0, 4.0)
5.0

wind_direction

wind_direction(u: 'float', v: 'float') -> 'float'

Meteorological wind direction from zonal and meridional components.

Wind direction\phi=\left(270-\dfrac{180}{\pi}\operatorname{atan2}(v,u)\right)\bmod 360
>>> from atmoflux.wind import wind_direction
>>> wind_direction(0.0, -1.0)
0.0
>>> wind_direction(-1.0, 0.0)
90.0

log_wind_profile

log_wind_profile(speed_ref: 'float', height_ref: 'float', height: 'float', roughness: 'float', displacement: 'float' = 0.0) -> 'float'

Adjust wind speed to a new height using the logarithmic wind profile.

Logarithmic wind profileu(z)=u_\mathrm{ref}\,\dfrac{\ln\!\big((z-d)/z_0\big)}{\ln\!\big((z_\mathrm{ref}-d)/z_0\big)}
>>> from atmoflux.wind import log_wind_profile
>>> round(log_wind_profile(5.0, 10.0, 2.0, 0.03), 3)
3.615

power_law_profile

power_law_profile(speed_ref: 'float', height_ref: 'float', height: 'float', exponent: 'float') -> 'float'

Adjust wind speed to a new height using the power-law wind profile.

Power-law profileu(z)=u_\mathrm{ref}\left(\dfrac{z}{z_\mathrm{ref}}\right)^{\alpha}
>>> from atmoflux.wind import power_law_profile
>>> round(power_law_profile(5.0, 10.0, 50.0, 0.143), 3)
6.294

friction_velocity

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

Friction velocity from a single wind measurement (neutral stability).

Friction velocityu_*=\dfrac{k\,u}{\ln\!\big((z-d)/z_0\big)}
>>> from atmoflux.wind import friction_velocity
>>> round(friction_velocity(5.0, 10.0, 0.03), 4)
0.3443

wind_shear

wind_shear(speed_lower: 'float', speed_upper: 'float', height_lower: 'float', height_upper: 'float') -> 'float'

Vertical wind shear between two heights.

Wind shearS=\dfrac{u_\mathrm{upper}-u_\mathrm{lower}}{z_\mathrm{upper}-z_\mathrm{lower}}
>>> from atmoflux.wind import wind_shear
>>> round(wind_shear(3.0, 7.0, 10.0, 50.0), 3)
0.1

wind_components

wind_components(speed: 'float', direction: 'float') -> 'tuple'

Zonal and meridional wind components from speed and meteorological direction.

Wind componentsu=-U\sin\phi,\qquad v=-U\cos\phi
>>> from atmoflux.wind import wind_components
>>> u, v = wind_components(10.0, 270.0)
>>> round(float(u), 2), round(float(v), 2)
10.0 0.0

wind_power_density

wind_power_density(speed: 'float', density: 'float' = 1.225) -> 'float'

Wind power density of the airflow.

Wind power densityP=\tfrac{1}{2}\,\rho\,U^3
>>> from atmoflux.wind import wind_power_density
>>> round(wind_power_density(8.0), 2)
313.6

roughness_from_canopy

roughness_from_canopy(canopy_height: 'float') -> 'float'

Estimate aerodynamic roughness length from vegetation canopy height.

Roughness rule of thumbz_0=0.1\,h
>>> from atmoflux.wind import roughness_from_canopy
>>> round(roughness_from_canopy(2.0), 3)
0.2

displacement_from_canopy

displacement_from_canopy(canopy_height: 'float') -> 'float'

Estimate zero-plane displacement height from vegetation canopy height.

Displacement rule of thumbd=0.67\,h
>>> from atmoflux.wind import displacement_from_canopy
>>> round(displacement_from_canopy(2.0), 3)
1.34

atmosphere — Standard atmosphere

Barometric helpers: pressure scale height, pressure with altitude, hypsometric thickness, density altitude, and the US Standard Atmosphere profile.

scale_height

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

Atmospheric pressure scale height for an isothermal layer.

Pressure scale heightH=\dfrac{R_d\,T}{g}
>>> from atmoflux.atmosphere import scale_height
>>> round(scale_height(15), 1)
8434.5

pressure_at_altitude

pressure_at_altitude(altitude: 'float', pressure_ref: 'float' = 101.325, temp: 'float' = 15.0, unit: 'str' = 'C') -> 'float'

Pressure at a given altitude using the isothermal barometric formula.

Isothermal barometric lawP=P_\mathrm{ref}\,\exp\!\left(-\dfrac{z}{H}\right),\quad H=\dfrac{R_d T}{g}
>>> from atmoflux.atmosphere import pressure_at_altitude
>>> round(pressure_at_altitude(1000), 3)
89.997

hypsometric_thickness

hypsometric_thickness(pressure_lower: 'float', pressure_upper: 'float', temp: 'float', unit: 'str' = 'C') -> 'float'

Geopotential thickness between two pressure levels (hypsometric equation).

Hypsometric equation\Delta z=\dfrac{R_d\,T}{g}\,\ln\!\dfrac{P_\mathrm{lower}}{P_\mathrm{upper}}
>>> from atmoflux.atmosphere import hypsometric_thickness
>>> round(hypsometric_thickness(101.325, 90.0, 15), 1)
999.7

density_altitude

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

Density altitude from station pressure and temperature.

Density altitude\mathrm{DA}=\dfrac{T_0}{L}\left[1-\left(\dfrac{\rho}{\rho_0}\right)^{\frac{L R_d}{g-L R_d}}\right],\quad \rho=\dfrac{P}{R_d T}
>>> from atmoflux.atmosphere import density_altitude
>>> round(density_altitude(101.325, 25), 1)
353.9

standard_atmosphere

standard_atmosphere(altitude: 'float', unit: 'str' = 'C') -> 'tuple'

Temperature and pressure of the US Standard Atmosphere (troposphere).

US Standard Atmosphere (1976)\begin{aligned}T&=T_0-L z\\ P&=P_0\left(\dfrac{T}{T_0}\right)^{g/(L R_d)}\end{aligned}\quad(T_0=288.15\,\mathrm{K},\ L=0.0065\,\mathrm{K/m})
>>> from atmoflux.atmosphere import standard_atmosphere
>>> temp, pres = standard_atmosphere(1000)
>>> round(temp, 2)
8.5
>>> round(pres, 3)
89.875