Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,77 @@ language_info:

# The Plants Model implementation

## Plant functional types

The Plants Model requires the definition of a set of plant functional types, which are
defined as a set of trait values that describe the allometry, demography and
stoichiometry of each PFT.

The PFT definitions for a simulation need to be stored in a
CSV file: each PFT must have a unique name and each row then provides the trait values
for that PFT. The configuration of the plants model must then provide the
`pft_definitions_path` setting that gives the path to that CSV file:

```toml
[plants]
pft_definitions_path = '/path/to/pft_definitions.csv'
```

The majority of the traits required for each PFT are used to define the allometry of
growing trees, the vertical structure of the canopy and the estimation of growth from
gross primary productivity. This modelling uses an implementation called the T Model
[insert citation] and you can read more
about the T Model and traits in the documentation for the [`pyrealm`
package](https://pyrealm.readthedocs.io/en/stable/users/demography/flora.html#plant-traits),
which is used by the Virtual Ecosystem to simulate plant growth.

In addition to the T Model, the Virtual Ecosystem also defines a set of extra traits to
describe the stoichiometry of plant tissues. Stoichiometry is not currently implemented
in the `pyrealm` package and so these values are additional requirements of the Virtual
Ecosystem.

The PFT definitions file needs to include the following fields defining the PFT names
and then values for all of the traits:

```{csv-table}
:header: >
: Field name,Description,Example value,VE only

name,TBD,pioneer,
hd,TBD,116.0,
ca_ratio,TBD,390.43,
f_g,TBD,0.02,
h_max,TBD,25.33,
lai,TBD,1.8,
m,TBD,2,
n,TBD,5,
name,TBD,'shrub',
par_ext,TBD,0.5,
resp_f,TBD,0.1,
resp_r,TBD,0.913,
resp_s,TBD,0.044,
resp_rt,TBD,0.05,
rho_s,TBD,200.0,
sla,TBD,14.0,
tau_f,TBD,4.0,
tau_r,TBD,1.04,
tau_rt,TBD,1,
yld,TBD,0.6,
zeta,TBD,0.17,
gpp_topslice,TBD,0.1,
p_foliage_for_reproductive_tissue,TBD,0.05,
deadwood_c_n_ratio,TBD,60.7,✓
deadwood_c_p_ratio,TBD,856.5,✓
leaf_turnover_c_n_ratio,TBD,25.5,✓
leaf_turnover_c_p_ratio,TBD,415.0,✓
plant_reproductive_tissue_turnover_c_n_ratio,TBD,12.5,✓
plant_reproductive_tissue_turnover_c_p_ratio,TBD,125.5,✓
root_turnover_c_p_ratio,TBD,656.7,✓
root_turnover_c_n_ratio,TBD,45.6,✓
foliage_c_n_ratio,TBD,15,✓
foliage_c_p_ratio,TBD,300,✓
```

## Required variables

The tables below show the variables that are required to initialise the plants model and
Expand Down
85 changes: 16 additions & 69 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Collection of fixtures to assist the testing scripts."""

from logging import DEBUG
from pathlib import Path
from unittest.mock import patch

import numpy as np
Expand Down Expand Up @@ -82,6 +83,17 @@ def reset_module_registry():
# Shared fixtures


@pytest.fixture
def fixture_root_data_dir():
"""Provides the absolute path of the root data directory.

Ideally we'd use something like pytest-datadir here, but it doesn't yet support
nested directories: https://github.com/gabrielcnr/pytest-datadir/issues/28
"""

return Path(__file__).parent / "data"


@pytest.fixture
def microbial_groups_cfg():
"""Configuration string containing full set of required microbial groups."""
Expand Down Expand Up @@ -225,12 +237,12 @@ def microbial_groups_cfg():


@pytest.fixture
def fixture_config(microbial_groups_cfg):
def fixture_config(fixture_root_data_dir, microbial_groups_cfg):
"""Simple configuration fixture for use in tests."""

from virtual_ecosystem.core.config import Config

cfg_string = """
cfg_string = f"""
[core]
[core.grid]
cell_nx = 2
Expand All @@ -252,73 +264,8 @@ def fixture_config(microbial_groups_cfg):
surface_layer_height = 0.1

[plants]
[[plants.pft_definition]]
a_hd = 116.0
ca_ratio = 390.43
f_g = 0.02
h_max = 25.33
lai = 1.8
m = 2
n = 5
name = 'shrub'
par_ext = 0.5
resp_f = 0.1
resp_r = 0.913
resp_s = 0.044
resp_rt = 0.05
rho_s = 200.0
sla = 14.0
tau_f = 4.0
tau_r = 1.04
tau_rt = 1
yld = 0.6
zeta = 0.17
gpp_topslice = 0.1
p_foliage_for_reproductive_tissue = 0.05
deadwood_c_n_ratio = 60.7
deadwood_c_p_ratio = 856.5
leaf_turnover_c_n_ratio = 25.5
leaf_turnover_c_p_ratio = 415.0
plant_reproductive_tissue_turnover_c_n_ratio = 12.5
plant_reproductive_tissue_turnover_c_p_ratio = 125.5
root_turnover_c_p_ratio = 656.7
root_turnover_c_n_ratio = 45.6
foliage_c_n_ratio = 15
foliage_c_p_ratio = 300

[[plants.pft_definition]]
a_hd = 116.0
ca_ratio = 390.43
f_g = 0.02
h_max = 30.33
lai = 1.8
m = 2
n = 5
name = 'broadleaf'
par_ext = 0.5
resp_f = 0.1
resp_r = 0.913
resp_s = 0.044
resp_rt = 0.05
rho_s = 200.0
sla = 14.0
tau_f = 4.0
tau_r = 1.04
tau_rt = 1
yld = 0.6
zeta = 0.17
gpp_topslice = 0.1
p_foliage_for_reproductive_tissue = 0.05
deadwood_c_n_ratio = 60.7
deadwood_c_p_ratio = 856.5
leaf_turnover_c_n_ratio = 25.5
leaf_turnover_c_p_ratio = 415.0
plant_reproductive_tissue_turnover_c_n_ratio = 12.5
plant_reproductive_tissue_turnover_c_p_ratio = 125.5
root_turnover_c_p_ratio = 656.7
root_turnover_c_n_ratio = 45.6
foliage_c_n_ratio = 15
foliage_c_p_ratio = 300
# Deliberately using single quote to provide TOML literal string for path
pft_definitions_path = '{(fixture_root_data_dir / "plant_pfts.csv")!s}'

[[animal.functional_groups]]
name = "carnivorous_bird"
Expand Down
68 changes: 1 addition & 67 deletions tests/core/data/all_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,73 +19,7 @@ save_final_state = true
save_initial_state = true

[plants]
[[plants.pft_definition]]
a_hd = 116.0
ca_ratio = 390.43
f_g = 0.02
gpp_topslice = 0.1
h_max = 25.33
lai = 1.8
m = 2
n = 5
name = 'shrub'
p_foliage_for_reproductive_tissue = 0.05
par_ext = 0.5
resp_f = 0.1
resp_r = 0.913
resp_rt = 0.05
resp_s = 0.044
rho_s = 200.0
sla = 14.0
tau_f = 4.0
tau_r = 1.04
tau_rt = 1
yld = 0.6
zeta = 0.17
deadwood_c_n_ratio = 60.7
deadwood_c_p_ratio = 856.5
leaf_turnover_c_n_ratio = 25.5
leaf_turnover_c_p_ratio = 415.0
plant_reproductive_tissue_turnover_c_n_ratio = 12.5
plant_reproductive_tissue_turnover_c_p_ratio = 125.5
root_turnover_c_p_ratio = 656.7
root_turnover_c_n_ratio = 45.6
foliage_c_n_ratio = 15
foliage_c_p_ratio = 300

[[plants.pft_definition]]
a_hd = 116.0
ca_ratio = 390.43
f_g = 0.02
gpp_topslice = 0.1
h_max = 15.33
lai = 1.8
m = 2
n = 5
name = 'broadleaf'
p_foliage_for_reproductive_tissue = 0.05
par_ext = 0.5
resp_f = 0.1
resp_r = 0.913
resp_rt = 0.05
resp_s = 0.044
rho_s = 200.0
sla = 14.0
tau_f = 4.0
tau_r = 1.04
tau_rt = 1
yld = 0.6
zeta = 0.17
deadwood_c_n_ratio = 60.7
deadwood_c_p_ratio = 856.5
leaf_turnover_c_n_ratio = 25.5
leaf_turnover_c_p_ratio = 415.0
plant_reproductive_tissue_turnover_c_n_ratio = 12.5
plant_reproductive_tissue_turnover_c_p_ratio = 125.5
root_turnover_c_p_ratio = 656.7
root_turnover_c_n_ratio = 45.6
foliage_c_n_ratio = 15
foliage_c_p_ratio = 300
pft_definitions_path = "pfts.csv"

[[animal.functional_groups]]
adult_mass = 1.0
Expand Down
3 changes: 3 additions & 0 deletions tests/data/plant_pfts.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name,a_hd,ca_ratio,f_g,h_max,lai,m,n,par_ext,resp_f,resp_r,resp_s,resp_rt,rho_s,sla,tau_f,tau_r,tau_rt,yld,zeta,gpp_topslice,p_foliage_for_reproductive_tissue,deadwood_c_n_ratio,deadwood_c_p_ratio,leaf_turnover_c_n_ratio,leaf_turnover_c_p_ratio,plant_reproductive_tissue_turnover_c_n_ratio,plant_reproductive_tissue_turnover_c_p_ratio,root_turnover_c_p_ratio,root_turnover_c_n_ratio,foliage_c_n_ratio,foliage_c_p_ratio
shrub,116,390.43,0.02,25.33,1.8,2,5,0.5,0.1,0.913,0.044,0.05,200,14,4,1.04,1,0.6,0.17,0.1,0.05,60.7,856.5,25.5,415,12.5,125.5,656.7,45.6,15,300
broadleaf,116,390.43,0.02,30.33,1.8,2,5,0.5,0.1,0.913,0.044,0.05,200,14,4,1.04,1,0.6,0.17,0.1,0.05,60.7,856.5,25.5,415,12.5,125.5,656.7,45.6,15,300
53 changes: 4 additions & 49 deletions tests/models/animals/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ def animal_data_for_model_instance(fixture_core_components):


@pytest.fixture
def animal_fixture_config(microbial_groups_cfg):
def animal_fixture_config(fixture_root_data_dir, microbial_groups_cfg):
"""Simple configuration fixture for use in tests."""

from virtual_ecosystem.core.config import Config

cfg_string = """
cfg_string = f"""
[core]
[core.grid]
cell_nx = 3
Expand All @@ -113,53 +113,8 @@ def animal_fixture_config(microbial_groups_cfg):
surface_layer_height = 0.1

[plants]
[[plants.pft_definition]]
a_hd = 116.0
ca_ratio = 390.43
f_g = 0.02
h_max = 25.33
lai = 1.8
m = 2
n = 5
name = 'shrub'
par_ext = 0.5
resp_f = 0.1
resp_r = 0.913
resp_s = 0.044
rho_s = 200.0
sla = 14.0
tau_f = 4.0
tau_r = 1.04
yld = 0.6
zeta = 0.17
resp_rt = 0.05
tau_rt = 1
gpp_topslice = 0.1
p_foliage_for_reproductive_tissue = 0.05

[[plants.pft_definition]]
a_hd = 116.0
ca_ratio = 390.43
f_g = 0.02
h_max = 30.33
lai = 1.8
m = 2
n = 5
name = 'broadleaf'
par_ext = 0.5
resp_f = 0.1
resp_r = 0.913
resp_s = 0.044
rho_s = 200.0
sla = 14.0
tau_f = 4.0
tau_r = 1.04
yld = 0.6
zeta = 0.17
resp_rt = 0.05
tau_rt = 1
gpp_topslice = 0.1
p_foliage_for_reproductive_tissue = 0.05
# Deliberately using single quote to provide TOML literal string for path
pft_definitions_path = '{(fixture_root_data_dir / "plant_pfts.csv")!s}'

[[animal.functional_groups]]
name = "carnivorous_bird"
Expand Down
3 changes: 0 additions & 3 deletions tests/models/plants/data/pfts.csv

This file was deleted.

25 changes: 1 addition & 24 deletions tests/models/plants/test_functional_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
This module tests the functionality of the plant functional types submodule.
"""

import pytest

from virtual_ecosystem.models.plants.functional_types import ExtraTraitsPFT


def test_get_flora_from_config(shared_datadir, fixture_config):
def test_get_flora_from_config(fixture_config):
"""Testing the pyrealm flora loading mechanism.

This tests the loader in two different configurations (data in TOML, data in CSV)
Expand All @@ -17,32 +15,11 @@ def test_get_flora_from_config(shared_datadir, fixture_config):

from pyrealm.demography.flora import Flora

from virtual_ecosystem.core.exceptions import ConfigurationError
from virtual_ecosystem.models.plants.functional_types import get_flora_from_config

# Initial fixture_config uses PFT definitions in the file
flora, extra_traits = get_flora_from_config(fixture_config)

assert isinstance(flora, Flora)
assert flora.n_pfts == 2

# Update to add a path _without_ removing local definitions
fixture_config["plants"]["pft_definitions_path"] = shared_datadir / "pfts.csv"

with pytest.raises(ConfigurationError) as err:
flora, extra_traits = get_flora_from_config(fixture_config)

assert (
str(err.value)
== "Do not use both `pft_definitions_path` and `pft_definition` in config."
)

# Remove original local definitions
fixture_config["plants"].pop("pft_definition")

flora, extra_traits = get_flora_from_config(fixture_config)

assert isinstance(flora, Flora)
assert flora.n_pfts == 2

assert isinstance(extra_traits, ExtraTraitsPFT)
Loading