API for the energy_balance
module
The models.abiotic.energy_balance
module calculates the energy balance for the
Virtual Ecosystem. Given that the time increments of the model are an hour or longer,
we can assume that below-canopy heat and vapour exchange attain steady state and heat
storage in the canopy does not need to be simulated explicitly.
(For application where very fine-temporal resolution data might be needed, heat and
vapour exchange must be modelled as transient processes, and heat storage by the canopy,
and the exchange of heat between different layers of the canopy, must be considered
explicitly, see Maclean and Klinges (2021). This is currently not implemented.)
Under steady-state, the balance equation for the leaves in each canopy layer is as follows (after Maclean and Klinges (2021)):
where \(R_{abs}\) is absorbed radiation, \(R_{em}\) emitted radiation, \(H\) the sensible heat flux, \(\lambda E\) the latent heat flux, \(\epsilon_{s}\) the emissivity of the leaf, \(\sigma\) the Stefan-Boltzmann constant, \(T_{L}\) the absolute temperature of the leaf, \(T_{A}\) the absolute temperature of the air surrounding the leaf, \(\lambda\) the latent heat of vapourisation of water, \(e_{L}\) the effective vapour pressure of the leaf, \(e_{A}\) the vapour pressure of air and \(p_{A}\) atmospheric pressure. \(g_{Ha}\) is the heat conductance between leaf and atmosphere, \(g_{v}\) represents the conductance for vapour loss from the leaves as a function of the stomatal conductance \(g_{c}\).
A challenge in solving this equation is the dependency of latent heat and emitted radiation on leaf temperature. We use a linearisation approach to solve the equation for leaf temperature and air temperature simultaneously after Maclean and Klinges (2021).
The soil energy balance functions are described in
soil_energy_balance
.
The conductivities are calculated as described in
conductivities
.
Functions:
Calculate change in canopy temperature (delta). |
|
|
Calculate leaf and air temperature under steady state. |
|
Calculate longwave emission using the Stefan Boltzmann law, [W m-2]. |
Calculate slope of the saturated pressure curve. |
|
Calculate initial light absorption profile. |
|
Initialise canopy temperature and energy fluxes. |
|
Initialise canopy temperature. |
|
Calculate factors for latent heat flux linearisation. |
|
Calculate factors for leaf and air temperature linearisation. |
|
|
Calculate factors for longwave radiative flux linearisation. |
Calculate factors for vapour pressure linearisation. |
- virtual_ecosystem.models.abiotic.energy_balance.calculate_delta_canopy_temperature(absorbed_radiation: ndarray[Any, dtype[float32]], a_R: ndarray[Any, dtype[float32]], a_L: ndarray[Any, dtype[float32]], b_R: ndarray[Any, dtype[float32]], b_L: ndarray[Any, dtype[float32]], b_H: ndarray[Any, dtype[float32]]) ndarray[Any, dtype[float32]]
Calculate change in canopy temperature (delta).
- Parameters:
absorbed_radiation – Radiation (shortwave) absorved by canopy, [W m-2]
a_R – Factor for longwave radiation emission linearisation
a_L – Factor for latent heat flux linearisation
b_R – Factor for longwave radiation emission linearisation
b_L – Factor for latent heat flux linearisation
b_H – Factor for sensible heat flux linearisation
- Returns:
Change in canopy temperature, [C]
- virtual_ecosystem.models.abiotic.energy_balance.calculate_leaf_and_air_temperature(data: Data, time_index: int, topsoil_layer_index: int, true_canopy_indexes: ndarray[Any, dtype[integer]], true_canopy_layers_n: int, layer_structure: LayerStructure, abiotic_constants: AbioticConsts, abiotic_simple_constants: AbioticSimpleConsts, core_constants: CoreConsts) dict[str, DataArray]
Calculate leaf and air temperature under steady state.
The air temperature surrounding the leaf \(T_{A}\) is assumed to be influenced by leaf temperature \(T_{L}\), soil temperature \(T_{0}\), and reference air temperature \(T_{R}\) as follows:
\[g_{tR} c_{p} (T_{R} - T_{A}) + g_{t0} c_{p} (T_{0} - T_{A}) + g_{L} c_{p} (T_{L} - T_{A}) = 0\]where \(c_{p}\) is the specific heat of air at constant pressure and \(g_{tR}\), \(g_{t0}\) and \(g_{L}\) are conductance from reference height, the ground and from the leaf, respectively. \(g_{L} = 1/(1/g_{HA} + 1/g_{z})\) where \(g_{HA}\) is leaf boundary layer conductance and \(g_{z}\) is the sub-canopy turbulent conductance at the height of the leaf over the mean distance between the leaf and the air.
Defining \(T_{L} - T_{A}\) as \(\Delta T\) and rearranging gives:
\[T_{A} = a_{A} + b_{A} \Delta T_{L}\]where \(a_{A} = \frac{(g_{tR} T_{R} + g_{t0} T_{0})}{(g_{tR} + g_{t0})}\) and \(b_{A} = \frac{g_{L}}{(g_{tR} + g_{t0})}\) .
The sensible heat flux between the leaf and the air is given by
\[g_{Ha} c_{p} (T_{L} - T_{A}) = b_{H} \Delta T_{L}\]where \(b_{H} = g_{Ha} c_{p}\). The equivalent vapour flux equation is
\[g_{tR}(e_{R} - e_{a}) + g_{t0} (e_{0} - e_{a}) + g_{v} (e_{L} - e_{a}) = 0\]where \(e_{L}\), \(e_{A}\), \(e_{0}\) and \(e_{R}\) are the vapour pressure of the leaf, air, soil and air at reference height, respectively, and \(g_{v}\) is leaf conductance for vapour given by \(g_{v} = \frac{1}{(\frac{1}{g_{c} + g_{L})}}\) where \(g_{c}\) is stomatal conductance. Assuming the leaf to be saturated, and approximated by \(e_{s} [T_{R}]+\Delta_{v} [T_{R}]\Delta T_{L}\) where \(\Delta_{v}\) is the slope of the saturated pressure curve at temperature \(T_{R}\), and rearranging gives
\[e_{a} = a_{E} + b_{E} \Delta T_{L}\]where \(a_{E} = \frac{(g_{tR} e_{R} + g_{t0} e_{0} + g_{v} e_{s}[T_{R}])} {(g_{tR} + g_{t0} + g_{v})}\) and \(b_{E} = \frac{\Delta_{V} [T_{R}])}{(g_{tR} + g_{t0} + g_{v})}\).
The latent heat term is given by
\[\lambda E = \frac{\lambda g_{v}}{p_{a}} (e_{L} - e_{A})\]Substituting \(e_{A}\) for its linearized form, again assuming \(e_{L}\) is approximated by \(e_{s} [T_{R}]+\Delta_{v} [T_{R}]\Delta T_{L}\), and rearranging gives:
\[\lambda E = a_{L} + b_{L} \Delta T_{L},\]where \(a_{L} = \frac{\lambda g_{v}}{p_{a}} (e_{s} [T_{R}] - a_{E})\) and \(b_{L} = \frac{\lambda g_{v}}{p_{a}} (\Delta_{V} [T_{R}] - b_{E})\).
The radiation emitted by the leaf \(R_{em}\) is given by the Stefan Boltzmann law and can be linearised as follows:
\[R_{em} = a_{R} + b_{R} \Delta T_{L}\]where \(a_{R} = \epsilon_{s} \sigma a_{A}^{4}\) and \(b_{R} = 4 \epsilon_{s} \sigma (a_{A}^{3} b_{A} + T_{R}^{3})\).
The full heat balance equation for the difference between leaf and canopy air temperature becomes
\[\Delta T_{L} = \frac{R_{abs} - a_{R} - a_{L}}{(1 + b_{R} + b_{L} + b_{H})}\]The equation is then used to calculate air and leaf temperature as follows:
\[T_{A} = a_{A} + b_{A} \Delta T_{L}\]and
\[T_{L} = T_{A} + \Delta T_{L}.\]the data object has to contain the previous and current values for the following:
air_temperature_ref: Air temperature at reference height 2m above canopy, [C]
vapour_pressure_ref: vapour pressure at reference height 2m above canopy, [kPa]
soil_temperature: Soil temperature, [C]
soil_moisture: Soil moisture, [mm]
layer_heights: Layer heights, [mm]
atmospheric_pressure_ref: Atmospheric pressure at reference height, [kPa]
air_temperature: Air temperature, [C]
canopy_temperature: Leaf temperature, [C]
latent_heat_vapourisation: Latent heat of vapourisation, [J kg-1]
absorbed_radiation: Absorbed radiation, [W m-2]
specific_heat_air: Specific heat of air, [J mol-1 K-1]
TODO * add latent heat flux from soil to atmosphere (-> VPD) * check time integration * set limits to temperature and VPD
- Parameters:
data – Instance of data object
time_index – Time index
topsoil_layer_index – Index of top soil layer
true_canopy_indexes – indexes of canopy layers that are not NaN
true_canopy_layers_n – Maximum number of canopy layers that are not NaN
layer_structure – Instance of LayerStructure that countains details about layers
abiotic_constants – Set of abiotic constants
abiotic_simple_constants – Set of abiotic constants
core_constants – Set of core constants
- Returns:
air temperature, [C], canopy temperature, [C], vapour pressure [kPa], vapour pressure deficit, [kPa]
- virtual_ecosystem.models.abiotic.energy_balance.calculate_longwave_emission(temperature: ndarray[Any, dtype[float32]], emissivity: float | ndarray[Any, dtype[float32]], stefan_boltzmann: float) ndarray[Any, dtype[float32]]
Calculate longwave emission using the Stefan Boltzmann law, [W m-2].
According to the Stefan Boltzmann law, the amount of radiation emitted per unit time from the area of a black body at absolute temperature is directly proportional to the fourth power of the temperature. Emissivity (which is equal to absorptive power) lies between 0 to 1.
- Parameters:
temperature – Temperature, [K]
emissivity – Emissivity, dimensionless
stefan_boltzmann – Stefan Boltzmann constant, [W m-2 K-4]
- Returns:
Longwave emission, [W m-2]
- virtual_ecosystem.models.abiotic.energy_balance.calculate_slope_of_saturated_pressure_curve(temperature: ndarray[Any, dtype[float32]], saturated_pressure_slope_parameters: list[float]) ndarray[Any, dtype[float32]]
Calculate slope of the saturated pressure curve.
- Parameters:
temperature – Temperature, [C]
saturated_pressure_slope_parameters – List of parameters to calcualte the slope of the saturated vapour pressure curve
- Returns:
Slope of the saturated pressure curve, \(\Delta_{v}\)
- virtual_ecosystem.models.abiotic.energy_balance.initialise_absorbed_radiation(topofcanopy_radiation: ndarray[Any, dtype[float32]], leaf_area_index: ndarray[Any, dtype[float32]], layer_heights: ndarray[Any, dtype[float32]], light_extinction_coefficient: float) ndarray[Any, dtype[float32]]
Calculate initial light absorption profile.
This function calculates the fraction of radiation absorbed by a multi-layered canopy based on its leaf area index (\(LAI\)) and extinction coefficient (\(k\)) at each layer, the depth of each measurement (\(z\)), and the incoming light intensity at the top of the canopy (\(I_{0}\)). The implementation based on Beer’s law:
\[I(z) = I_{0} * e^{(-k * LAI * z)}\]- Parameters:
topofcanopy_radiation – Top of canopy radiation shortwave radiation, [W m-2]
leaf_area_index – Leaf area index of each canopy layer, [m m-1]
layer_heights – Layer heights, [m]
light_extinction_coefficient – Light extinction coefficient, [m-1]
- Returns:
Shortwave radiation absorbed by canopy layers, [W m-2]
- virtual_ecosystem.models.abiotic.energy_balance.initialise_canopy_and_soil_fluxes(air_temperature: DataArray, topofcanopy_radiation: DataArray, leaf_area_index: DataArray, layer_heights: DataArray, true_canopy_indexes: ndarray[Any, dtype[integer]], topsoil_layer_index: int, light_extinction_coefficient: float, canopy_temperature_ini_factor: float) dict[str, DataArray]
Initialise canopy temperature and energy fluxes.
This function initializes the following variables to run the first step of the energy balance routine: absorbed radiation (canopy), canopy temperature, sensible and latent heat flux (canopy and soil), and ground heat flux.
- Parameters:
air_temperature – Air temperature, [C]
topofcanopy_radiation – Top of canopy radiation, [W m-2]
leaf_area_index – Leaf area index, [m m-2]
layer_heights – Layer heights, [m]
true_canopy_indexes – Indexes of canopy layers that are not NaN (maximum extent to capture all depths even if grid cells have different number of layers)
topsoil_layer_index – Index of topsoil layer
light_extinction_coefficient – Light extinction coefficient for canopy
canopy_temperature_ini_factor – Factor used to initialise canopy temperature as a function of air temperature and absorbed shortwave radiation
- Returns:
- Dictionary with absorbed radiation (canopy), canopy temperature, sensible
and latent heat flux (canopy and soil), and ground heat flux.
- virtual_ecosystem.models.abiotic.energy_balance.initialise_canopy_temperature(air_temperature: ndarray[Any, dtype[float32]], absorbed_radiation: ndarray[Any, dtype[float32]], canopy_temperature_ini_factor: float) ndarray[Any, dtype[float32]]
Initialise canopy temperature.
- Parameters:
air_temperature – Air temperature, [C]
canopy_temperature_ini_factor – Factor used to initialise canopy temperature as a function of air temperature and absorbed shortwave radiation
absorbed_radiation – Shortwave radiation absorbed by canopy
- Returns:
Initial canopy temperature, [C]
- virtual_ecosystem.models.abiotic.energy_balance.latent_heat_flux_linearisation(latent_heat_vapourisation: ndarray[Any, dtype[float32]], leaf_vapour_conductivity: ndarray[Any, dtype[float32]], atmospheric_pressure_ref: ndarray[Any, dtype[float32]], saturated_vapour_pressure_ref: ndarray[Any, dtype[float32]], a_E: ndarray[Any, dtype[float32]], b_E: ndarray[Any, dtype[float32]], delta_v_ref: ndarray[Any, dtype[float32]]) tuple[ndarray[Any, dtype[float32]], ndarray[Any, dtype[float32]]]
Calculate factors for latent heat flux linearisation.
- Parameters:
latent_heat_vapourisation – latent heat of vapourisation
leaf_vapour_conductivity – leaf vapour conductivity, [mol m-2 s-1]
atmospheric_pressure_ref – Atmospheric pressure at reference height 2 m above canopy, [kPa]
saturated_vapour_pressure_ref – Satuated vapour pressure at reference height 2 m above canopy, [kPa]
a_E – Factor for vapour pressure linearisation
b_E – Factor for vapour pressure linearisation
delta_v_ref – Slope of saturated vapour pressure curve
- Returns:
Factors a_L and b_L for latent heat flux linearisation
- virtual_ecosystem.models.abiotic.energy_balance.leaf_and_air_temperature_linearisation(conductivity_from_ref_height: ndarray[Any, dtype[float32]], conductivity_from_soil: ndarray[Any, dtype[float32]], leaf_air_heat_conductivity: ndarray[Any, dtype[float32]], air_temperature_ref: ndarray[Any, dtype[float32]], top_soil_temperature: ndarray[Any, dtype[float32]]) tuple[ndarray[Any, dtype[float32]], ndarray[Any, dtype[float32]]]
Calculate factors for leaf and air temperature linearisation.
- Parameters:
conductivity_from_ref_height – Conductivity from reference height, [mol m-2 s-2]
conductivity_from_soil – Conductivity from soil, [mol m-2 s-2]
leaf_air_heat_conductivity – Leaf air heat conductivity, [mol m-2 s-2]
air_temperature_ref – Air temperature at reference height 2m above the canopy,[C]
top_soil_temperature – Top soil temperature, [C]
- Returns:
Factors a_A and b_A for leaf and air temperature linearisation
- virtual_ecosystem.models.abiotic.energy_balance.longwave_radiation_flux_linearisation(a_A: ndarray[Any, dtype[float32]], b_A: ndarray[Any, dtype[float32]], air_temperature_ref: ndarray[Any, dtype[float32]], leaf_emissivity: float, stefan_boltzmann_constant: float) tuple[ndarray[Any, dtype[float32]], ndarray[Any, dtype[float32]]]
Calculate factors for longwave radiative flux linearisation.
- Parameters:
a_A – Factor for leaf and air temperature linearisation
b_A – Factor for leaf and air temperature linearisation
air_temperature_ref – Air temperature at reference height 2m above the canopy,[C]
leaf_emissivity – Leaf emissivity, dimensionless
stefan_boltzmann_constant – Stefan Boltzmann constant, [W m-2 K-4]
- Returns:
Factors a_R and b_R for longwave radiative flux linearisation
- virtual_ecosystem.models.abiotic.energy_balance.vapour_pressure_linearisation(vapour_pressure_ref: ndarray[Any, dtype[float32]], saturated_vapour_pressure_ref: ndarray[Any, dtype[float32]], soil_vapour_pressure: ndarray[Any, dtype[float32]], conductivity_from_soil: ndarray[Any, dtype[float32]], leaf_vapour_conductivity: ndarray[Any, dtype[float32]], conductivity_from_ref_height: ndarray[Any, dtype[float32]], delta_v_ref: ndarray[Any, dtype[float32]]) tuple[ndarray[Any, dtype[float32]], ndarray[Any, dtype[float32]]]
Calculate factors for vapour pressure linearisation.
- Parameters:
vapour_pressure_ref – Vapour pressure at reference height 2 m above canopy, [kPa]
saturated_vapour_pressure_ref – Saturated vapour pressure at reference height 2 m above canopy, [kPa]
soil_vapour_pressure – Soil vapour pressure, [kPa]
conductivity_from_soil – Conductivity from soil TODO unit
leaf_vapour_conductivity – Leaf vapour conductivity, [mol m-2 s-1]
conductivity_from_ref_height – Conductivity frm reference height, [mol m-2 s-1]
delta_v_ref – Slope of saturated vapour pressure curve
- Returns:
Factors a_E and b_E for vapour pressure linearisation