soil_heat.fao56_soil_heat_flux
- Implements soil heat flux estimation methods from:
Allen, R.G., Pereira, L.S., Raes, D., Smith, M. (1998). “Crop evapotranspiration - Guidelines for computing crop water requirements.” FAO Irrigation and Drainage Paper 56. Rome, Italy.
- Also includes the ASCE Standardized Reference ET hourly G estimation:
ASCE-EWRI (2005). “The ASCE Standardized Reference Evapotranspiration Equation.” ASCE Reston, VA.
Equations Implemented
Eq. 41: General soil heat flux from soil heat capacity, temperature change, effective depth, and time interval.
Eq. 42: Daily soil heat flux for a grass reference surface (G ≈ 0).
Eq. 43: Monthly soil heat flux using the previous and next month’s mean air temperatures.
Eq. 44: Monthly soil heat flux using the previous and current month’s mean air temperatures (when next month is unavailable).
ASCE Hourly: Sub-daily soil heat flux as a fraction of net radiation (Rn), with different coefficients for daytime and nighttime.
Units
Temperatures in degrees Celsius.
Soil heat flux in MJ m⁻² day⁻¹ (or MJ m⁻² hr⁻¹ for hourly).
Can be converted to equivalent evaporation (mm day⁻¹) using
energy_to_evap().
Author: Generated for Paul Inkenbrandt / Utah Geological Survey
Attributes
Functions
|
Soil heat flux from the general calorimetric equation (FAO-56 Eq. 41). |
|
Daily soil heat flux for a grass reference surface (FAO-56 Eq. 42). |
|
Monthly soil heat flux using adjacent months (FAO-56 Eq. 43). |
|
Monthly soil heat flux — next month unavailable (FAO-56 Eq. 44). |
|
Hourly (sub-daily) soil heat flux as a fraction of net radiation. |
|
Hourly soil heat flux, auto-detecting day/night from Rn sign. |
|
Compute soil heat flux for each month in a temperature time series. |
|
Monthly G for a complete 12-month annual cycle using Eq. 43. |
|
Convert energy flux to equivalent evaporation depth (FAO-56 Eq. 20). |
|
Convert equivalent evaporation depth back to energy flux. |
|
Convert flux from MJ m⁻² day⁻¹ to W m⁻². |
|
Convert flux from W m⁻² to MJ m⁻² day⁻¹. |
|
Reproduce FAO-56 Example 13 and other verification cases. |
Module Contents
- soil_heat.fao56_soil_heat_flux.soil_heat_flux_general(t_current: float | numpy.typing.ArrayLike, t_previous: float | numpy.typing.ArrayLike, delta_t: float, delta_z: float = 1.0, c_s: float = DEFAULT_CS) float | numpy.ndarray[source]
Soil heat flux from the general calorimetric equation (FAO-56 Eq. 41).
\[G = c_s \, \frac{T_i - T_{i-1}}{\Delta t} \, \Delta z\]- Parameters:
t_current (float or array_like) – Mean air temperature of the current period [°C].
t_previous (float or array_like) – Mean air temperature of the previous period [°C].
delta_t (float) – Length of the time interval in days. For successive months use ~30.4; for a single month pair use the actual number of days between the midpoints of the two months.
delta_z (float, optional) – Effective soil depth [m]. Typical values are 0.10–0.20 m for daily periods and 0.5–2.0 m for monthly periods. Default is 1.0 m (standard for successive-month calculations).
c_s (float, optional) – Soil heat capacity [MJ m⁻³ °C⁻¹]. Default
2.1.
- Returns:
Soil heat flux G [MJ m⁻² day⁻¹]. Positive values indicate heat transfer into the soil (warming); negative values indicate heat release from the soil (cooling).
- Return type:
float or numpy.ndarray
Notes
This is the most general form. Equations 43 and 44 are simplified versions derived from this equation by assuming c_s = 2.1 MJ/(m³·°C), Δz = 1.0 m, and Δt appropriate for monthly intervals (~30 days).
For Eq. 43: 0.07 ≈ 2.1 × 1.0 / (2 × 30) For Eq. 44: 0.14 ≈ 2.1 × 1.0 / (1 × 30) (÷ by half the interval)
Examples
FAO-56 Example 13 — March to April:
>>> soil_heat_flux_general(16.1, 14.1, delta_t=30.0, delta_z=1.0) 0.14
- soil_heat.fao56_soil_heat_flux.soil_heat_flux_daily() float[source]
Daily soil heat flux for a grass reference surface (FAO-56 Eq. 42).
For a daily time step, soil heat flux beneath a grass reference surface is small relative to net radiation and may be assumed to be zero.
- Returns:
0.0[MJ m⁻² day⁻¹].- Return type:
Notes
This assumption holds for a dense, grass-covered surface where the soil surface temperature cycle nearly cancels over 24 hours. For bare soil or sparse vegetation, daily G can be significant and should be estimated by other means (e.g., the general equation or measured data).
- soil_heat.fao56_soil_heat_flux.soil_heat_flux_monthly(t_month_prev: float | numpy.typing.ArrayLike, t_month_next: float | numpy.typing.ArrayLike) float | numpy.ndarray[source]
Monthly soil heat flux using adjacent months (FAO-56 Eq. 43).
When both the previous and next month’s mean air temperatures are available, this is the preferred monthly estimate.
\[G_{\text{month},i} = 0.07 \, (T_{i+1} - T_{i-1})\]- Parameters:
- Returns:
Monthly soil heat flux [MJ m⁻² day⁻¹].
- Return type:
float or numpy.ndarray
Notes
The coefficient 0.07 derives from Eq. 41 with c_s = 2.1 MJ/(m³·°C), Δz = 1.0 m, and a two-month span (Δt ≈ 2 × 30 = 60 days):
2.1 × 1.0 / 60 = 0.035 → rounded/adopted as 0.07 in FAO-56.
(The FAO text notes that the coefficient accounts for the relationship between air and soil temperature damping; it is empirically calibrated for a grass reference surface.)
Examples
FAO-56 Example 13 — April soil heat flux (March = 14.1 °C, May = 18.8 °C):
>>> soil_heat_flux_monthly(14.1, 18.8) 0.329
- soil_heat.fao56_soil_heat_flux.soil_heat_flux_monthly_prev_only(t_month_prev: float | numpy.typing.ArrayLike, t_month_cur: float | numpy.typing.ArrayLike) float | numpy.ndarray[source]
Monthly soil heat flux — next month unavailable (FAO-56 Eq. 44).
When the next month’s temperature is not yet known (e.g., real-time or forecast applications), use this equation with the current and previous month.
\[G_{\text{month},i} = 0.14 \, (T_i - T_{i-1})\]- Parameters:
- Returns:
Monthly soil heat flux [MJ m⁻² day⁻¹].
- Return type:
float or numpy.ndarray
Notes
The coefficient 0.14 is exactly twice the Eq. 43 coefficient because the temperature difference spans only one month instead of two:
2.1 × 1.0 / 30 ≈ 0.07 × 2 = 0.14
When both adjacent months are available, prefer
soil_heat_flux_monthly()(Eq. 43) for greater accuracy.Examples
FAO-56 Example 13 — March soil heat flux (Feb = 12.1 °C, Mar = 14.1 °C):
>>> soil_heat_flux_monthly_prev_only(12.1, 14.1) 0.28
- soil_heat.fao56_soil_heat_flux.soil_heat_flux_hourly(rn: float | numpy.typing.ArrayLike, is_daytime: bool | numpy.typing.ArrayLike, day_coeff: float = 0.1, night_coeff: float = 0.5) float | numpy.ndarray[source]
Hourly (sub-daily) soil heat flux as a fraction of net radiation.
Based on the ASCE Standardized Reference Evapotranspiration Equation (ASCE-EWRI, 2005), which recommends estimating G for hourly or shorter periods as a proportion of net radiation Rn:
\[ \begin{align}\begin{aligned}G_{\text{day}} &= 0.1 \; R_n \quad \text{(daytime)}\\G_{\text{night}} &= 0.5 \; R_n \quad \text{(nighttime)}\end{aligned}\end{align} \]- Parameters:
rn (float or array_like) – Net radiation at the crop surface [MJ m⁻² hr⁻¹].
is_daytime (bool or array_like of bool) –
Truefor daytime periods,Falsefor nighttime. For array inputs, must be broadcastable with rn.day_coeff (float, optional) – Fraction of Rn used for daytime G. Default
0.1.night_coeff (float, optional) – Fraction of Rn used for nighttime G. Default
0.5.
- Returns:
Soil heat flux [MJ m⁻² hr⁻¹] (same units as rn).
- Return type:
float or numpy.ndarray
Notes
Daytime is typically defined as the period when Rn > 0. Some implementations use the solar angle or the time relative to sunrise and sunset instead.
The default coefficients (0.1 / 0.5) are calibrated for a grass reference surface. For other surfaces the ratio G/Rn can vary considerably (see Allen et al., 1998, Table 7-2).
Examples
Daytime hour with Rn = 2.5 MJ m⁻² hr⁻¹:
>>> soil_heat_flux_hourly(2.5, is_daytime=True) 0.25
Nighttime hour with Rn = -0.4 MJ m⁻² hr⁻¹:
>>> soil_heat_flux_hourly(-0.4, is_daytime=False) -0.2
- soil_heat.fao56_soil_heat_flux.soil_heat_flux_hourly_auto(rn: float | numpy.typing.ArrayLike, day_coeff: float = 0.1, night_coeff: float = 0.5) float | numpy.ndarray[source]
Hourly soil heat flux, auto-detecting day/night from Rn sign.
Convenience wrapper around
soil_heat_flux_hourly()that usesRn > 0as the daytime indicator, which is the most common approach in practice.- Parameters:
- Returns:
Soil heat flux [MJ m⁻² hr⁻¹].
- Return type:
float or numpy.ndarray
Examples
>>> soil_heat_flux_hourly_auto(2.5) 0.25 >>> soil_heat_flux_hourly_auto(-0.4) -0.2
- soil_heat.fao56_soil_heat_flux.soil_heat_flux_monthly_series(t_monthly: numpy.typing.ArrayLike, method: str = 'centered') numpy.ndarray[source]
Compute soil heat flux for each month in a temperature time series.
This is a convenience function that applies the appropriate FAO-56 monthly equation to each element of a monthly mean-temperature array.
- Parameters:
t_monthly (array_like) – 1-D array of consecutive monthly mean air temperatures [°C]. Length N ≥ 2.
method ({"centered", "backward"}, optional) –
"centered"(default) — Uses Eq. 43 where both neighbors exist; falls back to Eq. 44 at the boundaries (first and last month)."backward"— Uses Eq. 44 for every month (each month compared only to the previous month). The first element is set toNaNbecause there is no previous month.
- Returns:
Array of monthly soil heat flux values [MJ m⁻² day⁻¹], same length as t_monthly.
- Return type:
numpy.ndarray
Examples
FAO-56 Example 13 — March, April, May temps:
>>> temps = [14.1, 16.1, 18.8] >>> soil_heat_flux_monthly_series(temps, method="centered") array([0.28 , 0.329, 0.378])
Using backward-only differences:
>>> soil_heat_flux_monthly_series(temps, method="backward") array([ nan, 0.28 , 0.378])
- soil_heat.fao56_soil_heat_flux.soil_heat_flux_annual_cycle(t_monthly_12: numpy.typing.ArrayLike) numpy.ndarray[source]
Monthly G for a complete 12-month annual cycle using Eq. 43.
Wraps around so that January uses December and February as neighbors, and December uses November and January.
- Parameters:
t_monthly_12 (array_like) – Exactly 12 monthly mean air temperatures [°C], January through December.
- Returns:
Shape
(12,)array of monthly soil heat flux [MJ m⁻² day⁻¹].- Return type:
numpy.ndarray
Examples
>>> temps = [5.2, 6.1, 9.3, 13.0, 17.5, 22.1, ... 25.4, 24.8, 20.6, 14.9, 9.2, 5.8] >>> g = soil_heat_flux_annual_cycle(temps) >>> g[0] # January: 0.07 * (Feb - Dec) 0.021...
- soil_heat.fao56_soil_heat_flux.energy_to_evap(energy: float | numpy.typing.ArrayLike) float | numpy.ndarray[source]
Convert energy flux to equivalent evaporation depth (FAO-56 Eq. 20).
\[E_{\text{equiv}} = 0.408 \times E\]
- soil_heat.fao56_soil_heat_flux.evap_to_energy(evap: float | numpy.typing.ArrayLike) float | numpy.ndarray[source]
Convert equivalent evaporation depth back to energy flux.
Inverse of
energy_to_evap().
- soil_heat.fao56_soil_heat_flux.mj_m2_day_to_w_m2(flux: float | numpy.typing.ArrayLike) float | numpy.ndarray[source]
Convert flux from MJ m⁻² day⁻¹ to W m⁻².
\[W\,m^{-2} = \frac{MJ\,m^{-2}\,day^{-1}}{0.0864}\]