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

DEFAULT_CS

LATENT_HEAT_INV

Functions

soil_heat_flux_general(→ Union[float, numpy.ndarray])

Soil heat flux from the general calorimetric equation (FAO-56 Eq. 41).

soil_heat_flux_daily(→ float)

Daily soil heat flux for a grass reference surface (FAO-56 Eq. 42).

soil_heat_flux_monthly(→ Union[float, numpy.ndarray])

Monthly soil heat flux using adjacent months (FAO-56 Eq. 43).

soil_heat_flux_monthly_prev_only(→ Union[float, ...)

Monthly soil heat flux — next month unavailable (FAO-56 Eq. 44).

soil_heat_flux_hourly(→ Union[float, numpy.ndarray])

Hourly (sub-daily) soil heat flux as a fraction of net radiation.

soil_heat_flux_hourly_auto(→ Union[float, numpy.ndarray])

Hourly soil heat flux, auto-detecting day/night from Rn sign.

soil_heat_flux_monthly_series(→ numpy.ndarray)

Compute soil heat flux for each month in a temperature time series.

soil_heat_flux_annual_cycle(→ numpy.ndarray)

Monthly G for a complete 12-month annual cycle using Eq. 43.

energy_to_evap(→ Union[float, numpy.ndarray])

Convert energy flux to equivalent evaporation depth (FAO-56 Eq. 20).

evap_to_energy(→ Union[float, numpy.ndarray])

Convert equivalent evaporation depth back to energy flux.

mj_m2_day_to_w_m2(→ Union[float, numpy.ndarray])

Convert flux from MJ m⁻² day⁻¹ to W m⁻².

w_m2_to_mj_m2_day(→ Union[float, numpy.ndarray])

Convert flux from W m⁻² to MJ m⁻² day⁻¹.

_run_tests(→ None)

Reproduce FAO-56 Example 13 and other verification cases.

Module Contents

soil_heat.fao56_soil_heat_flux.DEFAULT_CS = 2.1[source]
soil_heat.fao56_soil_heat_flux.LATENT_HEAT_INV = 0.408[source]
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:

float

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:
  • t_month_prev (float or array_like) – Mean air temperature of the previous month [°C].

  • t_month_next (float or array_like) – Mean air temperature of the next month [°C].

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:
  • t_month_prev (float or array_like) – Mean air temperature of the previous month [°C].

  • t_month_cur (float or array_like) – Mean air temperature of the current month [°C].

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) – True for daytime periods, False for 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 uses Rn > 0 as the daytime indicator, which is the most common approach in practice.

Parameters:
  • rn (float or array_like) – Net radiation at the crop surface [MJ m⁻² hr⁻¹].

  • 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⁻¹].

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 to NaN because 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\]
Parameters:

energy (float or array_like) – Energy flux [MJ m⁻² day⁻¹] (or per hour, etc.).

Returns:

Equivalent evaporation [mm day⁻¹] (or per hour, etc.).

Return type:

float or numpy.ndarray

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().

Parameters:

evap (float or array_like) – Equivalent evaporation [mm day⁻¹].

Returns:

Energy flux [MJ m⁻² day⁻¹].

Return type:

float or numpy.ndarray

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}\]
Parameters:

flux (float or array_like) – Energy flux [MJ m⁻² day⁻¹].

Returns:

Energy flux [W m⁻²].

Return type:

float or numpy.ndarray

soil_heat.fao56_soil_heat_flux.w_m2_to_mj_m2_day(flux: float | numpy.typing.ArrayLike) float | numpy.ndarray[source]

Convert flux from W m⁻² to MJ m⁻² day⁻¹.

Parameters:

flux (float or array_like) – Energy flux [W m⁻²].

Returns:

Energy flux [MJ m⁻² day⁻¹].

Return type:

float or numpy.ndarray

soil_heat.fao56_soil_heat_flux._run_tests() None[source]

Reproduce FAO-56 Example 13 and other verification cases.