Skip to content

Commit

Permalink
simplification to mtch other variables
Browse files Browse the repository at this point in the history
  • Loading branch information
vgro committed Dec 17, 2024
1 parent ec378db commit 3099d7b
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 393 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ display_markdown(

The `abiotic_simple` model is a simple regression model that estimates microclimatic
variables based on empirical relationships between leaf area index (LAI) and atmospheric
temperature (T), relative humidity (RH), and vapour pressure deficit (VPD) to derive
temperature (T), relative humidity (RH), vapour pressure deficit (VPD), and wind speed
to derive
logarithmic profiles of these variables from external climate data such as regional
climate models or satellite observations. The model also provides information on
atmospheric pressure and $\ce{CO_{2}}$ and soil temperatures at different depths.
Expand Down
10 changes: 10 additions & 0 deletions tests/models/abiotic_simple/test_abiotic_simple_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,16 @@ def test_setup(dummy_climate_data_varying_canopy, fixture_core_components):
]
xr.testing.assert_allclose(model.data["air_temperature"], exp_air_temp)

exp_wind = lyr_strct.from_template()
exp_wind[lyr_strct.index_filled_atmosphere] = [
[1, 1, 1, 1],
[0.993673, 0.995782, 0.997891, 0.997891],
[0.953925, 0.969284, np.nan, np.nan],
[0.885976, np.nan, np.nan, np.nan],
[0.434528, 0.623019, 0.811509, 0.811509],
]
xr.testing.assert_allclose(model.data["wind_speed"], exp_wind)

exp_soil_temp = lyr_strct.from_template()
exp_soil_temp[lyr_strct.index_all_soil] = [
[20.712458, 21.317566, 21.922674, 21.922674],
Expand Down
87 changes: 11 additions & 76 deletions tests/models/abiotic_simple/test_microclimate.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def test_run_microclimate(dummy_climate_data, fixture_core_components):

exp_wind = lyr_strct.from_template()
exp_wind[lyr_strct.index_filled_atmosphere] = np.array(
[5.955368, 0.734519, 0.001, 0.001, 0.187047]
[1.0, 0.993673, 0.953925, 0.885976, 0.434528]
)[:, None]
np.testing.assert_allclose(result["wind_speed"], exp_wind, rtol=1e-3, atol=1e-3)

Expand Down Expand Up @@ -254,6 +254,16 @@ def test_run_microclimate_varying_canopy(
]
xr.testing.assert_allclose(result["soil_temperature"], exp_soil_temp)

exp_wind = lyr_strct.from_template()
exp_wind[lyr_strct.index_filled_atmosphere] = [
[1, 1, 1, 1],
[0.993673, 0.995782, 0.997891, 0.997891],
[0.953925, 0.969284, np.nan, np.nan],
[0.885976, np.nan, np.nan, np.nan],
[0.434528, 0.623019, 0.811509, 0.811509],
]
xr.testing.assert_allclose(result["wind_speed"], exp_wind)

exp_pressure = lyr_strct.from_template()
exp_pressure[lyr_strct.index_atmosphere] = 96
xr.testing.assert_allclose(result["atmospheric_pressure"], exp_pressure)
Expand Down Expand Up @@ -283,78 +293,3 @@ def test_interpolate_soil_temperature(dummy_climate_data, fixture_core_component
exp_output[lyr_strct.index_all_soil] = np.array([20.505557, 20.0])[:, None]

xr.testing.assert_allclose(result, exp_output)


def test_calculate_zero_plane_displacement(dummy_climate_data):
"""Test if calculated correctly and set to zero without vegetation."""

from virtual_ecosystem.models.abiotic_simple.microclimate import (
calculate_zero_plane_displacement,
)

result = calculate_zero_plane_displacement(
canopy_height=dummy_climate_data["layer_heights"][1].to_numpy(),
leaf_area_index=np.array([0.0, np.nan, 7.0, 7.0]),
zero_plane_scaling_parameter=7.5,
)

np.testing.assert_allclose(result, np.array([0.0, 0.0, 25.86256, 25.86256]))


def test_calculate_roughness_length_momentum(dummy_climate_data):
"""Test roughness length governing momentum transfer."""

from virtual_ecosystem.core.constants import CoreConsts
from virtual_ecosystem.models.abiotic_simple.microclimate import (
calculate_roughness_length_momentum,
)

result = calculate_roughness_length_momentum(
canopy_height=dummy_climate_data["layer_heights"][1].to_numpy(),
leaf_area_index=np.array([np.nan, 0.0, 7, 7]),
zero_plane_displacement=np.array([0.0, 0.0, 27.58673, 27.58673]),
substrate_surface_drag_coefficient=0.003,
roughness_element_drag_coefficient=0.3,
roughness_sublayer_depth_parameter=0.193,
max_ratio_wind_to_friction_velocity=0.3,
min_roughness_length=0.01,
von_karman_constant=CoreConsts.von_karmans_constant,
)

np.testing.assert_allclose(
result, np.array([0.01, 0.01666, 0.524479, 0.524479]), rtol=1e-3, atol=1e-3
)


def test_calculate_wind_profile(dummy_climate_data, fixture_core_components):
"""Test calculation of wind profile."""

from virtual_ecosystem.core.constants import CoreConsts
from virtual_ecosystem.models.abiotic_simple.constants import AbioticSimpleConsts
from virtual_ecosystem.models.abiotic_simple.microclimate import (
calculate_wind_profile,
)

data = dummy_climate_data
abiotic_simple_constants = AbioticSimpleConsts()
core_constants = CoreConsts()
lyr_strct = fixture_core_components.layer_structure

result = calculate_wind_profile(
data=data,
time_index=0,
layer_structure=lyr_strct,
abiotic_simple_constants=abiotic_simple_constants,
core_constants=core_constants,
)

expected_wind_profile = lyr_strct.from_template()
expected_wind_profile[lyr_strct.index_filled_atmosphere] = [
[5.955368, 5.955368, 5.955368, 5.955368],
[0.7345195, 0.7345195, 0.7345195, 0.7345195],
[0.001, 0.001, 0.001, 0.001],
[0.001, 0.001, 0.001, 0.001],
[0.187047, 0.187047, 0.187047, 0.187047],
]

np.testing.assert_allclose(result, expected_wind_profile, rtol=1e-3, atol=1e-3)
4 changes: 2 additions & 2 deletions virtual_ecosystem/models/abiotic_simple/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
* The :mod:`~virtual_ecosystem.models.abiotic_simple.microclimate` submodule
contains a set functions and parameters that are used to calculate atmospheric
temperature, relative humidity, vapour pressure deficit, :math:`\ce{CO2}`, and
atmospheric pressure profiles as well as soil temperature profiles.
temperature, relative humidity, vapour pressure deficit, wind speed, :math:`\ce{CO2}`,
and atmospheric pressure profiles as well as soil temperature profiles.
* The :mod:`~virtual_ecosystem.models.abiotic_simple.constants` submodule provides a
set of dataclasses containing the constants required by the broader abiotic model
Expand Down
61 changes: 8 additions & 53 deletions virtual_ecosystem/models/abiotic_simple/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,6 @@ class AbioticSimpleConsts(ConstantsDataclass):
)
"""Factors for saturation vapour pressure calculation."""

zero_plane_scaling_parameter: float = 7.5
"""Control parameter for scaling zero displacement to height, dimensionless.
Implementation after :cite:t:`maclean_microclimc_2021`, value is taken from
:cite:t:`raupach_simplified_1994`."""

substrate_surface_drag_coefficient: float = 0.003
"""Substrate-surface drag coefficient, dimensionless.
The substrate-surface drag coefficient represents the resistance encountered by an
object moving on or through a surface and varies based on the nature of the surface
and the object's properties. Here, it affects how wind speed is altered by a surface
. Implementation and value from :cite:t:`maclean_microclimc_2021`."""

roughness_element_drag_coefficient: float = 0.3
"""Roughness-element drag coefficient, dimensionless.
The roughness-element drag coefficient refers to the dimensionless coefficient used
to quantify the drag force exerted by individual roughness elements (such as
buildings, trees, or surface irregularities) on airflow, influencing the overall
aerodynamic characteristics of a surface within the atmospheric boundary layer.
Implementation and value from :cite:t:`maclean_microclimc_2021`."""

roughness_sublayer_depth_parameter: float = 0.193
"""Parameter characterizes the roughness sublayer depth.
The roughness sublayer depth refers to the layer near the surface where the effects
of surface roughness significantly influence airflow, turbulence, and momentum
transfer, typically extending up to about 10% of the height of the roughness
elements or features on the surface. This layer is characterized by intense
turbulence and rapid velocity changes due to surface irregularities.
Implentation and value taken from :cite:p:`maclean_microclimc_2021`."""

max_ratio_wind_to_friction_velocity: float = 0.3
"""Maximum ratio of wind velocity to friction velocity, dimensionless.
Implementation and value from :cite:t:`maclean_microclimc_2021`."""

min_roughness_length: float = 0.01
"""Minimum roughness length, [m].
The minimum roughness length represents the lowest height at which the surface
roughness significantly affects the wind flow over a particular terrain or surface.
Implementation and value from :cite:t:`maclean_microclimc_2021`."""

wind_reference_height: float = 10.0
"""Reference height for wind speed above the canopy.
The reference height for horizontal wind is typically 10m above ground compared to
2m for other atmospheric variables such as temperature and relative humidity. We
assume here that the reference height is above the canopy, please check the input
data carefully and be aware of limitations."""


@dataclass(frozen=True)
class AbioticSimpleBounds(ConstantsDataclass):
Expand Down Expand Up @@ -102,5 +49,13 @@ class AbioticSimpleBounds(ConstantsDataclass):
leaf area index from :cite:t:`hardwick_relationship_2015`.
"""

wind_speed: tuple[float, float, float] = (0.001, 100.0, -0.1)
"""Bounds and gradient for wind speed, [m s-1].
Gradient for linear regression to calculate wind speed as a function of
leaf area index. The value is choses arbitrarily and needs to be replaced with
observations.
"""

soil_temperature: tuple[float, float] = (-10.0, 50.0)
"""Bounds for soil temperature, [C]."""
Loading

0 comments on commit 3099d7b

Please sign in to comment.