API for the wind module#
The wind module calculates the above- and within-canopy wind profile for the Virtual Ecosystem. The wind profile determines the exchange of heat, water, and \(CO_{2}\) between soil and atmosphere below the canopy as well as the exchange with the atmosphere above the canopy.
Functions:
Remove water by advection from above canopy layer. |
|
Calculate aerodynamic resistance in canopy. |
|
Calculate aerodynamic resistance in understorey. |
|
Calculate friction velocity. |
|
Calculate turbulent mixing coefficients within canopy. |
|
Calculate roughness length governing momentum transfer. |
|
Calculate ventilation rate from the top of the canopy to atmosphere above. |
|
|
Calculate wind speed profile. |
Calculate zero plane displacement height. |
|
|
Clamp an array of canopy data within limits. |
|
Apply vertical mixing and top-layer ventilation across multiple vertical layers. |
|
Index of nearest valid value above each layer. |
|
Index of nearest valid value below each layer. |
- virtual_ecosystem.models.abiotic.wind.advect_water_from_toplayer(specific_humidity: ndarray[tuple[Any, ...], dtype[floating]], layer_thickness: ndarray[tuple[Any, ...], dtype[floating]], density_air: ndarray[tuple[Any, ...], dtype[floating]], wind_speed: ndarray[tuple[Any, ...], dtype[floating]], characteristic_length: float, time_interval: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Remove water by advection from above canopy layer.
- Parameters:
specific_humidity – Specific humidity in top layer, [kg kg-1]
layer_thickness – Thickness of top layer, [m]
density_air – Air density in top layer, [kg m-3]
wind_speed – Horizontal wind speed above canopy, [m s-1]
characteristic_length – Horizontal length scale of the grid cell, [m]
time_interval – Time step, [s]
- Returns:
Updated specific humidity array after advection from the top layer.
- virtual_ecosystem.models.abiotic.wind.calculate_aerodynamic_resistance(wind_heights: ndarray[tuple[Any, ...], dtype[floating]], roughness_length: ndarray[tuple[Any, ...], dtype[floating]], zero_plane_displacement: ndarray[tuple[Any, ...], dtype[floating]], wind_speed: ndarray[tuple[Any, ...], dtype[floating]], von_karman_constant: float, fallback_resistance: float, denominator_tolerance: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate aerodynamic resistance in canopy.
The aerodynamic resistance \(r_{a}\) is calculated as (based on Jansson and Karlberg (2004)):
\[r_{a} = \frac{ln(\frac{z-d}{z_{m}})^{2}}{\kappa ^{2} u(z)}\]where \(z\) is the height where the aerodynamic resistance needs to be calculated, \(d\) is the zero plane displacement height, \(z_{m}\) is the roughness length of momentum, \(\kappa\) is the von Karman constant, and \(u(z)\) is the wind speed at height \(z\).
- Parameters:
wind_heights – Heights where wind speed is to be calculated, [m].
roughness_length – Momentum roughness length, [m]
zero_plane_displacement – Height above the actual ground where the wind speed is theoretically reduced to zero due to the obstruction caused by the roughness elements (like trees or buildings), [m]
wind_speed – Wind speed, [m s-1]
von_karman_constant – Von Karman’s constant, dimensionless constant describing the logarithmic velocity profile of a turbulent fluid near a no-slip boundary.
fallback_resistance – Fallback aerodynamic resistance value, [s m-1]
denominator_tolerance – Minimum value for denominator to avoid division by zero
- Returns:
aerodynamic resistance in canopy, [s m-1]
- virtual_ecosystem.models.abiotic.wind.calculate_aerodynamic_resistance_understorey(wind_speed_understorey: ndarray[tuple[Any, ...], dtype[floating]], coefficient_aerodynamic_resistance_understorey: float, min_wind_speed: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate aerodynamic resistance in understorey.
The aerodynamic resistance below the canopy is calculated using an empirical coefficient multiplied by the inverse of the wind speed within the understorey following Ogée and Brunet (2002)
- Parameters:
wind_speed_understorey – Wind speed below the canopy, [m s-1]
coefficient_aerodynamic_resistance_understorey – Empirical coefficient for calculating aerodynamic resistance below the canopy, [s m-2]
min_wind_speed – Minimum wind speed to avoid division by zero, [m s-1]
- Returns:
Aerodynamic resistance below the canopy, [s m-1]
- virtual_ecosystem.models.abiotic.wind.calculate_friction_velocity(reference_wind_speed: ndarray[tuple[Any, ...], dtype[floating]], reference_height: ndarray[tuple[Any, ...], dtype[floating]], roughness_length: ndarray[tuple[Any, ...], dtype[floating]], zero_plane_displacement: ndarray[tuple[Any, ...], dtype[floating]], von_karman_constant: float, denominator_tolerance: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate friction velocity.
Friction velocity is a measure of the shear stress exerted by the wind on the Earth’s surface, representing the velocity scale that relates to turbulent energy transfer near the surface.
The friction velocity (\(u_{*}\), [m s-1]) is calculated as (based on Holmes and Bekele (2020)):
\(u_{*} = \frac{\kappa u}{\ln{(\frac{z - d}{z_0})}}\)
Where \(\kappa\) is the von Kármán constant, \(u\) is the reference wind speed, \(z\) is the reference height, \(d\) is the zero plane displacement height, and \(z_{0}\) is the roughness length.
- Parameters:
reference_wind_speed – Reference wind speed above the canopy [m s-1].
reference_height – Reference height above the canopy, [m].
roughness_length – Momentum roughness length, [m]
zero_plane_displacement – Height above the actual ground where the wind speed is theoretically reduced to zero due to the obstruction caused by the roughness elements (like trees or buildings), [m]
von_karman_constant – Von Karman’s constant, dimensionless constant describing the logarithmic velocity profile of a turbulent fluid near a no-slip boundary.
denominator_tolerance – Minimum value for denominator to avoid division by zero
- Returns:
Friction velocity, [m s-1].
- virtual_ecosystem.models.abiotic.wind.calculate_mixing_coefficients_canopy(layer_midpoints: ndarray[tuple[Any, ...], dtype[floating]], canopy_height: ndarray[tuple[Any, ...], dtype[floating]], friction_velocity: ndarray[tuple[Any, ...], dtype[floating]], von_karman_constant: float, max_mixing_coefficient: float, denominator_tolerance: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate turbulent mixing coefficients within canopy.
This function calculates turbulent mixing coefficients for heat (\(k_H\)) and momentum (\(k_M\)) that are used to mix water and energy in the canopy. Inside the canopy, turbulence is strongly damped by vegetation drag, and a simple linear profile like used for the top of the canopy like \(k_{H,M} = \kappa u_{*}(z-d)\) (Raupach et al., 1996) does not match observed eddy diffusivity well. Instead, empirical profiles based on measurements are used, and these often take parabolic or other non-linear forms like :
\[k_{H,M}(z)=\kappa u_{*}z(\frac{1-z}{h_c})^{2}\]where \(\kappa\) is the von Karman constant (dimensionless), \(u_{*}\) is the friction velocity (m s-1), \(z\) is the height (m) for which coefficients are calculated, and \(h_c\) is the canopy height (m).
This particular form goes to zero at both z=0 and z=h and peaks somewhere within the canopy.
- Parameters:
layer_midpoints – The midpoints of all air layers, [m]
canopy_height – Canopy height, [m]
friction_velocity – Friction velocity, [m s-1]
von_karman_constant – Von Karman’s constant, dimensionless constant describing the logarithmic velocity profile of a turbulent fluid near a no-slip boundary.
max_mixing_coefficient – Maximum mixing coefficient
denominator_tolerance – Minimum value for denominator to avoid division by zero
- Returns:
turbulent mixing coefficients, [m2 s-1]
- virtual_ecosystem.models.abiotic.wind.calculate_roughness_length_momentum(canopy_height: ndarray[tuple[Any, ...], dtype[floating]], leaf_area_index: ndarray[tuple[Any, ...], dtype[floating]], zero_plane_displacement: ndarray[tuple[Any, ...], dtype[floating]], substrate_surface_roughness_length: float, roughness_element_drag_coefficient: float, roughness_sublayer_depth_parameter: float, max_ratio_wind_to_friction_velocity: float, min_roughness_length: float, von_karman_constant: float, denominator_tolerance: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate roughness length governing momentum transfer.
Roughness length is defined as the height at which the mean velocity is zero due to substrate roughness. Real surfaces such as the ground or vegetation are not smooth and often have varying degrees of roughness. Roughness length accounts for that effect. Implementation after Maclean and Klinges (2021).
- Parameters:
canopy_height – Canopy height, [m]
leaf_area_index – Total leaf area index, [m m-1]
zero_plane_displacement – Height above the actual ground where the wind speed is theoretically reduced to zero due to the obstruction caused by the roughness elements (like trees or buildings), [m]
substrate_surface_roughness_length – Substrate-surface roughness length is the baseline roughness of the ground itself before adding vegetation, [m]
roughness_element_drag_coefficient – Roughness-element drag coefficient
roughness_sublayer_depth_parameter – Parameter that characterizes the roughness sublayer depth, dimensionless
max_ratio_wind_to_friction_velocity – Maximum ratio of wind velocity to friction velocity, dimensionless
min_roughness_length – Minimum roughness length, [m]
von_karman_constant – Von Karman’s constant, dimensionless constant describing the logarithmic velocity profile of a turbulent fluid near a no-slip boundary.
denominator_tolerance – Minimum value for denominator to avoid division by zero
- Returns:
Momentum roughness length, [m]
- virtual_ecosystem.models.abiotic.wind.calculate_ventilation_rate(aerodynamic_resistance: float | ndarray[tuple[Any, ...], dtype[floating]], characteristic_height: float | ndarray[tuple[Any, ...], dtype[floating]], understorey_ventilation_rate: float, surface_layer_height: float, denominator_tolerance: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate ventilation rate from the top of the canopy to atmosphere above.
This function calculates the rate of water and heat exchange between the top of the canopy and the atmosphere above after Wolfe et al. (2011).
If the canopy height is zero, the value is set to a default value for understorey ventilation.
- Parameters:
aerodynamic_resistance – Aerodynamic resistance, [s m-1]
characteristic_height – Vertical scale of exchange, typically canopy height + zero plane displacement height [m]
understorey_ventilation_rate – Understorey ventilation rate, [s-1]. This is used in case there is no canopy.
surface_layer_height – Height of the surface layer, [m]
denominator_tolerance – Minimum value for denominator to avoid division by zero
- Returns:
Ventilation rate [s-1]
- virtual_ecosystem.models.abiotic.wind.calculate_wind_profile(reference_wind_speed: ndarray[tuple[Any, ...], dtype[floating]], reference_height: float | ndarray[tuple[Any, ...], dtype[floating]], wind_heights: ndarray[tuple[Any, ...], dtype[floating]], roughness_length: ndarray[tuple[Any, ...], dtype[floating]], zero_plane_displacement: ndarray[tuple[Any, ...], dtype[floating]], min_wind_speed: float, denominator_tolerance: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate wind speed profile.
The wind speed at different heights is calculated using the following equation (based on Holmes and Bekele (2020)):
\[u(z) = u_{ref} \times \frac{ \ln \left( \frac{z - d}{z_0} \right) } { \ln \left( \frac{z_{ref} - d}{z_0} \right) }\]where \(u(z)\) is the wind speed at height \(z\), \(u_{ref}\) is the reference wind speed at reference height \(z_{ref}\), \(z\) is the height at which the wind speed is calculated, \(z_0\) is the roughness length, and \(d\) is the zero plane displacement.
- Parameters:
reference_wind_speed – Reference wind speed above the canopy, [m s-1].
reference_height – Reference height above the canopy, [m].
wind_heights – Heights where wind speed is to be calculated, [m].
roughness_length – Momentum roughness length, [m]
zero_plane_displacement – Height above the actual ground where the wind speed is theoretically reduced to zero due to the obstruction caused by the roughness elements (like trees or buildings), [m]
min_wind_speed – Minimum wind speed to avoid division by zero, [m s-1]
denominator_tolerance – Minimum value for denominator to avoid division by zero
- Returns:
Wind speed, [m s-1]
- virtual_ecosystem.models.abiotic.wind.calculate_zero_plane_displacement(canopy_height: ndarray[tuple[Any, ...], dtype[floating]], leaf_area_index: ndarray[tuple[Any, ...], dtype[floating]], zero_plane_scaling_parameter: float, denominator_tolerance: float) ndarray[tuple[Any, ...], dtype[floating]][source]#
Calculate zero plane displacement height.
The zero plane displacement height is a concept used in micrometeorology to describe the flow of air near the ground or over surfaces like a forest canopy or crops. It represents the height above the actual ground where the wind speed is theoretically reduced to zero due to the obstruction caused by the roughness elements (like trees or buildings). Implementation after Maclean and Klinges (2021).
- Parameters:
canopy_height – Canopy height, [m]
leaf_area_index – Total leaf area index, [m m-1]
zero_plane_scaling_parameter – Control parameter for scaling d/h, dimensionless (Raupach, 1994)
denominator_tolerance – Minimum value for denominator to avoid division by zero
- Returns:
Zero plane displacement height, [m]
- virtual_ecosystem.models.abiotic.wind.clamp_variable_within_limits(variable: ndarray[tuple[Any, ...], dtype[floating]], limits: tuple[float, float]) ndarray[tuple[Any, ...], dtype[floating]][source]#
Clamp an array of canopy data within limits.
This function iterates from the bottom of the canopy, clamping the values of the input array within the limits. When a value is altered by clamping, the residual is added to the layer above to maintain the variable total within cells. Residual values may be redistributed across multiple layers and empty values (representing unoccupied canopy layers) are skipped.
Note
If the vertical layers cannot absorb all of the accumulated residuals without themselves being clamped, then the values in the top layer can still fall outside the clamping limits.
- Parameters:
variable – A numpy array containing canopy data.
limits – A tuple giving the upper and lower bounds within which to clamp the data
- virtual_ecosystem.models.abiotic.wind.mix_and_ventilate(input_variable: ndarray[tuple[Any, ...], dtype[floating]], mixing_coefficient: ndarray[tuple[Any, ...], dtype[floating]], ventilation_rate: ndarray[tuple[Any, ...], dtype[floating]], limits: tuple[float, float], surface_index: int) ndarray[tuple[Any, ...], dtype[floating]][source]#
Apply vertical mixing and top-layer ventilation across multiple vertical layers.
This function simulates diffusion-like mixing between vertical layers based on local gradients of atmospheric variables (e.g. temperature, relative humidity) and layer-specific mixing coefficients. For each layer, it computes upward and downward fluxes using the nearest valid (finite) values above.
Additionally, the function applies a ventilation adjustment to the top layer of each column, representing heat or water exchange with the above the canopy. This is based on the difference between the top and next valid layer, scaled by a user-provided ventilation rate, with optional limits to prevent overcorrection or negative concentrations.
Advection is currently not implemented as everything is removed with time interval > 1h and horizontal transfer is not implemented.
- Parameters:
input_variable – Input variable for all true atmospheric layers
mixing_coefficient – Turbulent mixing coefficients for canopy, [m2 s-1]
ventilation_rate – Ventilation rate, [s-1]
limits – Upper and lower limit for input variable, avoid overshoot when mixing
surface_index – Surface layer index
- Returns:
Vertically mixed input variable
- virtual_ecosystem.models.abiotic.wind.next_valid_above(array: ndarray[tuple[Any, ...], dtype[floating]]) ndarray[tuple[Any, ...], dtype[int64]][source]#
Index of nearest valid value above each layer.
- Parameters:
array – A 2D array with vertical layers as the first dimension and columns as the second dimension. NaN values represent invalid or unoccupied layers.
- Returns:
A 2D array of the same shape as the input, where each element contains the index of the nearest valid (non-NaN) value above it in the same column. If there is no valid value above, the element will be -1.
- virtual_ecosystem.models.abiotic.wind.next_valid_below(array: ndarray[tuple[Any, ...], dtype[floating]]) ndarray[tuple[Any, ...], dtype[int64]][source]#
Index of nearest valid value below each layer.
- Parameters:
array – A 2D array with vertical layers as the first dimension and columns as the second dimension. NaN values represent invalid or unoccupied layers.
- Returns:
A 2D array of the same shape as the input, where each element contains the index of the nearest valid (non-NaN) value below it in the same column. If there is no valid value below, the element will be -1.