advection.advection

Main module.

advection.advection.air_density(P, T, q, R_dry=287.05, R_vap=461.5)[source]

Calculate moist air density [kg/m^3] given pressure, temperature, and humidity.

Parameters:
  • P (float) – Ambient pressure [Pa].

  • T (float) – Air temperature [K].

  • q (float) – Specific humidity [kg/kg].

  • R_dry (float, optional) – Gas constant for dry air [J/(kg K)] (default 287.05).

  • R_vap (float, optional) – Gas constant for water vapor [J/(kg K)] (default 461.5).

Returns:

Air density [kg/m^3].

Return type:

float

advection.advection.air_heat_storage(rho, Cp, dT_dt, zm, h)[source]

Compute the air-column sensible-heat storage term J (W/m^2).

Implements Wang et al. (2024), Eq. 11:

T_storage = rho * Cp * (dT/dt) * (zm - h)

This is the rate at which sensible heat is stored in (positive) or released from (negative) the air layer between the canopy top h and the measurement height zm. It is the storage term J in the storage-resolved surface energy balance Rn - G - J = H + LE and is distinct from the soil heat storage Gs (see compute_soil_heat_storage_flux()), which is folded into G.

Parameters:
  • rho (float) – Air density [kg/m^3] during the period.

  • Cp (float) – Specific heat capacity of air [J/(kg K)] (use the moist-air value if available; see specific_heat_moist_air()).

  • dT_dt (float) – Time derivative of air temperature [K/s], representative of the h-to-zm layer.

  • zm (float) – Measurement (sensor) height [m].

  • h (float) – Canopy height [m].

Returns:

Air-column sensible-heat storage J [W/m^2].

Return type:

float

advection.advection.compute_bowen_ratio_variance(sigma_T=None, sigma_q=None, Cp=1005.0, Lv=None, *, T_prime=None, q_prime=None, cov_Tq=None, corr_Tq=None, T=None, zero_cov_tol=1e-12)[source]

Compute the variance (flux-variance) Bowen ratio beta with sign.

Implements Wang et al. (2024), Eq. 8:

|beta|     = (Cp / Lv) * (sigma_T / sigma_q)
sign(beta) = sign(corr(T', q')) = sign(cov(T', q'))
beta       = sign(beta) * |beta|

The variance method recovers only the magnitude of the Bowen ratio from the ratio of the temperature and humidity standard deviations; the sign must come from the temperature-humidity correlation (Wang Eq. 8). A negative beta is the oasis fingerprint: warm, dry air (positive T') arrives as the surface evaporates and moistens the air (negative q'), so corr(T', q') < 0. Per the Moderow et al. (2021) sign convention (CLAUDE.md), a negative beta corresponds to downward (negative) sensible heat flux H, i.e. sensible heat advected into the field (energy INTO the control volume). The classic daytime convective case has warm rising air carrying moisture upward, giving corr(T', q') > 0 and beta > 0.

The sign source may be supplied three ways, in order of precedence: a precomputed correlation corr_Tq; a precomputed covariance cov_Tq; or the raw fluctuation series T_prime/q_prime (from which the covariance – and, when not given explicitly, the standard deviations – are derived). When the sign source lies within zero_cov_tol of zero the sign is taken as +1 (documented tie-break), since a vanishing T-q correlation carries no advective signal.

Parameters:
  • sigma_T (float, optional) – Standard deviation of air temperature fluctuations [K]. If omitted it is computed from T_prime.

  • sigma_q (float, optional) – Standard deviation of specific humidity fluctuations [kg/kg]. If omitted it is computed from q_prime.

  • Cp (float, optional) – Specific heat capacity of air [J/(kg K)] (use the moist-air value if available; default 1005 J/(kg K) for dry air).

  • Lv (float, optional) – Latent heat of vaporization [J/kg]. If None and a temperature T is supplied, latent_heat_vaporization(T) is used; otherwise it falls back to ~2.45e6 J/kg (~20 °C).

  • T_prime (array_like, optional) – Time series of temperature [K] and specific-humidity [kg/kg] fluctuations. Used to derive cov(T', q') (for the sign) and, when not supplied explicitly, sigma_T/sigma_q.

  • q_prime (array_like, optional) – Time series of temperature [K] and specific-humidity [kg/kg] fluctuations. Used to derive cov(T', q') (for the sign) and, when not supplied explicitly, sigma_T/sigma_q.

  • cov_Tq (float, optional) – Precomputed covariance of T' and q'. Only its sign is used.

  • corr_Tq (float, optional) – Precomputed correlation of T' and q'. Only its sign is used. Takes precedence over cov_Tq and the fluctuation series.

  • T (float, optional) – Air temperature [°C or K] used to evaluate Lv when Lv is None.

  • zero_cov_tol (float, optional) – Magnitude at or below which the sign source is treated as zero and the sign is set to +1 (default 1e-12).

Returns:

Signed Bowen ratio beta (dimensionless). A negative value indicates downward H / advective input (the oasis fingerprint).

Return type:

float

Warns:

UserWarning – When no sign source (corr_Tq, cov_Tq or T_prime/q_prime) is supplied: the unsigned magnitude is returned and the sign is flagged as undetermined (backward-compatible behaviour).

References

Wang et al. (2024), Eq. 8. Moderow et al. (2021), sign convention.

advection.advection.compute_sensible_heat_flux(w_T_prime, rho_air, Cp=1005.0)[source]

Compute the sensible heat flux H (W/m^2) from the kinematic heat flux w’T’.

Implements the CLAUDE.md “Sensible heat” relation:

H = rho * Cp * w'T'                                   # W/m^2

Sign convention (Moderow et al. 2021, OUT-positive): a positive H is energy carried out of the control volume (upward kinematic heat flux), a negative H is energy into it (downward) – the oasis fingerprint. The sign is inherited directly from w'T'; no extra negation is applied. Use the WPL/humidity-corrected kinematic flux from correct_sonic_heat_flux() as w_T_prime.

Parameters:
  • w_T_prime (float) – Corrected kinematic sensible heat flux w’T’ [K m/s].

  • rho_air (float) – Air density [kg/m^3] during the period.

  • Cp (float, optional) – Specific heat capacity of air [J/(kg K)] (use moist-air value if available).

Returns:

Sensible heat flux H [W/m^2].

Return type:

float

References

Wang et al. (2024); Moderow et al. (2021), OUT-positive sign convention.

advection.advection.compute_soil_heat_storage_flux(Csoil, dT_dt, dz=0.02)[source]

Compute soil heat storage flux Gs (W/m^2) from the soil volumetric heat capacity and the temperature change rate.

Implements Equation 1a: Gs = Cs * dz * (dTsoil/dt).

Parameters:
  • Csoil (float) – Volumetric heat capacity of the soil layer [J/(m^3 K)].

  • dT_dt (float) – Time derivative of soil temperature [K/s] (temperature change rate), averaged over the storage layer.

  • dz (float, optional) – Thickness of the soil layer ABOVE the heat-flux plate [m] — i.e. the depth interval dz between the surface and the plate over which heat is stored, not an absolute installation depth. Heat-flux plates are typically buried at 0.05-0.08 m, so the storage layer thickness usually lies in that range; the 0.02 m default is a placeholder, not a universal value, and should be set to the actual plate-burial depth at your site.

Returns:

Soil heat storage flux Gs [W/m^2].

Return type:

float

advection.advection.compute_std(series)[source]

Compute the standard deviation of a time series.

Suitable for computing σ_T or σ_q over an averaging period.

Parameters:

series (iterable) – Iterable of data points (list or NumPy array).

Returns:

Standard deviation of the series.

Return type:

float

advection.advection.correct_sonic_heat_flux(w_Ts, T_mean, beta, Cp=1005.0, Lv=None, singular_tol=1e-06)[source]

Convert sonic (virtual) temperature flux w’Ts’ to the true kinematic sensible-heat flux w’T’ by removing the humidity contribution.

Implements Wang et al. (2024), Eq. 9:

w'T' = w'Ts' / (1 + 0.51 * Cp * T_mean / (Lv * beta))    # T_mean in KELVIN

where T_mean must be an absolute temperature in Kelvin and beta is the signed Bowen ratio for the period.

T_mean is passed through _to_kelvin(), so the caller may supply either Celsius or Kelvin (a value > 150 is assumed already Kelvin); Eq. 9 is then evaluated with the absolute temperature it requires.

Wang Eq. 7 carries an additional crosswind contribution, -(2 * T * q / cs**2) * u'w' (cs = speed of sound, q = specific humidity, u'w' = momentum flux). It is intentionally omitted here, matching Wang et al. (2024), Eq. 9: the sonic anemometer’s crosswind correction is already applied internally to the raw covariances, so re-applying it would double-count. This omission is deliberate, not an oversight.

A negative beta is valid – it is the oasis/advection fingerprint (downward H; see compute_bowen_ratio_variance() and CLAUDE.md) – and is handled exactly like a positive beta. The denominator factor 1 + 0.51 * Cp * T_mean / (Lv * beta) is order-unity for physically typical periods, but for a narrow band of small negative beta (around beta = -0.51 * Cp * T_mean / Lv) it passes through zero. Dividing there would yield an unphysically huge corrected flux, so that singular case is detected and reported as nan (see Warns) rather than returned.

Parameters:
  • w_Ts (float) – Sonic (virtual) temperature flux, w’Ts’ [K m/s].

  • T_mean (float) – Mean air temperature during the period [°C or K]. Eq. 9 requires Kelvin; the value is converted via _to_kelvin().

  • beta (float) – Signed Bowen ratio (dimensionless). Negative values (advection) are valid and handled.

  • Cp (float, optional) – Specific heat capacity of air [J/(kg K)] (use the moist-air value if available; default 1005).

  • Lv (float, optional) – Latent heat of vaporization lambda [J/kg] (if None, uses ~2.45e6 J/kg).

  • singular_tol (float, optional) – Magnitude below which the denominator factor is treated as singular (default 1e-6). The factor is order-unity for valid data, so a value this close to zero indicates the pathological small-negative-beta band.

Returns:

Corrected kinematic sensible-heat flux w’T’ [K m/s]. Returns w_Ts unchanged when beta == 0 (the Bowen-ratio humidity correction is undefined, so it is skipped), and nan when the denominator factor is within singular_tol of zero.

Return type:

float

Warns:

UserWarning – When the denominator factor 1 + 0.51 * Cp * T_mean / (Lv * beta) is within singular_tol of zero (the small-negative-beta singularity): nan is returned instead of an unphysically large flux.

References

Wang et al. (2024), Eq. 9 (and Eq. 7 for the deliberately dropped crosswind term). Moderow et al. (2021), sign convention.

advection.advection.latent_heat_flux_bowen(Rnet, G, beta, singular_tol=1e-06)[source]

Compute latent heat flux (λE) using the Bowen ratio method (no fast data needed).

Implements the Bowen-ratio partition of the available energy (Twine et al. 2000; Bowen 1926):

λE = (R_net - G) / (1 + beta)                         # W/m^2

where beta = H / λE is the Bowen ratio. (This is closure forcing, not advection accounting; see the caution below and advection.closure.bowen_ratio_closure().)

Note

Any measured open-path LE you compare against this estimate is assumed to be already WPL (Webb-Pearman-Leuning 1980) density-corrected. WPL is a mandatory, separate pre-step (not an advection fix); see wpl_latent_heat_flux() and the package README.

The denominator 1 + beta is order-unity for typical periods, but it passes through zero as beta -> -1 – a value that can occur in the oasis/advection regime (negative beta is the oasis fingerprint; see compute_bowen_ratio_variance() and CLAUDE.md). Dividing there would yield an unphysically huge flux, so that singular case is detected and reported as nan (see Warns) rather than returned.

Caution

Bowen-ratio closure is physically invalid when ``LE > (Rn - G)`` (the oasis/advection case). The method partitions the available energy R_net - G using the measured beta, which forces the residual to share that ratio; when warm dry air advects extra energy into the control volume, the true LE exceeds the available energy and no real beta reproduces it. Forcing closure here drives beta toward -1 and the estimate diverges or changes sign (Twine et al. 2000; Wang et al. 2024). In that regime do not force Bowen-ratio closure – instead add the measured advective fluxes (horizontal_heat_advection(), vertical_heat_advection(), etc.) to close the budget, gated by the conditional-inclusion rule (R_net > 75 W/m^2 AND spectrally-corrected H + LE < R_net - G; see CLAUDE.md). Never compute an advection term as the energy-balance residual.

Parameters:
  • Rnet (float) – Net radiation [W/m^2].

  • G (float) – Ground heat flux (storage-corrected) [W/m^2].

  • beta (float) – Bowen ratio (dimensionless). Negative values occur in the oasis regime; values near -1 are singular (see Warns).

  • singular_tol (float, optional) – Magnitude below which the denominator 1 + beta is treated as singular (default 1e-6). The denominator is order-unity for valid data, so a value this close to zero indicates the pathological beta -1 band.

Returns:

Latent heat flux λE [W/m^2]. Returns nan when 1 + beta is within singular_tol of zero.

Return type:

float

Warns:

UserWarning – When 1 + beta is within singular_tol of zero (beta -1): nan is returned instead of an unphysically large flux.

References

Twine, T. E., et al. (2000), Agric. For. Meteorol. 103, 279-300 – on the breakdown of Bowen-ratio closure when LE > (Rn - G). Wang et al. (2024). Moderow et al. (2021), sign convention.

advection.advection.latent_heat_flux_residual(Rnet, G, H)[source]

Compute latent heat flux (λE) as the residual of the energy balance.

Implements the residual-closure estimate (Twine et al. 2000):

λE = R_net - G - H                                    # W/m^2

i.e. H is trusted and LE absorbs the closure gap, the storage-free rearrangement of Rn - G = H + LE. This is the latent-heat-as-residual method (a legitimate standard closure choice), and is distinct from the CLAUDE.md prohibition on computing an advection term as a residual. See advection.closure.residual_le_closure() for the storage-aware form and the closure caveats.

Note

Any measured open-path LE you compare against this estimate is assumed to be already WPL (Webb-Pearman-Leuning 1980) density-corrected. WPL is a mandatory, separate pre-step (not an advection fix); see wpl_latent_heat_flux() and the package README.

Parameters:
  • Rnet (float) – Net radiation [W/m^2].

  • G (float) – Ground heat flux (storage-corrected) [W/m^2].

  • H (float) – Sensible heat flux [W/m^2].

Returns:

Latent heat flux λE [W/m^2].

Return type:

float

References

Twine, T. E., et al. (2000), Agric. For. Meteorol. 103, 279-300 (residual closure).

advection.advection.latent_heat_vaporization(T)[source]

Compute latent heat of vaporization of water (Lv) at temperature T.

Uses a polynomial fit for 0 <= T <= 40°C (from literature). T can be in °C or K (if K, it is converted to °C internally).

Parameters:

T (float) – Air temperature [°C or K].

Returns:

Latent heat of vaporization Lv [J/kg].

Return type:

float

advection.advection.rh_to_specific_humidity(RH, T, P=101325)[source]

Convert relative humidity to specific humidity.

Parameters:
  • RH (float) – Relative humidity [% (0-100) or fraction (0-1)].

  • T (float) – Air temperature [°C].

  • P (float, optional) – Ambient pressure [Pa] (default 101325 Pa, sea level).

Returns:

Specific humidity q [kg/kg].

Return type:

float

advection.advection.specific_heat_moist_air(q)[source]

Calculate the specific heat capacity of moist air [J/(kg K)] given the specific humidity.

Parameters:

q (float) – Specific humidity [kg/kg].

Returns:

Cp of moist air [J/(kg K)].

Return type:

float

advection.advection.total_ground_heat_flux(Gd, Gs)[source]

Compute the storage-corrected ground heat flux G by adding the raw ground flux Gd and the storage term Gs.

Implements Equation 1b: G = Gd + Gs.

Parameters:
  • Gd (float) – Ground heat flux at the sensor depth (plate measurement) [W/m^2].

  • Gs (float) – Soil heat storage flux (above the sensor) [W/m^2].

Returns:

Storage-corrected ground heat flux G [W/m^2].

Return type:

float

advection.advection.virtual_temperature(T, q)[source]

Calculate virtual temperature T_v (K) for moist air.

T_v = T * (1 + 0.61 * q), where q is specific humidity.

Parameters:
  • T (float) – Actual air temperature [K].

  • q (float) – Specific humidity [kg/kg].

Returns:

Virtual temperature T_v [K].

Return type:

float

advection.advection.wpl_latent_heat_flux(w_rhov, w_T, rho_v, T, mixing_ratio, Lv=None, mu=1.6077)[source]

Convenience WPL (Webb-Pearman-Leuning 1980) density-corrected latent heat flux.

Important

This is a convenience pre-step, not part of the advection accounting this library performs. The rest of advection assumes any open-path LE/CO2 flux it is given has already been WPL density-corrected (see latent_heat_flux_residual(), latent_heat_flux_bowen(), advection.closure.bowen_ratio_closure() and the package README). WPL is a mandatory, separate pre-processing step — it accounts for the density fluctuations of dry air that contaminate an open-path vapour covariance, and it is not an advection correction.

Caution

Prefer an established eddy-covariance processing package (e.g. EddyPro, EasyFlux, or your logger’s online WPL routine) for production work. This helper implements only the simplified form below — it omits the ambient-pressure fluctuation term and assumes the inputs are already coordinate-rotated, despiked, and frequency-response corrected. Use it for teaching, quick checks, or when you have the raw covariances but no full processing chain, not as a substitute for validated software.

Implements the simplified Webb et al. (1980) water-vapour flux:

E = (1 + mu * MR) * [ w'rho_v' + (rho_v / T) * w'T' ]     # kg m^-2 s^-1
LE = Lv * E                                               # W/m^2

with mu = M_d / M_v = 1.6077 (advection._constants.MU). The first bracket term is the raw (uncorrected) vapour covariance; the second adds the thermal-expansion contribution (rho_v / T) * w'T'; the (1 + mu*MR) prefactor is the dry-air dilution correction. T is passed through _to_kelvin(), so Celsius or Kelvin may be supplied (the ratio rho_v / T requires an absolute temperature).

Parameters:
  • w_rhov (float) – Raw covariance of vertical wind and water-vapour density, w'rho_v' [kg m^-2 s^-1] — the uncorrected open-path vapour flux.

  • w_T (float) – Kinematic sensible-heat flux w'T' [K m/s].

  • rho_v (float) – Mean water-vapour (mass) density [kg/m^3].

  • T (float) – Mean air temperature [°C or K]; converted to Kelvin via _to_kelvin().

  • mixing_ratio (float) – Water-vapour mass mixing ratio MR = rho_v / rho_d [kg/kg] (vapour mass per unit mass of dry air).

  • Lv (float, optional) – Latent heat of vaporization [J/kg]. If None, uses latent_heat_vaporization(T).

  • mu (float, optional) – Ratio of molar masses M_d / M_v [dimensionless]; default MU (1.6077).

Returns:

WPL density-corrected latent heat flux LE [W/m^2].

Return type:

float

References

Webb, E. K., Pearman, G. I., & Leuning, R. (1980), Correction of flux measurements for density effects due to heat and water vapour transfer, Q. J. R. Meteorol. Soc. 106, 85-100.