Skin temperature and ground heat flux
This page is a work in progress. If you have any questions or notice any errors, please raise an issue.
Overview
The skin temperature $T_s$ is the effective radiative temperature of the land surface. It represents the temperature at which the surface emits longwave radiation and is the temperature that directly controls evaporation and sensible heat flux in the surface energy balance.
Skin temperature differs from the air temperature at height $z$ by the effects of turbulent mixing and surface properties. It is also not necessarily the same as the subsurface ground temperature $T_g$ (the temperature of the uppermost soil or snow layer) due to the thermal resistance between the surface and the ground.
The skin temperature $T_s$ is determined by balancing the energy arriving at the skin from below (the ground heat flux $G$) with the radiative and turbulent losses above,
\[R_{\text{net}}(T_s) + H_s(T_s) + H_l(T_s) = G(T_s, T_g)\]
where $R_{\text{net}}$ is the net radiation budget, $H_s$ is the sensible heat flux, and $H_l$ is the latent heat flux from sublimation and evapotranspiration.
Implicit skin temperature
Terrarium.ImplicitSkinTemperature — Type
struct ImplicitSkinTemperature{NF, Solver} <: Terrarium.AbstractSkinTemperature{NF}Scheme for an implicit skin temperature $T_s$ satisfying:
\[R_{\text{net}}(T_s) + H_s(T_s) + H_l(T_s) - G(T_s, T_g) = 0 \]
where $R_{\text{net}}$ is the net radiation budget, $H_s$ is the sensible heat flux, $H_l$ is the latent heat flux from sublimation and evapotranspiration, $G$ is the ground heat flux, and $T_g$ is the ground temperature, or temperature of the uppermost subsurface (soil or snow) layer. All fluxes follow the positive upwards convention. For $G$, this means from the deeper soil towards the surface is positive. For the other fluxes, this means from the surface towards the atmosphere is positive.
Properties:
κₛ: Assumed thermal conductivity at the surfacesolver: Numerical solver for the implicit skin temperature
Skin temperature can be determined instantaneously at each time step by finding the roots of the above nonlinear energy balance equation at each grid point. Given a trial skin temperature $T_s$, the residual energy flux required to close the energy balance is
\[G^\star = R_{\text{net}}(T_s) + H_s(T_s) + H_l(T_s)\]
Correspondingly, the implied conductive flux between the skin and the ground surface (uppermost soil layer) at temperature $T_g$, across the half-cell of thickness $\Delta z_1 / 2$, is
\[G = \frac{2 \kappa_s}{\Delta z_1} (T_g - T_s)\]
Setting the conductive flux equal to the residual energy flux and rearranging terms yields the skin temperature,
\[T_s^\star = T_g - G^\star \frac{\Delta z_1}{2 \kappa_s}\]
and the residual driving the nonlinear solve is the difference between the current and implied skin temperatures,
\[r(T_s) = T_s - T_s^\star\]
The root $r(T_s) = 0$ is the skin temperature at which the conductive flux balances the radiative and turbulent fluxes, i.e. the solution of the surface energy balance.
The solve is performed by solve_skin_temperature!, which wraps compute_skin_temperature_residual! in an ObjectiveFunction targeting the skin_temperature field and hands it to the configured solver. The default solver, default_skin_temperature_solver, is a Newton-Raphson (RootSolver provided by RootSolvers.jl) with a fixed iteration budget of $n = 5$ to balance accuracy with GPU efficiency. The prognostic skin_temperature is seeded with the current ground_temperature by initialize! so that the iteration starts from a physically sensible guess close to the root. After the solve converges, the surface energy fluxes are recomputed from the final skin temperature.
Prescribed skin temperature
Terrarium.PrescribedSkinTemperature — Type
struct PrescribedSkinTemperature{NF} <: Terrarium.AbstractSkinTemperature{NF}Simple scheme for prescribed skin temperatures from input variables.
Properties:
κₛ: Assumed thermal conductivity at the surface
When the skin temperature is prescribed, it is supplied directly as the skin_temperature input field (for example by an external coupler) and no nonlinear solve is performed: solve_skin_temperature! is a no-op for PrescribedSkinTemperature. The fused surface-energy-balance kernel then evaluates the radiative and turbulent fluxes from the prescribed skin temperature and closes the ground heat flux as the residual
\[G = R_{\text{net}} + H_s + H_l\]
This configuration can be used to defer the surface energy balance to an external solver, often in tandem with PrescribedTurbulentFluxes when the turbulent fluxes are also supplied as inputs (see Surface energy balance).
Process interface
Terrarium.initialize! — Method
initialize!(
state,
grid,
_::ImplicitSkinTemperature,
args...
)
Seed the prognostic skin_temperature with the current ground_temperature so the implicit nonlinear solve starts from a physically sensible guess close to the root.
Terrarium.compute_auxiliary! — Method
compute_auxiliary!(
state,
grid,
skinT::ImplicitSkinTemperature,
seb::Terrarium.AbstractSurfaceEnergyBalance,
args...
)
Methods
Terrarium.compute_skin_temperature — Method
compute_skin_temperature(
_::ImplicitSkinTemperature,
Tg,
G,
Δz,
κ
) -> Any
Compute the implicit update of the skin temperature from the sub-surface temperature Tg, ground heat flux G, half-cell distance Δz, and effective conductivity κ, by equating G to the half-cell conductive flux 2κ(Tg − Ts)/Δz.
Terrarium.compute_ground_heat_flux — Method
compute_ground_heat_flux(
_::Terrarium.AbstractSkinTemperature,
R_net,
H_s,
H_l
) -> Any
Compute the ground heat flux G that closes the surface energy balance. With all fluxes positive upward (aligned with +z), the energy arriving at the skin from below must balance the radiative and turbulent losses above, so G = R_net + H_s + H_l.
Terrarium.compute_skin_temperature! — Method
compute_skin_temperature!(
state,
grid,
skinT::ImplicitSkinTemperature,
constants::PhysicalConstants
)
compute_skin_temperature!(
state,
grid,
skinT::ImplicitSkinTemperature,
constants::PhysicalConstants,
snow::Union{Nothing, Terrarium.AbstractSnow}
)
Compute skin_temperature from the current ground_heat_flux using the (optionally snow-aware) conduction target. constants supplies the material properties for the conduction blend; passing a snow component (default nothing) selects the snow-covered ground_thermal_interface, while snow === nothing recovers the snow-free soil conduction.
Terrarium.compute_ground_heat_flux! — Method
compute_ground_heat_flux!(
state,
grid,
skinT::Terrarium.AbstractSkinTemperature,
seb::Terrarium.AbstractSurfaceEnergyBalance
)
Compute ground_heat_flux as the residual $R_\text{net} + H_s + H_l$ (all fluxes positive upward).
Terrarium.default_skin_temperature_solver — Function
default_skin_temperature_solver(
_::Type{NF}
) -> Terrarium.RootSolver{NF, RootSolvers.NewtonsMethod{T}, RootSolvers.CompactSolution, RootSolvers.ResidualTolerance{NF}} where {NF, T<:Union{Real, AbstractArray}}
Construct the default solver for the implicit skin temperature: a Newton root-finder (RootSolver backed by RootSolvers.jl) with a small iteration budget.
Kernel functions
Terrarium.compute_skin_temperature — Method
compute_skin_temperature(
i,
j,
grid,
fields,
skinT::ImplicitSkinTemperature,
constants::PhysicalConstants
) -> Any
compute_skin_temperature(
i,
j,
grid,
fields,
skinT::ImplicitSkinTemperature,
constants::PhysicalConstants,
snow::Union{Nothing, Terrarium.AbstractSnow}
) -> Any
Estimate the skin temperature from the current ground_heat_flux at grid cell i, j, using the effective conduction target of the medium below the skin. The optional snow argument enables the snow-covered blend (see ground_thermal_interface); with snow === nothing this is the snow-free soil conduction.
Terrarium.compute_ground_heat_flux — Method
compute_ground_heat_flux(
i,
j,
grid,
fields,
skinT::Terrarium.AbstractSkinTemperature,
_::Terrarium.AbstractSurfaceEnergyBalance
) -> Any
Compute the ground heat flux from the surface net radiation and sensible/latent heat flux at grid cell i, j.
Terrarium.compute_ground_heat_flux! — Method
compute_ground_heat_flux!(
out,
i,
j,
grid,
fields,
skinT::Terrarium.AbstractSkinTemperature,
seb::Terrarium.AbstractSurfaceEnergyBalance
)
Per-cell mutating variant used by the fused surface-energy-balance kernel: store the ground heat flux into the auxiliary output field out.
Terrarium.compute_skin_temperature! — Method
compute_skin_temperature!(
out,
i,
j,
grid,
fields,
skinT::ImplicitSkinTemperature,
seb::Terrarium.AbstractSurfaceEnergyBalance,
constants::PhysicalConstants
)
compute_skin_temperature!(
out,
i,
j,
grid,
fields,
skinT::ImplicitSkinTemperature,
seb::Terrarium.AbstractSurfaceEnergyBalance,
constants::PhysicalConstants,
snow::Union{Nothing, Terrarium.AbstractSnow},
seb_args...
)
Recompute surface energy fluxes using compute_surface_energy_fluxes! and update the skin temperature based on the resulting ground heat flux.
Terrarium.compute_skin_temperature_residual! — Function
compute_skin_temperature_residual!(
out,
i,
j,
grid,
fields,
skinT::ImplicitSkinTemperature,
seb::Terrarium.AbstractSurfaceEnergyBalance,
snow,
constants,
seb_args...
) -> Any
Same as compute_skin_temperature! but returns the residual instead of updating the skin_temperature Field.
Terrarium.solve_skin_temperature! — Function
solve_skin_temperature!(
out,
i,
j,
grid,
fields,
skinT::ImplicitSkinTemperature,
seb::Terrarium.AbstractSurfaceEnergyBalance,
snow,
seb_args...
) -> Any
Run a full nonlinear solve to determine the skin_temperature at grid cell i, j that solves the surface energy balance.