From 769a27c5afc7c4bb2483004c95d59ce45de4852c Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:06:05 +0000 Subject: [PATCH 1/9] Added test file for i.biomass module --- imagery/i.biomass/testsuite/test_i_biomass.py | 357 ++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 imagery/i.biomass/testsuite/test_i_biomass.py diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py new file mode 100644 index 00000000000..df939e6d5c8 --- /dev/null +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -0,0 +1,357 @@ +import numpy as np +from grass.script import array +from grass.gunittest.case import TestCase +from grass.gunittest.main import test + + +class TestIBiomass(TestCase): + """Regression tests for the i.biomass GRASS GIS module.""" + + input_rasters = { + "fpar": "test_fpar", + "lightuse_eff": "test_lightuse_eff", + "latitude": "test_latitude", + "dayofyear": "test_dayofyear", + "transmissivity": "test_transmissivity", + "water": "test_water_availability", + } + output_raster = "biomass_output" + + @classmethod + def setUpClass(cls): + """Set up input rasters and configure test environment.""" + cls.use_temp_region() + cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10) + + cls.runModule( + "r.mapcalc", + expression=f"{cls.input_rasters['fpar']} = col() * 0.1", + overwrite=True, + ) + cls.runModule( + "r.mapcalc", + expression=f"{cls.input_rasters['lightuse_eff']} = row() * 0.1", + overwrite=True, + ) + cls.runModule( + "r.mapcalc", + expression=f"{cls.input_rasters['latitude']} = 45.0", + overwrite=True, + ) + cls.runModule( + "r.mapcalc", + expression=f"{cls.input_rasters['dayofyear']} = 150", + overwrite=True, + ) + cls.runModule( + "r.mapcalc", + expression=f"{cls.input_rasters['transmissivity']} = 0.75", + overwrite=True, + ) + cls.runModule( + "r.mapcalc", + expression=f"{cls.input_rasters['water']} = 0.8", + overwrite=True, + ) + + @classmethod + def tearDownClass(cls): + """Clean up generated data and reset the region.""" + rasters_to_remove = list(cls.input_rasters.values()) + [cls.output_raster] + cls.runModule( + "g.remove", + type="raster", + name=",".join(rasters_to_remove), + flags="f", + quiet=True, + ) + cls.del_temp_region() + + def test_biomass_with_zero_inputs(self): + """Test the behavior of i.biomass when all inputs are zero.""" + for raster in self.input_rasters.values(): + self.runModule("r.mapcalc", expression=f"{raster} = 0", overwrite=True) + + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + self.assertRasterExists(self.output_raster) + + output_values = array.array(self.output_raster) + self.assertTrue( + np.allclose(output_values, 0), "Biomass raster should be all zeros" + ) + + def test_biomass_linearity(self): + """Test linearity of i.biomass by scaling inputs.""" + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['fpar']} = col() * 0.5", + overwrite=True, + ) + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + self.assertRasterExists(self.output_raster) + + scaled_output_values = array.array(self.output_raster) + + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['fpar']} = col() * 1.0", + overwrite=True, + ) + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + self.assertRasterExists(self.output_raster) + + original_output_values = array.array(self.output_raster) + self.assertTrue( + np.allclose(scaled_output_values * 2, original_output_values, atol=1e-5), + "Linearity property failed for biomass computation", + ) + + def test_biomass_with_extreme_values(self): + """Test the behavior of i.biomass with extreme input values.""" + extreme_values = { + "fpar": [0, 1], + "lightuse_eff": [0, 10], + "latitude": [-90, 90], + "dayofyear": [1, 365], + "transmissivity": [0, 1], + "water": [0, 1], + } + + for key, (min_val, max_val) in extreme_values.items(): + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters[key]} = {min_val}", + overwrite=True, + ) + + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + self.assertRasterExists(self.output_raster) + + output_values_min = array.array(self.output_raster) + self.assertTrue( + np.all(output_values_min >= 0), + "Biomass output should not contain negative values.", + ) + + for key, (min_val, max_val) in extreme_values.items(): + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters[key]} = {max_val}", + overwrite=True, + ) + + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + self.assertRasterExists(self.output_raster) + + output_values_max = array.array(self.output_raster) + self.assertTrue( + np.all(np.isfinite(output_values_max)), + "Biomass output contains non-finite values.", + ) + + def test_biomass_large_processing(self): + """Test processing large input rasters with i.biomass.""" + self.runModule("g.region", n=90, s=-90, e=180, w=-180, rows=1000, cols=1000) + + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['fpar']} = col() * 0.01", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['lightuse_eff']} = row() * 0.01", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['latitude']} = 45.0", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['dayofyear']} = 150", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['transmissivity']} = 0.75", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['water']} = 0.8", + overwrite=True, + ) + + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + + self.assertRasterExists(self.output_raster) + + output_values = array.array(self.output_raster) + self.assertTrue( + np.isfinite(output_values).all(), + "Output contains non-finite values for large input rasters.", + ) + + def test_biomass_latitude_dependency(self): + """Test that biomass values vary reasonably with latitude.""" + + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['latitude']} = 0", + overwrite=True, + ) + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + equatorial_output = array.array(self.output_raster) + + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['latitude']} = 90", + overwrite=True, + ) + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + polar_output = array.array(self.output_raster) + + self.assertTrue( + np.mean(equatorial_output) > np.mean(polar_output), + "Biomass at equatorial regions should generally exceed" + "biomass at polar regions.", + ) + + def test_biomass_ecological_range(self): + """Test that biomass values fall within an expected ecological range.""" + + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['fpar']} = col() * 0.5", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['lightuse_eff']} = row() * 0.1", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['latitude']} = 45.0", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['dayofyear']} = 150", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['transmissivity']} = 0.75", + overwrite=True, + ) + self.runModule( + "r.mapcalc", + expression=f"{self.input_rasters['water']} = 0.8", + overwrite=True, + ) + + self.assertModule( + "i.biomass", + fpar=self.input_rasters["fpar"], + lightuse_efficiency=self.input_rasters["lightuse_eff"], + latitude=self.input_rasters["latitude"], + dayofyear=self.input_rasters["dayofyear"], + transmissivity_singleway=self.input_rasters["transmissivity"], + water_availability=self.input_rasters["water"], + output=self.output_raster, + overwrite=True, + ) + self.assertRasterExists(self.output_raster) + + output_values = array.array(self.output_raster) + self.assertTrue( + np.all((output_values >= 0) & (output_values <= 1000)), + "Biomass output values should be within the range [0, 1000].", + ) + + +if __name__ == "__main__": + test() From e479b2059b760eb67e99c2d7eaeb47786fa0aee0 Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Fri, 31 Jan 2025 00:18:50 +0000 Subject: [PATCH 2/9] Addressed the review comments --- imagery/i.biomass/testsuite/test_i_biomass.py | 115 ++++-------------- 1 file changed, 25 insertions(+), 90 deletions(-) diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py index df939e6d5c8..fbbb5aa429e 100644 --- a/imagery/i.biomass/testsuite/test_i_biomass.py +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -22,37 +22,24 @@ def setUpClass(cls): """Set up input rasters and configure test environment.""" cls.use_temp_region() cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10) + cls._create_input_rasters() - cls.runModule( - "r.mapcalc", - expression=f"{cls.input_rasters['fpar']} = col() * 0.1", - overwrite=True, - ) - cls.runModule( - "r.mapcalc", - expression=f"{cls.input_rasters['lightuse_eff']} = row() * 0.1", - overwrite=True, - ) - cls.runModule( - "r.mapcalc", - expression=f"{cls.input_rasters['latitude']} = 45.0", - overwrite=True, - ) - cls.runModule( - "r.mapcalc", - expression=f"{cls.input_rasters['dayofyear']} = 150", - overwrite=True, - ) - cls.runModule( - "r.mapcalc", - expression=f"{cls.input_rasters['transmissivity']} = 0.75", - overwrite=True, - ) - cls.runModule( - "r.mapcalc", - expression=f"{cls.input_rasters['water']} = 0.8", - overwrite=True, - ) + @classmethod + def _create_input_rasters(cls): + """Helper method to create all input rasters with defined expressions.""" + expressions = { + "fpar": "col() * 0.1", + "lightuse_eff": "row() * 0.1", + "latitude": "45.0", + "dayofyear": "150", + "transmissivity": "0.75", + "water": "0.8", + } + for raster_key, expr in expressions.items(): + raster_name = cls.input_rasters[raster_key] + cls.runModule( + "r.mapcalc", expression=f"{raster_name} = {expr}", overwrite=True + ) @classmethod def tearDownClass(cls): @@ -67,10 +54,9 @@ def tearDownClass(cls): ) cls.del_temp_region() - def test_biomass_with_zero_inputs(self): - """Test the behavior of i.biomass when all inputs are zero.""" - for raster in self.input_rasters.values(): - self.runModule("r.mapcalc", expression=f"{raster} = 0", overwrite=True) + def test_biomass_regression(self): + """Regression test to ensure i.biomass output remains consistent.""" + reference_raster = "biomass_reference" self.assertModule( "i.biomass", @@ -84,10 +70,14 @@ def test_biomass_with_zero_inputs(self): overwrite=True, ) self.assertRasterExists(self.output_raster) + self.assertRasterExists(reference_raster) output_values = array.array(self.output_raster) + reference_values = array.array(reference_raster) + self.assertTrue( - np.allclose(output_values, 0), "Biomass raster should be all zeros" + np.allclose(output_values, reference_values, atol=2.0), + "Biomass raster values should match the reference values", ) def test_biomass_linearity(self): @@ -199,61 +189,6 @@ def test_biomass_with_extreme_values(self): "Biomass output contains non-finite values.", ) - def test_biomass_large_processing(self): - """Test processing large input rasters with i.biomass.""" - self.runModule("g.region", n=90, s=-90, e=180, w=-180, rows=1000, cols=1000) - - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['fpar']} = col() * 0.01", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['lightuse_eff']} = row() * 0.01", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['latitude']} = 45.0", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['dayofyear']} = 150", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['transmissivity']} = 0.75", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['water']} = 0.8", - overwrite=True, - ) - - self.assertModule( - "i.biomass", - fpar=self.input_rasters["fpar"], - lightuse_efficiency=self.input_rasters["lightuse_eff"], - latitude=self.input_rasters["latitude"], - dayofyear=self.input_rasters["dayofyear"], - transmissivity_singleway=self.input_rasters["transmissivity"], - water_availability=self.input_rasters["water"], - output=self.output_raster, - overwrite=True, - ) - - self.assertRasterExists(self.output_raster) - - output_values = array.array(self.output_raster) - self.assertTrue( - np.isfinite(output_values).all(), - "Output contains non-finite values for large input rasters.", - ) - def test_biomass_latitude_dependency(self): """Test that biomass values vary reasonably with latitude.""" From 21eba7527e47a80681ee9ea2d10a3f5ed5dc77f6 Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Fri, 31 Jan 2025 03:46:18 +0000 Subject: [PATCH 3/9] added a fix to create reference raster --- imagery/i.biomass/testsuite/test_i_biomass.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py index fbbb5aa429e..b34f5da2520 100644 --- a/imagery/i.biomass/testsuite/test_i_biomass.py +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -23,6 +23,7 @@ def setUpClass(cls): cls.use_temp_region() cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10) cls._create_input_rasters() + cls._create_reference_raster() @classmethod def _create_input_rasters(cls): @@ -41,6 +42,21 @@ def _create_input_rasters(cls): "r.mapcalc", expression=f"{raster_name} = {expr}", overwrite=True ) + @classmethod + def _create_reference_raster(cls): + """Create the reference raster for regression testing.""" + cls.runModule( + "i.biomass", + fpar=cls.input_rasters["fpar"], + lightuse_efficiency=cls.input_rasters["lightuse_eff"], + latitude=cls.input_rasters["latitude"], + dayofyear=cls.input_rasters["dayofyear"], + transmissivity_singleway=cls.input_rasters["transmissivity"], + water_availability=cls.input_rasters["water"], + output="biomass_reference", + overwrite=True, + ) + @classmethod def tearDownClass(cls): """Clean up generated data and reset the region.""" From 140a78ea7dee9e64b09f915e946e33026fb84102 Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Fri, 31 Jan 2025 05:07:47 +0000 Subject: [PATCH 4/9] fixed the line causing error --- imagery/i.biomass/testsuite/test_i_biomass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py index b34f5da2520..b54aa75b35a 100644 --- a/imagery/i.biomass/testsuite/test_i_biomass.py +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -23,7 +23,6 @@ def setUpClass(cls): cls.use_temp_region() cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10) cls._create_input_rasters() - cls._create_reference_raster() @classmethod def _create_input_rasters(cls): @@ -72,6 +71,7 @@ def tearDownClass(cls): def test_biomass_regression(self): """Regression test to ensure i.biomass output remains consistent.""" + self._create_reference_raster() reference_raster = "biomass_reference" self.assertModule( From 473a5e976e91ccbfd7ea933f2aa8e1975728aaed Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Wed, 5 Feb 2025 15:37:28 +0000 Subject: [PATCH 5/9] Addressed the review comments --- imagery/i.biomass/testsuite/test_i_biomass.py | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py index b54aa75b35a..d56f61e7fe2 100644 --- a/imagery/i.biomass/testsuite/test_i_biomass.py +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -69,11 +69,23 @@ def tearDownClass(cls): ) cls.del_temp_region() - def test_biomass_regression(self): - """Regression test to ensure i.biomass output remains consistent.""" - self._create_reference_raster() - reference_raster = "biomass_reference" - + def test_biomass_against_reference(self): + """ + Compare output of i.biomass with precomputed reference statistics. + The reference raster was created using the following commands: + g.region n=10 s=0 e=10 w=0 rows=10 cols=10 + r.mapcalc "test_fpar = col() * 0.1" + r.mapcalc "test_lightuse_eff = row() * 0.1" + r.mapcalc "test_latitude = 45.0" + r.mapcalc "test_dayofyear = 150" + r.mapcalc "test_transmissivity = 0.75" + r.mapcalc "test_water_availability = 0.8" + i.biomass fpar=test_fpar lightuse_efficiency=test_lightuse_eff \ + latitude=test_latitude dayofyear=test_dayofyear \ + transmissivity_singleway=test_transmissivity \ + water_availability=test_water_availability output=biomass_reference + r.univar -g biomass_reference + """ self.assertModule( "i.biomass", fpar=self.input_rasters["fpar"], @@ -86,14 +98,16 @@ def test_biomass_regression(self): overwrite=True, ) self.assertRasterExists(self.output_raster) - self.assertRasterExists(reference_raster) - output_values = array.array(self.output_raster) - reference_values = array.array(reference_raster) + expected_stats = ( + "min=4.51592674628609\n" + "max=75.2654457714349\n" + "mean=33.1167961394313\n" + "stddev=18.5128518411928" + ) - self.assertTrue( - np.allclose(output_values, reference_values, atol=2.0), - "Biomass raster values should match the reference values", + self.assertRasterFitsUnivar( + raster=self.output_raster, reference=expected_stats, precision=1e-8 ) def test_biomass_linearity(self): From 68879a8085aa39a1ee7ddad5eab2201bd01e9597 Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Wed, 5 Feb 2025 15:47:08 +0000 Subject: [PATCH 6/9] removed extra lines of code --- imagery/i.biomass/testsuite/test_i_biomass.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py index d56f61e7fe2..83eeb6f3ad7 100644 --- a/imagery/i.biomass/testsuite/test_i_biomass.py +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -41,21 +41,6 @@ def _create_input_rasters(cls): "r.mapcalc", expression=f"{raster_name} = {expr}", overwrite=True ) - @classmethod - def _create_reference_raster(cls): - """Create the reference raster for regression testing.""" - cls.runModule( - "i.biomass", - fpar=cls.input_rasters["fpar"], - lightuse_efficiency=cls.input_rasters["lightuse_eff"], - latitude=cls.input_rasters["latitude"], - dayofyear=cls.input_rasters["dayofyear"], - transmissivity_singleway=cls.input_rasters["transmissivity"], - water_availability=cls.input_rasters["water"], - output="biomass_reference", - overwrite=True, - ) - @classmethod def tearDownClass(cls): """Clean up generated data and reset the region.""" From ad963ac20afec262f334b1811762145575fe3154 Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:56:37 +0000 Subject: [PATCH 7/9] refactored the code and made adjustments --- imagery/i.biomass/testsuite/test_i_biomass.py | 61 ++++++------------- 1 file changed, 19 insertions(+), 42 deletions(-) diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py index 83eeb6f3ad7..a3b17ea7316 100644 --- a/imagery/i.biomass/testsuite/test_i_biomass.py +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -22,12 +22,10 @@ def setUpClass(cls): """Set up input rasters and configure test environment.""" cls.use_temp_region() cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10) - cls._create_input_rasters() - @classmethod - def _create_input_rasters(cls): - """Helper method to create all input rasters with defined expressions.""" - expressions = { + def setUp(self): + """Reset input rasters to default state before each test.""" + input_expressions = { "fpar": "col() * 0.1", "lightuse_eff": "row() * 0.1", "latitude": "45.0", @@ -35,6 +33,11 @@ def _create_input_rasters(cls): "transmissivity": "0.75", "water": "0.8", } + self._create_input_rasters(input_expressions) + + @classmethod + def _create_input_rasters(cls, expressions): + """Helper method to create input rasters with specified expressions.""" for raster_key, expr in expressions.items(): raster_name = cls.input_rasters[raster_key] cls.runModule( @@ -84,15 +87,10 @@ def test_biomass_against_reference(self): ) self.assertRasterExists(self.output_raster) - expected_stats = ( - "min=4.51592674628609\n" - "max=75.2654457714349\n" - "mean=33.1167961394313\n" - "stddev=18.5128518411928" - ) + expected_stats = "min=0.752654\nmax=75.265445\nmean=22.767797\nstddev=17.924991" self.assertRasterFitsUnivar( - raster=self.output_raster, reference=expected_stats, precision=1e-8 + raster=self.output_raster, reference=expected_stats, precision=1e-6 ) def test_biomass_linearity(self): @@ -252,36 +250,15 @@ def test_biomass_latitude_dependency(self): def test_biomass_ecological_range(self): """Test that biomass values fall within an expected ecological range.""" - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['fpar']} = col() * 0.5", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['lightuse_eff']} = row() * 0.1", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['latitude']} = 45.0", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['dayofyear']} = 150", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['transmissivity']} = 0.75", - overwrite=True, - ) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['water']} = 0.8", - overwrite=True, - ) + test_expressions = { + "fpar": "col() * 0.5", + "lightuse_eff": "row() * 0.1", + "latitude": "45.0", + "dayofyear": "150", + "transmissivity": "0.75", + "water": "0.8", + } + self._create_input_rasters(test_expressions) self.assertModule( "i.biomass", From 2d1e0075e7977adafd2a115001e16a411285a85f Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Sun, 9 Feb 2025 21:31:20 +0000 Subject: [PATCH 8/9] removed redundant setUp method --- imagery/i.biomass/testsuite/test_i_biomass.py | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py index a3b17ea7316..1a76459dfbe 100644 --- a/imagery/i.biomass/testsuite/test_i_biomass.py +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -23,18 +23,6 @@ def setUpClass(cls): cls.use_temp_region() cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10) - def setUp(self): - """Reset input rasters to default state before each test.""" - input_expressions = { - "fpar": "col() * 0.1", - "lightuse_eff": "row() * 0.1", - "latitude": "45.0", - "dayofyear": "150", - "transmissivity": "0.75", - "water": "0.8", - } - self._create_input_rasters(input_expressions) - @classmethod def _create_input_rasters(cls, expressions): """Helper method to create input rasters with specified expressions.""" @@ -95,11 +83,16 @@ def test_biomass_against_reference(self): def test_biomass_linearity(self): """Test linearity of i.biomass by scaling inputs.""" - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['fpar']} = col() * 0.5", - overwrite=True, - ) + input_expressions = { + "fpar": "col() * 0.5", + "lightuse_eff": "row() * 0.1", + "latitude": "45.0", + "dayofyear": "150", + "transmissivity": "0.75", + "water": "0.8", + } + self._create_input_rasters(input_expressions) + self.assertModule( "i.biomass", fpar=self.input_rasters["fpar"], @@ -204,12 +197,16 @@ def test_biomass_with_extreme_values(self): def test_biomass_latitude_dependency(self): """Test that biomass values vary reasonably with latitude.""" + input_expressions = { + "fpar": "col() * 0.1", + "lightuse_eff": "row() * 0.1", + "latitude": "0", + "dayofyear": "150", + "transmissivity": "0.75", + "water": "0.8", + } + self._create_input_rasters(input_expressions) - self.runModule( - "r.mapcalc", - expression=f"{self.input_rasters['latitude']} = 0", - overwrite=True, - ) self.assertModule( "i.biomass", fpar=self.input_rasters["fpar"], @@ -243,14 +240,12 @@ def test_biomass_latitude_dependency(self): self.assertTrue( np.mean(equatorial_output) > np.mean(polar_output), - "Biomass at equatorial regions should generally exceed" - "biomass at polar regions.", + "Biomass at equatorial regions should generally exceed biomass at polar regions.", ) def test_biomass_ecological_range(self): """Test that biomass values fall within an expected ecological range.""" - - test_expressions = { + input_expressions = { "fpar": "col() * 0.5", "lightuse_eff": "row() * 0.1", "latitude": "45.0", @@ -258,7 +253,7 @@ def test_biomass_ecological_range(self): "transmissivity": "0.75", "water": "0.8", } - self._create_input_rasters(test_expressions) + self._create_input_rasters(input_expressions) self.assertModule( "i.biomass", From 96654eeb8c7c9932883ce1a852e72939af84a176 Mon Sep 17 00:00:00 2001 From: Jayneel Shah <80264736+jayneel-shah18@users.noreply.github.com> Date: Sun, 9 Feb 2025 22:45:05 +0000 Subject: [PATCH 9/9] fixed the error --- imagery/i.biomass/testsuite/test_i_biomass.py | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/imagery/i.biomass/testsuite/test_i_biomass.py b/imagery/i.biomass/testsuite/test_i_biomass.py index 1a76459dfbe..e4fd3732f39 100644 --- a/imagery/i.biomass/testsuite/test_i_biomass.py +++ b/imagery/i.biomass/testsuite/test_i_biomass.py @@ -23,6 +23,16 @@ def setUpClass(cls): cls.use_temp_region() cls.runModule("g.region", n=10, s=0, e=10, w=0, rows=10, cols=10) + input_expressions = { + "fpar": "col() * 0.1", + "lightuse_eff": "row() * 0.1", + "latitude": "45.0", + "dayofyear": "150", + "transmissivity": "0.75", + "water": "0.8", + } + cls._create_input_rasters(input_expressions) + @classmethod def _create_input_rasters(cls, expressions): """Helper method to create input rasters with specified expressions.""" @@ -62,6 +72,16 @@ def test_biomass_against_reference(self): water_availability=test_water_availability output=biomass_reference r.univar -g biomass_reference """ + input_expressions = { + "fpar": "col() * 0.1", + "lightuse_eff": "row() * 0.1", + "latitude": "45.0", + "dayofyear": "150", + "transmissivity": "0.75", + "water": "0.8", + } + self._create_input_rasters(input_expressions) + self.assertModule( "i.biomass", fpar=self.input_rasters["fpar"], @@ -76,7 +96,6 @@ def test_biomass_against_reference(self): self.assertRasterExists(self.output_raster) expected_stats = "min=0.752654\nmax=75.265445\nmean=22.767797\nstddev=17.924991" - self.assertRasterFitsUnivar( raster=self.output_raster, reference=expected_stats, precision=1e-6 )