Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add soil enzymes to model #341

Merged
merged 36 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2ee63af
Moved environment factor calculations to seperate submodule
jacobcook1995 Oct 9, 2023
e0435c2
Added functions to calculate enzyme production and decay
jacobcook1995 Oct 10, 2023
0abcf13
Added calculation of POM enzyme balence to the main integration
jacobcook1995 Oct 10, 2023
31cfbea
Added new dummy data so that vr_run example works
jacobcook1995 Oct 10, 2023
9e592ad
Added flow of broken down enzymes to LMWC
jacobcook1995 Oct 10, 2023
d25fec3
Consolidating all biomass losses into a single data class
jacobcook1995 Oct 12, 2023
a06a8bc
Removed now outdated function to add necromass to MAOM
jacobcook1995 Oct 12, 2023
09dc90b
Made POM decomposition enzyme explicit
jacobcook1995 Oct 13, 2023
b4075d5
Merge branch 'develop' into feature/add_enzymes
jacobcook1995 Oct 16, 2023
eed4811
Merge branch 'develop' into feature/add_enzymes
jacobcook1995 Oct 17, 2023
2dff041
Added a rate constant dependance on pH
jacobcook1995 Oct 18, 2023
3f4c913
Added new pH stuff into the main carbon loop
jacobcook1995 Oct 18, 2023
2c70ab2
Added function to capture impact of soil clay on effective enzyme sat…
jacobcook1995 Oct 19, 2023
3407317
Added a function for the impact of clay on necromass decay
jacobcook1995 Oct 19, 2023
556f4c9
Add pom decomposition to maom
jacobcook1995 Oct 19, 2023
05597a5
Merge branch 'develop' into feature/add_enzymes
jacobcook1995 Oct 20, 2023
5f42d02
Changed microbial uptake to follow form used in the enzyme-explict model
jacobcook1995 Oct 23, 2023
8bcf607
Merge branch 'develop' into feature/add_enzymes
jacobcook1995 Oct 23, 2023
5b9dda8
Added a mechanistic function for nutrient leaching
jacobcook1995 Nov 15, 2023
8b5ba09
Added explicit MAOM enzyme pool
jacobcook1995 Nov 15, 2023
95d1753
Made enzyme decomp function generic
jacobcook1995 Nov 15, 2023
07813cd
Removed outdated lmwc to maom transfer functions
jacobcook1995 Nov 16, 2023
7ed0d3b
Added step to break MAOM down into LMWC
jacobcook1995 Nov 20, 2023
b7f8584
Wrote function to calculate set of environmental factors
jacobcook1995 Nov 20, 2023
10f7ea7
Started using environmental factors function in main simulation flow
jacobcook1995 Nov 20, 2023
33746ba
Fixed broken docstring
jacobcook1995 Nov 20, 2023
71dd83f
Merge branch 'develop' into feature/add_enzymes
jacobcook1995 Nov 20, 2023
636cbd0
Removed unnecessary layer selection for vertical flow
jacobcook1995 Nov 27, 2023
682131e
Renamed environmental factors function
jacobcook1995 Nov 27, 2023
60b29fc
Added extra test for too high water potentials
jacobcook1995 Nov 27, 2023
891abbe
Merge branch 'develop' into feature/add_enzymes
jacobcook1995 Nov 28, 2023
afdc368
Switched to using map(str as it is cleaner
jacobcook1995 Nov 30, 2023
0ba8e0e
Renamed response curvature constant to make it clearer what it actual…
jacobcook1995 Dec 1, 2023
abf19b1
Changed depth of first soil level to match depth used in the soil and…
jacobcook1995 Dec 4, 2023
d80b5a0
Removed unneccessary line from soil_model_fixture
jacobcook1995 Dec 4, 2023
9f76084
Added extra TODOs for vertical flow averaging issue
jacobcook1995 Dec 5, 2023
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
23 changes: 23 additions & 0 deletions docs/source/api/soil/env_factors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
jupytext:
cell_metadata_filter: -all
formats: md:myst
main_language: python
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.13.8
kernelspec:
display_name: vr_python3
language: python
name: vr_python3
---

# API documentation for the {mod}`~virtual_rainforest.models.soil.env_factors` module

```{eval-rst}
.. automodule:: virtual_rainforest.models.soil.env_factors
:autosummary:
:members:
```
115 changes: 37 additions & 78 deletions docs/source/data_recipes/soil_dummy.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,85 +22,42 @@ this data is a set of plausible values for which the soil model absolutely has t
function sensibly for.

```{code-cell} ipython3
import numpy as np
from xarray import Dataset

def generate_pH_values(x: float, y: float) -> float:
"""Function to generate a reasonable range of pH values.

We're looking at acidic soils so a range of 3.5-4.5 seems plausible.
"""
return 3.5 + (x * y) / (64)


def generate_BD_values(x: float, y: float) -> float:
"""Function to generate a reasonable range of bulk density values.

Bulk density can vary quite a lot so a range of 1200-1800 kg m^-3 seems sensible.
"""
return 1200.0 + 600.0 * (x * y) / (64)


def generate_clay_values(x: float, y: float) -> float:
"""Function to generate a reasonable range of clay content values.

We're considering fairly clayey soils, so look at a range of 27.0-40.0 % clay.
"""
return 27.0 + 13.0 * (x * y) / (64)


def generate_lmwc_values(x: float, y: float) -> float:
"""Function to generate a reasonable range of lmwc values.

LMWC generally a very small carbon pool, so a range of 0.005-0.01 kg C m^-3 is used.
"""
return 0.005 + 0.005 * (x * y) / (64)


def generate_maom_values(x: float, y: float) -> float:
"""Function to generate a reasonable range of maom values.

A huge amount of carbon can be locked away as MAOM, so a range of 1.0-3.0 kg C m^-3
is used.
"""
return 1.0 + 2.0 * (x * y) / (64)


def generate_microbial_C_values(x: float, y: float) -> float:
"""Function to generate a reasonable range of microbial C values.

The carbon locked up as microbial biomass is tiny, so a range of 0.0015-0.005
kg C m^-3 is used.
"""
return 0.0015 + 0.0035 * (x * y) / (64)

def generate_pom_values(x: float, y: float) -> float:
"""Function to generate a reasonable range of pom values.

A reasonable amount of carbon is stored as particulate organic matter (POM), so a
range of 0.1-1.0 kg C m^-3 is used.
"""
return 0.1 + 0.9 * (x * y) / (64)


# Generate range of cell numbers in the a x and y directions. Here we have a 9x9 grid,
# so cells are numbered from 0 to 8 in each direction.
x_cell_ids = range(0, 9)
y_cell_ids = range(0, 9)

# Make matrices containing all the relevant values
pH_values = [[generate_pH_values(x, y) for y in y_cell_ids] for x in x_cell_ids]
bulk_density_values = [
[generate_BD_values(x, y) for y in y_cell_ids] for x in x_cell_ids
]
percent_clay_values = [
[generate_clay_values(x, y) for y in y_cell_ids] for x in x_cell_ids
]
lmwc_values = [[generate_lmwc_values(x, y) for y in y_cell_ids] for x in x_cell_ids]
maom_values = [[generate_maom_values(x, y) for y in y_cell_ids] for x in x_cell_ids]
microbial_C_values = [
[generate_microbial_C_values(x, y) for y in y_cell_ids] for x in x_cell_ids
]
pom_values = [[generate_pom_values(x, y) for y in y_cell_ids] for x in x_cell_ids]
# How far the center of each cell is from the origin. This applies to both the x and y
# direction independently, so cell (0,0) is at the origin, whereas cell (2,3) is 180m
# from the origin in the x direction and 270m in the y direction.
cell_spacing = np.arange(0, 721, 90)
gradient = np.multiply.outer(cell_spacing/90, cell_spacing/90)

# Generate a range of plausible values (3.5-4.5) for the soil pH [unitless].
pH_values = 3.5 + 1.00 * (gradient) / (64)

# Generate a range of plausible values (1200-1800) for the bulk density [kg m^-3].
bulk_density_values = 1200.0 + 600.0 * (gradient) / (64)

# Generate a range of plausible values (0.27-0.40) for the clay fraction [fraction].
clay_fraction_values = 0.27 + 0.13 * (gradient) / (64)

# Generate a range of plausible values (0.005-0.01) for the lmwc pool [kg C m^-3].
lmwc_values = 0.005 + 0.005 * (gradient) / (64)

# Generate a range of plausible values (1.0-3.0) for the maom pool [kg C m^-3].
maom_values = 1.0 + 2.0 * (gradient) / (64)

# Generate a range of plausible values (0.0015-0.005) for the microbial C pool
# [kg C m^-3].
microbial_C_values = 0.0015 + 0.0035 * (gradient) / (64)

# Generate a range of plausible values (0.1-1.0) for the POM pool [kg C m^-3].
pom_values = 0.1 + 0.9 * (gradient) / (64)

# Generate a range of plausible values (0.01-0.5) for the POM enzyme pool [kg C m^-3].
pom_enzyme_values = 0.01 + 0.49 * (gradient) / (64)

# Generate a range of plausible values (0.01-0.5) for the MAOM enzyme pool [kg C m^-3].
maom_enzyme_values = 0.01 + 0.49 * (gradient) / (64)

# How far the center of each cell is from the origin. This applies to both the x and y
# direction independently, so cell (0,0) is at the origin, whereas cell (2,3) is 180m
Expand All @@ -112,11 +69,13 @@ dummy_soil_data = Dataset(
data_vars=dict(
pH=(["x", "y"], pH_values),
bulk_density=(["x", "y"], bulk_density_values),
percent_clay=(["x", "y"], percent_clay_values),
clay_fraction=(["x", "y"], clay_fraction_values),
soil_c_pool_lmwc=(["x", "y"], lmwc_values),
soil_c_pool_maom=(["x", "y"], maom_values),
soil_c_pool_microbe=(["x", "y"], microbial_C_values),
soil_c_pool_pom=(["x", "y"], pom_values),
soil_enzyme_pom = (["x", "y"], pom_enzyme_values),
soil_enzyme_maom = (["x", "y"], maom_enzyme_values),
),
coords=dict(
x=(["x"], cell_displacements),
Expand Down
1 change: 1 addition & 0 deletions docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ team.
Soil Overview <api/soil.md>
Soil Model <api/soil/soil_model.md>
Soil Carbon <api/soil/carbon.md>
Soil Environmental Factors <api/soil/env_factors.md>
Soil Constants <api/soil/constants.md>
Abiotic Simple Overview <api/abiotic_simple.md>
Abiotic Simple Model <api/abiotic_simple/abiotic_simple_model.md>
Expand Down
49 changes: 33 additions & 16 deletions docs/source/refs.bib
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
@article{porporato_hydrologic_2003,
title = {Hydrologic controls on soil carbon and nitrogen cycles. {I}. {Modeling} scheme},
volume = {26},
issn = {03091708},
url = {https://linkinghub.elsevier.com/retrieve/pii/S0309170802000945},
doi = {10.1016/S0309-1708(02)00094-5},
language = {en},
number = {1},
urldate = {2023-11-14},
journal = {Advances in Water Resources},
author = {Porporato, A and D’Odorico, P and Laio, F and Rodriguez-Iturbe, I},
month = jan,
year = {2003},
pages = {45--58},
}

@article{orwin_organic_2011,
title = {Organic nutrient uptake by mycorrhizal fungi enhances ecosystem carbon storage: a model-based assessment},
volume = {14},
issn = {1461023X},
shorttitle = {Organic nutrient uptake by mycorrhizal fungi enhances ecosystem carbon storage},
url = {https://onlinelibrary.wiley.com/doi/10.1111/j.1461-0248.2011.01611.x},
doi = {10.1111/j.1461-0248.2011.01611.x},
language = {en},
number = {5},
urldate = {2023-10-18},
journal = {Ecology Letters},
author = {Orwin, Kate H. and Kirschbaum, Miko U. F. and St John, Mark G. and Dickie, Ian A.},
month = may,
year = {2011},
pages = {493--502},
}


@book{monteith_light_1969,
address = {Madison, Wisconsin, U.S.A.},
Expand Down Expand Up @@ -333,22 +366,6 @@ @book{campbell_introduction_1998
year = {1998},
}

@article{mayes_relation_2012,
title = {Relation between {Soil} {Order} and {Sorption} of {Dissolved} {Organic} {Carbon} in {Temperate} {Subsoils}},
volume = {76},
issn = {0361-5995, 1435-0661},
url = {https://onlinelibrary.wiley.com/doi/10.2136/sssaj2011.0340},
doi = {10.2136/sssaj2011.0340},
language = {en},
number = {3},
urldate = {2023-02-22},
journal = {Soil Science Society of America Journal},
author = {Mayes, Melanie A. and Heal, Katherine R. and Brandt, Craig C. and Phillips, Jana R. and Jardine, Philip M.},
month = may,
year = {2012},
pages = {1027--1037},
}

@article{davis_simple_2017,
title = {Simple process-led algorithms for simulating habitats ({SPLASH} v.1.0): robust indices of radiation, evapotranspiration and plant-available moisture},
volume = {10},
Expand Down
15 changes: 12 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,22 @@ def dummy_carbon_data(layer_roles_fixture):
"""Microbial biomass (carbon) pool (kg C m^-3)"""
data["soil_c_pool_pom"] = DataArray([0.1, 1.0, 0.7, 0.35], dims=["cell_id"])
"""Particulate organic matter pool (kg C m^-3)"""
data["soil_enzyme_pom"] = DataArray(
[0.022679, 0.009576, 0.050051, 0.003010], dims=["cell_id"]
)
"""Soil enzyme that breaks down particulate organic matter (kg C m^-3)"""
data["soil_enzyme_maom"] = DataArray(
[0.0356, 0.0117, 0.02509, 0.00456], dims=["cell_id"]
)
"""Soil enzyme that breaks down mineral associated organic matter (kg C m^-3)"""
data["pH"] = DataArray([3.0, 7.5, 9.0, 5.7], dims=["cell_id"])
data["bulk_density"] = DataArray([1350.0, 1800.0, 1000.0, 1500.0], dims=["cell_id"])
data["percent_clay"] = DataArray([80.0, 30.0, 10.0, 90.0], dims=["cell_id"])
data["clay_fraction"] = DataArray([0.8, 0.3, 0.1, 0.9], dims=["cell_id"])
data["litter_C_mineralisation_rate"] = DataArray(
[0.00212106, 0.00106053, 0.00049000, 0.0055], dims=["cell_id"]
)
# Data for combined vertical flow (for entire timestep)
data["vertical_flow"] = DataArray([3.0, 15.0, 75.0, 47.7], dims=["cell_id"])

# The layer dependant data has to be handled separately
data["soil_moisture"] = xr.concat(
Expand All @@ -186,7 +196,7 @@ def dummy_carbon_data(layer_roles_fixture):
# At present the soil model only uses the top soil layer, so this is the
# only one with real test values in
DataArray(
[[0.472467929, 0.399900047, 0.256053640, 0.153616897]],
[[0.9304620050, 0.787549327, 0.504263188, 0.302527807]],
dims=["layers", "cell_id"],
),
DataArray(np.full((1, 4), np.nan), dims=["layers", "cell_id"]),
Expand All @@ -200,7 +210,6 @@ def dummy_carbon_data(layer_roles_fixture):
"cell_id": data.grid.cell_id,
}
)
# TODO - Eventually this should replace the dummy soil moisture entirely
data["matric_potential"] = xr.concat(
[
DataArray(np.full((13, 4), np.nan), dims=["layers", "cell_id"]),
Expand Down
8 changes: 4 additions & 4 deletions tests/core/test_constants_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ class Test(ConstantsDataclass): # type: ignore [misc]
pytest.param(
{},
does_not_raise(),
123.4,
0.25,
(),
id="defaults_with_no_config",
),
pytest.param(
{"placeholder": 432.1},
{"depth_of_active_soil_layer": 1.55},
does_not_raise(),
432.1,
1.55,
(),
id="configured",
),
Expand Down Expand Up @@ -70,6 +70,6 @@ def test_ConstantsDataclass_from_config(caplog, config, raises, exp_val, exp_log
constants_instance = CoreConsts.from_config(config)

if isinstance(raises, does_not_raise):
assert constants_instance.placeholder == exp_val
assert constants_instance.depth_of_active_soil_layer == exp_val

log_check(caplog=caplog, expected_log=exp_log)
10 changes: 5 additions & 5 deletions tests/core/test_constants_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
"core",
"CoreConsts",
does_not_raise(),
123.4,
0.25,
((INFO, "Initialised core.CoreConsts from config"),),
id="default_values",
),
pytest.param(
"[core.constants.CoreConsts]\nplaceholder=432.1",
"[core.constants.CoreConsts]\ndepth_of_active_soil_layer=1.5",
"core",
"CoreConsts",
does_not_raise(),
432.1,
1.5,
((INFO, "Initialised core.CoreConsts from config"),),
id="configured_value",
),
Expand Down Expand Up @@ -96,7 +96,7 @@ def test_load_constants(
assert isinstance(constants_instance, CoreConsts)
# The unconfigurable zero_Celsius should take the default value
assert constants_instance.zero_Celsius == constants.zero_Celsius
# Check the placeholder constant has been configured
assert constants_instance.placeholder == exp_val
# Check the depth_of_active_soil_layer constant has been configured
assert constants_instance.depth_of_active_soil_layer == exp_val

log_check(caplog=caplog, expected_log=exp_log)
2 changes: 2 additions & 0 deletions tests/core/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,8 @@ def test_output_current_state(mocker, dummy_carbon_data, time_index):
"soil_c_pool_lmwc",
"soil_c_pool_microbe",
"soil_c_pool_pom",
"soil_enzyme_pom",
"soil_enzyme_maom",
],
time_index,
)
Expand Down
Loading