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

Apply overrides in Land and surfaces #82

Merged
merged 26 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5c0f623
Apply overrides in Land
liuly12 Mar 5, 2024
3bac612
Apply overrides in Surface
liuly12 Mar 5, 2024
8702d9a
Apply overrides in ImperviousSurface
liuly12 Mar 5, 2024
0ad68ef
Apply overrides in PerviousSurface
liuly12 Mar 5, 2024
33b7150
Apply overrides in GrowingSurface
liuly12 Mar 5, 2024
ebf13e0
Apply overrides in IrrigationSurface
liuly12 Mar 5, 2024
bf5bbf1
Apply overrides in NutrientPool
liuly12 Mar 5, 2024
ac54634
Add test_land_overrides
liuly12 Mar 5, 2024
9eac911
Add test_surface_overrides
liuly12 Mar 5, 2024
6902447
Add test_impervioussurface_overrides
liuly12 Mar 5, 2024
996d804
Add test_pervioussurface_overrides
liuly12 Mar 5, 2024
108c2bc
Add test_growingsurface_overrides
liuly12 Mar 5, 2024
7195683
Add test_nutrientpool_overrides
liuly12 Mar 5, 2024
325ea01
Apply overrides of data_input_dict in Surface and its superclasses
liuly12 Mar 18, 2024
e9a3ea1
Update warning
liuly12 Apr 10, 2024
8a22275
Remove duplicate line
liuly12 Apr 10, 2024
4b32b9b
Update error
liuly12 Apr 10, 2024
9641dbf
Direct assign to self rather than return variables
liuly12 Apr 10, 2024
962d329
Merge branch 'main' into land-surface-overrides
dalonsoa Jul 16, 2024
f0e1ee7
fix the load error
liuly12 Aug 1, 2024
fc5bc58
pre-commit reformatted
liuly12 Aug 1, 2024
c850d51
merge
barneydobson Oct 1, 2024
0862658
Merge branch 'main' into land-surface-overrides
barneydobson Oct 1, 2024
cbb2df9
fix import
barneydobson Oct 1, 2024
eb0f9b6
typo
barneydobson Oct 1, 2024
a0ef857
fix imports
barneydobson Oct 1, 2024
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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pip install -e .[dev,demos]
## How to cite WSIMOD

[![DOI](https://joss.theoj.org/papers/10.21105/joss.04996/status.svg)](https://doi.org/10.21105/joss.04996)
[![DOI](https://img.shields.io/badge/GMD-10.5194/gmd--17--449--2024-brightgreen)](https://doi.org/10.5194/gmd-17-4495-2024)

If you would like to use our software, please cite it using the following:

Expand Down Expand Up @@ -109,6 +110,32 @@ Find the bibtex citation below:
}
```

Please also include citation to the WSIMOD theory paper:

> Dobson, B., Liu, L. and Mijic, A. (2024)
‘Modelling water quantity and quality for integrated water cycle management with the Water Systems Integrated Modelling framework (WSIMOD) software’,
Geoscientific Model Development.
Copernicus Publications,
17(10),
p. 4495.
doi: 10.5194/gmd-17-4495-2024

Find the bibtex citation below:

```bibtex
@article{gmd-17-4495-2024,
author = {Barnaby Dobson and Leyang Liu and Ana Mijic},
title = {Modelling water quantity and quality for integrated water cycle management with the Water Systems Integrated Modelling framework (WSIMOD) software},
journal = {Geoscientific Model Development},
volume = {17},
year = {2024},
number = {10},
pages = {4495--4513},
url = {https://gmd.copernicus.org/articles/17/4495/2024/},
doi = {10.5194/gmd-17-4495-2024}
}
```

## Acknowledgements

WSIMOD was developed by [Barnaby Dobson](https://github.com/barneydobson) and [Leyang Liu](https://github.com/liuly12).
Expand Down
Binary file added tests/example_data_input_dict.csv.gz
Binary file not shown.
258 changes: 256 additions & 2 deletions tests/test_land.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
PerviousSurface,
Surface,
)
from wsimod.nodes.nodes import Node
from wsimod.nodes.nodes import Node, DecayTank
from wsimod.nodes.sewer import Sewer
from wsimod.nodes.storage import Reservoir
from wsimod.orchestration.model import to_datetime

from pathlib import Path


class MyTestClass(TestCase):
def assertDictAlmostEqual(self, d1, d2, accuracy=19):
Expand Down Expand Up @@ -903,7 +905,7 @@ def test_soil_pool(self):
d1["org-phosphorus"] = disso["P"]
d1["org-nitrogen"] = disso["N"]

self.assertDictAlmostEqual(d1, r1, 15)
self.assertDictAlmostEqual(d1, r1, 14)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get it - why did the normal tests change?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the odd one and I'm not very sure what the reason is. After applying the overrides, if I leave it as 15 float accuracy it will report error, but 14 is fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh that number is float accuracy - no problem from me then

self.assertDictAlmostEqual(d2, r2, 15)

def test_crop_uptake(self):
Expand Down Expand Up @@ -1168,6 +1170,258 @@ def test_garden(self):
d3 = {"phosphate": 0, "temperature": 0, "volume": 0.2 * 0.5 * 1.5}
self.assertDictAlmostEqual(d3, surface.storage, 16)

def test_land_overrides(self):
constants.set_simple_pollutants()
node = Land(name="")
node.apply_overrides(
{
"surface_residence_time": 4.9,
"subsurface_residence_time": 23.7,
"percolation_residence_time": 56.1,
}
)
self.assertEqual(node.surface_residence_time, 4.9)
self.assertEqual(node.surface_runoff.residence_time, 4.9)
self.assertEqual(node.subsurface_residence_time, 23.7)
self.assertEqual(node.subsurface_runoff.residence_time, 23.7)
self.assertEqual(node.percolation_residence_time, 56.1)

def test_surface_overrides(self):
constants.set_default_pollutants()
decaytank = DecayTank()
surface = Surface(
parent=decaytank, area=5, depth=0.1, pollutant_load={"nitrate": 5.7}
)
surface.apply_overrides(
{
"surface": "test_surface",
"area": 9.8,
"depth": 7.5,
"pollutant_load": {"phosphate": 10.1},
"decays": {"nitrate": {"constant": 0.001, "exponent": 1.005}},
}
)
self.assertEqual(surface.surface, "test_surface")
self.assertEqual(surface.area, 9.8)
self.assertEqual(surface.depth, 7.5)
self.assertEqual(surface.capacity, 9.8 * 7.5)
self.assertDictEqual(
surface.pollutant_load, {"nitrate": 5.7, "phosphate": 10.1}
)
self.assertDictEqual(
surface.decays, {"nitrate": {"constant": 0.001, "exponent": 1.005}}
)

# override the data_input_dict
# test the format of dict
new_data_input_dict = {
("temperature", 1): 10,
("temperature", 2): 20,
}
surface.apply_overrides({"data_input_dict": new_data_input_dict})
self.assertDictEqual(surface.data_input_dict, new_data_input_dict)
# test the format of str
new_data_input_dict = str(
Path(__file__).parent / "example_data_input_dict.csv.gz"
)
surface.apply_overrides({"data_input_dict": new_data_input_dict})
from wsimod.orchestration.model import read_csv

new_data_input_dict = read_csv(new_data_input_dict)
self.assertDictEqual(surface.data_input_dict, new_data_input_dict)
print(dict(list(surface.data_input_dict.items())[:5]))

def test_impervioussurface_overrides(self):
constants.set_default_pollutants()
decaytank = DecayTank()
surface = Surface(parent=decaytank, area=5, depth=0.1)
impervioussurface = ImperviousSurface(
parent=surface, area=1.5, et0_to_e=0.9, pore_depth=0.015
)
impervioussurface.apply_overrides(
{"surface": "test_surface", "area": 9.8, "pore_depth": 7.5, "et0_to_e": 3.5}
)
self.assertEqual(impervioussurface.area, 9.8)
self.assertEqual(impervioussurface.pore_depth, 7.5)
self.assertEqual(impervioussurface.depth, 7.5)
self.assertEqual(impervioussurface.capacity, 9.8 * 7.5)
self.assertEqual(impervioussurface.et0_to_e, 3.5)

def test_pervioussurface_overrides(self):
constants.set_default_pollutants()
decaytank = DecayTank()
surface = Surface(parent=decaytank, area=5, depth=0.1)
pervioussurface = PerviousSurface(
parent=surface, depth=0.5, area=1.5, initial_storage=0.5 * 1.5 * 0.25
)
pervioussurface.apply_overrides(
{
"field_capacity": 0.335,
"wilting_point": 0.112,
"total_porosity": 0.476,
"infiltration_capacity": 0.678,
"surface_coefficient": 0.237,
"percolation_coefficient": 0.777,
"et0_coefficient": 0.697,
"ihacres_p": 10.096,
"soil_temp_w_prev": 37.1,
"soil_temp_w_air": 23.6,
"soil_temp_w_deep": 3.4,
"soil_temp_deep": 2.2,
"surface": "test_surface",
"area": 9.8,
"depth": 7.5,
}
)
self.assertEqual(pervioussurface.field_capacity, 0.335)
self.assertEqual(pervioussurface.wilting_point, 0.112)
self.assertEqual(pervioussurface.total_porosity, 0.476)
self.assertEqual(pervioussurface.infiltration_capacity, 0.678)
self.assertEqual(pervioussurface.surface_coefficient, 0.237)
self.assertEqual(pervioussurface.percolation_coefficient, 0.777)
self.assertEqual(pervioussurface.et0_coefficient, 0.697)
self.assertEqual(pervioussurface.ihacres_p, 10.096)
self.assertEqual(pervioussurface.soil_temp_w_prev, 37.1)
self.assertEqual(pervioussurface.soil_temp_w_air, 23.6)
self.assertEqual(pervioussurface.soil_temp_w_deep, 3.4)
self.assertEqual(pervioussurface.soil_temp_deep, 2.2)

self.assertEqual(pervioussurface.field_capacity_m, 0.335 * 7.5)
self.assertEqual(pervioussurface.wilting_point_m, 0.112 * 7.5)
self.assertEqual(pervioussurface.depth, 0.476 * 7.5)
self.assertEqual(pervioussurface.area, 9.8)
self.assertEqual(pervioussurface.capacity, 7.5 * 0.476 * 9.8)
self.assertEqual(pervioussurface.surface, "test_surface")
self.assertEqual(pervioussurface.subsurface_coefficient, 1 - 0.777)

def test_growingsurface_overrides(self):
constants.set_default_pollutants()
decaytank = DecayTank()
surface = Surface(parent=decaytank, area=5, depth=0.1)
pervioussurface = PerviousSurface(
parent=surface, depth=0.5, area=1.5, initial_storage=0.5 * 1.5 * 0.25
)
growingsurface = GrowingSurface(parent=pervioussurface, area=1.5)
overrides = {
"ET_depletion_factor": 0.521,
"crop_cover_max": 1.342,
"ground_cover_max": 1.111,
"crop_factor_stages": [1, 2, 1],
"crop_factor_stage_dates": [1, 32, 90],
"sowing_day": 35,
"harvest_day": 89,
"satact": 0.567,
"thetaupp": 4.324,
"thetalow": 3.582,
"thetapow": 7.324,
"uptake1": 1.278,
"uptake2": 2.753,
"uptake3": 5.298,
"uptake_PNratio": 3.263,
"erodibility": 2.863,
"sreroexp": 5.634,
"cohesion": 8.903,
"slope": 6.231,
"srfilt": 9.231,
"macrofilt": 7.394,
"limpar": 4.211,
"exppar": 5.872,
"hsatINs": 20.321,
"denpar": 0.204,
"adosorption_nr_limit": 1.943,
"adsorption_nr_maxiter": 6321,
"kfr": 80.2,
"nfr": 42.3,
"kadsdes": 0.972,
"bulk_density": 1672,
"field_capacity": 0.335,
"wilting_point": 0.112,
"total_porosity": 0.476,
"rooting_depth": 7.5,
}
overrides_to_check = overrides.copy()
growingsurface.apply_overrides(overrides)

for k, v in overrides_to_check.items():
if isinstance(v, list):
self.assertListEqual(getattr(growingsurface, k), v)
else:
self.assertEqual(getattr(growingsurface, k), v)

harvest_sow_calendar = [
0,
35,
89,
89 + 1,
365,
]
self.assertListEqual(growingsurface.harvest_sow_calendar, harvest_sow_calendar)
self.assertListEqual(growingsurface.ground_cover_stages, [0, 0, 1.111, 0, 0])
self.assertListEqual(growingsurface.crop_cover_stages, [0, 0, 1.342, 0, 0])
self.assertEqual(growingsurface.autumn_sow, False)
self.assertEqual(growingsurface.total_available_water, (0.335 - 0.112) * 7.5)
self.assertEqual(
growingsurface.readily_available_water, (0.335 - 0.112) * 7.5 * 0.521
)
self.assertEqual(growingsurface.depth, 0.476 * 7.5)
self.assertEqual(growingsurface.capacity, 0.476 * 7.5 * 1.5)

def test_nutrientpool_overrides(self):
constants.set_default_pollutants()
decaytank = DecayTank()
surface = Surface(parent=decaytank, area=5, depth=0.1)
pervioussurface = PerviousSurface(
parent=surface, depth=0.5, area=1.5, initial_storage=0.5 * 1.5 * 0.25
)
growingsurface = GrowingSurface(parent=pervioussurface, area=1.5)
overrides = {
"fraction_dry_n_to_dissolved_inorganic": 0.29,
"degrhpar": {"N": 7 * 1e-1},
"dishpar": {"P": 7 * 1e-1},
"minfpar": {"N": 1.00013, "P": 1.000003},
"disfpar": {"N": 1.000003, "P": 1.0000001},
"immobdpar": {"N": 1.0056, "P": 1.2866},
"fraction_manure_to_dissolved_inorganic": {"N": 0.35, "P": 0.21},
"fraction_residue_to_fast": {"N": 0.61, "P": 0.71},
}
growingsurface.nutrient_pool.apply_overrides(overrides)
self.assertEqual(
growingsurface.nutrient_pool.fraction_dry_n_to_dissolved_inorganic, 0.29
)
self.assertDictEqual(
growingsurface.nutrient_pool.degrhpar, {"N": 7 * 1e-1, "P": 7 * 1e-6}
)
self.assertDictEqual(
growingsurface.nutrient_pool.dishpar, {"N": 7 * 1e-5, "P": 7 * 1e-1}
)
self.assertDictEqual(
growingsurface.nutrient_pool.minfpar, {"N": 1.00013, "P": 1.000003}
)
self.assertDictEqual(
growingsurface.nutrient_pool.disfpar, {"N": 1.000003, "P": 1.0000001}
)
self.assertDictEqual(
growingsurface.nutrient_pool.immobdpar, {"N": 1.0056, "P": 1.2866}
)
self.assertDictEqual(
growingsurface.nutrient_pool.fraction_manure_to_dissolved_inorganic,
{"N": 0.35, "P": 0.21},
)
self.assertDictEqual(
growingsurface.nutrient_pool.fraction_residue_to_fast,
{"N": 0.61, "P": 0.71},
)

self.assertDictEqual(
growingsurface.nutrient_pool.fraction_manure_to_fast,
{"N": 1 - 0.35, "P": 1 - 0.21},
)
self.assertDictEqual(
growingsurface.nutrient_pool.fraction_residue_to_humus,
{"N": 1 - 0.61, "P": 1 - 0.71},
)
self.assertEqual(growingsurface.nutrient_pool.fraction_dry_n_to_fast, 0.71)


if __name__ == "__main__":
unittest.main()
Loading
Loading