diff --git a/tests/conftest.py b/tests/conftest.py index 421611ce3..e03c25145 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -265,11 +265,16 @@ def dummy_carbon_data(fixture_core_components): "soil_n_pool_particulate": [0.00714285, 0.00071425, 0.00285714, 0.01428571], "soil_n_pool_necromass": [0.00288462, 0.01788462, 0.02019231, 0.01115385], "soil_n_pool_maom": [0.86538462, 0.48076923, 0.32692308, 0.09615385], + "soil_p_pool_dop": [5.714e-6, 2.2857120e-5, 5.7142800e-5, 1.1428568e-4], + "soil_p_pool_particulate": [2.857e-5, 2.85714e-4, 1.142856e-4, 5.714284e-4], + "soil_p_pool_necromass": [0.00080769, 0.00011538, 0.00071538, 0.00044615], + "soil_p_pool_maom": [0.01307692, 0.03461538, 0.01923077, 0.00384615], "pH": [3.0, 7.5, 9.0, 5.7], "bulk_density": [1350.0, 1800.0, 1000.0, 1500.0], "clay_fraction": [0.8, 0.3, 0.1, 0.9], "litter_C_mineralisation_rate": [0.00212106, 0.00106053, 0.00049000, 0.0055], "litter_N_mineralisation_rate": [3.5351e-5, 7.0702e-5, 0.000183, 1.63333e-5], + "litter_P_mineralisation_rate": [7.32e-6, 1.41404e-6, 2.82808e-6, 6.53332e-7], "vertical_flow": [0.1, 0.5, 2.5, 1.59], } diff --git a/tests/core/test_data.py b/tests/core/test_data.py index 05a983ae4..cb7cbdfbd 100644 --- a/tests/core/test_data.py +++ b/tests/core/test_data.py @@ -978,6 +978,10 @@ def test_output_current_state(mocker, dummy_carbon_data, time_index): "soil_n_pool_particulate", "soil_n_pool_necromass", "soil_n_pool_maom", + "soil_p_pool_dop", + "soil_p_pool_particulate", + "soil_p_pool_necromass", + "soil_p_pool_maom", ], time_index, ) diff --git a/tests/models/soil/conftest.py b/tests/models/soil/conftest.py index 72d8b5fc5..6ae392cf2 100644 --- a/tests/models/soil/conftest.py +++ b/tests/models/soil/conftest.py @@ -115,6 +115,7 @@ def microbial_changes( return calculate_microbial_changes( soil_c_pool_lmwc=dummy_carbon_data["soil_c_pool_lmwc"], soil_n_pool_don=dummy_carbon_data["soil_n_pool_don"], + soil_p_pool_dop=dummy_carbon_data["soil_p_pool_dop"], soil_c_pool_microbe=dummy_carbon_data["soil_c_pool_microbe"], soil_enzyme_pom=dummy_carbon_data["soil_enzyme_pom"], soil_enzyme_maom=dummy_carbon_data["soil_enzyme_maom"], diff --git a/tests/models/soil/test_pools.py b/tests/models/soil/test_pools.py index ca23af31a..59ace5586 100644 --- a/tests/models/soil/test_pools.py +++ b/tests/models/soil/test_pools.py @@ -36,17 +36,21 @@ def test_calculate_all_pool_updates(dummy_carbon_data, fixture_core_components): soil_pools = SoilPools(data=dummy_carbon_data, pools=pools, constants=SoilConsts) change_in_pools = { - "soil_c_pool_lmwc": [0.0129365, 0.0060499, 0.03697928, 0.02425546], + "soil_c_pool_lmwc": [0.01510858, 0.01400719, 0.03697928, 0.02426899], "soil_c_pool_maom": [0.038767651, 0.00829848, 0.05982197, 0.07277182], - "soil_c_pool_microbe": [-0.05362396, -0.02020101, -0.11965575, -0.00719517], + "soil_c_pool_microbe": [-0.0544059, -0.02282691, -0.11965575, -0.00720166], "soil_c_pool_pom": [0.00177803841, -0.007860960795, -0.012016245, 0.00545032], "soil_c_pool_necromass": [0.001137474, 0.009172067, 0.033573266, -0.08978050], "soil_enzyme_pom": [1.18e-8, 1.67e-8, 1.8e-9, -1.12e-8], "soil_enzyme_maom": [-0.00031009, -5.09593e-5, 0.0005990658, -3.72112e-5], - "soil_n_pool_don": [0.00104884, 0.00419763, 0.00496839, 0.00251317], + "soil_n_pool_don": [0.00119921, 0.00470261, 0.00496839, 0.00251442], "soil_n_pool_particulate": [1.102338e-5, 6.422491e-5, 0.000131687, 1.461799e-5], "soil_n_pool_necromass": [0.00786114, -0.01209909, 0.00432363, -0.00891218], "soil_n_pool_maom": [0.00148604, 0.01179891, 0.01365197, 0.0077315], + "soil_p_pool_dop": [1.92918032e-4, 6.24454858e-5, 1.57222238e-4, 9.94118894e-5], + "soil_p_pool_particulate": [7.22218e-6, -1.13464e-6, 7.86083e-7, 5.85634364e-7], + "soil_p_pool_necromass": [2.674836e-3, 1.333056e-3, 6.8090685e-3, 4.1429847e-5], + "soil_p_pool_maom": [5.52086672e-4, 3.68566732e-5, 4.7566130e-4, 3.09257058e-4], } # Make order of pools object @@ -72,9 +76,10 @@ def test_calculate_microbial_changes( from virtual_ecosystem.models.soil.pools import calculate_microbial_changes - expected_lmwc_uptake = [2.241176e-3, 8.433524e-3, 1.556094e-3, 5.7736357e-5] - expected_don_uptake = [1.5515837e-4, 5.3520443e-4, 8.97746776e-5, 5.3295099e-6] - expected_microbe = [-0.05362396, -0.02020101, -0.11965575, -0.00719517] + expected_lmwc_uptake = [6.90989514e-5, 4.76229800e-4, 1.55609440e-3, 4.42097002e-5] + expected_don_uptake = [4.78377356e-6, 3.02222758e-5, 8.97746767e-5, 4.08089540e-6] + expected_dop_uptake = [1.55472641e-6, 9.82223962e-6, 2.91767699e-5, 1.32629101e-6] + expected_microbe = [-0.0544059, -0.02282691, -0.11965575, -0.00720166] expected_pom_enzyme = [1.17571917e-8, 1.67442231e-8, 1.83311362e-9, -1.11675865e-8] expected_maom_enzyme = [-3.1009224e-4, -5.0959256e-5, 5.9906583e-4, -3.7211168e-5] expected_necromass = [0.05474086, 0.02303502, 0.11952352, 0.00726011] @@ -82,6 +87,7 @@ def test_calculate_microbial_changes( mic_changes = calculate_microbial_changes( soil_c_pool_lmwc=dummy_carbon_data["soil_c_pool_lmwc"], soil_n_pool_don=dummy_carbon_data["soil_n_pool_don"], + soil_p_pool_dop=dummy_carbon_data["soil_p_pool_dop"], soil_c_pool_microbe=dummy_carbon_data["soil_c_pool_microbe"], soil_enzyme_pom=dummy_carbon_data["soil_enzyme_pom"], soil_enzyme_maom=dummy_carbon_data["soil_enzyme_maom"], @@ -95,6 +101,7 @@ def test_calculate_microbial_changes( # Check that each rate matches expectation assert np.allclose(mic_changes.lmwc_uptake, expected_lmwc_uptake) assert np.allclose(mic_changes.don_uptake, expected_don_uptake) + assert np.allclose(mic_changes.dop_uptake, expected_dop_uptake) assert np.allclose(mic_changes.microbe_change, expected_microbe) assert np.allclose(mic_changes.pom_enzyme_change, expected_pom_enzyme) assert np.allclose(mic_changes.maom_enzyme_change, expected_maom_enzyme) @@ -225,27 +232,36 @@ def test_calculate_nutrient_uptake_rates( calculate_nutrient_uptake_rates, ) - expected_carbon_gain = [8.06823526e-4, 2.78306304e-3, 4.66828324e-4, 2.77134516e-5] - expected_nitrogen_gain = [1.5515837e-4, 5.3520443e-4, 8.97746776e-5, 5.3295099e-6] - expected_carbon_consumption = [2.241176e-3, 8.433524e-3, 1.556094e-3, 5.7736357e-5] - - actual_carbon_gain, actual_carbon_consumption, actual_nitrogen_gain = ( - calculate_nutrient_uptake_rates( - soil_c_pool_lmwc=dummy_carbon_data["soil_c_pool_lmwc"], - soil_n_pool_don=dummy_carbon_data["soil_n_pool_don"], - soil_c_pool_microbe=dummy_carbon_data["soil_c_pool_microbe"], - water_factor=environmental_factors.water, - pH_factor=environmental_factors.pH, - soil_temp=dummy_carbon_data["soil_temperature"][ - fixture_core_components.layer_structure.index_topsoil_scalar - ].to_numpy(), - constants=SoilConsts, - ) + expected_carbon_gain = [2.48756225e-5, 1.57155834e-4, 4.66828319e-4, 2.12206561e-5] + expected_consumption_rates = { + "nitrogen": [4.78377356e-6, 3.02222758e-5, 8.97746767e-5, 4.08089540e-6], + "phosphorus": [1.55472641e-6, 9.82223962e-6, 2.91767699e-5, 1.32629101e-6], + "carbon": [6.90989514e-5, 4.76229800e-4, 1.55609440e-3, 4.42097002e-5], + } + + actual_carbon_gain, actual_consumption_rates = calculate_nutrient_uptake_rates( + soil_c_pool_lmwc=dummy_carbon_data["soil_c_pool_lmwc"], + soil_n_pool_don=dummy_carbon_data["soil_n_pool_don"], + soil_p_pool_dop=dummy_carbon_data["soil_p_pool_dop"], + soil_c_pool_microbe=dummy_carbon_data["soil_c_pool_microbe"], + water_factor=environmental_factors.water, + pH_factor=environmental_factors.pH, + soil_temp=dummy_carbon_data["soil_temperature"][ + fixture_core_components.layer_structure.index_topsoil_scalar + ].to_numpy(), + constants=SoilConsts, ) assert np.allclose(actual_carbon_gain, expected_carbon_gain) - assert np.allclose(actual_nitrogen_gain, expected_nitrogen_gain) - assert np.allclose(actual_carbon_consumption, expected_carbon_consumption) + + assert set(expected_consumption_rates.keys()) == set( + actual_consumption_rates.keys() + ) + + for key in expected_consumption_rates.keys(): + assert np.allclose( + expected_consumption_rates[key], actual_consumption_rates[key] + ) def test_calculate_highest_achievable_nutrient_uptake( @@ -409,52 +425,71 @@ def test_calculate_nutrient_flows_to_necromass(microbial_changes): ) expected_n_flow_to_necromass = [0.01052709, 0.00442981, 0.02298529, 0.00139617] + expected_p_flow_to_necromass = [0.0034213, 0.00143969, 0.00747022, 0.00045376] - actual_n_flow_to_necromass = calculate_nutrient_flows_to_necromass( - microbial_changes=microbial_changes, constants=SoilConsts + actual_n_flow_to_necromass, actual_p_flow_to_necromass = ( + calculate_nutrient_flows_to_necromass( + microbial_changes=microbial_changes, constants=SoilConsts + ) ) assert np.allclose(actual_n_flow_to_necromass, expected_n_flow_to_necromass) + assert np.allclose(actual_p_flow_to_necromass, expected_p_flow_to_necromass) -def test_find_necromass_nitrogen_outflows( +def test_find_necromass_nutrient_outflows( dummy_carbon_data, necromass_breakdown, necromass_sorption ): - """Test that function to find necromass nitrogen losses works correctly.""" - from virtual_ecosystem.models.soil.pools import find_necromass_nitrogen_outflows - - expected_decay = [0.00066649, 0.00413222, 0.00466541, 0.00257709] - expected_sorption = [0.00199947, 0.01239667, 0.01399624, 0.00773126] + """Test that function to find necromass nutrient losses works correctly.""" + from virtual_ecosystem.models.soil.pools import find_necromass_nutrient_outflows + + expected_rates = { + "decay_nitrogen": [0.00066649, 0.00413222, 0.00466541, 0.00257709], + "sorption_nitrogen": [0.00199947, 0.01239667, 0.01399624, 0.00773126], + "decay_phosphorus": [1.86616016e-4, 2.6658441e-5, 1.65287877e-4, 1.03082538e-4], + "sorption_phosphorus": [5.5984805e-4, 7.9975322e-5, 4.958636e-4, 3.0924762e-4], + } - actual_decay, actual_sorption = find_necromass_nitrogen_outflows( + actual_rates = find_necromass_nutrient_outflows( necromass_carbon=dummy_carbon_data["soil_c_pool_necromass"], necromass_nitrogen=dummy_carbon_data["soil_n_pool_necromass"], + necromass_phosphorus=dummy_carbon_data["soil_p_pool_necromass"], necromass_decay=necromass_breakdown, necromass_sorption=necromass_sorption, ) - assert np.allclose(actual_decay, expected_decay) - assert np.allclose(actual_sorption, expected_sorption) + assert set(expected_rates.keys()) == set(actual_rates.keys()) + for key in expected_rates.keys(): + assert np.allclose(expected_rates[key], actual_rates[key]) -def test_calculate_net_nitrogen_transfer_from_maom_to_don( + +def test_calculate_net_nutrient_transfers_from_maom_to_lmwc( dummy_carbon_data, enzyme_mediated_rates, lmwc_sorption, maom_desorption ): """Test function to find net exchange of nitrogen between maom and don.""" from virtual_ecosystem.models.soil.pools import ( - calculate_net_nitrogen_transfer_from_maom_to_don, + calculate_net_nutrient_transfers_from_maom_to_lmwc, ) - expected_transfer = [5.13427177e-4, 5.97759087e-4, 3.44268148e-4, -2.36081562e-7] + expected_transfers = { + "nitrogen": [5.13427177e-4, 5.97759087e-4, 3.44268148e-4, -2.36081562e-7], + "phosphorus": [7.76137416e-6, 4.31186485e-5, 2.02023283e-5, -9.44337153e-9], + } - actual_transfer = calculate_net_nitrogen_transfer_from_maom_to_don( + actual_transfers = calculate_net_nutrient_transfers_from_maom_to_lmwc( lmwc_carbon=dummy_carbon_data["soil_c_pool_lmwc"], lmwc_nitrogen=dummy_carbon_data["soil_n_pool_don"], + lmwc_phosphorus=dummy_carbon_data["soil_p_pool_dop"], maom_carbon=dummy_carbon_data["soil_c_pool_maom"], maom_nitrogen=dummy_carbon_data["soil_n_pool_maom"], + maom_phosphorus=dummy_carbon_data["soil_p_pool_maom"], maom_breakdown=enzyme_mediated_rates.maom_to_lmwc, maom_desorption=maom_desorption, lmwc_sorption=lmwc_sorption, ) - assert np.allclose(actual_transfer, expected_transfer) + assert set(expected_transfers.keys()) == set(actual_transfers.keys()) + + for key in expected_transfers.keys(): + assert np.allclose(expected_transfers[key], actual_transfers[key]) diff --git a/tests/models/soil/test_soil_model.py b/tests/models/soil/test_soil_model.py index ca07c812a..2b292e283 100644 --- a/tests/models/soil/test_soil_model.py +++ b/tests/models/soil/test_soil_model.py @@ -25,6 +25,10 @@ (DEBUG, "soil model: required var 'soil_n_pool_particulate' checked"), (DEBUG, "soil model: required var 'soil_n_pool_necromass' checked"), (DEBUG, "soil model: required var 'soil_n_pool_maom' checked"), + (DEBUG, "soil model: required var 'soil_p_pool_dop' checked"), + (DEBUG, "soil model: required var 'soil_p_pool_particulate' checked"), + (DEBUG, "soil model: required var 'soil_p_pool_necromass' checked"), + (DEBUG, "soil model: required var 'soil_p_pool_maom' checked"), (DEBUG, "soil model: required var 'pH' checked"), (DEBUG, "soil model: required var 'bulk_density' checked"), (DEBUG, "soil model: required var 'clay_fraction' checked"), @@ -285,20 +289,20 @@ def test_update(mocker, fixture_soil_model, dummy_carbon_data): Dataset( data_vars=dict( soil_c_pool_lmwc=DataArray( - [0.0558832, 0.02294602, 0.11309406, 0.01485682], dims="cell_id" + [0.0571695, 0.02695769, 0.11767019, 0.01488859], dims="cell_id" ), soil_c_pool_maom=DataArray( [2.5194618, 1.70483236, 4.53238116, 0.52968038], dims="cell_id" ), soil_c_pool_microbe=DataArray( - [5.77347072, 2.29002259, 11.24219185, 0.99642319], + [5.77300855, 2.28870164, 11.24082106, 0.99640795], dims="cell_id", ), soil_c_pool_pom=DataArray( [0.10088826, 0.99607827, 0.69401858, 0.35272508], dims="cell_id" ), soil_c_pool_necromass=DataArray( - [0.05840173, 0.01865113, 0.10631256, 0.06904725], dims="cell_id" + [0.05840079, 0.01864821, 0.10630987, 0.06904723], dims="cell_id" ), soil_enzyme_pom=DataArray( [0.02267842, 0.00957576, 0.05004963, 0.00300993], dims="cell_id" @@ -307,17 +311,31 @@ def test_update(mocker, fixture_soil_model, dummy_carbon_data): [0.0354453, 0.01167442, 0.02538637, 0.00454144], dims="cell_id" ), soil_n_pool_don=DataArray( - [0.00124825, 0.00320679, 0.00236633, 0.00388298], dims="cell_id" + [0.00133728, 0.00346121, 0.00262946, 0.0038859], dims="cell_id" ), soil_n_pool_particulate=DataArray( [0.00714836, 0.00074629, 0.00292269, 0.01429302], dims="cell_id" ), soil_n_pool_necromass=DataArray( - [0.00602181, 0.01303618, 0.02189848, 0.00758444], dims="cell_id" + [0.00602163, 0.01303562, 0.02189796, 0.00758443], dims="cell_id" ), soil_n_pool_maom=DataArray( [0.86671423, 0.48576345, 0.33406677, 0.09935391], dims="cell_id" ), + soil_p_pool_dop=DataArray( + [1.59404568e-4, 8.17510225e-5, 2.73598058e-4, 1.64590927e-4], + dims="cell_id", + ), + soil_p_pool_particulate=DataArray( + [3.21780215e-5, 2.85147941e-4, 1.14676885e-4, 5.71721209e-4], + dims="cell_id", + ), + soil_p_pool_necromass=DataArray( + [0.00187526, 0.00064761, 0.00343342, 0.00046239], dims="cell_id" + ), + soil_p_pool_maom=DataArray( + [0.01355237, 0.03473323, 0.01997613, 0.00400384], dims="cell_id" + ), ) ), (), @@ -398,6 +416,7 @@ def test_order_independance( "clay_fraction", "litter_C_mineralisation_rate", "litter_N_mineralisation_rate", + "litter_P_mineralisation_rate", ] for not_pool in not_pools: new_data[not_pool] = dummy_carbon_data[not_pool] @@ -436,18 +455,18 @@ def test_construct_full_soil_model(dummy_carbon_data, fixture_core_components): ) delta_pools = [ - 0.0129365, - 0.0060499, + 0.01510858, + 0.01400719, 0.03697928, - 0.02425546, + 0.02426899, 0.038767651, 0.00829848, 0.05982197, 0.07277182, - -0.05362396, - -0.02020101, + -0.0544059, + -0.02282691, -0.11965575, - -0.00719517, + -0.00720166, 0.00177803841, -0.007860960795, -0.012016245, @@ -464,10 +483,10 @@ def test_construct_full_soil_model(dummy_carbon_data, fixture_core_components): -5.09593e-5, 0.0005990658, -3.72112e-5, - 0.00104884, - 0.00419763, + 0.00119921, + 0.00470261, 0.00496839, - 0.00251317, + 0.00251442, 1.102338e-5, 6.422491e-5, 0.000131687, @@ -480,6 +499,22 @@ def test_construct_full_soil_model(dummy_carbon_data, fixture_core_components): 0.01179891, 0.01365197, 0.0077315, + 1.92918032e-4, + 6.24454858e-5, + 1.57222238e-4, + 9.94118894e-5, + 7.22218e-6, + -1.13464e-6, + 7.86083e-7, + 5.85634364e-7, + 2.674836e-3, + 1.333056e-3, + 6.8090685e-3, + 4.1429847e-5, + 5.52086672e-4, + 3.68566732e-5, + 4.7566130e-4, + 3.09257058e-4, ] # make pools diff --git a/tests/test_main.py b/tests/test_main.py index a388bbe0e..ed82ae103 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -32,6 +32,10 @@ (DEBUG, "soil model: required var 'soil_n_pool_particulate' checked"), (DEBUG, "soil model: required var 'soil_n_pool_necromass' checked"), (DEBUG, "soil model: required var 'soil_n_pool_maom' checked"), + (DEBUG, "soil model: required var 'soil_p_pool_dop' checked"), + (DEBUG, "soil model: required var 'soil_p_pool_particulate' checked"), + (DEBUG, "soil model: required var 'soil_p_pool_necromass' checked"), + (DEBUG, "soil model: required var 'soil_p_pool_maom' checked"), (DEBUG, "soil model: required var 'pH' checked"), (DEBUG, "soil model: required var 'bulk_density' checked"), (DEBUG, "soil model: required var 'clay_fraction' checked"), diff --git a/virtual_ecosystem/data_variables.toml b/virtual_ecosystem/data_variables.toml index dc6d23ae3..e177291c7 100644 --- a/virtual_ecosystem/data_variables.toml +++ b/virtual_ecosystem/data_variables.toml @@ -600,6 +600,34 @@ name = "soil_n_pool_maom" unit = "kg N m^-3" variable_type = "float" +[[variable]] +axis = ["spatial"] +description = "Dissolved organic phosphorus pool" +name = "soil_p_pool_dop" +unit = "kg P m^-3" +variable_type = "float" + +[[variable]] +axis = ["spatial"] +description = "Particulate organic phosphorus pool" +name = "soil_p_pool_particulate" +unit = "kg P m^-3" +variable_type = "float" + +[[variable]] +axis = ["spatial"] +description = "Amount of phosphorus contained in the necromass pool" +name = "soil_p_pool_necromass" +unit = "kg P m^-3" +variable_type = "float" + +[[variable]] +axis = ["spatial"] +description = "Amount of phosphorus contained in the mineral associated organic matter pool" +name = "soil_p_pool_maom" +unit = "kg P m^-3" +variable_type = "float" + [[variable]] axis = ["spatial"] description = "Bulk density of soil" diff --git a/virtual_ecosystem/example_data/config/data_config.toml b/virtual_ecosystem/example_data/config/data_config.toml index 6bc9c5cb1..f6dc4a2ba 100644 --- a/virtual_ecosystem/example_data/config/data_config.toml +++ b/virtual_ecosystem/example_data/config/data_config.toml @@ -77,6 +77,18 @@ var_name = "soil_n_pool_necromass" [[core.data.variable]] file = "../data/example_soil_data.nc" var_name = "soil_n_pool_maom" +[[core.data.variable]] +file = "../data/example_soil_data.nc" +var_name = "soil_p_pool_dop" +[[core.data.variable]] +file = "../data/example_soil_data.nc" +var_name = "soil_p_pool_particulate" +[[core.data.variable]] +file = "../data/example_soil_data.nc" +var_name = "soil_p_pool_necromass" +[[core.data.variable]] +file = "../data/example_soil_data.nc" +var_name = "soil_p_pool_maom" # Litter [[core.data.variable]] diff --git a/virtual_ecosystem/example_data/data/example_soil_data.nc b/virtual_ecosystem/example_data/data/example_soil_data.nc index cb06a00f0..581bf0df2 100644 Binary files a/virtual_ecosystem/example_data/data/example_soil_data.nc and b/virtual_ecosystem/example_data/data/example_soil_data.nc differ diff --git a/virtual_ecosystem/example_data/generation_scripts/soil_example_data.py b/virtual_ecosystem/example_data/generation_scripts/soil_example_data.py index d3d81fcca..e4b55268e 100644 --- a/virtual_ecosystem/example_data/generation_scripts/soil_example_data.py +++ b/virtual_ecosystem/example_data/generation_scripts/soil_example_data.py @@ -59,6 +59,21 @@ # nitrogen pool [kg N m^-3]. necromass_n_values = 3e-5 + 7e-5 * gradient / 64.0 +# Generate a range of plausible values (1e-5 - 2e-5) for the DOP pool [kg P m^-3] +dop_values = 1e-5 + 1e-5 * gradient / 64.0 + +# Generate a range of plausible values (3e-5 - 6e-5) for the particulate P pool [kg P +# m^-3] +particulate_p_values = 3e-5 + 3e-5 * gradient / 64.0 + +# Generate a range of plausible values (0.008-0.024) for the maom phosphorus pool [kg P +# m^-3]. +maom_p_values = 0.008 + 0.016 * gradient / 64.0 + +# Generate a range of plausible values (1.2e-6 - 4e-6) for the microbial necromass +# phosphorus pool [kg P m^-3]. +necromass_p_values = 1.2e-6 + 2.8e-6 * gradient / 64.0 + # Make example soil dataset example_soil_data = Dataset( data_vars=dict( @@ -76,6 +91,10 @@ soil_n_pool_particulate=(["x", "y"], particulate_n_values), soil_n_pool_maom=(["x", "y"], maom_n_values), soil_n_pool_necromass=(["x", "y"], necromass_n_values), + soil_p_pool_dop=(["x", "y"], dop_values), + soil_p_pool_particulate=(["x", "y"], particulate_p_values), + soil_p_pool_maom=(["x", "y"], maom_p_values), + soil_p_pool_necromass=(["x", "y"], necromass_p_values), ), coords=dict( x=(["x"], cell_displacements), diff --git a/virtual_ecosystem/models/soil/constants.py b/virtual_ecosystem/models/soil/constants.py index 92178c8b4..004e23711 100644 --- a/virtual_ecosystem/models/soil/constants.py +++ b/virtual_ecosystem/models/soil/constants.py @@ -263,6 +263,13 @@ class SoilConsts(ConstantsDataclass): a loose manner. """ + solubility_coefficient_dop: float = 1.0 + """Solubility coefficient for dissolved organic phosphorus [unitless]. + + Value taken from :cite:t:`fatichi_mechanistic_2019`, where it is estimated in quite + a loose manner. + """ + necromass_decay_rate: float = (1 / 3) * np.log(2) """Rate at which microbial necromass decays to low molecular weight carbon [day^-1] @@ -310,6 +317,13 @@ class SoilConsts(ConstantsDataclass): an order of magnitude estimate taken from :cite:t:`fatichi_mechanistic_2019`. """ + litter_leaching_fraction_phosphorus = 0.0001 + """Fraction of phosphorus mineralisation from litter that occurs by leaching. + + [unitless]. The remainder of the mineralisation consists of particulates. Value is + an order of magnitude estimate taken from :cite:t:`fatichi_mechanistic_2019`. + """ + microbial_c_n_ratio = 5.2 """Ratio of carbon to nitrogen in microbial biomass [unitless]. @@ -318,8 +332,16 @@ class SoilConsts(ConstantsDataclass): added this constant needs to be split. """ + microbial_c_p_ratio = 16 + """Ratio of carbon to phosphorus in microbial biomass [unitless]. + + Estimate taken from :cite:t:`fatichi_mechanistic_2019`, which estimates this based + on previous literature. Here using specifically the bacterial value, once fungi are + added this constant needs to be split. + """ + max_uptake_rate_don = 0.0077 - """Maximum rate at for dissolved organic nitrogen uptake [day^-1]. + """Maximum possible rate for dissolved organic nitrogen uptake [day^-1]. This rate corresponds to the reference temperature given by :attr:`arrhenius_reference_temp`, with the corresponding activation energy given by @@ -339,3 +361,25 @@ class SoilConsts(ConstantsDataclass): TODO - At present I've invented the value for this constant, so it really needs to be better pinned down. """ + + max_uptake_rate_dop = 0.0025 + """Maximum possible rate for dissolved organic phosphorus uptake [day^-1]. + + This rate corresponds to the reference temperature given by + :attr:`arrhenius_reference_temp`, with the corresponding activation energy given by + :attr:`activation_energy_microbial_uptake`. + + TODO - At present I've invented the value for this constant, so it really needs to + be better pinned down. + """ + + half_sat_dop_uptake: float = 0.02275 + """Half saturation constant for uptake of dissolved organic phosphorus (DOP). + + [kg P m^-3]. The reference temperature is given by :attr:`arrhenius_reference_temp`, + and the corresponding activation energy is given by + :attr:`activation_energy_uptake_saturation`. + + TODO - At present I've invented the value for this constant, so it really needs to + be better pinned down. + """ diff --git a/virtual_ecosystem/models/soil/pools.py b/virtual_ecosystem/models/soil/pools.py index baa3def1f..394819306 100644 --- a/virtual_ecosystem/models/soil/pools.py +++ b/virtual_ecosystem/models/soil/pools.py @@ -1,9 +1,9 @@ """The ``models.soil.pools`` module simulates all soil pools for the Virtual -Ecosystem. At the moment four carbon pools are modelled (low molecular weight carbon +Ecosystem. At the moment five carbon pools are modelled (low molecular weight carbon (LMWC), mineral associated organic matter (MAOM), microbial biomass, particulate organic -matter (POM)), as well as two enzyme pools (POM and MAOM) degrading enzymes, and two -nitrogen pools (dissolved organic nitrogen (DON) and particulate organic nitrogen -(PON)). +matter (POM), microbial necromass), as well as two enzyme pools (POM and MAOM) degrading +enzymes. Pools that track the nitrogen and phosphorus pools associated with each of the +carbon pools are also included. """ # noqa: D205 from dataclasses import dataclass @@ -38,6 +38,11 @@ class MicrobialChanges: Units of [kg N m^-3 day^-1].""" + dop_uptake: NDArray[np.float32] + """Total rate of microbial uptake of dissolved organic phosphorus. + + Units of [kg P m^-3 day^-1].""" + microbe_change: NDArray[np.float32] """Rate of change of microbial biomass pool [kg C m^-3 day^-1].""" @@ -147,6 +152,7 @@ def calculate_all_pool_updates( microbial_changes = calculate_microbial_changes( soil_c_pool_lmwc=self.pools["soil_c_pool_lmwc"], soil_n_pool_don=self.pools["soil_n_pool_don"], + soil_p_pool_dop=self.pools["soil_p_pool_dop"], soil_c_pool_microbe=self.pools["soil_c_pool_microbe"], soil_enzyme_pom=self.pools["soil_enzyme_pom"], soil_enzyme_maom=self.pools["soil_enzyme_maom"], @@ -177,6 +183,12 @@ def calculate_all_pool_updates( soil_moisture=soil_moisture, solubility_coefficient=self.constants.solubility_coefficient_don, ) + dop_leaching = calculate_leaching_rate( + solute_density=self.pools["soil_p_pool_dop"], + vertical_flow_rate=self.data["vertical_flow"].to_numpy(), + soil_moisture=soil_moisture, + solubility_coefficient=self.constants.solubility_coefficient_dop, + ) # Calculate transfers between the lmwc, necromass and maom pools maom_desorption_to_lmwc = calculate_maom_desorption( @@ -208,32 +220,44 @@ def calculate_all_pool_updates( mineralisation_rate=self.data["litter_N_mineralisation_rate"].to_numpy(), litter_leaching_coefficient=self.constants.litter_leaching_fraction_nitrogen, ) + litter_mineralisation_fluxes_P = calculate_litter_mineralisation_split( + mineralisation_rate=self.data["litter_P_mineralisation_rate"].to_numpy(), + litter_leaching_coefficient=self.constants.litter_leaching_fraction_phosphorus, + ) - # Find mineralisation rate from POM + # Find mineralisation rates from POM pom_n_mineralisation = calculate_soil_nutrient_mineralisation( pool_carbon=self.pools["soil_c_pool_pom"], pool_nutrient=self.pools["soil_n_pool_particulate"], breakdown_rate=enzyme_mediated.pom_to_lmwc, ) + pom_p_mineralisation = calculate_soil_nutrient_mineralisation( + pool_carbon=self.pools["soil_c_pool_pom"], + pool_nutrient=self.pools["soil_p_pool_particulate"], + breakdown_rate=enzyme_mediated.pom_to_lmwc, + ) # Find flow of nitrogen to necromass pool - necromass_n_flow = calculate_nutrient_flows_to_necromass( + necromass_n_flow, necromass_p_flow = calculate_nutrient_flows_to_necromass( microbial_changes=microbial_changes, constants=self.constants ) # Find nitrogen released by necromass breakdown/sorption - necromass_n_decay, necromass_n_sorption = find_necromass_nitrogen_outflows( + necromass_outflows = find_necromass_nutrient_outflows( necromass_carbon=self.pools["soil_c_pool_necromass"], necromass_nitrogen=self.pools["soil_n_pool_necromass"], + necromass_phosphorus=self.pools["soil_p_pool_necromass"], necromass_decay=necromass_decay_to_lmwc, necromass_sorption=necromass_sorption_to_maom, ) # Find net nitrogen transfer between maom and lmwc/don - nitrogen_transfer_maom_to_don = ( - calculate_net_nitrogen_transfer_from_maom_to_don( + nutrient_transfers_maom_to_lmwc = ( + calculate_net_nutrient_transfers_from_maom_to_lmwc( lmwc_carbon=self.pools["soil_c_pool_lmwc"], lmwc_nitrogen=self.pools["soil_n_pool_don"], + lmwc_phosphorus=self.pools["soil_p_pool_dop"], maom_carbon=self.pools["soil_c_pool_maom"], maom_nitrogen=self.pools["soil_n_pool_maom"], + maom_phosphorus=self.pools["soil_p_pool_maom"], maom_breakdown=enzyme_mediated.maom_to_lmwc, maom_desorption=maom_desorption_to_lmwc, lmwc_sorption=lmwc_sorption_to_maom, @@ -271,8 +295,8 @@ def calculate_all_pool_updates( delta_pools_ordered["soil_n_pool_don"] = ( litter_mineralisation_fluxes_N["dissolved"] + pom_n_mineralisation - + necromass_n_decay - + nitrogen_transfer_maom_to_don + + necromass_outflows["decay_nitrogen"] + + nutrient_transfers_maom_to_lmwc["nitrogen"] - microbial_changes.don_uptake - don_leaching ) @@ -281,10 +305,33 @@ def calculate_all_pool_updates( litter_mineralisation_fluxes_N["particulate"] - pom_n_mineralisation ) delta_pools_ordered["soil_n_pool_necromass"] = ( - necromass_n_flow - necromass_n_decay - necromass_n_sorption + necromass_n_flow + - necromass_outflows["decay_nitrogen"] + - necromass_outflows["sorption_nitrogen"] ) delta_pools_ordered["soil_n_pool_maom"] = ( - necromass_n_sorption - nitrogen_transfer_maom_to_don + necromass_outflows["sorption_nitrogen"] + - nutrient_transfers_maom_to_lmwc["nitrogen"] + ) + delta_pools_ordered["soil_p_pool_dop"] = ( + litter_mineralisation_fluxes_P["dissolved"] + + pom_p_mineralisation + + necromass_outflows["decay_phosphorus"] + + nutrient_transfers_maom_to_lmwc["phosphorus"] + - microbial_changes.dop_uptake + - dop_leaching + ) + delta_pools_ordered["soil_p_pool_particulate"] = ( + litter_mineralisation_fluxes_P["particulate"] - pom_p_mineralisation + ) + delta_pools_ordered["soil_p_pool_necromass"] = ( + necromass_p_flow + - necromass_outflows["decay_phosphorus"] + - necromass_outflows["sorption_phosphorus"] + ) + delta_pools_ordered["soil_p_pool_maom"] = ( + necromass_outflows["sorption_phosphorus"] + - nutrient_transfers_maom_to_lmwc["phosphorus"] ) delta_pools_ordered["soil_enzyme_pom"] = microbial_changes.pom_enzyme_change delta_pools_ordered["soil_enzyme_maom"] = microbial_changes.maom_enzyme_change @@ -296,6 +343,7 @@ def calculate_all_pool_updates( def calculate_microbial_changes( soil_c_pool_lmwc: NDArray[np.float32], soil_n_pool_don: NDArray[np.float32], + soil_p_pool_dop: NDArray[np.float32], soil_c_pool_microbe: NDArray[np.float32], soil_enzyme_pom: NDArray[np.float32], soil_enzyme_maom: NDArray[np.float32], @@ -313,6 +361,7 @@ def calculate_microbial_changes( Args: soil_c_pool_lmwc: Low molecular weight carbon pool [kg C m^-3] soil_n_pool_don: Dissolved organic nitrogen pool [kg N m^-3] + soil_p_pool_dop: Dissolved organic phosphorus pool [kg P m^-3] soil_c_pool_microbe: Microbial biomass (carbon) pool [kg C m^-3] soil_enzyme_pom: Amount of enzyme class which breaks down particulate organic matter [kg C m^-3] @@ -324,21 +373,20 @@ def calculate_microbial_changes( constants: Set of constants for the soil model. Returns: - A dataclass containing the rate at which microbes uptake LMWC, the rate of - change in the microbial biomass pool and the enzyme pools. + A dataclass containing the rate at which microbes uptake LMWC, DON and DOP, and + the rate of change in the microbial biomass pool and the enzyme pools. """ # Calculate uptake, growth rate, and loss rate - biomass_growth, microbial_C_uptake, microbial_N_uptake = ( - calculate_nutrient_uptake_rates( - soil_c_pool_lmwc=soil_c_pool_lmwc, - soil_n_pool_don=soil_n_pool_don, - soil_c_pool_microbe=soil_c_pool_microbe, - water_factor=env_factors.water, - pH_factor=env_factors.pH, - soil_temp=soil_temp, - constants=constants, - ) + biomass_growth, microbial_uptake = calculate_nutrient_uptake_rates( + soil_c_pool_lmwc=soil_c_pool_lmwc, + soil_n_pool_don=soil_n_pool_don, + soil_p_pool_dop=soil_p_pool_dop, + soil_c_pool_microbe=soil_c_pool_microbe, + water_factor=env_factors.water, + pH_factor=env_factors.pH, + soil_temp=soil_temp, + constants=constants, ) biomass_loss = calculate_maintenance_biomass_synthesis( soil_c_pool_microbe=soil_c_pool_microbe, @@ -361,8 +409,9 @@ def calculate_microbial_changes( ) * biomass_loss return MicrobialChanges( - lmwc_uptake=microbial_C_uptake, - don_uptake=microbial_N_uptake, + lmwc_uptake=microbial_uptake["carbon"], + don_uptake=microbial_uptake["nitrogen"], + dop_uptake=microbial_uptake["phosphorus"], microbe_change=biomass_growth - biomass_loss, pom_enzyme_change=pom_enzyme_net_change, maom_enzyme_change=maom_enzyme_net_change, @@ -547,12 +596,13 @@ def calculate_enzyme_turnover( def calculate_nutrient_uptake_rates( soil_c_pool_lmwc: NDArray[np.float32], soil_n_pool_don: NDArray[np.float32], + soil_p_pool_dop: NDArray[np.float32], soil_c_pool_microbe: NDArray[np.float32], water_factor: NDArray[np.float32], pH_factor: NDArray[np.float32], soil_temp: NDArray[np.float32], constants: SoilConsts, -) -> tuple[NDArray[np.float32], NDArray[np.float32], NDArray[np.float32]]: +) -> tuple[NDArray[np.float32], dict[str, NDArray[np.float32]]]: """Calculate the rate at which microbes uptake each nutrient. These rates are found based on the assumption that microbial stochiometry is @@ -569,6 +619,7 @@ def calculate_nutrient_uptake_rates( Args: soil_c_pool_lmwc: Low molecular weight carbon pool [kg C m^-3] soil_n_pool_don: Dissolved organic nitrogen pool [kg N m^-3] + soil_p_pool_dop: Dissolved organic phosphorus pool [kg P m^-3] soil_c_pool_microbe: Microbial biomass (carbon) pool [kg C m^-3] water_factor: A factor capturing the impact of soil water potential on microbial rates [unitless] @@ -579,7 +630,8 @@ def calculate_nutrient_uptake_rates( Returns: A tuple containing the rate at which microbial biomass increases due to nutrient - uptake, and the rate at which carbon and nitrogen get taken up. + uptake, as well as a dictionary containing the rate at which carbon, nitrogen + and phosphorus get taken up. """ # Calculate carbon use efficiency @@ -611,23 +663,40 @@ def calculate_nutrient_uptake_rates( half_saturation_constant=constants.half_sat_don_uptake, constants=constants, ) + phosphorus_uptake_rate_max = calculate_highest_achievable_nutrient_uptake( + labile_nutrient_pool=soil_p_pool_dop, + soil_c_pool_microbe=soil_c_pool_microbe, + water_factor=water_factor, + pH_factor=pH_factor, + soil_temp=soil_temp, + max_uptake_rate=constants.max_uptake_rate_dop, + half_saturation_constant=constants.half_sat_dop_uptake, + constants=constants, + ) # Use carbon use efficency to determine maximum possible rate of carbon gain carbon_gain_max = carbon_uptake_rate_max * carbon_use_efficency # Find actual rate of carbon gain based on most limiting uptake rate, then find # nutrient gain and total carbon consumption based on this - actual_carbon_gain = np.minimum( - carbon_gain_max, constants.microbial_c_n_ratio * nitrogen_uptake_rate_max + actual_carbon_gain = np.minimum.reduce( + [ + carbon_gain_max, + constants.microbial_c_n_ratio * nitrogen_uptake_rate_max, + constants.microbial_c_p_ratio * phosphorus_uptake_rate_max, + ] ) - nitrogen_consumption_rate = actual_carbon_gain / constants.microbial_c_n_ratio - carbon_consumption_rate = actual_carbon_gain / carbon_use_efficency + consumption_rates = { + "nitrogen": actual_carbon_gain / constants.microbial_c_n_ratio, + "phosphorus": actual_carbon_gain / constants.microbial_c_p_ratio, + "carbon": actual_carbon_gain / carbon_use_efficency, + } # TODO - the quantities calculated above can be used to calculate the carbon # respired instead of being uptaken. This isn't currently of interest, but will be # in future - return actual_carbon_gain, carbon_consumption_rate, nitrogen_consumption_rate + return actual_carbon_gain, consumption_rates def calculate_highest_achievable_nutrient_uptake( @@ -880,7 +949,7 @@ def calculate_soil_nutrient_mineralisation( def calculate_nutrient_flows_to_necromass( microbial_changes: MicrobialChanges, constants: SoilConsts -) -> NDArray[np.float32]: +) -> tuple[NDArray[np.float32], NDArray[np.float32]]: """Calculate the rate at which nutrients flow into the necromass pool. These flows comprise of the nitrogen and phosphorus content of the dead cells and @@ -897,70 +966,87 @@ def calculate_nutrient_flows_to_necromass( constants: Set of constants for the soil model. Returns: - The rate at which nitrogen is added to the necromass pool [kg N m^-3 day^-1] + A tuple containing the rates at which nitrogen [kg N m^-3 day^-1] and phosphorus + [kg P m^-3 day^-1] are added to the soil necromass pool """ - return microbial_changes.necromass_generation / constants.microbial_c_n_ratio + return ( + microbial_changes.necromass_generation / constants.microbial_c_n_ratio, + microbial_changes.necromass_generation / constants.microbial_c_p_ratio, + ) -def find_necromass_nitrogen_outflows( +def find_necromass_nutrient_outflows( necromass_carbon: NDArray[np.float32], necromass_nitrogen: NDArray[np.float32], + necromass_phosphorus: NDArray[np.float32], necromass_decay: NDArray[np.float32], necromass_sorption: NDArray[np.float32], -) -> tuple[NDArray[np.float32], NDArray[np.float32]]: - """Find the amount of nitrogen flowing out of the necromass pool. +) -> dict[str, NDArray[np.float32]]: + """Find the amount of each nutrient flowing out of the necromass pool. There are two sources for this outflow. Firstly, the decay of necromass to dissolved - organic nitrogen. Secondly, the sorption of necromass to soil minerals to form - mineral associated organic matter. A key assumption here is that nitrogen flow - directly follows the carbon flow, i.e. it follows the same split between pathways as - the carbon does. + organic nitrogen/phosphorus. Secondly, the sorption of necromass to soil minerals to + form mineral associated organic matter. A key assumption here is that the nitrogen + and phosphorus flows directly follows the carbon flow, i.e. it follows the same + split between pathways as the carbon does. Args: necromass_carbon: The amount of carbon stored as microbial necromass [kg C m^-3] necromass_nitrogen: The amount of nitrogen stored as microbial necromass [kg N m^-3] + necromass_phosphorus: The amount of phosphorus stored as microbial necromass [kg + P m^-3] necromass_decay: The rate at which necromass decays to form lmwc [kg C m^-3 day^-1] necromass_sorption: The rate at which necromass gets sorbed to soil minerals to form mineral associated organic matter [kg C m^-3 day^-1] Returns: - A tuple containing the rate at which nitrogen contained in necromass is released - as dissolved organic nitrogen, and the rate at which it gets sorbed to soil - minerals to form soil associated organic matter [kg N m^-3 day^-1]. + A dictionary containing the rates at which nitrogen and phosphrous contained in + necromass is released as dissolved organic nitrogen, and the rates at which they + gets sorbed to soil minerals to form soil associated organic matter [kg nutrient + m^-3 day^-1]. """ - # Find carbon:nitrogen ratio of the necromass + # Find carbon:nitrogen and carbon:phosphorus ratios of the necromass c_n_ratio = necromass_carbon / necromass_nitrogen + c_p_ratio = necromass_carbon / necromass_phosphorus - decay_nitrogen = necromass_decay / c_n_ratio - sorption_nitrogen = necromass_sorption / c_n_ratio - - return decay_nitrogen, sorption_nitrogen + return { + "decay_nitrogen": necromass_decay / c_n_ratio, + "sorption_nitrogen": necromass_sorption / c_n_ratio, + "decay_phosphorus": necromass_decay / c_p_ratio, + "sorption_phosphorus": necromass_sorption / c_p_ratio, + } -def calculate_net_nitrogen_transfer_from_maom_to_don( +def calculate_net_nutrient_transfers_from_maom_to_lmwc( lmwc_carbon: NDArray[np.float32], lmwc_nitrogen: NDArray[np.float32], + lmwc_phosphorus: NDArray[np.float32], maom_carbon: NDArray[np.float32], maom_nitrogen: NDArray[np.float32], + maom_phosphorus: NDArray[np.float32], maom_breakdown: NDArray[np.float32], maom_desorption: NDArray[np.float32], lmwc_sorption: NDArray[np.float32], -) -> NDArray[np.float32]: - """Calculate the net rate of transfer of nitrogen between MAOM and LMWC/DON. +) -> dict[str, NDArray[np.float32]]: + """Calculate the net rate of transfer of nutrients between MAOM and LMWC. Args: lmwc_carbon: The amount of carbon stored as low molecular weight carbon [kg C m^-3] lmwc_nitrogen: The amount of nitrogen stored as low molecular weight carbon/dissolved organic nitrogen [kg N m^-3] + lmwc_phosphorus: The amount of phosphorus stored as low molecular weight + carbon/dissolved organic phosphorus [kg P m^-3] maom_carbon: The amount of carbon stored as mineral associated organic matter [kg C m^-3] maom_nitrogen: The amount of nitrogen stored as mineral associated organic matter [kg N m^-3] + maom_phosphorus: The amount of phosphorus stored as mineral associated organic + matter [kg P m^-3] maom_breakdown: The rate at which the mineral associated organic matter pool is being broken down by enzymes (expressed in carbon terms) [kg C m^-3 day^-1] maom_desorption: The rate at which the mineral associated organic matter pool is @@ -969,9 +1055,9 @@ def calculate_net_nitrogen_transfer_from_maom_to_don( to minerals to form mineral associated organic matter [kg C m^-3 day^-1] Returns: - The net rate of transfer from nitrogen contained in mineral associated - organic matter and nitrogen existing as dissolved organic nitrogen [kg N m^-3 - day^-1] + The net nutrient transfer rates of transfer from mineral associated organic + matter into dissolved organic forms. This is currently includes nitrogen and + phosphorus [kg nutrient m^-3 day^-1] """ # Find carbon:nitrogen ratio of the lwmc and maom @@ -981,4 +1067,14 @@ def calculate_net_nitrogen_transfer_from_maom_to_don( maom_nitrogen_gain = lmwc_sorption / c_n_ratio_lmwc maom_nitrogen_loss = (maom_breakdown + maom_desorption) / c_n_ratio_maom - return maom_nitrogen_loss - maom_nitrogen_gain + # Find carbon:phosphorus ratio of the lwmc and maom + c_p_ratio_lmwc = lmwc_carbon / lmwc_phosphorus + c_p_ratio_maom = maom_carbon / maom_phosphorus + + maom_phosphorus_gain = lmwc_sorption / c_p_ratio_lmwc + maom_phosphorus_loss = (maom_breakdown + maom_desorption) / c_p_ratio_maom + + return { + "nitrogen": maom_nitrogen_loss - maom_nitrogen_gain, + "phosphorus": maom_phosphorus_loss - maom_phosphorus_gain, + } diff --git a/virtual_ecosystem/models/soil/soil_model.py b/virtual_ecosystem/models/soil/soil_model.py index 9413e3c28..be664d2d5 100644 --- a/virtual_ecosystem/models/soil/soil_model.py +++ b/virtual_ecosystem/models/soil/soil_model.py @@ -56,6 +56,10 @@ class SoilModel( "soil_n_pool_particulate", "soil_n_pool_necromass", "soil_n_pool_maom", + "soil_p_pool_dop", + "soil_p_pool_particulate", + "soil_p_pool_necromass", + "soil_p_pool_maom", "pH", "bulk_density", "clay_fraction", @@ -73,12 +77,17 @@ class SoilModel( "soil_n_pool_particulate", "soil_n_pool_necromass", "soil_n_pool_maom", + "soil_p_pool_dop", + "soil_p_pool_particulate", + "soil_p_pool_necromass", + "soil_p_pool_maom", "matric_potential", "vertical_flow", "soil_temperature", "soil_moisture", "litter_C_mineralisation_rate", "litter_N_mineralisation_rate", + "litter_P_mineralisation_rate", ), vars_updated=( "soil_c_pool_maom", @@ -92,6 +101,10 @@ class SoilModel( "soil_n_pool_particulate", "soil_n_pool_necromass", "soil_n_pool_maom", + "soil_p_pool_dop", + "soil_p_pool_particulate", + "soil_p_pool_necromass", + "soil_p_pool_maom", ), vars_populated_by_first_update=(), ):