API for the abiotic_tools module#
The models.abiotic.abiotic_tools module contains a set of general functions that
are shared across submodules in the
abiotic_model model.
TODO cross-check with pyrealm for duplication/ different implementation TODO change temperatures to Kelvin
Functions:
|
Build indices for different layers and variables for easier access. |
Calculate actual vapour pressure, [kPa]. |
|
|
Calculate the density of air using the ideal gas law. |
|
Calculate heights, layer thickness, and midpoints for atmospheric layers. |
Calculate latent heat of vapourisation. |
|
|
Calculate temperature-dependent molar density of air. |
Calculate slope of the saturated pressure curve. |
|
|
Calculate specific humidity. |
|
Calculate layer thickness for above ground layers only. |
Calculate layer thickness for varying canopy layers, true layers only. |
|
Convert a 2D radiation array into normalized weights that sum to 1. |
|
|
Fill layer template with index values. |
|
Find last valid value in array for each column. |
|
Test that values are finite and within bounds. |
Generate synthetic hourly forcing for one day from monthly averages. |
|
|
Create a data_record dict with a new leading time dimension. |
|
Return mean value over time for given variable and fill into layer structure. |
|
Record hourly data. |
|
Clean up outputs: set unintended NaNs to 0, preserve intended NaNs. |
Update a layer-based profile for a given time index using a reference variable. |
|
|
Validate all variables are in update dictionary. |
- virtual_ecosystem.models.abiotic.abiotic_tools.build_indices(data: Data, layer_structure: LayerStructure) SimpleNamespace[source]#
Build indices for different layers and variables for easier access.
- Parameters:
data – Data object
layer_structure – Layer structure object
- Returns:
SimpleNamespace with indices for different layers and variables
- virtual_ecosystem.models.abiotic.abiotic_tools.calculate_actual_vapour_pressure(air_temperature: DataArray, relative_humidity: DataArray, pyrealm_core_constants: CoreConst) DataArray[source]#
Calculate actual vapour pressure, [kPa].
- Parameters:
air_temperature – Air temperature, [C]
relative_humidity – Relative humidity, [-]
pyrealm_core_constants – Set of constants from pyrealm
- Returns:
actual vapour pressure, [kPa]
- virtual_ecosystem.models.abiotic.abiotic_tools.calculate_air_density(air_temperature: ndarray[tuple[Any, ...], dtype[floating]], atmospheric_pressure: ndarray[tuple[Any, ...], dtype[floating]], specific_gas_constant_dry_air: float, celsius_to_kelvin: float)[source]#
Calculate the density of air using the ideal gas law.
- Parameters:
air_temperature – Air temperature, [C]
atmospheric_pressure – Atmospheric pressure, [kPa]
specific_gas_constant_dry_air – Specific gas constant for dry air, [J kg-1 K-1]
celsius_to_kelvin – Factor to convert temperature in Celsius to absolute temperature in Kelvin
- Returns:
density of air, [kg m-3].
- virtual_ecosystem.models.abiotic.abiotic_tools.calculate_atmospheric_layer_geometry(data: Data, idx: SimpleNamespace, minimum_mixing_depth: float) dict[str, ndarray[tuple[Any, ...], dtype[floating]]][source]#
Calculate heights, layer thickness, and midpoints for atmospheric layers.
The midpoint values are distances in metres above ground for each cell. For layer heights below the surface layer, a minimum mixing depth is introduced. This is to prevent unrealistically low mixing depths and therefore high temperatures in the lowest canopy layer when the layer height is very low. Note that this is an artificial inflation of the mixing depth.
- Parameters:
data – Data object
idx – SimpleNamespace containing layer indices
minimum_mixing_depth – Minimum depth for lowest canopy layer, [m]
- Returns:
dict containing heights, thickness, layer_top, layer_midpoints
- virtual_ecosystem.models.abiotic.abiotic_tools.calculate_latent_heat_vapourisation(temperature: ndarray[tuple[Any, ...], dtype[floating]], celsius_to_kelvin: float, latent_heat_vap_equ_factors: tuple[float, float]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate latent heat of vapourisation.
Implementation after Eq. 8, Henderson-Sellers (1984).
- Parameters:
temperature – Air temperature, [C]
celsius_to_kelvin – Factor to convert temperature in Celsius to absolute temperature in Kelvin
latent_heat_vap_equ_factors – Factors in calculation of latent heat of vapourisation
- Returns:
latent heat of vapourisation, [kJ kg-1]
- virtual_ecosystem.models.abiotic.abiotic_tools.calculate_molar_density_air(temperature: ndarray[tuple[Any, ...], dtype[floating]], atmospheric_pressure: ndarray[tuple[Any, ...], dtype[floating]], standard_mole: float, standard_pressure: float, celsius_to_kelvin: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate temperature-dependent molar density of air.
Implementation after Maclean and Klinges (2021).
- Parameters:
temperature – Air temperature, [C]
atmospheric_pressure – Atmospheric pressure, [kPa]
standard_mole – Moles of ideal gas in 1 m^3 air at standard atmosphere
standard_pressure – Standard atmospheric pressure, [kPa]
celsius_to_kelvin – Factor to convert temperature in Celsius to absolute temperature in Kelvin
- Returns:
molar density of air, [mol m-3]
- virtual_ecosystem.models.abiotic.abiotic_tools.calculate_slope_of_saturated_pressure_curve(temperature: ndarray[tuple[Any, ...], dtype[floating]], saturated_pressure_slope_parameters: tuple[float, float, float, float]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate slope of the saturated pressure curve.
- Parameters:
temperature – Temperature, [C]
saturated_pressure_slope_parameters – List of parameters to calculate the slope of the saturated vapour pressure curve
- Returns:
Slope of the saturated pressure curve, \(\Delta_{v}\)
- virtual_ecosystem.models.abiotic.abiotic_tools.calculate_specific_humidity(air_temperature: ndarray[tuple[Any, ...], dtype[floating]], relative_humidity: ndarray[tuple[Any, ...], dtype[floating]], atmospheric_pressure: ndarray[tuple[Any, ...], dtype[floating]], molecular_weight_ratio_water_to_dry_air: float, pyrealm_core_constants: CoreConst) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate specific humidity.
- Parameters:
air_temperature – Air temperature, [C]
relative_humidity – Relative humidity, [%]
atmospheric_pressure – Atmospheric pressure, [kPa]
molecular_weight_ratio_water_to_dry_air – The ratio of the molar mass of water vapour to the molar mass of dry air
pyrealm_core_constants – Pyrealm core constants
- Returns:
Specific humidity, [kg kg-1]
- virtual_ecosystem.models.abiotic.abiotic_tools.compute_aboveground_layer_thickness(heights: ndarray[tuple[Any, ...], dtype[floating]]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate layer thickness for above ground layers only.
Calculate layer thickness by subtracting from the next valid layer below (skipping NaNs), and for the last valid layer in each column subtract from zero (ground level). Soil layers are set to NaN.
- Parameters:
heights – 2D array of layer heights, [m]
- Returns:
2D array of layer thickness, [m], same shape as input
- virtual_ecosystem.models.abiotic.abiotic_tools.compute_layer_thickness_for_varying_canopy(heights: ndarray[tuple[Any, ...], dtype[floating]]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate layer thickness for varying canopy layers, true layers only.
Calculate layer thickness by subtracting from the next valid layer below (skipping NaNs), and for the last valid layer in each column subtract from zero (ground level).
- Parameters:
heights – 2D array of layer heights, [m]
- Returns:
2D array of layer thickness, [m], same shape as input
- virtual_ecosystem.models.abiotic.abiotic_tools.compute_weights_from_absorbed_radiation(radiation: ndarray[tuple[Any, ...], dtype[floating]]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Convert a 2D radiation array into normalized weights that sum to 1.
Weights sum to 1 along the layer axis (axis=0) for each cell independently, ignoring NaN values. NaN entries in the input remain NaN in the output. Cells where all valid radiation is zero return NaN weights — these are cells with no canopy and no radiation to distribute.
- Parameters:
radiation – 2D array of absorbed radiation values for each layer and cell
- Returns:
2D array of normalized weights corresponding to the absorbed radiation
- virtual_ecosystem.models.abiotic.abiotic_tools.fill_layer_template(layer_structure: LayerStructure, assignments: list[tuple]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Fill layer template with index values.
- Parameters:
layer_structure – LayerStructure
assignments – list of variable names, indices and values
- Returns:
array with updated indices
- virtual_ecosystem.models.abiotic.abiotic_tools.find_last_valid_row(array: ndarray[tuple[Any, ...], dtype[floating]]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Find last valid value in array for each column.
This function looks for the last valid value in each column of a 2-dimensional array. If the previous value is nan, it moved up the array. If all values are NaN, the value is set to NaN, too.
- Parameters:
array – Two-dimesional array for which last valid values should be found
- Returns:
Array that contains last valid values
- virtual_ecosystem.models.abiotic.abiotic_tools.finite_and_within(arr: DataArray, low: float, high: float, name: str) None[source]#
Test that values are finite and within bounds.
- Parameters:
arr – Output DataArray to be tested
low – Minimum value
high – maximum value
name – name of variable
- Returns:
None.
- Raises:
AssertionError – if values are not finite or outside bounds.
- virtual_ecosystem.models.abiotic.abiotic_tools.generate_diurnal_cycle_from_monthly_data(monthly_air_temperature: ndarray[tuple[Any, ...], dtype[floating]], monthly_shortwave_absorption: ndarray[tuple[Any, ...], dtype[floating]], monthly_relative_humidity: ndarray[tuple[Any, ...], dtype[floating]], monthly_evapotranspiration: ndarray[tuple[Any, ...], dtype[floating]], monthly_soil_evaporation: ndarray[tuple[Any, ...], dtype[floating]], latitude_deg: float, month: int, days: int, daily_temp_amplitude: float = 5.0) dict[str, ndarray[tuple[Any, ...], dtype[floating]]][source]#
Generate synthetic hourly forcing for one day from monthly averages.
- Parameters:
monthly_air_temperature – Monthly mean air temperature [C]
monthly_shortwave_absorption – Monthly mean daily shortwave absorption [W m-2]
monthly_relative_humidity – Monthly mean relative humidity [%]
monthly_evapotranspiration – Monthly total evapotranspiration [mm/month]
monthly_soil_evaporation – Monthly total soil evaporation [mm/month]
latitude_deg – Latitude for daylength calculation [deg]
month – Month number [1-12]
days – Number of days in month
daily_temp_amplitude – typical diurnal temperature swing [C]
- Returns:
dict of arrays air_temperature_hourly, shortwave_absorption_hourly, relative_humidity_hourly, evapotranspiration_hourly, soil_evaporation_hourly
- virtual_ecosystem.models.abiotic.abiotic_tools.initialize_data_record(variables: dict[str, DataArray], time_dim: int, layers: int, cell_ids: int) dict[str, ndarray[tuple[Any, ...], dtype[floating]]][source]#
Create a data_record dict with a new leading time dimension.
Assumptions are that 1D variables have shape (cell_ids,) and 2D variables have shape (layers, cell_ids).
- Parameters:
variables – Dictionary of variable names to template arrays
time_dim – Size of the new time dimension (e.g. 24)
layers – Number of layers
cell_ids – Number of cell ids
- Returns:
Dictionary with initialized arrays filled with NaNs.
- Raises:
ValueError – is number of dimensions cannot be matched
- virtual_ecosystem.models.abiotic.abiotic_tools.mean_to_layers(var: str, index: list[int], data_record: dict, layer_structure: LayerStructure) DataArray[source]#
Return mean value over time for given variable and fill into layer structure.
- Parameters:
var – Variable name
index – List of layer indices to fill
data_record – Data record dict
layer_structure – LayerStructure object
- Returns:
DataArray with mean values filled into layer structure
- virtual_ecosystem.models.abiotic.abiotic_tools.record_hourly_output(hour: int, data_record: dict, hourly_values: dict)[source]#
Record hourly data.
- Parameters:
hour – Hour of the day
data_record – dict that contains all hourly data
hourly_values – Hourly values
- Returns:
updated dict with hour values
- virtual_ecosystem.models.abiotic.abiotic_tools.set_unintended_nan_to_zero(input_array: ndarray[tuple[Any, ...], dtype[floating]], input_nan_mask: ndarray[tuple[Any, ...], dtype[bool]]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Clean up outputs: set unintended NaNs to 0, preserve intended NaNs.
- Parameters:
input_array – Input array that may contain NaN
input_nan_mask – A mask of intended NaN
- Returns:
Array with unintended NaN set to zero
- virtual_ecosystem.models.abiotic.abiotic_tools.update_profile_from_reference(layer_structure: LayerStructure, mask_variable: DataArray, variable_name: DataArray, time_index: int) DataArray[source]#
Update a layer-based profile for a given time index using a reference variable.
This function
extracts a mask from air temperature to determine valid atmosphere layers
reads the reference variable at the given time index
applies the mask to keep only valid layers
fills the profile template for those layers
- Parameters:
layer_structure – LayerStructure object defining the layer setup
mask_variable – DataArray used to create the atmospheric mask
variable_name – Reference variable (e.g. data[“atmospheric_pressure_ref”])
time_index – Index of the current time step
- Returns:
Updated layer profile as a DataArray
- virtual_ecosystem.models.abiotic.abiotic_tools.validate_variables(names: tuple[str, ...], values: dict[str, object], exclude: Iterable[str] = ()) None[source]#
Validate all variables are in update dictionary.
- Parameters:
names – variable names in output
values – variables in hourly update
exclude – variable names to ignore in the comparison
- Returns:
None
- Raises:
ValueError – if variable mismatch is detected.