Skip to content

Commit

Permalink
Merge pull request #322 from ImperialCollegeLondon/feature/plants_model
Browse files Browse the repository at this point in the history
Feature/plants model
  • Loading branch information
davidorme authored Oct 5, 2023
2 parents f02b0d0 + 84aec8c commit 62f0612
Show file tree
Hide file tree
Showing 20 changed files with 258 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ kernelspec:
name: vr_python3
---

# API for the {mod}`~virtual_rainforest.models.animals.dummy_plants` module
# API for the {mod}`~virtual_rainforest.models.animals.plant_resources` module

```{eval-rst}
.. automodule:: virtual_rainforest.models.animals.dummy_plants
.. automodule:: virtual_rainforest.models.animals.plant_resources
:autosummary:
:members:
:exclude-members: model_name
30 changes: 22 additions & 8 deletions docs/source/data_recipes/plant_dummy.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@ section provides a recipe to create such an input conform with the dummy data fo
import numpy as np
from xarray import DataArray, Dataset
# set layer roles
layer_roles = ["above"] + 10 * ["canopy"] + ["subcanopy"] + ["surface"] + 2 * ["soil"]
from virtual_rainforest.core.utils import set_layer_roles
plant_dummy = {}
layer_roles = set_layer_roles(10, [-0.5, -1.0])
# Compile a dataset
plant_dummy_dataset = Dataset()
layer_heights = np.repeat(
a=[32.0, 30.0, 20.0, 10.0, np.nan, 1.5, 0.1, -0.1, -1.0],
repeats=[1, 1, 1, 1, 7, 1, 1, 1, 1],
)
plant_dummy["layer_heights"] = DataArray(
plant_dummy_dataset["layer_heights"] = DataArray(
np.broadcast_to(layer_heights, (81, 15)).T,
dims=["layers", "cell_id"],
coords={
Expand All @@ -46,7 +49,7 @@ plant_dummy["layer_heights"] = DataArray(
)
leaf_area_index = np.repeat(a=[np.nan, 1.0, np.nan], repeats=[1, 3, 11])
plant_dummy["leaf_area_index"] = DataArray(
plant_dummy_dataset["leaf_area_index"] = DataArray(
np.broadcast_to(leaf_area_index, (81, 15)).T,
dims=["layers", "cell_id"],
coords={
Expand All @@ -57,8 +60,21 @@ plant_dummy["leaf_area_index"] = DataArray(
name="leaf_area_index",
)
layer_leaf_mass = np.repeat(a=[np.nan, 10000.0, np.nan], repeats=[1, 3, 11])
plant_dummy_dataset["layer_leaf_mass"] = DataArray(
np.broadcast_to(leaf_area_index, (81, 15)).T,
dims=["layers", "cell_id"],
coords={
"layers": np.arange(15),
"layer_roles": ("layers", layer_roles),
"cell_id": np.arange(0,81),
},
name="layer_leaf_mass",
)
evapotranspiration = np.repeat(a=[np.nan, 20.0, np.nan], repeats=[1, 3, 11])
plant_dummy["evapotranspiration"] = DataArray(
plant_dummy_dataset["evapotranspiration"] = DataArray(
np.broadcast_to(evapotranspiration, (81, 15)).T,
dims=["layers", "cell_id"],
coords={
Expand All @@ -68,8 +84,6 @@ plant_dummy["evapotranspiration"] = DataArray(
},
name="evapotranspiration",
)
# Make dictionary of DataArrays into a Dataset
plant_dummy_dataset = Dataset(plant_dummy)
plant_dummy_dataset
```
Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ team.
Animal Scaling Functions <api/animals/scaling_functions.md>
Animal Constants <api/animals/constants.md>
Animal Decay <api/animals/decay.md>
Animal Dummy Plants and Soils <api/animals/dummy_plants.md>
Animal Plant Resources <api/animals/plant_resources.md>
Litter Overview <api/litter.md>
Litter Model <api/litter/litter_model.md>
Litter Pools <api/litter/litter_pools.md>
Expand Down
73 changes: 0 additions & 73 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,76 +401,3 @@ def dummy_climate_data(layer_roles_fixture):
)

return data


@pytest.fixture
def functional_group_list_instance(shared_datadir):
"""Fixture for an animal functional group used in tests."""
from virtual_rainforest.models.animals.functional_group import (
import_functional_groups,
)

file = shared_datadir / "example_functional_group_import.csv"
fg_list = import_functional_groups(file)

return fg_list


@pytest.fixture
def animal_model_instance(data_instance, functional_group_list_instance):
"""Fixture for an animal model object used in tests."""
from pint import Quantity

from virtual_rainforest.models.animals.animal_model import AnimalModel

return AnimalModel(data_instance, Quantity("1 day"), functional_group_list_instance)


@pytest.fixture
def animal_community_instance(functional_group_list_instance, animal_model_instance):
"""Fixture for an animal community used in tests."""
from virtual_rainforest.models.animals.animal_communities import AnimalCommunity

return AnimalCommunity(
functional_group_list_instance,
0,
[0, 1, 3],
animal_model_instance.get_community_by_key,
)


@pytest.fixture
def herbivore_functional_group_instance(shared_datadir):
"""Fixture for an animal functional group used in tests."""
from virtual_rainforest.models.animals.functional_group import (
import_functional_groups,
)

file = shared_datadir / "example_functional_group_import.csv"
fg_list = import_functional_groups(file)

return fg_list[3]


@pytest.fixture
def herbivore_cohort_instance(herbivore_functional_group_instance):
"""Fixture for an animal cohort used in tests."""
from virtual_rainforest.models.animals.animal_cohorts import AnimalCohort

return AnimalCohort(herbivore_functional_group_instance, 10000.0, 1)


@pytest.fixture
def excrement_instance():
"""Fixture for a soil pool used in tests."""
from virtual_rainforest.models.animals.decay import ExcrementPool

return ExcrementPool(100000.0, 0.0)


@pytest.fixture
def plant_instance():
"""Fixture for a plant community used in tests."""
from virtual_rainforest.models.animals.dummy_plants import PlantCommunity

return PlantCommunity(10000.0)
98 changes: 98 additions & 0 deletions tests/models/animals/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""Collection of fixtures to assist the animal model testing scripts."""

import numpy as np
import pytest
import xarray


@pytest.fixture
def plant_data_instance():
"""Fixture returning a simple data instance containing plant resource data."""
from virtual_rainforest.core.data import Data
from virtual_rainforest.core.grid import Grid

# Populate data with a layers x cell id layer_leaf_mass array
data = Data(grid=Grid(cell_nx=3, cell_ny=3))
leaf_mass = np.full((15, 9), fill_value=np.nan)
leaf_mass[1:4, :] = 10000
data["layer_leaf_mass"] = xarray.DataArray(
data=leaf_mass, dims=["layers", "cell_id"]
)

return data


@pytest.fixture
def functional_group_list_instance(shared_datadir):
"""Fixture for an animal functional group used in tests."""
from virtual_rainforest.models.animals.functional_group import (
import_functional_groups,
)

file = shared_datadir / "example_functional_group_import.csv"
fg_list = import_functional_groups(file)

return fg_list


@pytest.fixture
def animal_model_instance(data_instance, functional_group_list_instance):
"""Fixture for an animal model object used in tests."""
from pint import Quantity

from virtual_rainforest.models.animals.animal_model import AnimalModel

return AnimalModel(data_instance, Quantity("1 day"), functional_group_list_instance)


@pytest.fixture
def animal_community_instance(
functional_group_list_instance, animal_model_instance, plant_data_instance
):
"""Fixture for an animal community used in tests."""
from virtual_rainforest.models.animals.animal_communities import AnimalCommunity

return AnimalCommunity(
functional_groups=functional_group_list_instance,
data=plant_data_instance,
community_key=4,
neighbouring_keys=[1, 3, 5, 7],
get_destination=animal_model_instance.get_community_by_key,
)


@pytest.fixture
def herbivore_functional_group_instance(shared_datadir):
"""Fixture for an animal functional group used in tests."""
from virtual_rainforest.models.animals.functional_group import (
import_functional_groups,
)

file = shared_datadir / "example_functional_group_import.csv"
fg_list = import_functional_groups(file)

return fg_list[3]


@pytest.fixture
def herbivore_cohort_instance(herbivore_functional_group_instance):
"""Fixture for an animal cohort used in tests."""
from virtual_rainforest.models.animals.animal_cohorts import AnimalCohort

return AnimalCohort(herbivore_functional_group_instance, 10000.0, 1)


@pytest.fixture
def excrement_instance():
"""Fixture for a soil pool used in tests."""
from virtual_rainforest.models.animals.decay import ExcrementPool

return ExcrementPool(100000.0, 0.0)


@pytest.fixture
def plant_instance(plant_data_instance):
"""Fixture for a plant community used in tests."""
from virtual_rainforest.models.animals.plant_resources import PlantResources

return PlantResources(data=plant_data_instance, cell_id=4)
4 changes: 2 additions & 2 deletions tests/models/animals/test_animal_cohorts.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,13 @@ def test_forage_cohort(
from virtual_rainforest.models.animals.animal_cohorts import AnimalCohort
from virtual_rainforest.models.animals.animal_traits import DietType
from virtual_rainforest.models.animals.decay import CarcassPool, ExcrementPool
from virtual_rainforest.models.animals.dummy_plants import PlantCommunity
from virtual_rainforest.models.animals.plant_resources import PlantResources

# Mocking the eat method of AnimalCohort
mock_eat = mocker.patch.object(AnimalCohort, "eat")

# Instances
plant_list_instance = [mocker.MagicMock(spec=PlantCommunity)]
plant_list_instance = [mocker.MagicMock(spec=PlantResources)]
animal_list_instance = [
mocker.MagicMock(spec=AnimalCohort) for _ in range(3)
] # Assuming 3 animal cohorts
Expand Down
11 changes: 6 additions & 5 deletions tests/models/animals/test_animal_communities.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@

@pytest.fixture
def animal_community_destination_instance(
functional_group_list_instance, animal_model_instance
functional_group_list_instance, animal_model_instance, plant_data_instance
):
"""Fixture for an animal community used in tests."""
from virtual_rainforest.models.animals.animal_communities import AnimalCommunity

return AnimalCommunity(
functional_group_list_instance,
1,
[0, 1, 2, 4],
animal_model_instance.get_community_by_key,
functional_groups=functional_group_list_instance,
data=plant_data_instance,
community_key=4,
neighbouring_keys=[1, 3, 5, 7],
get_destination=animal_model_instance.get_community_by_key,
)


Expand Down
8 changes: 4 additions & 4 deletions tests/models/animals/test_animal_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def test_animal_model_initialization(
)
def test_generate_animal_model(
caplog,
data_instance,
plant_data_instance,
config,
time_interval,
raises,
Expand All @@ -114,7 +114,7 @@ def test_generate_animal_model(
# Check whether model is initialised (or not) as expected
with raises:
model = AnimalModel.from_config(
data_instance,
plant_data_instance,
config,
pint.Quantity(config["core"]["timing"]["update_interval"]),
)
Expand Down Expand Up @@ -198,13 +198,13 @@ def test_update_method_sequence(data_instance, functional_group_list_instance):


def test_update_method_time_index_argument(
data_instance, functional_group_list_instance
plant_data_instance, functional_group_list_instance
):
"""Test update to ensure the time index argument does not create an error."""
from virtual_rainforest.models.animals.animal_model import AnimalModel

model = AnimalModel(
data_instance, pint.Quantity("1 week"), functional_group_list_instance
plant_data_instance, pint.Quantity("1 week"), functional_group_list_instance
)

time_index = 5
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,9 @@
"""Test module for dummy_plants.py."""
"""Test module for plant_resources.py."""

import pytest


class TestPlantCommunity:
class TestPlantResources:
"""Test Plant class."""

@pytest.mark.parametrize(
"initial, final",
[(182000000000.0, 182000000000.0), (10000.0, 19999.999450), (0.0, 0.0)],
)
def test_grow(self, plant_instance, initial, final):
"""Testing grow at 100%, 50%, and 0% maximum energy."""
plant_instance.stored_energy = initial
plant_instance.grow()
assert plant_instance.stored_energy == pytest.approx(final, rel=1e-6)

def test_die(self, plant_instance):
"""Testing die."""
assert plant_instance.is_alive
plant_instance.die()
assert not plant_instance.is_alive

def test_get_eaten(
self, plant_instance, herbivore_cohort_instance, excrement_instance
):
Expand Down
Loading

0 comments on commit 62f0612

Please sign in to comment.